summaryrefslogtreecommitdiff
path: root/unrpyc/renpy/display/render.pyx
diff options
context:
space:
mode:
Diffstat (limited to 'unrpyc/renpy/display/render.pyx')
-rw-r--r--unrpyc/renpy/display/render.pyx1174
1 files changed, 0 insertions, 1174 deletions
diff --git a/unrpyc/renpy/display/render.pyx b/unrpyc/renpy/display/render.pyx
deleted file mode 100644
index 5aa45a0..0000000
--- a/unrpyc/renpy/display/render.pyx
+++ /dev/null
@@ -1,1174 +0,0 @@
-#cython: profile=False
-# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-import collections
-import pygame
-import threading
-import renpy
-import gc
-
-# We grab the blit lock each time it is necessary to blit
-# something. This allows call to the pygame.transform functions to
-# disable blitting, should it prove necessary.
-blit_lock = threading.Condition()
-
-# 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
-# displayable.
-render_cache = collections.defaultdict(dict)
-
-# The queue of redraws. A list of (time, displayable) pairs.
-redraw_queue = [ ]
-
-# The render returned from render_screen.
-screen_render = None
-
-# A list of renders the system knows about, and thinks are still alive.
-cdef list live_renders
-live_renders = [ ]
-
-# A copy of renpy.display.interface.frame_time, for speed reasons.
-cdef double frame_time
-frame_time = 0
-
-def free_memory():
- """
- Frees memory used by the render system.
- """
-
- global screen_render
- screen_render = None
-
- mark_sweep()
-
- render_cache.clear()
-
- # This can hang onto a render.
- renpy.display.interface.surftree = None
-
-
-def check_at_shutdown():
- """
- This is called at shutdown time to check that everything went okay.
- The big thing it checks for is memory leaks.
- """
-
- if not renpy.config.developer:
- return
-
- free_memory()
-
- gc.collect()
- l = gc.get_objects()
-
- count = 0
- objects = gc.get_objects()
-
- for i in objects:
- if isinstance(i, Render):
- count += 1
-
- if count:
- raise Exception("%d Renders are alive at shutdown. This is probably a memory leak bug in Ren'Py." % count)
-
-
-
-cpdef render(d, object widtho, object heighto, double st, double at):
- """
- :doc: udd_utility
- :args: (d, width, height, st, at)
-
- Causes a displayable to be rendered, and a renpy.Render object to
- be returned.
-
- `d`
- The displayable to render.
-
- `width`, `height`
- The width and height available for the displayable to render into.
-
- `st`, `at`
- The shown and animation timebases.
-
- Renders returned by this object may be cached, and should not be modified
- once they have been retrieved.
- """
-
- cdef float width, height
- cdef float orig_width, orig_height
- cdef tuple orig_wh, wh
- cdef dict render_cache_d
- cdef Render rv
-
- orig_wh = (widtho, heighto, frame_time-st, frame_time-at)
-
- render_cache_d = render_cache[d]
- rv = render_cache_d.get(orig_wh, None)
-
- if rv is not None:
- return rv
-
- orig_width = width = widtho
- orig_height = height = heighto
-
- style = d.style
- xmaximum = style.xmaximum
- ymaximum = style.ymaximum
-
- if xmaximum is not None:
- if isinstance(xmaximum, float):
- width = width * xmaximum
- else:
- width = min(xmaximum, width)
-
- if ymaximum is not None:
- if isinstance(ymaximum, float):
- height = height * ymaximum
- else:
- height = min(ymaximum, height)
-
- if width < 0:
- width = 0
- if height < 0:
- height = 0
-
- if orig_width != width or orig_height != height:
- widtho = width
- heighto = height
- wh = (widtho, heighto, frame_time-st, frame_time-at)
- rv = render_cache_d.get(wh, None)
-
- if rv is not None:
- return rv
-
- else:
- wh = orig_wh
-
- rv = d.render(widtho, heighto, st, at)
-
- rv.render_of.append(d)
-
- if style.clipping:
- rv = rv.subsurface((0, 0, rv.width, rv.height), focus=True)
- rv.render_of.append(d)
-
- render_cache_d[wh] = rv
-
- if wh is not orig_wh:
- render_cache_d[orig_wh] = rv
-
- return rv
-
-
-# This is true if something has been invalidated, and a redraw needs
-# to occur. It's automatically cleared to False at the end of each
-# redraw.
-invalidated = False
-
-def invalidate(d):
- """
- Removes d from the render cache. If we're not in a redraw, triggers
- a redraw to start.
- """
-
- global invalidated
-
- if d in render_cache:
- for v in render_cache[d].values():
- v.kill_cache()
-
- invalidated = True
-
-
-def process_redraws():
- """
- Called to determine if any redraws are pending. Returns true if we
- need to redraw the screen now, false otherwise.
- """
-
- global redraw_queue
-
- redraw_queue.sort()
-
- now = renpy.display.core.get_time()
- rv = invalidated
-
- new_redraw_queue = [ ]
- seen = set()
-
- for t in redraw_queue:
- when, d = t
-
- if d in seen:
- continue
-
- seen.add(d)
-
- if d not in render_cache:
- continue
-
- if when <= now:
- # Remove this displayable and all its parents from the
- # render cache. But don't kill them yet, as that will kill the
- # children that we want to reuse.
-
- for v in render_cache[d].values():
- v.kill_cache()
-
- rv = True
-
- else:
- new_redraw_queue.append(t)
-
- redraw_queue = new_redraw_queue
-
- return rv
-
-
-def redraw_time():
- """
- Returns the time at which the next redraw is scheduled.
- """
-
- if redraw_queue:
- return redraw_queue[0][0]
-
- return None
-
-
-def redraw(d, when):
- """
- :doc: udd_utility
-
- Causes the displayable `d` to be redrawn after `when` seconds have
- elapsed.
- """
-
- if not renpy.game.interface:
- return
-
- redraw_queue.append((when + renpy.game.interface.frame_time, d))
-
-
-cdef class Matrix2D:
- """
- This represents a 2d matrix that can be used to transform
- points and things like that.
- """
-
- def __getstate__(self):
- return dict(
- xdx = self.xdx,
- xdy = self.xdy,
- ydx = self.ydx,
- ydy = self.ydy)
-
- def __setstate__(self, state):
- self.xdx = state['xdx']
- self.xdy = state['xdy']
- self.ydx = state['ydx']
- self.ydy = state['ydy']
-
- def __init__(Matrix2D self, double xdx, double xdy, double ydx, double ydy):
- self.xdx = xdx
- self.xdy = xdy
- self.ydx = ydx
- self.ydy = ydy
-
- cpdef tuple transform(Matrix2D self, double x, double y):
- return (x * self.xdx + y * self.xdy), (x * self.ydx + y * self.ydy)
-
- def __mul__(Matrix2D self, Matrix2D other):
- return Matrix2D(
- other.xdx * self.xdx + other.xdy * self.ydx,
- other.xdx * self.xdy + other.xdy * self.ydy,
- other.ydx * self.xdx + other.ydy * self.ydx,
- other.ydx * self.xdy + other.ydy * self.ydy)
-
- def __repr__(self):
- return "Matrix2D(xdx=%f, xdy=%f, ydx=%f, ydy=%f)" % (self.xdx, self.xdy, self.ydx, self.ydy)
-
-IDENTITY = Matrix2D(1, 0, 0, 1)
-
-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)
-
-# The result of focus_at_point for a modal render. This overrides any
-# specific focus from below us.
-Modal = object()
-
-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.
- """
-
- if screen_render is None:
- return None
-
- cf = screen_render.focus_at_point(x, y)
- if cf is None or cf is Modal:
- 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.
- """
-
- renpy.display.draw.mutated_surface(surf)
-
-
-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
- global frame_time
-
- frame_time = renpy.display.interface.frame_time
-
- rv = render(root, width, height, 0, 0)
- screen_render = rv
-
- invalidated = False
-
- rv.is_opaque()
-
- return rv
-
-def mark_sweep():
- """
- This performs mark-and-sweep garbage collection on the live_renders
- list.
- """
-
- global live_renders
-
- cdef list worklist
- cdef int i
- cdef Render r, j
-
- worklist = [ ]
-
- if screen_render is not None:
- worklist.append(screen_render)
-
- i = 0
-
- while i < len(worklist):
- r = worklist[i]
-
- for j in r.depends_on_list:
- if not j.mark:
- j.mark = True
- worklist.append(j)
-
- i += 1
-
- for r in live_renders:
- if not r.mark:
- r.kill_cache()
- else:
- r.mark = False
-
- live_renders = worklist
-
-def compute_subline(sx0, sw, cx0, cw):
- """
- Given a source line (start sx0, width sw) and a crop line (cx0, cw),
- return three things:
-
- * The offset of the portion of the source line that overlaps with
- the crop line, relative to the crop line.
- * The offset of the portion of the source line that overlaps with the
- the crop line, relative to the source line.
- * The length of the overlap in pixels. (can be <= 0)
- """
-
- sx1 = sx0 + sw
- cx1 = cx0 + cw
-
- if sx0 > cx0:
- start = sx0
- else:
- start = cx0
-
- offset = start - cx0
- crop = start - sx0
-
- if sx1 < cx1:
- width = sx1 - start
- else:
- width = cx1 - start
-
-
- return offset, crop, width
-
-
-
-
-# Possible operations that can be done as part of a render.
-BLIT = 0
-DISSOLVE = 1
-IMAGEDISSOLVE = 2
-PIXELLATE = 3
-
-cdef class Render:
-
- def __init__(Render self, float width, float height, draw_func=None, layer_name=None, bint opaque=None): #@DuplicatedSignature
- """
- Creates a new render corresponding to the given widget with
- the specified width and height.
-
- If `layer_name` is given, then this render corresponds to a
- layer.
- """
-
- # The mark bit, used for mark/sweep-style garbage collection of
- # renders.
- self.mark = False
-
- # Is has this render been removed from the cache?
- self.cache_killed = False
-
-
- self.width = width
- self.height = height
-
- self.layer_name = layer_name
-
- # A list of (surface/render, xoffset, yoffset, focus, main) tuples, ordered from
- # back to front.
- self.children = [ ]
-
- # The set of renders that either have us as children, or depend on
- # us.
- self.parents = set()
-
- # The renders we depend on, including our children.
- self.depends_on_list = [ ]
-
- # The operation we're performing. (BLIT, DISSOLVE, OR IMAGE_DISSOLVE)
- self.operation = BLIT
-
- # The fraction of the operation that is complete.
- self.operation_complete = 0.0
-
- # Should the dissolve operations preserve alpha?
- self.operation_alpha = False
-
- # The parameter to the operation.
- self.operation_parameter = 0
-
- # Forward is used to transform from screen coordinates to child
- # coordinates.
- # Reverse is used to transform from child coordinates to screen
- # coordinates.
- #
- # For performance reasons, these aren't used to transform the
- # x and y offsets found in self.children. Those offsets should
- # be of the (0, 0) point in the child coordinate space.
- self.forward = None
- self.reverse = None
-
- # This is used to adjust the alpha of children of this render.
- self.alpha = 1
-
- # A list of focus regions in this displayable.
- self.focuses = None
-
- # Other renders that we should pass focus onto.
- self.pass_focuses = None
-
- # The displayable(s) that this is a render of. (Set by render)
- self.render_of = [ ]
-
- # If set, this is a function that's called to draw this render
- # instead of the default.
- self.draw_func = draw_func
-
- # Is this displayable opaque? (May be set on init, or later on
- # if we have opaque children.) This may be True, False, or None
- # to indicate we don't know yet.
- self.opaque = opaque
-
- # A list of our visible children. (That is, children above and
- # including our uppermost opaque child.) If nothing is opaque,
- # includes all children.
- self.visible_children = self.children
-
- # Should children be clipped to a rectangle?
- self.clipping = False
-
- # Caches of the texture created by rendering this surface.
- self.surface = None
- self.alpha_surface = None
-
- # Cache of the texture created by rendering this surface at half size.
- # (This is set in gldraw.)
- self.half_cache = None
-
- # Are we modal?
- self.modal = False
-
- live_renders.append(self)
-
- def __repr__(self): #@DuplicatedSignature
- return "<Render %x of %r>" % (id(self), self.render_of)
-
- def __getstate__(self): #@DuplicatedSignature
- if renpy.config.developer:
- raise Exception("Can't pickle a Render.")
- else:
- return { }
-
- def __setstate__(self, state): #@DuplicatedSignature
- return
-
- cpdef int blit(Render self, source, tuple pos, object focus=True, object main=True, object index=None):
- """
- Blits `source` (a Render or Surface) to this Render, offset by
- xo and yo.
-
- If `focus` is true, then focuses are added from the child to the
- parent.
-
- This will only blit on integer pixel boundaries.
- """
-
- (xo, yo) = pos
-
- if source is self:
- raise Exception("Blitting to self.")
-
- xo = int(xo)
- yo = int(yo)
-
- if index is None:
- self.children.append((source, xo, yo, focus, main))
- else:
- self.children.insert(index, (source, xo, yo, focus, main))
-
- if isinstance(source, Render):
- self.depends_on_list.append(source)
- source.parents.add(self)
-
- return 0
-
- cpdef int subpixel_blit(Render self, source, tuple pos, object focus=True, object main=True, object index=None):
- """
- Blits `source` (a Render or Surface) to this Render, offset by
- xo and yo.
-
- If `focus` is true, then focuses are added from the child to the
- parent.
-
- This blits at fractional pixel boundaries.
- """
-
- (xo, yo) = pos
-
- xo = float(xo)
- yo = float(yo)
-
- if index is None:
- self.children.append((source, xo, yo, focus, main))
- else:
- self.children.insert(index, (source, xo, yo, focus, main))
-
- if isinstance(source, Render):
- self.depends_on_list.append(source)
- source.parents.add(self)
-
- return 0
-
- def get_size(self):
- """
- Returns the size of this Render, a mostly ficticious value
- that's taken from the inputs to the constructor. (As in, we
- don't clip to this size.)
- """
-
- return self.width, self.height
-
-
- def render_to_texture(self, alpha=True):
- """
- Returns a texture constructed from this render. This may return
- a cached textue, if one has already been rendered.
-
- `alpha` is a hint that controls if the surface should have
- alpha or not.
- """
-
- if alpha:
- if self.alpha_surface is not None:
- return self.alpha_surface
- else:
- if self.surface is not None:
- return self.surface
-
- rv = None
-
- opaque = self.is_opaque()
-
- # If we can, reuse a child's texture.
- if opaque or alpha:
-
- if not self.forward and len(self.children) == 1:
- child, x, y, focus, main = self.children[0]
- cw, ch = child.get_size()
- if x <= 0 and y <= 0 and cw + x >= self.width and ch + y >= self.height:
- # Our single child overlaps us.
- if isinstance(child, Render):
- child = child.render_to_texture(alpha)
-
- if x != 0 or y != 0 or cw != self.width or ch != self.height:
- rv = child.subsurface((-x, -y, self.width, self.height))
- else:
- rv = child
-
- # Otherwise, render to a texture.
- if rv is None:
- # is_opaque has already been called.
- rv = renpy.display.draw.render_to_texture(self, alpha)
-
- # Stash and return the surface.
- if alpha:
- self.alpha_surface = rv
- else:
- self.surface = rv
-
- return rv
-
- pygame_surface = render_to_texture
-
- def subsurface(self, rect, focus=False):
- """
- Returns a subsurface of this render. If `focus` is true, then
- the focuses are copied from this render to the child.
- """
-
- (x, y, w, h) = rect
- rv = Render(w, h)
-
- reverse = self.reverse
-
- # This doesn't actually make a subsurface, as we can't easily do
- # so for non-rectangle-aligned renders.
- if (reverse is not None) and (
- reverse.xdx != 1.0 or
- reverse.xdy != 0.0 or
- reverse.ydx != 0.0 or
- reverse.ydy != 1.0):
-
- rv.clipping = True
- rv.blit(self, (-x, -y), focus=focus, main=True)
- return rv
-
- # This is the path that executes for rectangle-aligned surfaces,
- # making an actual subsurface.
-
- for child, cx, cy, cfocus, cmain in self.children:
-
- cw, ch = child.get_size()
- xo, cx, cw = compute_subline(cx, cw, x, w)
- yo, cy, ch = compute_subline(cy, ch, y, h)
-
- if cw <= 0 or ch <= 0:
- continue
-
- crop = (cx, cy, cw, ch)
- offset = (xo, yo)
-
- if isinstance(child, Render):
- newchild = child.subsurface(crop, focus=focus)
- newchild.render_of = child.render_of[:]
- else:
- newchild = child.subsurface(crop)
- renpy.display.draw.mutated_surface(newchild)
-
- rv.blit(newchild, offset, focus=cfocus, main=cmain)
-
- if focus and self.focuses:
-
- for (d, arg, xo, yo, fw, fh, mx, my, mask) in self.focuses:
-
- if xo is None:
- rv.add_focus(d, arg, xo, yo, fw, fh, mx, my, mask)
- continue
-
- xo, cx, fw = compute_subline(xo, fw, x, w)
- yo, cy, fh = compute_subline(yo, fh, y, h)
-
- if cw <= 0 or ch <= 0:
- continue
-
- if mx is not None:
-
- mw, mh = mask.get_size()
-
- mx, mcx, mw = compute_subline(mx, mw, x, w)
- my, mcy, mh = compute_subline(my, mh, y, h)
-
- if mw <= 0 or mh <= 0:
- mx = None
- my = None
- mask = None
- else:
- mask = mask.subsurface((mcx, mcy, mw, mh))
-
- rv.add_focus(d, arg, xo, yo, fw, fh, mx, my, mask)
-
- rv.depends_on(self)
- rv.alpha = self.alpha
- rv.operation = self.operation
- rv.operation_alpha = self.operation_alpha
- rv.operation_complete = self.operation_complete
-
- return rv
-
-
- def depends_on(self, source, focus=False):
- """
- Used to indicate that this render depends on another
- render. Useful, for example, if we use pygame_surface to make
- a surface, and then blit that surface into another render.
- """
-
- if source is self:
- raise Exception("Render depends on itself.")
-
- self.depends_on_list.append(source)
- source.parents.add(self)
-
- if focus:
- if self.pass_focuses is None:
- self.pass_focuses = [ source ]
- else:
- self.pass_focuses.append(source)
-
-
- def kill_cache(self):
- """
- Removes this render and its transitive parents from the cache.
- """
-
- if self.cache_killed:
- return
-
- self.cache_killed = True
-
- for i in self.parents:
- i.kill_cache()
-
- self.parents.clear()
-
- for i in self.depends_on_list:
- if not i.cache_killed:
- i.parents.discard(self)
-
- for ro in self.render_of:
- cache = render_cache[ro]
- for k, v in cache.items():
- if v is self:
- del cache[k]
-
- if not cache:
- del render_cache[ro]
-
- def kill(self):
- """
- Retained for compatibility.
- """
-
- def add_focus(self, d, arg=None, x=0, y=0, w=None, h=None, mx=None, my=None, mask=None):
- """
- This is called to indicate a region of the screen that can be
- focused.
-
- `d` - the displayable that is being focused.
- `arg` - an argument.
-
- The rest of the parameters are a rectangle giving the portion of
- this region corresponding to the focus. If they are all None, than
- this focus is assumed to be the singular full-screen focus.
- """
-
- if mask is not None and mask is not self:
- self.depends_on(mask)
-
- t = (d, arg, x, y, w, h, mx, my, mask)
-
- if self.focuses is None:
- self.focuses = [ t ]
- else:
- self.focuses.append(t)
-
- def take_focuses(self, cminx, cminy, cmaxx, cmaxy, reverse, x, y, focuses): #@DuplicatedSignature
- """
- 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.modal:
- focuses[:] = [ ]
-
- if self.reverse:
- reverse = reverse * self.reverse
-
- if self.focuses:
-
- for (d, arg, xo, yo, w, h, mx, my, mask) in self.focuses:
-
- if xo is None:
- focuses.append(renpy.display.focus.Focus(d, arg, None, None, None, None))
- continue
-
- x1, y1 = reverse.transform(xo, yo)
- x2, y2 = reverse.transform(xo + w, yo + h)
-
- minx = min(x1, x2) + x
- miny = min(y1, y2) + y
- 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(cminx, cminy, cmaxx, cmaxy, reverse, x + xo, y + yo, focuses)
-
- if self.pass_focuses:
- for child in self.pass_focuses:
- child.take_focuses(cminx, cminy, cmaxx, cmaxy, reverse, x, y, focuses)
-
- def focus_at_point(self, x, y): #@DuplicatedSignature
- """
- 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
-
- if self.focuses:
- for (d, arg, xo, yo, w, h, mx, my, mask) in self.focuses:
-
- if xo is None:
- continue
-
- elif mx is not None:
- cx = x - mx
- cy = y - my
-
- if self.forward:
- cx, cy = self.forward.transform(cx, cy)
-
- if mask.is_pixel_opaque(cx, cy):
- rv = d, arg
-
- elif xo <= x < xo + w and yo <= y < yo + h:
- rv = d, arg
-
- for child, xo, yo, focus, main in self.children:
-
- if not focus or not isinstance(child, Render):
- continue
-
- cx = x - xo
- cy = y - yo
-
- if self.forward:
- cx, cy = self.forward.transform(cx, cy)
-
- cf = child.focus_at_point(cx, cy)
- if cf is not None:
- rv = cf
-
- if self.pass_focuses:
- for child in self.pass_focuses:
- cf = child.focus_at_point(x, y)
- if cf is not None:
- rv = cf
-
- if rv is None and self.modal:
- rv = Modal
-
- return rv
-
-
- def main_displayables_at_point(self, x, y, layers, depth=None):
- """
- Returns the displayable at `x`, `y` on one of the layers in
- the set or list `layers`.
- """
-
- rv = [ ]
-
- if x < 0 or y < 0 or x >= self.width or y >= self.height:
- return rv
-
- if depth is not None:
- for d in self.render_of:
- rv.append((depth, self.width, self.height, d))
- depth += 1
- elif self.layer_name in layers:
- depth = 0
-
- for (child, xo, yo, focus, main) in self.children:
- if not main or not isinstance(child, Render):
- continue
-
- cx = x - xo
- cy = y - yo
-
- if self.forward:
- cx, cy = self.forward.transform(cx, cy)
-
- cf = child.main_displayables_at_point(cx, cy, layers, depth)
- rv.extend(cf)
-
- return rv
-
-
- def is_opaque(self):
- """
- Returns true if this displayable is opaque, or False otherwise.
- Also sets self.visible_children.
- """
-
- if self.opaque is not None:
- return self.opaque
-
- # A rotated image is never opaque. (This isn't actually true, but it
- # saves us from the expensive calculations require to prove it is.)
- if self.forward:
- self.opaque = False
- return False
-
- rv = False
- vc = [ ]
-
- for i in self.children:
- child, xo, yo, focus, main = i
-
- if xo <= 0 and yo <= 0:
- cw, ch = child.get_size()
- if cw + xo < self.width or ch + yo < self.height:
- if child.is_opaque():
- vc = [ ]
- rv = True
-
- vc.append(i)
-
- self.visible_children = vc
- self.opaque = rv
- return rv
-
-
- def is_pixel_opaque(self, x, y):
- """
- 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
-
- if self.is_opaque():
- return True
-
- return renpy.display.draw.is_pixel_opaque(self, x, y)
-
-
- def fill(self, color):
- """
- Fills this Render with the given color.
- """
-
- color = renpy.easy.color(color)
- solid = renpy.display.imagelike.Solid(color)
- surf = render(solid, self.width, self.height, 0, 0)
- self.blit(surf, (0, 0), focus=False, main=False)
-
-
- def canvas(self):
- """
- Returns a canvas object that draws to this Render.
- """
-
- surf = renpy.display.pgrender.surface((self.width, self.height), True)
-
- mutated_surface(surf)
-
- self.blit(surf, (0, 0))
-
- return Canvas(surf)
-
-
-class Canvas(object):
-
- def __init__(self, surf): #@DuplicatedSignature
- self.surf = surf
-
- def rect(self, color, rect, width=0):
-
- try:
- blit_lock.acquire()
- pygame.draw.rect(self.surf,
- renpy.easy.color(color),
- rect,
- width)
- finally:
- blit_lock.release()
-
- def polygon(self, color, pointlist, width=0):
- try:
- blit_lock.acquire()
- pygame.draw.polygon(self.surf,
- renpy.easy.color(color),
- pointlist,
- width)
- finally:
- blit_lock.release()
-
- def circle(self, color, pos, radius, width=0):
-
- try:
- blit_lock.acquire()
- pygame.draw.circle(self.surf,
- renpy.easy.color(color),
- pos,
- radius,
- width)
-
- finally:
- blit_lock.release()
-
- def ellipse(self, color, rect, width=0):
- try:
- blit_lock.acquire()
- pygame.draw.ellipse(self.surf,
- renpy.easy.color(color),
- rect,
- width)
- finally:
- blit_lock.release()
-
-
- def arc(self, color, rect, start_angle, stop_angle, width=1):
- try:
- blit_lock.acquire()
- pygame.draw.arc(self.surf,
- renpy.easy.color(color),
- rect,
- start_angle,
- stop_angle,
- width)
- finally:
- blit_lock.release()
-
-
- def line(self, color, start_pos, end_pos, width=1):
- try:
- blit_lock.acquire()
- pygame.draw.line(self.surf,
- renpy.easy.color(color),
- start_pos,
- end_pos,
- width)
- finally:
- blit_lock.release()
-
- def lines(self, color, closed, pointlist, width=1):
- try:
- blit_lock.acquire()
- pygame.draw.lines(self.surf,
- renpy.easy.color(color),
- closed,
- pointlist,
- width)
- finally:
- blit_lock.release()
-
- def aaline(self, color, startpos, endpos, blend=1):
- try:
- blit_lock.acquire()
- pygame.draw.aaline(self.surf,
- renpy.easy.color(color),
- startpos,
- endpos,
- blend)
- finally:
- blit_lock.release()
-
- def aalines(self, color, closed, pointlist, blend=1):
- try:
- blit_lock.acquire()
- pygame.draw.aalines(self.surf,
- renpy.easy.color(color),
- closed,
- pointlist,
- blend)
- finally:
- blit_lock.release()