Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a305d6e725 | |||
| 1feff344b8 | |||
| 4fa4ffae54 | |||
| 4ecd72de6e | |||
| 3ec495c3fc | |||
| 5efc437384 | |||
| a777f4d3b1 |
+11
-6
@@ -104,6 +104,12 @@ example) a dissolve would cause the overlay to blink out and then
|
||||
dissolve back in again.
|
||||
|
||||
|
||||
MoveTransition and define.move_transitions have been changed to take
|
||||
a layers argument, giving the list of layers the transition applies
|
||||
to. By default, this is only the master layer, which is a change in
|
||||
their behavior.
|
||||
|
||||
|
||||
Calling theme.roundrect() no longer implies layout.button_menu().
|
||||
|
||||
|
||||
@@ -111,16 +117,15 @@ Ren'Py now autosaves when entering the quit prompt, and will not actually
|
||||
quit until this autosave is complete.
|
||||
|
||||
|
||||
The default framerate limit has been raised to 100fps. This make
|
||||
tearing less noticable than on a 60hz screen.
|
||||
|
||||
|
||||
Fixed a divide by zero error that occured when Alpha was used for 0
|
||||
seconds.
|
||||
|
||||
|
||||
The sound libraries have been upgraded:
|
||||
|
||||
* libvorbis is now at 1.2.0
|
||||
* SDL_sound is now a development version, which includes the mpg123
|
||||
decoder. According to the release announcment: ". Unlike mpglib, this
|
||||
decoder seems to play mp3s that were recorded after 1999, too. :-)"
|
||||
Libvorbis has been upgraded to version 1.2.0.
|
||||
|
||||
|
||||
To reduce distribution size, OGG Speex support was dropped.
|
||||
|
||||
@@ -62,58 +62,67 @@ init -1110 python:
|
||||
return .5 - math.cos(math.pi * x) / 2.0
|
||||
|
||||
# This defines a family of move transitions.
|
||||
def move_transitions(prefix, delay, time_warp=None, in_time_warp=None, out_time_warp=None, old=False):
|
||||
def move_transitions(prefix, delay, time_warp=None, in_time_warp=None, out_time_warp=None, old=False, layers=[ 'master' ]):
|
||||
moves = {
|
||||
"" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp)),
|
||||
|
||||
"inright" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((1.0, None, 0.0, None), time_warp=in_time_warp)),
|
||||
|
||||
"inleft" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((0.0, None, 1.0, None), time_warp=in_time_warp)),
|
||||
|
||||
"intop" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((None, 0.0, None, 1.0), time_warp=in_time_warp)),
|
||||
|
||||
"inbottom" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
enter_factory=MoveIn((None, 1.0, None, 0.0), time_warp=in_time_warp)),
|
||||
|
||||
"outright" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((1.0, None, 0.0, None), time_warp=out_time_warp)),
|
||||
|
||||
"outleft" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((0.0, None, 1.0, None), time_warp=out_time_warp)),
|
||||
|
||||
"outtop" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((None, 0.0, None, 1.0), time_warp=out_time_warp)),
|
||||
|
||||
"outbottom" : MoveTransition(
|
||||
delay,
|
||||
old=old,
|
||||
layers=layers,
|
||||
factory=MoveFactory(time_warp=time_warp),
|
||||
leave_factory=MoveOut((None, 1.0, None, 0.0), time_warp=time_warp)),
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ label demo_multimedia:
|
||||
# This plays a sound effect.
|
||||
play sound "18005551212.ogg"
|
||||
|
||||
e "We can also play up to eight channels of sound effects on top of the music."
|
||||
e "We can play two channels of sound effects on top of the music."
|
||||
|
||||
e "Voice support is included as part of Ren'Py, although we don't yet have a demonstration."
|
||||
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ label new:
|
||||
if d.startswith("."):
|
||||
dirs.remove(d)
|
||||
dn = dir + "/" + d
|
||||
shutil.rmtree(dn)
|
||||
shutil.rmtree(dn, True)
|
||||
|
||||
# Change the save directory.
|
||||
options = file(name + "/game/options.rpy").read()
|
||||
|
||||
+21
-6
@@ -79,6 +79,13 @@
|
||||
movq_r2m(r, scratch); \
|
||||
printf(s, scratch);
|
||||
|
||||
// This expands registers 4 and 5, which are initialized below.
|
||||
#define MMX_EXPAND() \
|
||||
pxor_r2r(mm2, mm2); \
|
||||
punpcklbw_r2r(mm2, mm4); \
|
||||
punpcklbw_r2r(mm2, mm5);
|
||||
|
||||
|
||||
// This expects the two old pixels to be arranged like:
|
||||
// mm4 mm0
|
||||
// mm5 mm1
|
||||
@@ -159,7 +166,7 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
|
||||
|
||||
long long scratch;
|
||||
|
||||
|
||||
if (!SDL_HasMMX()) {
|
||||
return 0;
|
||||
}
|
||||
@@ -207,7 +214,8 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
}
|
||||
|
||||
// Figure out how many pixels we need to draw on each line.
|
||||
normal_pixels = min(srcw - sy - 1, dstw - xo);
|
||||
normal_pixels = min(srcw - sx - 1, dstw - xo);
|
||||
|
||||
if (normal_pixels < dstw - xo) {
|
||||
draw_finalx = 1;
|
||||
} else {
|
||||
@@ -228,11 +236,11 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
if (xo >= dstw) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
// Draw the first line, when sy == -1.
|
||||
|
||||
if (sy == -1) {
|
||||
|
||||
|
||||
if (yo >= dsth) {
|
||||
goto done;
|
||||
}
|
||||
@@ -249,7 +257,8 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
|
||||
movd_m2r(blankpixel, mm4);
|
||||
movd_m2r(pixel, mm5);
|
||||
|
||||
|
||||
MMX_EXPAND();
|
||||
s1 += 4;
|
||||
|
||||
d = dstpixels + xo * 4 + yo * dstpitch;
|
||||
@@ -300,17 +309,21 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
movd_m2r(* (unsigned int *) s1, mm5);
|
||||
}
|
||||
|
||||
MMX_EXPAND();
|
||||
|
||||
s0 += 4;
|
||||
s1 += 4;
|
||||
|
||||
d = dstpixels + xo * 4 + yo * dstpitch;
|
||||
dend = d + normal_pixels * 4;
|
||||
|
||||
unsigned char *dp = d;
|
||||
|
||||
while (d != dend) {
|
||||
movd_m2r(* (unsigned int *) s0, mm0);
|
||||
movd_m2r(* (unsigned int *) s1, mm1);
|
||||
MMX_INTERP(* (unsigned int *) d);
|
||||
|
||||
|
||||
d += 4;
|
||||
s0 += 4;
|
||||
s1 += 4;
|
||||
@@ -354,6 +367,8 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
|
||||
movd_m2r(blankpixel, mm5);
|
||||
}
|
||||
|
||||
MMX_EXPAND();
|
||||
|
||||
s0 += 4;
|
||||
|
||||
d = dstpixels + xo * 4 + yo * dstpitch;
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@
|
||||
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
|
||||
# Be sure to change script_version in launcher/script_version.rpy, too!
|
||||
# Also check to see if we have to update renpy.py.
|
||||
version = "Ren'Py 6.9.0a"
|
||||
version = "Ren'Py 6.9.0d"
|
||||
script_version = 5003000
|
||||
savegame_suffix = "-LT1.save"
|
||||
|
||||
|
||||
@@ -257,6 +257,8 @@ def bootstrap(renpy_base):
|
||||
keep_running = False
|
||||
|
||||
except KeyboardInterrupt:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
break
|
||||
|
||||
except renpy.game.UtterRestartException:
|
||||
@@ -362,6 +364,7 @@ def report_exception(e):
|
||||
print >>f
|
||||
|
||||
print >>f, renpy.game.exception_info
|
||||
report_tb(f, tb)
|
||||
|
||||
print >>f
|
||||
print >>f, "Ren'Py Version:", renpy.version
|
||||
|
||||
+1
-1
@@ -262,7 +262,7 @@ font_replacement_map = { }
|
||||
with_callback = None
|
||||
|
||||
# The framerate limit, in frames per second.
|
||||
framerate = 60
|
||||
framerate = 100
|
||||
|
||||
# The number of frames that Ren'Py has shown.
|
||||
frames = 0
|
||||
|
||||
+19
-14
@@ -289,13 +289,16 @@ class Displayable(renpy.object.Object):
|
||||
xoff = xpos
|
||||
|
||||
if type(xoff) is float:
|
||||
xoff = xoff * width
|
||||
xoff_mul = width
|
||||
else:
|
||||
xoff_mul = 1
|
||||
|
||||
if type(xanchor) is float:
|
||||
xoff -= sw * xanchor
|
||||
xanchor_mul = sw
|
||||
else:
|
||||
xoff -= xanchor
|
||||
xanchor_mul = 1
|
||||
|
||||
xoff = xoff * xoff_mul - xanchor * xanchor_mul
|
||||
xoff += x
|
||||
|
||||
# y
|
||||
@@ -303,13 +306,16 @@ class Displayable(renpy.object.Object):
|
||||
yoff = ypos
|
||||
|
||||
if type(yoff) is float:
|
||||
yoff = yoff * height
|
||||
yoff_mul = height
|
||||
else:
|
||||
yoff_mul = 1
|
||||
|
||||
if type(yanchor) is float:
|
||||
yoff -= sh * yanchor
|
||||
if absolute or isinstance(yanchor, int):
|
||||
yoff -= yanchor
|
||||
yanchor_mul = sh
|
||||
else:
|
||||
yanchor_mul = 1
|
||||
|
||||
yoff = yoff * yoff_mul - yanchor * yanchor_mul
|
||||
yoff += y
|
||||
|
||||
# Add in offsets.
|
||||
@@ -812,7 +818,7 @@ class Display(object):
|
||||
next_frame = self.next_frame
|
||||
now = pygame.time.get_ticks()
|
||||
|
||||
frametime = 1000 / framerate
|
||||
frametime = 1000.0 / framerate
|
||||
|
||||
# Handle timer rollover.
|
||||
if next_frame > now + frametime:
|
||||
@@ -823,10 +829,10 @@ class Display(object):
|
||||
return False
|
||||
|
||||
# Otherwise, it is. Schedule the next frame.
|
||||
if next_frame + frametime < now:
|
||||
next_frame = now + frametime
|
||||
else:
|
||||
next_frame += frametime
|
||||
# if next_frame + frametime < now:
|
||||
next_frame = now + frametime
|
||||
# else:
|
||||
# next_frame += frametime
|
||||
|
||||
self.next_frame = next_frame
|
||||
|
||||
@@ -967,7 +973,7 @@ class Display(object):
|
||||
|
||||
updates.extend(self.draw_mouse(False))
|
||||
|
||||
damage = renpy.display.render.draw_screen(self.screen_xoffset, self.screen_yoffset)
|
||||
damage = renpy.display.render.draw_screen(self.screen_xoffset, self.screen_yoffset, self.full_redraw)
|
||||
|
||||
if damage:
|
||||
updates.extend(damage)
|
||||
@@ -1099,7 +1105,6 @@ class Interface(object):
|
||||
|
||||
# Are we focused?
|
||||
self.focused = True
|
||||
|
||||
|
||||
# Properties for each layer.
|
||||
self.layer_properties = { }
|
||||
|
||||
+12
-1
@@ -45,6 +45,16 @@ class Focus(object):
|
||||
self.w,
|
||||
self.h)
|
||||
|
||||
def __repr__(self):
|
||||
return "<Focus: %r %r (%r, %r, %r, %r)>" % (
|
||||
self.widget,
|
||||
self.arg,
|
||||
self.x,
|
||||
self.y,
|
||||
self.w,
|
||||
self.h)
|
||||
|
||||
|
||||
# The current focus argument.
|
||||
argument = None
|
||||
|
||||
@@ -355,6 +365,7 @@ def focus_nearest(from_x0, from_y0, from_x1, from_y1,
|
||||
new_focus_dist = (65536.0 * renpy.config.focus_crossrange_penalty) ** 2
|
||||
|
||||
for f in focus_list:
|
||||
|
||||
if f is from_focus:
|
||||
continue
|
||||
|
||||
@@ -364,7 +375,7 @@ def focus_nearest(from_x0, from_y0, from_x1, from_y1,
|
||||
|
||||
if not condition(from_focus, f):
|
||||
continue
|
||||
|
||||
|
||||
tx0 = f.x + f.w * to_x0
|
||||
ty0 = f.y + f.h * to_y0
|
||||
tx1 = f.x + f.w * to_x1
|
||||
|
||||
+15
-14
@@ -188,7 +188,7 @@ class Cache(object):
|
||||
surf = image.load()
|
||||
has_alpha = surf.get_masks()[3]
|
||||
surf = surf.convert_alpha(renpy.game.interface.display.window)
|
||||
|
||||
|
||||
ce = CacheEntry(image, surf)
|
||||
self.total_cache_size += ce.size
|
||||
self.cache[image] = ce
|
||||
@@ -202,26 +202,27 @@ class Cache(object):
|
||||
# RLE detection. (ce.size is used to check that we're not
|
||||
# 0 pixels big.)
|
||||
if id(ce.surf) not in rle_cache and ce.size:
|
||||
rle = image.rle
|
||||
rle = not renpy.game.less_memory
|
||||
# rle = image.rle
|
||||
surf = ce.surf
|
||||
|
||||
# If we don't know if the image is RLE or not, guess.
|
||||
# Only do so if the image has an alpha channel.
|
||||
if rle is None and has_alpha and not renpy.game.less_memory:
|
||||
sw, sh = surf.get_size()
|
||||
|
||||
for i in range(0, 10):
|
||||
if surf.get_at((random.randint(0, sw-1),
|
||||
random.randint(0, sh-1)))[3] == 0:
|
||||
rle = True
|
||||
break
|
||||
# # If we don't know if the image is RLE or not, guess.
|
||||
# # Only do so if the image has an alpha channel.
|
||||
# if rle is None and has_alpha and not renpy.game.less_memory:
|
||||
# sw, sh = surf.get_size()
|
||||
|
||||
# for i in range(0, 10):
|
||||
# if surf.get_at((random.randint(0, sw-1),
|
||||
# random.randint(0, sh-1)))[3] == 0:
|
||||
# rle = True
|
||||
# break
|
||||
|
||||
if rle:
|
||||
|
||||
|
||||
# We must copy the surface, so we have a RLE-specific version.
|
||||
rle_surf = ce.surf.convert_alpha(renpy.game.interface.display.window)
|
||||
|
||||
rle_surf.set_alpha(255, RLEACCEL)
|
||||
|
||||
rle_cache[id(ce.surf)] = rle_surf
|
||||
renpy.display.render.mutated_surface(ce.surf)
|
||||
if renpy.config.debug_image_cache:
|
||||
|
||||
@@ -735,7 +735,7 @@ class Window(Container):
|
||||
# Draw the background. The background should render at exactly the
|
||||
# requested size. (That is, be a Frame or a Solid).
|
||||
if style.background:
|
||||
bw = width - cxmargin
|
||||
bw = width - cxmargin
|
||||
bh = height - cymargin
|
||||
|
||||
back = render(style.background, bw, bh, st, at)
|
||||
@@ -937,13 +937,13 @@ class Interpolate(object):
|
||||
|
||||
if c is not None:
|
||||
if type(a) is float:
|
||||
a = renpy.display.core.absolute(a * c)
|
||||
a = a * c
|
||||
if type(b) is float:
|
||||
b = renpy.display.core.absolute(b * c)
|
||||
b = b * c
|
||||
|
||||
rv = a + t * (b - a)
|
||||
|
||||
return type(a)(rv)
|
||||
return renpy.display.core.absolute(rv)
|
||||
|
||||
return [ interp(a, b, c) for a, b, c in zip(self.start, self.end, sizes) ]
|
||||
|
||||
|
||||
+393
-117
@@ -55,69 +55,6 @@ def free_memory():
|
||||
|
||||
render_cache.clear()
|
||||
|
||||
def render_screen(root, width, height):
|
||||
"""
|
||||
Renders `root` (a displayable) as the root of a screen with the given
|
||||
`width` and `height`.
|
||||
"""
|
||||
|
||||
global old_screen_render
|
||||
global screen_render
|
||||
global invalidated
|
||||
|
||||
old_screen_render = screen_render
|
||||
|
||||
rv = render(root, width, height, 0, 0)
|
||||
screen_render = rv
|
||||
|
||||
invalidated = False
|
||||
|
||||
return rv
|
||||
|
||||
def draw_screen(xoffset, yoffset):
|
||||
"""
|
||||
Draws the render produced by render_screen to the screen.
|
||||
"""
|
||||
|
||||
screen_render.is_opaque()
|
||||
draw(pygame.display.get_surface(), screen_render, xoffset, yoffset, True)
|
||||
|
||||
return [ (xoffset, yoffset, screen_render.width, screen_render.height) ]
|
||||
|
||||
def kill_old_screen():
|
||||
"""
|
||||
Kills the old screen if it's different from the current screen.
|
||||
"""
|
||||
|
||||
global old_screen_render
|
||||
|
||||
if old_screen_render is None or old_screen_render is screen_render:
|
||||
return
|
||||
|
||||
old_screen_render.kill()
|
||||
old_screen_render = None
|
||||
|
||||
def take_focuses(focuses):
|
||||
"""
|
||||
Adds a list of rectangular focus regions to the focuses list.
|
||||
"""
|
||||
|
||||
screen_render.take_focuses(IDENTITY, 0, 0, focuses)
|
||||
|
||||
def focus_at_point(x, y):
|
||||
"""
|
||||
Returns a focus object corresponding to the uppermost displayable
|
||||
at point, or None if nothing focusable is at point.
|
||||
"""
|
||||
|
||||
cf = screen_render.focus_at_point(x, y)
|
||||
if cf is None:
|
||||
return None
|
||||
else:
|
||||
d, arg = cf
|
||||
return renpy.display.focus.Focus(d, arg, None, None, None, None)
|
||||
|
||||
|
||||
def render(d, width, height, st, at):
|
||||
"""
|
||||
Causes the displayable `d` to be rendered in an area of size
|
||||
@@ -147,6 +84,11 @@ def render(d, width, height, st, at):
|
||||
else:
|
||||
height = min(ymaximum, height)
|
||||
|
||||
if width < 0:
|
||||
width = 0
|
||||
if height < 0:
|
||||
height = 0
|
||||
|
||||
wh = (width, height)
|
||||
|
||||
rv = render_cache[d].get(wh, None)
|
||||
@@ -239,17 +181,6 @@ def redraw(d, when):
|
||||
redraw_queue.append((when + renpy.game.interface.frame_time, d))
|
||||
|
||||
|
||||
# TODO: The master function that redraws the screen.
|
||||
|
||||
def mutated_surface(surf):
|
||||
"""
|
||||
Called to indicate that the given surface has changed. (Does nothing
|
||||
right now.)
|
||||
"""
|
||||
|
||||
# Doesn't do anything anymore, but keep it in case we need it again,
|
||||
# and for compatibility with the public api.
|
||||
|
||||
class Matrix2D(object):
|
||||
"""
|
||||
This represents a 2d matrix that can be used to transform
|
||||
@@ -273,14 +204,206 @@ class Matrix2D(object):
|
||||
other.ydx * self.xdy + other.ydy * self.ydy)
|
||||
|
||||
IDENTITY = Matrix2D(1, 0, 0, 1)
|
||||
|
||||
def draw(dest, what, xo, yo, screen):
|
||||
|
||||
class Clipper(object):
|
||||
"""
|
||||
This is used to calculate the clipping rectangle and update rectangles
|
||||
used for a particular draw of the screen.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Lists of (x0, y0, x1, y1, clip, surface, transform) tuples,
|
||||
# representing how a displayable is drawn to the screen.
|
||||
self.blits = [ ]
|
||||
self.old_blits = [ ]
|
||||
|
||||
# Sets of (x0, y0, x1, y1) tuples, representing areas that
|
||||
# aren't part of any displayable.
|
||||
self.forced = set()
|
||||
self.old_forced = set()
|
||||
|
||||
# The set of surfaces that have been mutated recently.
|
||||
self.mutated = set()
|
||||
|
||||
def compute(self, full_redraw):
|
||||
"""
|
||||
This returns a clipping rectangle, and a list of update rectangles
|
||||
that cover the changes between the old and new frames.
|
||||
"""
|
||||
|
||||
# First, get things out of the fields, and update them. This
|
||||
# allows us to just return without having to do any cleanup
|
||||
# code.
|
||||
bl0 = self.old_blits
|
||||
bl1 = self.blits
|
||||
old_forced = self.old_forced
|
||||
forced = self.forced
|
||||
mutated = self.mutated
|
||||
|
||||
self.old_blits = bl1
|
||||
self.blits = [ ]
|
||||
self.old_forced = forced
|
||||
self.forced = set()
|
||||
self.mutated = set()
|
||||
|
||||
sw = renpy.config.screen_width
|
||||
sh = renpy.config.screen_height
|
||||
sa = sw * sh
|
||||
|
||||
# A tuple representing the size of the fullscreen.
|
||||
fullscreen = (0, 0, sw, sh)
|
||||
|
||||
# Check to see if a full redraw has been forced, and return
|
||||
# early.
|
||||
if full_redraw:
|
||||
return fullscreen, [ fullscreen ]
|
||||
|
||||
# Quick checks to see if a dissolve is happening, or something like
|
||||
# that.
|
||||
changes = forced | old_forced
|
||||
|
||||
if fullscreen in changes:
|
||||
return fullscreen, [ fullscreen ]
|
||||
|
||||
# Compute the differences between the two sets, and add those
|
||||
# to changes.
|
||||
i0 = 0
|
||||
i1 = 0
|
||||
bl1set = set(bl1)
|
||||
|
||||
while True:
|
||||
if i0 >= len(bl0) or i1 >= len(bl1):
|
||||
break
|
||||
|
||||
b0 = bl0[i0]
|
||||
b1 = bl1[i1]
|
||||
|
||||
if b0 == b1:
|
||||
if id(b0[5]) in mutated:
|
||||
changes.add(b0[:5])
|
||||
|
||||
i0 += 1
|
||||
i1 += 1
|
||||
|
||||
elif b0 not in bl1set:
|
||||
changes.add(b0[:5])
|
||||
i0 += 1
|
||||
|
||||
else:
|
||||
changes.add(b1[:5])
|
||||
i1 += 1
|
||||
|
||||
changes.update(i[:5] for i in bl0[i0:])
|
||||
changes.update(i[:5] for i in bl1[i1:])
|
||||
|
||||
# No changes? Quit.
|
||||
if not changes:
|
||||
return None, [ ]
|
||||
|
||||
# Compute the sizes of the updated rectangles.
|
||||
sized = [ ]
|
||||
|
||||
for x0, y0, x1, y1, (sx0, sy0, sx1, sy1) in changes:
|
||||
|
||||
if x0 < sx0:
|
||||
x0 = sx0
|
||||
if y0 < sy0:
|
||||
y0 = sy0
|
||||
if x1 > sx1:
|
||||
x1 = sx1
|
||||
if y1 > sy1:
|
||||
y1 = sy1
|
||||
|
||||
w = x1 - x0
|
||||
h = y1 - y0
|
||||
area = w * h
|
||||
|
||||
if area >= sa:
|
||||
return fullscreen, [ fullscreen ]
|
||||
|
||||
sized.append((area, x0, y0, x1, y1))
|
||||
|
||||
sized.sort()
|
||||
|
||||
# The list of non-contiguous updates.
|
||||
noncont = [ ]
|
||||
|
||||
# The total area of noncont.
|
||||
nca = 0
|
||||
|
||||
# Pick the largest area, merge with all overlapping smaller areas, repeat
|
||||
# until no merge possible.
|
||||
while sized:
|
||||
area, x0, y0, x1, y1 = sized.pop()
|
||||
|
||||
merged = False
|
||||
|
||||
if nca + area >= sa:
|
||||
return (0, 0, sw, sh), [ (0, 0, sw, sh) ]
|
||||
|
||||
i = 0
|
||||
|
||||
while i < len(sized):
|
||||
iarea, ix0, iy0, ix1, iy1 = sized[i]
|
||||
|
||||
if (x0 <= ix0 <= x1 or x0 <= ix1 <= x1) and \
|
||||
(y0 <= iy0 <= y1 or y0 <= iy1 <= y1):
|
||||
|
||||
merged = True
|
||||
x0 = min(x0, ix0)
|
||||
x1 = max(x1, ix1)
|
||||
y0 = min(y0, iy0)
|
||||
y1 = max(y1, iy1)
|
||||
|
||||
area = (x1 - x0) * (y1 - y0)
|
||||
|
||||
sized.pop(i)
|
||||
|
||||
else:
|
||||
i += 1
|
||||
|
||||
if merged:
|
||||
sized.append((area, x0, y0, x1, y1))
|
||||
else:
|
||||
noncont.append((x0, y0, x1, y1))
|
||||
nca += area
|
||||
|
||||
x0, y0, x1, y1 = noncont.pop()
|
||||
x0 = int(x0)
|
||||
y0 = int(y0)
|
||||
x1 = int(math.ceil(x1))
|
||||
y1 = int(math.ceil(y1))
|
||||
|
||||
# A list of (x, y, w, h) tuples for each update.
|
||||
updates = [ (x0, y0, x1 - x0, y1 - y0) ]
|
||||
|
||||
for ix0, iy0, ix1, iy1 in noncont:
|
||||
ix0 = int(ix0)
|
||||
iy0 = int(iy0)
|
||||
ix1 = int(math.ceil(ix1))
|
||||
iy1 = int(math.ceil(iy1))
|
||||
|
||||
x0 = min(x0, ix0)
|
||||
y0 = min(y0, iy0)
|
||||
x1 = max(x1, ix1)
|
||||
y1 = max(y1, iy1)
|
||||
|
||||
updates.append((ix0, iy0, ix1 - ix0, iy1 - iy0))
|
||||
|
||||
return (x0, y0, x1 - x0, y1 - y0), updates
|
||||
|
||||
clippers = [ Clipper() ]
|
||||
|
||||
def draw(dest, clip, what, xo, yo, screen):
|
||||
"""
|
||||
This is the simple draw routine, which only works when alpha is 1.0
|
||||
and the matrices are None. If those aren't the case, draw_complex
|
||||
is used instead.
|
||||
|
||||
`dest` - The destination surface.
|
||||
`dest` - Either a destination surface, or a clipper.
|
||||
`clip` - If None, we should draw. Otherwise we should clip, and this is
|
||||
the rectangle to clip to.
|
||||
`what` - The Render or Surface we're drawing to.
|
||||
`xo` - The X offset.
|
||||
`yo` - The Y offset.
|
||||
@@ -294,13 +417,21 @@ def draw(dest, what, xo, yo, screen):
|
||||
if screen:
|
||||
what = renpy.display.im.rle_cache.get(id(what), what)
|
||||
|
||||
blit_lock.acquire()
|
||||
dest.blit(what, (xo, yo))
|
||||
blit_lock.release()
|
||||
if clip:
|
||||
w, h = what.get_size()
|
||||
dest.blits.append((xo, yo, xo + w, yo + h, clip, what, None))
|
||||
else:
|
||||
blit_lock.acquire()
|
||||
dest.blit(what, (xo, yo))
|
||||
blit_lock.release()
|
||||
|
||||
# Subpixel blit.
|
||||
else:
|
||||
renpy.display.module.subpixel(what, dest, xo, yo)
|
||||
if clip:
|
||||
w, h = what.get_size()
|
||||
dest.blits.append((xo, yo, xo + w, yo + h, clip, what, None))
|
||||
else:
|
||||
renpy.display.module.subpixel(what, dest, xo, yo)
|
||||
|
||||
return
|
||||
|
||||
@@ -310,7 +441,12 @@ def draw(dest, what, xo, yo, screen):
|
||||
xo = int(xo)
|
||||
yo = int(yo)
|
||||
|
||||
dw, dh = dest.get_size()
|
||||
if clip:
|
||||
dx0, dy0, dx1, dy1 = clip
|
||||
dw = dx1 - dx0
|
||||
dh = dy1 - dy0
|
||||
else:
|
||||
dw, dh = dest.get_size()
|
||||
|
||||
if xo >= 0:
|
||||
newx = 0
|
||||
@@ -339,44 +475,71 @@ def draw(dest, what, xo, yo, screen):
|
||||
if subw <= 0 or subh <= 0:
|
||||
return
|
||||
|
||||
newdest = dest.subsurface((subx, suby, subw, subh))
|
||||
what.draw_func(newdest, newx, newy)
|
||||
if clip:
|
||||
dest.forced.add((subx, suby, subx + subw, suby + subh, clip))
|
||||
else:
|
||||
newdest = dest.subsurface((subx, suby, subw, subh))
|
||||
what.draw_func(newdest, newx, newy)
|
||||
|
||||
return
|
||||
|
||||
# Deal with clipping, if necessary.
|
||||
if what.clipping:
|
||||
|
||||
width = what.width
|
||||
height = what.height
|
||||
|
||||
if xo < 0:
|
||||
width = width + xo
|
||||
xo = 0
|
||||
if yo < 0:
|
||||
height = height + yo
|
||||
yo = 0
|
||||
if clip:
|
||||
cx0, cy0, cx1, cy1 = clip
|
||||
|
||||
dw, dh = dest.get_size()
|
||||
width = min(dw - xo, width)
|
||||
height = min(dh - yo, height)
|
||||
cx0 = max(cx0, xo)
|
||||
cy0 = max(cy0, yo)
|
||||
cx1 = min(cx1, xo + what.width)
|
||||
cy1 = min(cy1, yo + what.height)
|
||||
|
||||
if cx0 > cx1 or cy0 > cy1:
|
||||
return
|
||||
|
||||
dest = dest.subsurface((xo, yo, width, height))
|
||||
xo = 0
|
||||
yo = 0
|
||||
|
||||
clip = (cx0, cy0, cx1, cy1)
|
||||
|
||||
else:
|
||||
|
||||
# After this code, x and y are the coordinates of the subsurface
|
||||
# relative to the destination. xo and yo are the offset of the
|
||||
# upper-left corner relative to the subsurface.
|
||||
|
||||
if xo >= 0:
|
||||
x = xo
|
||||
xo = 0
|
||||
else:
|
||||
x = 0
|
||||
# xo = xo
|
||||
|
||||
if yo >= 0:
|
||||
y = yo
|
||||
yo = 0
|
||||
else:
|
||||
y = 0
|
||||
# yo = yo
|
||||
|
||||
dw, dh = dest.get_size()
|
||||
|
||||
width = min(dw - x, what.width + xo)
|
||||
height = min(dh - y, what.height + yo)
|
||||
|
||||
if width < 0 or height < 0:
|
||||
return
|
||||
|
||||
dest = dest.subsurface((x, y, width, height))
|
||||
|
||||
# Deal with alpha and transforms by passing them off to draw_transformed.
|
||||
if what.alpha != 1 or what.forward:
|
||||
for child, cxo, cyo, focus, main in what.visible_children:
|
||||
draw_transformed(dest, child, xo + cxo, yo + cyo,
|
||||
draw_transformed(dest, clip, child, xo + cxo, yo + cyo,
|
||||
what.alpha, what.forward, what.reverse)
|
||||
return
|
||||
|
||||
for child, cxo, cyo, focus, main in what.visible_children:
|
||||
draw(dest, child, xo + cxo, yo + cyo, screen)
|
||||
draw(dest, clip, child, xo + cxo, yo + cyo, screen)
|
||||
|
||||
def draw_transformed(dest, what, xo, yo, alpha, forward, reverse):
|
||||
def draw_transformed(dest, clip, what, xo, yo, alpha, forward, reverse):
|
||||
|
||||
if not isinstance(what, Render):
|
||||
|
||||
@@ -386,7 +549,12 @@ def draw_transformed(dest, what, xo, yo, alpha, forward, reverse):
|
||||
# Figure out where the other corner of the transformed surface
|
||||
# is on the screen.
|
||||
sw, sh = what.get_size()
|
||||
dw, dh = dest.get_size()
|
||||
if clip:
|
||||
dx0, dy0, dx1, dy1 = clip
|
||||
dw = dx1 - dx0
|
||||
dh = dy1 - dy0
|
||||
else:
|
||||
dw, dh = dest.get_size()
|
||||
|
||||
x0, y0 = 0, 0
|
||||
x1, y1 = reverse.transform(sw, 0)
|
||||
@@ -409,15 +577,25 @@ def draw_transformed(dest, what, xo, yo, alpha, forward, reverse):
|
||||
maxy = dh
|
||||
|
||||
cx, cy = forward.transform(minx - xo, miny - yo)
|
||||
|
||||
dest = dest.subsurface((minx, miny, maxx - minx, maxy - miny))
|
||||
|
||||
renpy.display.module.alpha_transform(
|
||||
what, dest,
|
||||
cx, cy,
|
||||
forward.xdx, forward.ydx,
|
||||
forward.xdy, forward.ydy,
|
||||
alpha)
|
||||
if clip:
|
||||
dest.blits.append(
|
||||
(minx, miny, maxx, maxy, clip, what,
|
||||
(cx, cy,
|
||||
forward.xdx, forward.ydx,
|
||||
forward.xdy, forward.ydy,
|
||||
alpha)))
|
||||
|
||||
else:
|
||||
|
||||
dest = dest.subsurface((minx, miny, maxx - minx, maxy - miny))
|
||||
|
||||
renpy.display.module.alpha_transform(
|
||||
what, dest,
|
||||
cx, cy,
|
||||
forward.xdx, forward.ydx,
|
||||
forward.xdy, forward.ydy,
|
||||
alpha)
|
||||
|
||||
return
|
||||
|
||||
@@ -438,7 +616,98 @@ def draw_transformed(dest, what, xo, yo, alpha, forward, reverse):
|
||||
child_forward = forward
|
||||
child_reverse = reverse
|
||||
|
||||
draw_transformed(dest, child, xo + cxo, yo + cyo, alpha * what.alpha, child_forward, child_reverse)
|
||||
draw_transformed(dest, clip, child, xo + cxo, yo + cyo, alpha * what.alpha, child_forward, child_reverse)
|
||||
|
||||
|
||||
|
||||
def render_screen(root, width, height):
|
||||
"""
|
||||
Renders `root` (a displayable) as the root of a screen with the given
|
||||
`width` and `height`.
|
||||
"""
|
||||
|
||||
global old_screen_render
|
||||
global screen_render
|
||||
global invalidated
|
||||
|
||||
old_screen_render = screen_render
|
||||
|
||||
rv = render(root, width, height, 0, 0)
|
||||
screen_render = rv
|
||||
|
||||
invalidated = False
|
||||
|
||||
return rv
|
||||
|
||||
def draw_screen(xoffset, yoffset, full_redraw):
|
||||
"""
|
||||
Draws the render produced by render_screen to the screen.
|
||||
"""
|
||||
|
||||
screen_render.is_opaque()
|
||||
|
||||
clip = (xoffset, yoffset, xoffset + screen_render.width, yoffset + screen_render.height)
|
||||
clipper = clippers[0]
|
||||
|
||||
draw(clipper, clip, screen_render, xoffset, yoffset, True)
|
||||
|
||||
cliprect, updates = clipper.compute(full_redraw)
|
||||
|
||||
# print "CR", cliprect
|
||||
# print "UD", updates
|
||||
|
||||
if cliprect is None:
|
||||
return [ ]
|
||||
|
||||
x, y, w, h = cliprect
|
||||
|
||||
dest = pygame.display.get_surface().subsurface(cliprect)
|
||||
draw(dest, None, screen_render, -x, -y, True)
|
||||
|
||||
return updates
|
||||
|
||||
def kill_old_screen():
|
||||
"""
|
||||
Kills the old screen if it's different from the current screen.
|
||||
"""
|
||||
|
||||
global old_screen_render
|
||||
|
||||
if old_screen_render is None or old_screen_render is screen_render:
|
||||
return
|
||||
|
||||
old_screen_render.kill()
|
||||
old_screen_render = None
|
||||
|
||||
def take_focuses(focuses):
|
||||
"""
|
||||
Adds a list of rectangular focus regions to the focuses list.
|
||||
"""
|
||||
|
||||
screen_render.take_focuses(IDENTITY, 0, 0, focuses)
|
||||
|
||||
def focus_at_point(x, y):
|
||||
"""
|
||||
Returns a focus object corresponding to the uppermost displayable
|
||||
at point, or None if nothing focusable is at point.
|
||||
"""
|
||||
|
||||
cf = screen_render.focus_at_point(x, y)
|
||||
if cf is None:
|
||||
return None
|
||||
else:
|
||||
d, arg = cf
|
||||
return renpy.display.focus.Focus(d, arg, None, None, None, None)
|
||||
|
||||
|
||||
def mutated_surface(surf):
|
||||
"""
|
||||
Called to indicate that the given surface has changed.
|
||||
"""
|
||||
|
||||
for i in clippers:
|
||||
i.mutated.add(id(surf))
|
||||
|
||||
|
||||
|
||||
class Render(object):
|
||||
@@ -563,8 +832,6 @@ class Render(object):
|
||||
if isinstance(source, Render):
|
||||
source.parents.add(self)
|
||||
source.refcount += 1
|
||||
|
||||
|
||||
|
||||
def get_size(self):
|
||||
"""
|
||||
@@ -619,7 +886,7 @@ class Render(object):
|
||||
self.is_opaque()
|
||||
|
||||
rv = pygame.Surface((self.width, self.height), 0, sample)
|
||||
draw(rv, self, 0, 0, False)
|
||||
draw(rv, None, self, 0, 0, False)
|
||||
|
||||
# Stash and return the surface.
|
||||
if alpha:
|
||||
@@ -752,7 +1019,7 @@ class Render(object):
|
||||
maxx = max(x1, x2) + x
|
||||
maxy = max(y1, y2) + y
|
||||
|
||||
focuses.append(renpy.display.focus.Focus(d, arg, minx, miny, maxx, maxy))
|
||||
focuses.append(renpy.display.focus.Focus(d, arg, minx, miny, maxx - minx, maxy - miny))
|
||||
|
||||
for child, xo, yo, focus, main in self.children:
|
||||
if not focus or not isinstance(child, Render):
|
||||
@@ -914,6 +1181,15 @@ class Render(object):
|
||||
|
||||
return False
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fills this Render with the given color.
|
||||
"""
|
||||
|
||||
color = renpy.easy.color(color)
|
||||
solid = renpy.display.im.SolidImage(color, self.width, self.height)
|
||||
surf = render(solid, self.width, self.height, 0, 0)
|
||||
self.blit(surf, (0, 0), focus=False, main=False)
|
||||
|
||||
def canvas(self):
|
||||
"""
|
||||
|
||||
@@ -692,7 +692,7 @@ def RevolveInOut(start, end, pos, delay, d, **kwargs):
|
||||
return renpy.display.layout.Revolve(start, end, delay, d, pos=pos, **kwargs)
|
||||
|
||||
# TODO: Move isn't properly respecting positions when x < 0.
|
||||
def MoveTransition(delay, old_widget=None, new_widget=None, factory=None, enter_factory=None, leave_factory=None, old=False):
|
||||
def MoveTransition(delay, old_widget=None, new_widget=None, factory=None, enter_factory=None, leave_factory=None, old=False, layers=[ 'master' ]):
|
||||
"""
|
||||
This transition attempts to find images that have changed
|
||||
position, and moves them from the old position to the new
|
||||
@@ -758,10 +758,11 @@ def MoveTransition(delay, old_widget=None, new_widget=None, factory=None, enter_
|
||||
|
||||
f = new.layers[layer]
|
||||
|
||||
if isinstance(f, renpy.display.layout.MultiBox) \
|
||||
and f.scene_list is not None \
|
||||
and layer not in renpy.config.overlay_layers:
|
||||
|
||||
if (isinstance(f, renpy.display.layout.MultiBox)
|
||||
and layer in layers
|
||||
and f.scene_list is not None
|
||||
and layer not in renpy.config.overlay_layers):
|
||||
|
||||
f = merge_slide(old.layers[layer], new.layers[layer])
|
||||
|
||||
rv.layers[layer] = f
|
||||
|
||||
Reference in New Issue
Block a user