Compare commits

...

7 Commits

Author SHA1 Message Date
Tom Rothamel a305d6e725 6.9.0d 2009-03-08 01:58:50 -05:00
Tom Rothamel 1feff344b8 New clipping code. 2009-03-07 21:23:01 -05:00
Tom Rothamel 4fa4ffae54 Releasing 6.9.0c. 2009-03-06 18:32:31 -05:00
Tom Rothamel 4ecd72de6e Readying 6.9.0b 2009-03-02 22:40:15 -05:00
Tom Rothamel 3ec495c3fc Fix fill problem.
Move only named layers.
Fix focus problem.
2009-03-02 21:50:50 -05:00
Tom Rothamel 5efc437384 Fixed rounding issue in place. 2009-03-02 15:29:55 -05:00
Tom Rothamel a777f4d3b1 Fix negative render size. 2009-03-01 20:06:19 -05:00
14 changed files with 498 additions and 172 deletions
+11 -6
View File
@@ -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.
+10 -1
View File
@@ -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)),
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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:
+4 -4
View File
@@ -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
View File
@@ -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):
"""
+6 -5
View File
@@ -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