diff options
Diffstat (limited to 'unrpyc/renpy/display/render.pyx')
-rw-r--r-- | unrpyc/renpy/display/render.pyx | 1174 |
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() |