Compare commits

...

13 Commits

Author SHA1 Message Date
Tom Rothamel cac4238b12 6.9.0g 2009-03-17 23:46:55 -04:00
Tom Rothamel 8c402c2dc3 Fix button_menu problem. 2009-03-17 23:12:31 -04:00
Tom Rothamel 9bff95826a Fix bug in is_pixel_opaque. 2009-03-17 23:06:22 -04:00
Tom Rothamel fc0f7cecc4 Fix for viewport focus bugs? 2009-03-16 01:42:27 -04:00
Tom Rothamel 0b5c5ce17e Fix memory leak bug. 2009-03-16 00:45:43 -04:00
Tom Rothamel 9aa61532ff Refix bugs in pefile.py. 2009-03-12 22:39:56 -04:00
Tom Rothamel 3271557f8a Fix pefile.py to match latest py2exe. 2009-03-11 21:08:31 -04:00
Tom Rothamel 9587342129 6.9.0f
Fixes an overflow bug in subpixel.
2009-03-10 20:07:08 -04:00
Tom Rothamel 9b4821308d Change semantics of set_pan to be slightly more useful.
6.9.0e.
2009-03-09 23:12:04 -04:00
Tom Rothamel 663978906a Added renpy.partial. 2009-03-08 20:49:12 -04:00
Tom Rothamel 60f3308b8b Autobar now uses floating point numbers, making it smoother when the range is small.
Up the script version to 6.9.0.
2009-03-08 10:09:43 -04:00
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
19 changed files with 519 additions and 163 deletions
+8
View File
@@ -117,6 +117,14 @@ Ren'Py now autosaves when entering the quit prompt, and will not actually
quit until this autosave is complete.
The default framerate limit (config.framerate) has been raised to
100fps. This make tearing less noticable than on a 60hz screen.
Added renpy.partial as a version of renpy.curry that requires two
function calls, rather than three.
Fixed a divide by zero error that occured when Alpha was used for 0
seconds.
+1 -1
View File
@@ -18,7 +18,7 @@ init -1105 python:
# This takes care of actually displaying button menus.
def _display_button_menu(menuitems):
narration = [ s for s, i in menuitems if i is None and s ]
menuitems = [ (s, i) for s, i in menuitems if i is not None or not s ]
+1 -1
View File
@@ -306,7 +306,7 @@ init -1110 python hide:
gm_root = None):
if button_menu is None:
if config.script_version < (6, 9, 0):
if (config.script_version is not None) and (config.script_version < (6, 9, 0)):
button_menu = True
else:
button_menu = False
+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."
+19 -8
View File
@@ -7,31 +7,38 @@ import sys
import array
# The starting point of the resource segment in the file.
RESOURCE_BASE=0x3400
RESOURCE_BASE=0x3600
# The virtual memory location the resource segment is loaded
# to.
RESOURCE_VIRTUAL=0x6000
# The offset of the field that tells us with the alignment need be.
ALIGNMENT_FIELD = 0x138
ALIGNMENT_FIELD = 0x130
# The start of the .rsrc segment header.
RSRC_HEADER = 0x268
# Locations in the file where we need to patch in the resource
# segment length.
RESOURCE_LENGTH_PATCHES = [ 0x018c, 0x278 ]
RESOURCE_LENGTH_PATCHES = [ 0x0184, RSRC_HEADER + 0x8 ]
# Locations in the file where we need to patch in the padded
# resource segment length.
RESOURCE_PADDED_PATCHES = [ 0x280 ]
RESOURCE_PADDED_PATCHES = [ RSRC_HEADER + 0x10 ]
# Locations in the file where we need to patch in the change in the
# size of the resource segement (and hence the change in the file's
# total size.)
SIZE_DELTA_PATCHES = [ 0x150 ]
SIZE_DELTA_PATCHES = [ 0x148 ]
# A location in the file that will be checked to be sure it matches
# RESOURCE_BASE.
CHECK_ADDRESS = 0x284
CHECK_ADDRESS = RSRC_HEADER + 0x14
# A location in the file that will be checked to make sure it matches
# RESOURCE_VIRTUAL
CHECK_ADDRESS2 = RSRC_HEADER + 0xc
# This class performs various operations on memory-loaded binary files,
# including modifications.
@@ -285,10 +292,14 @@ def change_icons(oldexe, icofn):
global pe
pe = BinFile(oldexe)
# Check that RESOURCE_BASE is still valid.
# Check that RESOURCE_BASE and RESOURCE_VIRTUAL are still valid.
pe.seek(CHECK_ADDRESS)
if pe.u32() != RESOURCE_BASE:
raise Exception("RESOURCE_BASE is no longer correct. Please check all relocations.")
raise Exception("RESOURCE_BASE is no longer correct. Please check all relocations.")
pe.seek(CHECK_ADDRESS2)
if pe.u32() != RESOURCE_VIRTUAL:
raise Exception("RESOURCE_VIRTUAL is no longer correct. Please check all relocations.")
resources = parse_directory(0)
# show_resources(resources, "")
+1 -1
View File
@@ -1,3 +1,3 @@
init -999:
$ config.script_version = (6, 8, 0)
$ config.script_version = (6, 9, 0)
+4
View File
@@ -213,6 +213,10 @@ int subpixel32(PyObject *pysrc, PyObject *pydst,
sy = -1;
}
if (sx >= srcw - 1 || sy >= srch - 1) {
goto done;
}
// Figure out how many pixels we need to draw on each line.
normal_pixels = min(srcw - sx - 1, dstw - xo);
+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.0c"
version = "Ren'Py 6.9.0g"
script_version = 5003000
savegame_suffix = "-LT1.save"
+2 -1
View File
@@ -80,7 +80,6 @@ if mix:
old_midi = mix.get_midi()
mixer_enabled = True
def disable_mixer():
global mixer_enabled
@@ -529,6 +528,8 @@ class Channel(object):
if pcm_ok:
self.pan_delay = delay
self.pan_time = _pan_time.get(self.number)
pss.set_pan(self.number, _pan.get(self.number, 0.0), self.pan_delay)
# The number of channels we support.
+2 -9
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:
@@ -396,23 +398,14 @@ def memory_profile():
objs = gc.get_objects()
c = { } # count
dead_renders = 0
for i in objs:
t = type(i)
c[t] = c.get(t, 0) + 1
if isinstance(i, renpy.display.render.Render):
if i.dead:
dead_renders += 1
results = [ (count, ty) for ty, count in c.iteritems() ]
results.sort()
for count, ty in results:
print count, str(ty)
if dead_renders:
print
print "*** found", dead_renders, "dead Renders. ***"
+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
+10
View File
@@ -59,3 +59,13 @@ def curry(fn):
"""
return Curry(Curry, fn)
def partial(function, *args, **kwargs):
"""
Stores the arguments and keyword arguments of function, and
returns something that, when called, calls the function with
a combination of the supplied arguments and the arguments of
the second call.
"""
return Curry(function, *args, **kwargs)
+6 -7
View File
@@ -818,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:
@@ -829,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
@@ -973,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)
@@ -1105,7 +1105,6 @@ class Interface(object):
# Are we focused?
self.focused = True
# Properties for each layer.
self.layer_properties = { }
+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:
+3 -1
View File
@@ -1756,7 +1756,9 @@ class RotoZoom(renpy.display.core.Displayable):
culcx, culcy,
xdx, ydx, xdy, ydy)
return renpy.display.render.Render(dw, dh, draw_func=draw, opaque=self.opaque)
rv = renpy.display.render.Render(dw, dh, draw_func=draw, opaque=self.opaque)
rv.depends_on(child_rend)
return rv
class Viewport(Container):
+440 -115
View File
@@ -32,6 +32,9 @@ import renpy
# disable blitting, should it prove necessary.
blit_lock = threading.Condition()
# The number of living renders. (That is, the number that have been
# constructed, but not had kill() called.
render_count = 0
# This is a dictionary containing all the renders that we know of. It's a
# map from displayable to dictionaries containing the render of that
@@ -53,70 +56,28 @@ def free_memory():
Frees memory used by the render system.
"""
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
if screen_render:
screen_render.refcount -= 1
screen_render.kill()
screen_render = None
rv = render(root, width, height, 0, 0)
screen_render = rv
invalidated = False
render_cache.clear()
return rv
def draw_screen(xoffset, yoffset):
def check_at_shutdown():
"""
Draws the render produced by render_screen to the screen.
This is called at shutdown time to check that everything went okay.
The big thing it checks for is memory leaks.
"""
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:
if not renpy.config.developer:
return
old_screen_render.kill()
old_screen_render = None
free_memory()
if render_count != 0:
raise Exception("Render count is %d at shutdown. This probably indicates a memory leak bug in Ren'Py." % render_count)
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):
"""
@@ -244,17 +205,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
@@ -278,14 +228,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.
@@ -299,13 +441,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
@@ -315,7 +465,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
@@ -344,44 +499,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):
@@ -391,7 +573,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)
@@ -414,15 +601,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
@@ -443,8 +640,105 @@ 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
screen_render.refcount += 1
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:
return
old_screen_render.refcount -= 1
if 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(
0, 0, screen_render.width, screen_render.height,
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):
@@ -457,6 +751,9 @@ class Render(object):
layer.
"""
global render_count
render_count += 1
self.width = width
self.height = height
@@ -622,7 +919,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:
@@ -652,9 +949,10 @@ class Render(object):
a surface, and then blit that surface into another render.
"""
self.depends_on_set.add(source)
source.depends_on_us.add(self)
source.refcount += 1
if source not in self.depends_on_set:
self.depends_on_set.add(source)
source.depends_on_us.add(self)
source.refcount += 1
if focus:
self.pass_focuses.append(source)
@@ -695,6 +993,9 @@ class Render(object):
self.dead = True
global render_count
render_count -= 1
for c, xo, yo, focus, main in self.children:
if not isinstance(c, Render):
@@ -711,6 +1012,7 @@ class Render(object):
for c in self.depends_on_set:
c.depends_on_us.remove(self)
c.refcount -= 1
if c.refcount == 0:
c.kill()
@@ -731,11 +1033,16 @@ class Render(object):
self.focuses.append((d, arg, x, y, w, h, mx, my, mask))
def take_focuses(self, reverse, x, y, focuses):
def take_focuses(self, cminx, cminy, cmaxx, cmaxy, reverse, x, y, focuses):
"""
This adds to focuses Focuse objects corresponding to the focuses
This adds to focuses Focus objects corresponding to the focuses
added to this object and its children, transformed into screen
coordinates.
`cminx`, `cminy`, `cmaxx`, `cmaxy` - The clipping rectangle.
`reverse` - The transform from render to screen coordinates.
`x`, `y` - The offset of the upper-left corner of the render.
`focuses` - The list of focuses to add to.
"""
if self.reverse:
@@ -755,23 +1062,41 @@ class Render(object):
maxx = max(x1, x2) + x
maxy = max(y1, y2) + y
minx = max(minx, cminx)
miny = max(miny, cminy)
maxx = min(maxx, cmaxx)
maxy = min(maxy, cmaxy)
if minx >= maxx or miny >= maxy:
continue
focuses.append(renpy.display.focus.Focus(d, arg, minx, miny, maxx - minx, maxy - miny))
if self.clipping:
cminx = max(cminx, x)
cminy = max(cminy, y)
cmaxx = min(cmaxx, x + self.width)
cmaxy = min(cmaxx, x + self.height)
for child, xo, yo, focus, main in self.children:
if not focus or not isinstance(child, Render):
continue
xo, yo = reverse.transform(xo, yo)
child.take_focuses(reverse, x + xo, y + yo, focuses)
child.take_focuses(cminx, cminy, cmaxx, cmaxy, reverse, x + xo, y + yo, focuses)
for child in self.pass_focuses:
child.take_focuses(reverse, x, y, focuses)
child.take_focuses(cminx, cminy, cmaxx, cmaxy, reverse, x, y, focuses)
def focus_at_point(self, x, y):
"""
This returns the focus of this object at the given point.
"""
if self.clipping:
if x < 0 or x >= self.width or y < 0 or y >= self.height:
return None
rv = None
for (d, arg, xo, yo, w, h, mx, my, mask) in self.focuses:
@@ -893,7 +1218,7 @@ class Render(object):
"""
Determine if the pixel at x and y is opaque or not.
"""
if x < 0 or y < 0 or x >= self.width or y >= self.height:
return False
@@ -905,13 +1230,13 @@ class Render(object):
cx, cy = self.forward.transform(cx, cy)
if isinstance(child, Render):
if child.is_pixel_opaque(x, y):
if child.is_pixel_opaque(cx, cy):
return True
else:
cw, ch = child.get_size()
if cx >= cw or cy >= ch:
return False
if not child.get_masks()[3] or child.get_at((cx, cy))[3]:
return True
+1 -1
View File
@@ -33,7 +33,7 @@ from renpy.display.font import register_sfont, register_mudgefont, register_bmfo
from renpy.display.behavior import Keymap
from renpy.display.minigame import Minigame
from renpy.curry import curry
from renpy.curry import curry, partial
from renpy.audio.sound import play
from renpy.display.video import movie_start_fullscreen, movie_start_displayable, movie_stop
from renpy.loadsave import load, save, list_saved_games, can_load, rename_save, unlink_save, scan_saved_game
+2
View File
@@ -316,5 +316,7 @@ def main():
except game.FullRestartException, e:
restart = e.reason
# This is stuff we do on a normal, non-error return.
renpy.display.core.cpu_idle.set()
renpy.display.render.check_at_shutdown()
renpy.loadsave.autosave_not_running.wait()
+1 -1
View File
@@ -384,7 +384,7 @@ def _autobar_interpolate(range, start, end, time, st, at, **properties):
t = st / time
redraw = 0
value = type(start)(start + t * (end - start))
value = start + t * (end - start)
return renpy.display.behavior.Bar(range, value, None, None, **properties), redraw
autobar_interpolate = renpy.curry.curry(_autobar_interpolate)