Created
April 18, 2016 16:21
-
-
Save anonymous/18130022bf8001ac08147c6c025892ca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright 2004-2016 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. | |
# NOTE: | |
# Transitions need to be able to work even when old_widget and new_widget | |
# are None, at least to the point of making it through __init__. This is | |
# so that prediction of images works. | |
import renpy.display | |
from renpy.display.render import render | |
class Transition(renpy.display.core.Displayable): | |
""" | |
This is the base class of most transitions. It takes care of event | |
dispatching. | |
""" | |
def __init__(self, delay, **properties): | |
super(Transition, self).__init__(**properties) | |
self.delay = delay | |
self.events = True | |
def event(self, ev, x, y, st): | |
if self.events or ev.type == renpy.display.core.TIMEEVENT: | |
return self.new_widget.event(ev, x, y, st) # E1101 | |
else: | |
return None | |
def visit(self): | |
return [ self.new_widget, self.old_widget ] # E1101 | |
def null_render(d, width, height, st, at): | |
d.events = True | |
surf = renpy.display.render.render(d.new_widget, | |
width, | |
height, | |
st, at) | |
rv = renpy.display.render.Render(surf.width, surf.height) | |
rv.blit(surf, (0, 0)) | |
return rv | |
class NoTransition(Transition): | |
""" | |
:doc: transition function | |
:name: Pause | |
:args: (delay) | |
Returns a transition that only displays the new screen for `delay` seconds. | |
It can be useful as part of a MultipleTransition. | |
""" | |
def __init__(self, delay, old_widget=None, new_widget=None, **properties): | |
super(NoTransition, self).__init__(delay, **properties) | |
self.old_widget = old_widget | |
self.new_widget = new_widget | |
self.events = True | |
def render(self, width, height, st, at): | |
return null_render(self, width, height, st, at) | |
class MultipleTransition(Transition): | |
""" | |
:doc: transition function | |
:args: (args) | |
Returns a transition that allows multiple transitions to be displayed, one | |
after the other. | |
`args` | |
A *list* containing an odd number of items. The first, third, and | |
other odd-numbered items must be scenes, and the even items | |
must be transitions. A scene can be one of: | |
* A displayable. | |
* False, to use the old scene. | |
* True, to use the new scene. | |
Almost always, the first argument will be False and the last True. | |
The transitions in `args` are applied in order. For each transition, | |
the old scene is the screen preceding it, and the new scene is the | |
scene following it. For example:: | |
define logodissolve = MultipleTransition([ | |
False, Dissolve(0.5) | |
"logo.jpg", Pause(1.0), | |
"logo.jpg", dissolve, | |
True]) | |
This example will dissolve to logo.jpg, wait 1 second, and then | |
dissolve to the new scene. | |
""" | |
def __init__(self, args, old_widget=None, new_widget=None, **properties): | |
if len(args) % 2 != 1 or len(args) < 3: | |
raise Exception("MultipleTransition requires an odd number of arguments, and at least 3 arguments.") | |
self.transitions = [ ] | |
# The screens that we use for the transition. | |
self.screens = [ renpy.easy.displayable(i) for i in args[0::2] ] | |
def oldnew(w): | |
if w is False: | |
return old_widget | |
if w is True: | |
return new_widget | |
return w | |
for old, trans, new in zip(self.screens[0:], args[1::2], self.screens[1:]): | |
old = oldnew(old) | |
new = oldnew(new) | |
self.transitions.append(trans(old_widget=old, new_widget=new)) | |
super(MultipleTransition, self).__init__(sum([i.delay for i in self.transitions]), **properties) | |
self.new_widget = self.transitions[-1] | |
self.events = False | |
def visit(self): | |
return [ i for i in self.screens if isinstance(i, renpy.display.core.Displayable)] + self.transitions | |
def event(self, ev, x, y, st): | |
if self.events or ev.type == renpy.display.core.TIMEEVENT: | |
return self.transitions[-1].event(ev, x, y, st) | |
else: | |
return None | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates: | |
return null_render(self, width, height, st, at) | |
for trans in self.transitions[:-1]: | |
if trans.delay > st: | |
break | |
st -= trans.delay | |
else: | |
trans = self.transitions[-1] | |
self.events = True | |
if trans is not self.transitions[-1]: | |
renpy.display.render.render(self.transitions[-1], width, height, 0, 0) | |
surf = renpy.display.render.render(trans, width, height, st, at) | |
width, height = surf.get_size() | |
rv = renpy.display.render.Render(width, height) | |
rv.blit(surf, (0, 0)) | |
if st < trans.delay: | |
renpy.display.render.redraw(self, trans.delay - st) | |
return rv | |
def Fade(out_time, | |
hold_time, | |
in_time, | |
old_widget=None, | |
new_widget=None, | |
color=None, | |
widget=None, | |
alpha=False, | |
): | |
""" | |
:doc: transition function | |
:args: (out_time, hold_time, in_time, color="#000") | |
:name: Fade | |
Returns a transition that takes `out_time` seconds to fade to | |
a screen filled with `color`, holds at that screen for `hold_time` | |
seconds, and then takes `in_time` to fade to then new screen. | |
:: | |
# Fade to black and back. | |
define fade = Fade(0.5, 0.0, 0.5) | |
# Hold at black for a bit. | |
define fadehold = Fade(0.5, 1.0, 0.5) | |
# Camera flash - quickly fades to white, then back to the scene. | |
define flash = Fade(0.1, 0.0, 0.5, color="#fff") | |
""" | |
dissolve = renpy.curry.curry(Dissolve) | |
notrans = renpy.curry.curry(NoTransition) | |
widget = renpy.easy.displayable_or_none(widget) | |
if color: | |
widget = renpy.display.image.Solid(color) | |
if not widget: | |
widget = renpy.display.image.Solid((0, 0, 0, 255)) | |
args = [ False, dissolve(out_time, alpha=alpha), widget ] | |
if hold_time: | |
args.extend([ notrans(hold_time), widget, ]) | |
args.extend([dissolve(in_time, alpha=alpha), True ]) | |
return MultipleTransition(args, old_widget=old_widget, new_widget=new_widget) | |
class Pixellate(Transition): | |
""" | |
:doc: transition function | |
:args: (time, steps) | |
:name: Pixellate | |
Returns a transition that pixellates out the old screen, and then | |
pixellates in the new screen. | |
`time` | |
The total time the transition will take, in seconds. | |
`steps` | |
The number of steps that will occur, in each direction. Each step | |
creates pixels about twice the size of those in the previous step, | |
so a 5-step pixellation will create 32x32 pixels. | |
""" | |
def __init__(self, time, steps, old_widget=None, new_widget=None, **properties): | |
time = float(time) | |
super(Pixellate, self).__init__(time, **properties) | |
self.time = time | |
self.steps = steps | |
self.old_widget = old_widget | |
self.new_widget = new_widget | |
self.events = False | |
self.quantum = time / (2 * steps) | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates: | |
return null_render(self, width, height, st, at) | |
if st >= self.time: | |
self.events = True | |
return render(self.new_widget, width, height, st, at) | |
step = st // self.quantum + 1 | |
visible = self.old_widget | |
if step > self.steps: | |
step = (self.steps * 2) - step + 1 | |
visible = self.new_widget | |
self.events = True | |
rdr = render(visible, width, height, st, at) | |
rv = renpy.display.render.Render(rdr.width, rdr.height) | |
rv.blit(rdr, (0, 0)) | |
rv.operation = renpy.display.render.PIXELLATE | |
rv.operation_parameter = 2 ** step | |
renpy.display.render.redraw(self, 0) | |
return rv | |
class Dissolve(Transition): | |
""" | |
:doc: transition function | |
:args: (time, alpha=False, time_warp=None) | |
:name: Dissolve | |
Returns a transition that dissolves from the old scene to the new scene. | |
`time` | |
The time the dissolve will take. | |
`alpha` | |
If true, the dissolve will alpha-composite the the result of the | |
transition with the screen. If false, the result of the transition | |
will replace the screen, which is more efficient. | |
`time_warp` | |
A function that adjusts the timeline. If not None, this should be a | |
function that takes a fractional time between 0.0 and 1.0, and returns | |
a number in the same range. | |
""" | |
__version__ = 1 | |
def after_upgrade(self, version): | |
if version < 1: | |
self.alpha = False | |
time_warp = None | |
def __init__(self, time, old_widget=None, new_widget=None, alpha=False, time_warp=None, **properties): | |
super(Dissolve, self).__init__(time, **properties) | |
self.time = time | |
self.old_widget = old_widget | |
self.new_widget = new_widget | |
self.events = False | |
self.alpha = alpha | |
self.time_warp = time_warp | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates: | |
return null_render(self, width, height, st, at) | |
if st >= self.time: | |
self.events = True | |
return render(self.new_widget, width, height, st, at) | |
complete = min(1.0, st / self.time) | |
if self.time_warp is not None: | |
complete = self.time_warp(complete) | |
bottom = render(self.old_widget, width, height, st, at) | |
top = render(self.new_widget, width, height, st, at) | |
width = min(top.width, bottom.width) | |
height = min(top.height, bottom.height) | |
rv = renpy.display.render.Render(width, height, opaque=not self.alpha) | |
rv.operation = renpy.display.render.DISSOLVE | |
rv.operation_alpha = self.alpha | |
rv.operation_complete = complete | |
rv.blit(bottom, (0, 0), focus=False, main=False) | |
rv.blit(top, (0, 0), focus=True, main=True) | |
renpy.display.render.redraw(self, 0) | |
return rv | |
class ImageDissolve(Transition): | |
""" | |
:doc: transition function | |
:args: (image, time, ramplen=8, reverse=False, alpha=True, time_warp=None) | |
:name: ImageDissolve | |
Returns a transition that dissolves the old scene into the new scene, using | |
an image to control the dissolve process. This means that white pixels will | |
dissolve in first, and black pixels will dissolve in last. | |
`image` | |
A control image to use. This must be either an image file or | |
image manipulator. The control image should be the size of | |
the scenes being dissolved. | |
`time` | |
The time the dissolve will take. | |
`ramplen` | |
The length of the ramp to use. This must be an integer power | |
of 2. When this is the default value of 8, when a white pixel | |
is fully dissolved, a pixel 8 shades of gray darker will have | |
completed one step of dissolving in. | |
`reverse` | |
If true, black pixels will dissolve in before white pixels. | |
`alpha` | |
If true, the dissolve will alpha-composite the the result of the | |
transition with the screen. If false, the result of the transition | |
will replace the screen, which is more efficient. | |
`time_warp` | |
A function that adjusts the timeline. If not None, this should be a | |
function that takes a fractional time between 0.0 and 1.0, and returns | |
a number in the same range. | |
:: | |
define circirisout = ImageDissolve("circiris.png", 1.0) | |
define circirisin = ImageDissolve("circiris.png", 1.0, reverse=True) | |
define circiristbigramp = ImageDissolve("circiris.png", 1.0, ramplen=256) | |
""" | |
__version__ = 1 | |
def after_upgrade(self, version): | |
if version < 1: | |
self.alpha = False | |
time_warp = None | |
def __init__( | |
self, | |
image, | |
time, | |
ramplen=8, | |
ramptype='linear', | |
ramp=None, | |
reverse=False, | |
alpha=False, | |
old_widget=None, | |
new_widget=None, | |
time_warp=None, | |
**properties): | |
# ramptype and ramp are now unused, but are kept for compatbility with | |
# older code. | |
super(ImageDissolve, self).__init__(time, **properties) | |
self.old_widget = old_widget | |
self.new_widget = new_widget | |
self.events = False | |
self.alpha = alpha | |
self.time_warp = time_warp | |
if not reverse: | |
# Copies red -> alpha | |
matrix = renpy.display.im.matrix( | |
0, 0, 0, 0, 1, | |
0, 0, 0, 0, 1, | |
0, 0, 0, 0, 1, | |
1, 0, 0, 0, 0) | |
else: | |
# Copies 1-red -> alpha | |
matrix = renpy.display.im.matrix( | |
0, 0, 0, 0, 1, | |
0, 0, 0, 0, 1, | |
0, 0, 0, 0, 1, | |
- 1, 0, 0, 0, 1) | |
self.image = renpy.display.im.MatrixColor(image, matrix) | |
if ramp is not None: | |
ramplen = len(ramp) | |
# The length of the ramp. | |
self.ramplen = max(ramplen, 1) | |
def visit(self): | |
return super(ImageDissolve, self).visit() + [ self.image ] | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates or renpy.display.less_imagedissolve: | |
return null_render(self, width, height, st, at) | |
if st >= self.delay: | |
self.events = True | |
return render(self.new_widget, width, height, st, at) | |
image = render(self.image, width, height, st, at) | |
bottom = render(self.old_widget, width, height, st, at) | |
top = render(self.new_widget, width, height, st, at) | |
width = min(bottom.width, top.width, image.width) | |
height = min(bottom.height, top.height, image.height) | |
rv = renpy.display.render.Render(width, height, opaque=not self.alpha) | |
complete = st / self.delay | |
if self.time_warp is not None: | |
complete = self.time_warp(complete) | |
rv.operation = renpy.display.render.IMAGEDISSOLVE | |
rv.operation_alpha = self.alpha | |
rv.operation_complete = complete | |
rv.operation_parameter = self.ramplen | |
rv.blit(image, (0, 0), focus=False, main=False) | |
rv.blit(bottom, (0, 0), focus=False, main=False) | |
rv.blit(top, (0, 0), focus=True, main=True) | |
renpy.display.render.redraw(self, 0) | |
return rv | |
class AlphaDissolve(Transition): | |
""" | |
:doc: transition function | |
:args: (control, delay=0.0, alpha=False, reverse=False) | |
Returns a transition that uses a control displayable (almost always some | |
sort of animated transform) to transition from one screen to another. The | |
transform is evaluated. The new screen is used where the transform is | |
opaque, and the old image is used when it is transparent. | |
`control` | |
The control transform. | |
`delay` | |
The time the transition takes, before ending. | |
`alpha` | |
If true, the image is composited with what's behind it. If false, | |
the default, the image is opaque and overwrites what's behind it. | |
`reverse` | |
If true, the alpha channel is reversed. Opaque areas are taken | |
from the old image, while transparent areas are taken from the | |
new image. | |
""" | |
def __init__( | |
self, | |
control, | |
delay=0.0, | |
old_widget=None, | |
new_widget=None, | |
alpha=False, | |
reverse=False, | |
**properties): | |
super(AlphaDissolve, self).__init__(delay, **properties) | |
self.control = renpy.display.layout.Fixed() | |
self.control.add(control) | |
self.old_widget = renpy.easy.displayable(old_widget) | |
self.new_widget = renpy.easy.displayable(new_widget) | |
self.events = False | |
self.alpha = alpha | |
self.reverse = reverse | |
def visit(self): | |
return super(AlphaDissolve, self).visit() + [ self.control ] | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates or renpy.display.less_imagedissolve: | |
return null_render(self, width, height, st, at) | |
if st >= self.delay: | |
self.events = True | |
bottom = render(self.old_widget, width, height, st, at) | |
top = render(self.new_widget, width, height, st, at) | |
width = min(bottom.width, top.width) | |
height = min(bottom.height, top.height) | |
control = render(self.control, width, height, st, at) | |
rv = renpy.display.render.Render(width, height, opaque=not self.alpha) | |
rv.operation = renpy.display.render.IMAGEDISSOLVE | |
rv.operation_alpha = self.alpha | |
rv.operation_complete = 256.0 / (256.0 + 256.0) | |
rv.operation_parameter = 256 | |
rv.blit(control, (0, 0), focus=False, main=False) | |
if not self.reverse: | |
rv.blit(bottom, (0, 0), focus=False, main=False) | |
rv.blit(top, (0, 0), focus=True, main=True) | |
else: | |
rv.blit(top, (0, 0), focus=True, main=True) | |
rv.blit(bottom, (0, 0), focus=False, main=False) | |
return rv | |
class CropMove(Transition): | |
""" | |
:doc: transition function | |
:args: (time, mode="slideright", startcrop=(0.0, 0.0, 0.0, 1.0), startpos=(0.0, 0.0), endcrop=(0.0, 0.0, 1.0, 1.0), endpos=(0.0, 0.0), topnew=True) | |
:name: CropMove | |
Returns a transition that works by cropping a scene and positioning it on the | |
screen. This can be used to implement a variety of effects, all of which | |
involved changing rectangular slices of scenes. | |
`time` | |
The time the transition takes. | |
`mode` | |
The name of the mode of the transition. There are three groups | |
of modes: wipes, slides, and other. This can also be "custom", | |
to allow a custom mode to be defined. | |
In a wipe, the image stays fixed, and more of it is revealed as | |
the transition progresses. For example, in "wiperight", a wipe from left to right, first the left edge of the image is | |
revealed at the left edge of the screen, then the center of the image, | |
and finally the right side of the image at the right of the screen. | |
Other supported wipes are "wipeleft", "wipedown", and "wipeup". | |
In a slide, the image moves. So in a "slideright", the right edge of the | |
image starts at the left edge of the screen, and moves to the right | |
as the transition progresses. Other slides are "slideleft", "slidedown", | |
and "slideup". | |
There are also slideaways, in which the old image moves on top of | |
the new image. Slideaways include "slideawayright", "slideawayleft", | |
"slideawayup", and "slideawaydown". | |
We also support a rectangular iris in with "irisin" and a | |
rectangular iris out with "irisout". | |
The following parameters are only respected if the mode is "custom". Positions | |
are relative to the size of the screen, while the crops are relative to the | |
size of the image. So a crop of (0.25, 0.0, 0.5, 1.0) takes the middle | |
half of an image. | |
`startcrop` | |
The starting rectangle that is cropped out of the | |
top image. A 4-element tuple containing x, y, width, and height. | |
`startpos` | |
The starting place that the top image is drawn | |
to the screen at, a 2-element tuple containing x and y. | |
`endcrop` | |
The ending rectangle that is cropped out of the | |
top image. A 4-element tuple containing x, y, width, and height. | |
`endpos` | |
The ending place that the top image is drawn | |
to the screen at, a 2-element tuple containing x and y. | |
`topnew` | |
If true, the scene that is cropped and moved (and is on top of | |
the other scene) is the new scene. If false, it is the old scene. | |
:: | |
define wiperight = CropMove(1.0, "wiperight") | |
define wipeleft = CropMove(1.0, "wipeleft") | |
define wipeup = CropMove(1.0, "wipeup") | |
define wipedown = CropMove(1.0, "wipedown") | |
define slideright = CropMove(1.0, "slideright") | |
define slideleft = CropMove(1.0, "slideleft") | |
define slideup = CropMove(1.0, "slideup") | |
define slidedown = CropMove(1.0, "slidedown") | |
define slideawayright = CropMove(1.0, "slideawayright") | |
define slideawayleft = CropMove(1.0, "slideawayleft") | |
define slideawayup = CropMove(1.0, "slideawayup") | |
define slideawaydown = CropMove(1.0, "slideawaydown") | |
define irisout = CropMove(1.0, "irisout") | |
define irisin = CropMove(1.0, "irisin") | |
""" | |
def __init__(self, time, | |
mode="slideright", | |
startcrop=(0.0, 0.0, 0.0, 1.0), | |
startpos=(0.0, 0.0), | |
endcrop=(0.0, 0.0, 1.0, 1.0), | |
endpos=(0.0, 0.0), | |
topnew=True, | |
old_widget=None, | |
new_widget=None, | |
**properties): | |
super(CropMove, self).__init__(time, **properties) | |
self.time = time | |
if mode == "wiperight": | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 0.0, 1.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "wipeleft": | |
startpos = (1.0, 0.0) | |
startcrop = (1.0, 0.0, 0.0, 1.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "wipedown": | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 1.0, 0.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "wipeup": | |
startpos = (0.0, 1.0) | |
startcrop = (0.0, 1.0, 1.0, 0.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "slideright": | |
startpos = (0.0, 0.0) | |
startcrop = (1.0, 0.0, 0.0, 1.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "slideleft": | |
startpos = (1.0, 0.0) | |
startcrop = (0.0, 0.0, 0.0, 1.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "slideup": | |
startpos = (0.0, 1.0) | |
startcrop = (0.0, 0.0, 1.0, 0.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "slidedown": | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 1.0, 1.0, 0.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "slideawayleft": | |
endpos = (0.0, 0.0) | |
endcrop = (1.0, 0.0, 0.0, 1.0) | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = False | |
elif mode == "slideawayright": | |
endpos = (1.0, 0.0) | |
endcrop = (0.0, 0.0, 0.0, 1.0) | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = False | |
elif mode == "slideawaydown": | |
endpos = (0.0, 1.0) | |
endcrop = (0.0, 0.0, 1.0, 0.0) | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = False | |
elif mode == "slideawayup": | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 1.0, 1.0, 0.0) | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = False | |
elif mode == "irisout": | |
startpos = (0.5, 0.5) | |
startcrop = (0.5, 0.5, 0.0, 0.0) | |
endpos = (0.0, 0.0) | |
endcrop = (0.0, 0.0, 1.0, 1.0) | |
topnew = True | |
elif mode == "irisin": | |
startpos = (0.0, 0.0) | |
startcrop = (0.0, 0.0, 1.0, 1.0) | |
endpos = (0.5, 0.5) | |
endcrop = (0.5, 0.5, 0.0, 0.0) | |
topnew = False | |
elif mode == "custom": | |
pass | |
else: | |
raise Exception("Invalid mode %s passed into CropMove." % mode) | |
self.delay = time | |
self.time = time | |
self.startpos = startpos | |
self.endpos = endpos | |
self.startcrop = startcrop | |
self.endcrop = endcrop | |
self.topnew = topnew | |
self.old_widget = old_widget | |
self.new_widget = new_widget | |
self.events = False | |
if topnew: | |
self.bottom = old_widget | |
self.top = new_widget | |
else: | |
self.bottom = new_widget | |
self.top = old_widget | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates: | |
return null_render(self, width, height, st, at) | |
time = 1.0 * st / self.time | |
# Done rendering. | |
if time >= 1.0: | |
self.events = True | |
return render(self.new_widget, width, height, st, at) | |
# How we scale each element of a tuple. | |
scales = (width, height, width, height) | |
def interpolate_tuple(t0, t1): | |
return tuple([ int(s * (a * (1.0 - time) + b * time)) | |
for a, b, s in zip(t0, t1, scales) ]) | |
crop = interpolate_tuple(self.startcrop, self.endcrop) | |
pos = interpolate_tuple(self.startpos, self.endpos) | |
top = render(self.top, width, height, st, at) | |
bottom = render(self.bottom, width, height, st, at) | |
width = min(bottom.width, width) | |
height = min(bottom.height, height) | |
rv = renpy.display.render.Render(width, height) | |
rv.blit(bottom, (0, 0), focus=not self.topnew) | |
ss = top.subsurface(crop, focus=self.topnew) | |
rv.blit(ss, pos, focus=self.topnew) | |
renpy.display.render.redraw(self, 0) | |
return rv | |
class PushMove(Transition): | |
""" | |
:doc: transition function | |
:args: (time, mode="pushright") | |
:name: PushMove | |
Returns a transition that works by taking the new scene and using it to | |
"push" the old scene off the screen. | |
`time` | |
The time the transition takes. | |
`mode` | |
There are four possible modes: "pushright", "pushleft", "pushup", | |
and "pushdown", which push the old scene off the screen in the | |
direction indicated. | |
:: | |
define pushright = PushMove(1.0, "pushright") | |
define pushleft = PushMove(1.0, "pushleft") | |
define pushup = PushMove(1.0, "pushup") | |
define pushdown = PushMove(1.0, "pushdown") | |
""" | |
def __init__(self, time, | |
mode="pushright", | |
old_widget=None, | |
new_widget=None, | |
**properties): | |
super(PushMove, self).__init__(time, **properties) | |
self.time = time | |
if mode == "pushright": | |
self.new_startpos = (0.0, 0.0) | |
self.new_startcrop = (1.0, 0.0, 0.0, 1.0) | |
self.new_endpos = (0.0, 0.0) | |
self.new_endcrop = (0.0, 0.0, 1.0, 1.0) | |
self.old_endpos = (1.0, 0.0) | |
self.old_endcrop = (0.0, 0.0, 0.0, 1.0) | |
self.old_startpos = (0.0, 0.0) | |
self.old_startcrop = (0.0, 0.0, 1.0, 1.0) | |
elif mode == "pushleft": | |
self.new_startpos = (1.0, 0.0) | |
self.new_startcrop = (0.0, 0.0, 0.0, 1.0) | |
self.new_endpos = (0.0, 0.0) | |
self.new_endcrop = (0.0, 0.0, 1.0, 1.0) | |
self.old_endpos = (0.0, 0.0) | |
self.old_endcrop = (1.0, 0.0, 0.0, 1.0) | |
self.old_startpos = (0.0, 0.0) | |
self.old_startcrop = (0.0, 0.0, 1.0, 1.0) | |
elif mode == "pushup": | |
self.new_startpos = (0.0, 1.0) | |
self.new_startcrop = (0.0, 0.0, 1.0, 0.0) | |
self.new_endpos = (0.0, 0.0) | |
self.new_endcrop = (0.0, 0.0, 1.0, 1.0) | |
self.old_endpos = (0.0, 0.0) | |
self.old_endcrop = (0.0, 1.0, 1.0, 0.0) | |
self.old_startpos = (0.0, 0.0) | |
self.old_startcrop = (0.0, 0.0, 1.0, 1.0) | |
elif mode == "pushdown": | |
self.new_startpos = (0.0, 0.0) | |
self.new_startcrop = (0.0, 1.0, 1.0, 0.0) | |
self.new_endpos = (0.0, 0.0) | |
self.new_endcrop = (0.0, 0.0, 1.0, 1.0) | |
self.old_endpos = (0.0, 1.0) | |
self.old_endcrop = (0.0, 0.0, 1.0, 0.0) | |
self.old_startpos = (0.0, 0.0) | |
self.old_startcrop = (0.0, 0.0, 1.0, 1.0) | |
else: | |
raise Exception("Invalid mode %s passed into PushMove." % mode) | |
self.delay = time | |
self.time = time | |
self.old_widget = old_widget | |
self.new_widget = new_widget | |
self.events = False | |
def render(self, width, height, st, at): | |
if renpy.game.less_updates: | |
return null_render(self, width, height, st, at) | |
time = 1.0 * st / self.time | |
# Done rendering. | |
if time >= 1.0: | |
self.events = True | |
return render(self.new_widget, width, height, st, at) | |
# How we scale each element of a tuple. | |
scales = (width, height, width, height) | |
def interpolate_tuple(t0, t1): | |
return tuple([ int(s * (a * (1.0 - time) + b * time)) | |
for a, b, s in zip(t0, t1, scales) ]) | |
new_crop = interpolate_tuple(self.new_startcrop, self.new_endcrop) | |
new_pos = interpolate_tuple(self.new_startpos, self.new_endpos) | |
old_crop = interpolate_tuple(self.old_startcrop, self.old_endcrop) | |
old_pos = interpolate_tuple(self.old_startpos, self.old_endpos) | |
new = render(self.new_widget, width, height, st, at) | |
old = render(self.old_widget, width, height, st, at) | |
rv = renpy.display.render.Render(width, height) | |
old_ss = old.subsurface(old_crop, focus = True) | |
rv.blit(old_ss, old_pos, focus = True) | |
new_ss = new.subsurface(new_crop, focus = True) | |
rv.blit(new_ss, new_pos, focus = True) | |
renpy.display.render.redraw(self, 0) | |
return rv | |
def ComposeTransition(trans, before=None, after=None, new_widget=None, old_widget=None): | |
""" | |
:doc: transition function | |
:args: (trans, before, after) | |
Returns a transition that composes up to three transitions. If not None, | |
the `before` and `after` transitions are applied to the old and new | |
scenes, respectively. These updated old and new scenes are then supplied | |
to the `trans` transition. | |
:: | |
# Move the images in and out while dissolving. (This is a fairly expensive transition.) | |
define moveinoutdissolve = ComposeTransition(dissolve, before=moveoutleft, after=moveinright) | |
""" | |
if before is not None: | |
old = before(new_widget=new_widget, old_widget=old_widget) | |
else: | |
old = old_widget | |
if after is not None: | |
new = after(new_widget=new_widget, old_widget=old_widget) | |
else: | |
new = new_widget | |
return trans(new_widget=new, old_widget=old) | |
def SubTransition(rect, trans, old_widget=None, new_widget=None, **properties): | |
""" | |
Applies a transition to a subset of the screen. Not documented. | |
""" | |
x, y, _w, _h = rect | |
old = renpy.display.layout.LiveCrop(rect, old_widget) | |
new = renpy.display.layout.LiveCrop(rect, new_widget) | |
inner = trans(old_widget=old, new_widget=new) | |
delay = inner.delay | |
inner = renpy.display.layout.Position(inner, xpos=x, ypos=y, xanchor=0, yanchor=0) | |
f = renpy.display.layout.MultiBox(layout='fixed') | |
f.add(new_widget) | |
f.add(inner) | |
return NoTransition(delay, old_widget=f, new_widget=f) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment