Compare commits

...

139 Commits

Author SHA1 Message Date
Tom Rothamel cc54d1970b Windows & Distribution fixes. 2011-01-29 18:26:49 -05:00
Tom Rothamel e6915fffd3 Ensure that we can load Matrix2Ds. 2011-01-29 12:16:36 -05:00
Tom Rothamel 964d746f6d Move yesno_prompt back to 6.11 location. 2011-01-29 10:44:33 -05:00
Tom Rothamel de6af43d74 Bump copyright year. 2011-01-29 09:27:48 -05:00
Tom Rothamel 0dc1a6e46c Android docs. 2011-01-29 00:23:53 -05:00
Tom Rothamel 4098830804 Prevent get_screenshot from returning None. 2011-01-28 00:29:48 -05:00
Tom Rothamel 304ab15b8f Doc and tutorial additions/fixes. 2011-01-28 00:26:24 -05:00
Tom Rothamel 16fa9410db Pixel opacity can't be determined in GLES mode - so don't bother trying. 2011-01-28 00:10:38 -05:00
Tom Rothamel 9ff69de20c Kill a possible INVALID_ENUM error. 2011-01-27 21:51:14 -05:00
Tom Rothamel cd50f1ee86 Document snowblossom. 2011-01-27 19:07:19 -05:00
Tom Rothamel 195f3d6130 Documentation; Particle fix; Sprite demo. 2011-01-27 18:36:10 -05:00
Tom Rothamel 89d8622f6f Typo fix in tutorial. Change how we setup modulefinder. 2011-01-27 01:58:18 -05:00
Tom Rothamel d71e054eb4 Changes to import so that we can build packages. 2011-01-27 01:17:27 -05:00
Tom Rothamel 48a648eecd A far more minimial solution. 2011-01-27 00:07:16 -05:00
Tom Rothamel 63268d079e Remove the clipper from the software renderer, as it was causing problems
with transformed scaled images.
2011-01-26 23:24:54 -05:00
Tom Rothamel 743d5ca81a Add starfield effect. 2011-01-26 16:30:44 -05:00
Tom Rothamel dffb33c8e0 Fix the demo. 2011-01-25 21:36:11 -05:00
Tom Rothamel a6ea0931dd Fix Philippines flag orientation.
Never trust mugenjohncel.
2011-01-24 23:33:36 -05:00
Tom Rothamel 17016c0eb2 Fix bugs, tweak memory usage. 2011-01-24 23:33:31 -05:00
Tom Rothamel 67c703d934 Use big textures for RTT. 2011-01-24 22:28:58 -05:00
Tom Rothamel c163d1c936 Add focus_mask to screen language. 2011-01-24 21:12:33 -05:00
Tom Rothamel e3c15a2c58 Automatically size the window on initial load. 2011-01-24 19:28:43 -05:00
Tom Rothamel dfc149f292 Use glrtt fbo to render to textures.
Fix problem w/ rtt format.
2011-01-23 23:57:49 -05:00
Tom Rothamel 627ba65b9a Partially fix distribute, fixes for android. 2011-01-22 21:02:57 -05:00
Tom Rothamel a92170d88a Various fixes required to fix the Ren'Py tutorial. 2011-01-22 13:35:26 -05:00
Tom Rothamel 503653cb5e Fix sound problem. 2011-01-22 10:55:47 -05:00
Tom Rothamel 68c277ff9a Cleanup after merging. 2011-01-21 23:13:22 -05:00
Tom Rothamel 7b171b4f9b Spacing. 2011-01-21 22:42:34 -05:00
Tom Rothamel 30956e4c58 Rewrite the code that writes bytecode.rpyb, so that it uses md5 hashes
so that we don't have to recompile the code every time Ren'Py is
upgraded. (This matters on android.)
2011-01-21 22:36:40 -05:00
Tom Rothamel 6a956aacab Ren'Py now treats filenames as if they were case-insensitive. This
means that filename mismatches on Linux should no longer be a problem.
2011-01-21 00:20:33 -05:00
Tom Rothamel 681c845e2d Fix ordering problem the meant a parent's per_interact could be called
before its children's.

Fix lp:680266.
2011-01-19 23:45:07 -05:00
Tom Rothamel 11594ef5e8 Fix problems with SnowBlossom/Particles. 2011-01-19 00:19:21 -05:00
Tom Rothamel 28f06291db sl: add spacing 2011-01-18 23:04:14 -05:00
Tom Rothamel c6937698ed Fix screen prediction, especially for menus.
Rewrote tutorial to use an imagemap-screen.
2011-01-18 21:01:21 -05:00
Tom Rothamel 15f85c8b80 Merge with mainline. 2011-01-17 23:04:27 -05:00
Tom Rothamel 7fd5695f83 More build tweaks. 2011-01-17 23:03:18 -05:00
Tom Rothamel 952880287b Change how we version the module. 2011-01-17 22:01:44 -05:00
Tom Rothamel f76c7cf25a Lower the double-click to quit time to .75 seconds, to prevent confusion. 2011-01-16 14:03:17 -05:00
Tom Rothamel 7c14b4d381 Fix bug that prevented canvas from working in GL mode. 2011-01-16 13:59:42 -05:00
Tom Rothamel c67389f0a3 Fix dbz in audio code. 2011-01-16 11:13:35 -05:00
Tom Rothamel 219994ced2 Fix problems switching from sw -> gl, in 00gltest. 2011-01-15 23:21:28 -05:00
Tom Rothamel 274f08807e Allow Ren'Py to run on ancient OpenGL implementations. 2011-01-15 21:35:03 -05:00
Tom Rothamel 7601b4d3da Ensure Ren'Py can start even when OpenGL is missing. 2011-01-15 20:13:56 -05:00
Tom Rothamel 05d14b4bfd Fix im.matrix.colorize. 2011-01-15 19:24:24 -05:00
Tom Rothamel c5b63fd1c5 Fix get_screenshot regression. 2011-01-15 19:05:58 -05:00
Tom Rothamel 0bb6a926b2 Add config.screenshot_callback. 2011-01-15 18:54:38 -05:00
Tom Rothamel 0124eacb15 Add hovered and unhovered to Bar.
Remove spritemanager sl statement.
2011-01-15 18:19:04 -05:00
Tom Rothamel 7ac06761d6 Add MouseArea/mousearea. Add spritemanager to screen language. 2011-01-15 16:59:47 -05:00
Tom Rothamel c8c6226045 Add screen prediction to say, menu, and call screen statements, and
to several Actions.
2011-01-15 13:53:58 -05:00
Tom Rothamel 507d9610c7 Implement screen variants. 2011-01-15 00:10:53 -05:00
Tom Rothamel 5f4075fc35 Add NVL screen. 2011-01-14 09:39:07 -05:00
Tom Rothamel 514571cc80 Fix problems with options and shift+R reloading. 2011-01-13 01:09:51 -05:00
Tom Rothamel 6ff34b71cf Round stencil box coordinates more accurately. 2011-01-13 01:06:09 -05:00
Tom Rothamel 37416daa53 Fixes for menu screens. 2011-01-13 00:20:23 -05:00
Tom Rothamel 6bd5401633 Make the tutorial game use screens; improve screen support as necessary. 2011-01-12 23:59:25 -05:00
Tom Rothamel ea6b9571b5 Fixed software rendering / transform for now. This required ensuring that
there is always a 2-pixel band around the border of each image, up from
the previous 1-pixel border.
2011-01-10 02:06:00 -05:00
Tom Rothamel bd7c403986 Rewrite Solid and Frame so that they use the GPU to do scaling. Frame
no longer requires its argument to be an image manipulator.
2011-01-09 22:44:14 -05:00
Tom Rothamel 99417726ce Prediction of screens. 2011-01-09 18:14:52 -05:00
Tom Rothamel 4319e542f7 Add accessor for prefixed style properties.
Add prediction for images used in windows, buttons, and bars.
2011-01-09 00:25:44 -05:00
Tom Rothamel 61d8445949 Rewrote image prediction code. 2011-01-08 23:42:13 -05:00
Tom Rothamel 743095064d Update logging. 2011-01-08 01:41:29 -05:00
Tom Rothamel efa12ab5a6 Add logging infrastructure. 2011-01-08 01:15:39 -05:00
Tom Rothamel b49b1b392c Action prediction code. 2011-01-08 00:16:16 -05:00
Tom Rothamel 09e54e9915 Doc fix. 2011-01-07 23:39:14 -05:00
Tom Rothamel 373d175f2d Make imagemap caching configurable on a per-screen basis. 2011-01-04 01:57:10 -05:00
Tom Rothamel 5f3955a04a Cache imagemap hotspots to disk. 2011-01-04 01:37:33 -05:00
Tom Rothamel 98c0e51527 Document images and image manipulators. 2011-01-01 01:03:43 -05:00
Tom Rothamel 8b3a6e8fc6 Checkin to merge docs from wrong place. 2011-01-01 00:47:13 -05:00
Tom Rothamel b2d2e8ba7e Brillantly documented im.py in the wrong place. Checking in for a merge. 2011-01-01 00:46:29 -05:00
Tom Rothamel f1efced19c merge from trunk 2010-12-29 23:54:46 -05:00
Tom Rothamel 5b09dfc80c merge from trunk 2010-12-29 23:54:22 -05:00
Tom Rothamel 39f91a4368 Doc work 2010-12-29 23:52:37 -05:00
Tom Rothamel 3b6c9bde63 Fix sprites and add documentation. 2010-12-29 00:57:54 -05:00
Tom Rothamel 1df05ea53e fix bug when computing determinant. 2010-12-29 00:34:33 -05:00
Tom Rothamel 3e9aee1c6f Documentation. 2010-12-28 00:09:13 -05:00
Tom Rothamel 5231a460da Document Drag and Drop. 2010-12-26 21:10:31 -05:00
Tom Rothamel e6b3b36df9 Tweak sphinx building to handle methods; add (some) docs to dragdrop. 2010-12-25 10:13:22 -05:00
Tom Rothamel 060d510658 Random tweaks to work better with cardgame. 2010-12-25 02:34:23 -05:00
Tom Rothamel 3b21a4aa97 Redo joining support to be a better design; add clicked, hovered, and
unhovered to drag and drop.
2010-12-24 16:19:26 -05:00
Tom Rothamel 4824b44950 Added joins to achieve reasonably working drag and drop. 2010-12-24 01:25:31 -05:00
Tom Rothamel 988a92d4a5 Drag and drop uses style prefixes. 2010-12-23 11:21:53 -05:00
Tom Rothamel 378e2e61bd Implement drag & drop callbacks. 2010-12-23 01:29:23 -05:00
Tom Rothamel eb94a7d9bb Implement drag groups. 2010-12-23 00:40:25 -05:00
Tom Rothamel fe2ba07a57 Remember drag position. 2010-12-22 01:12:57 -05:00
Tom Rothamel 2788b12eb2 Add drag to SL and UI, restrict positions to the screen. 2010-12-21 00:01:59 -05:00
Tom Rothamel 265b553b4e Initial working drag and drop code. 2010-12-20 22:39:55 -05:00
Tom Rothamel 5f800681aa Make field presentable, preventing a memory leak. 2010-12-16 21:56:50 -05:00
Tom Rothamel 890c9cf591 Delete the correct file on restart. 2010-12-16 11:29:23 -05:00
Tom Rothamel 2c356b80ed Reset clear color to black. 2010-12-15 23:20:00 -05:00
Tom Rothamel cc097ba7da Use glScissor for clipping. 2010-12-15 23:12:08 -05:00
Tom Rothamel 78401f1c4a implement config.linear_saves_page_size 2010-12-14 21:43:48 -05:00
Tom Rothamel 8802363544 implement config.linear_saves_page_size 2010-12-14 21:39:51 -05:00
Tom Rothamel 05388c3733 Setup android keymap. 2010-12-14 11:51:54 -05:00
Tom Rothamel 8f84301b39 Android fixes. 2010-12-12 16:26:05 -05:00
Tom Rothamel 774ba5d990 Merge changes from lp:renpy. 2010-12-05 16:46:21 -05:00
Tom Rothamel 6bf0cd93d1 Merge bug fixes. 2010-12-05 16:43:56 -05:00
Tom Rothamel 7f63c26348 Since OpenGL ES doesn't support ClipPlanes, don't use them. 2010-12-05 13:04:22 -05:00
Tom Rothamel bce3e6ede1 More android fixes. 2010-12-05 00:17:48 -05:00
Tom Rothamel 4f642041f9 Change how reloading a game works.
Other minor android-related fixes.
2010-12-04 00:49:02 -05:00
Tom Rothamel b990b2768c Implement fast dissolve, config.simulate_android. 2010-11-29 22:28:42 -05:00
Tom Rothamel 53b8d37d8c Android fixes. 2010-11-28 16:29:47 -05:00
Tom Rothamel db9f63c2d9 Sound on Android Ren'Py. 2010-11-23 12:00:47 -05:00
Tom Rothamel 87df4ff487 Add power management support. 2010-11-16 23:08:49 -05:00
Tom Rothamel f0fe459460 GLES Video Working. 2010-11-14 23:02:07 -05:00
Tom Rothamel f71a35751a Fix problem with texture signedness. 2010-11-08 19:39:32 -05:00
Tom Rothamel 2458d9cbb3 Starting to display using GLES. 2010-11-07 22:15:15 -05:00
Tom Rothamel 81c6d33005 Limited environment. 2010-11-06 23:54:56 -04:00
Tom Rothamel dba5c20e34 Use RGBA instead of BGRA. 2010-11-05 22:34:38 -04:00
Tom Rothamel c2eddb21e5 Android work. 2010-11-04 00:06:55 -04:00
Tom Rothamel de1d289670 Better fix. 2010-11-01 08:01:12 -04:00
Tom Rothamel 623201fd75 fix crash bugs 2010-10-31 23:18:29 -04:00
Tom Rothamel 2f900b6bc7 Bump minimum GL version to 1.3. Rewrite drawing to use array-based functions that are supported by OpenGL ES. 2010-10-31 23:10:48 -04:00
Tom Rothamel 375af0cccd 6.11.2b 2010-10-26 22:12:50 -04:00
Tom Rothamel 8ae8e887f5 Fix a bug in Frame that can cause an image to be drawn more than once
a border size is 0.
2010-10-24 18:06:36 -04:00
Tom Rothamel 1e6e0f0800 Fix spritemanager when st=0, add destroy_all method. 2010-10-11 18:20:48 -04:00
Tom Rothamel b3b3c55473 Factor environments and RTTs out into their own files, so we don't have
to compile them for Android.
2010-10-09 13:50:34 -04:00
Tom Rothamel 7f2c6fd977 Fix software rendering. 2010-10-09 13:22:10 -04:00
Tom Rothamel 59338d3ae3 Eliminate the use of the tegl and pysdlgl modules. 2010-10-09 12:41:55 -04:00
Tom Rothamel 98a5647f97 Convert glenviron and glshader to use GL directly. 2010-10-09 11:26:41 -04:00
Tom Rothamel 5d11642776 Convert gldraw and gltexture to use GL directly. 2010-10-09 10:52:11 -04:00
Tom Rothamel 297277451f Use the TEGL infrastructure to auto-generate gl.pxd. (The result is
checked in for convenience's sake.)
2010-10-09 02:37:12 -04:00
Tom Rothamel d5ec269811 Rewrite Particles in terms of SpriteManager. 2010-10-09 00:25:58 -04:00
Tom Rothamel 02bbe29ccb Finished sprite manager.
Expose python objects in store.
2010-10-08 18:48:39 -04:00
Tom Rothamel 3844ace955 New SpriteManager. 2010-10-08 01:04:20 -04:00
Tom Rothamel 3715a03598 Checkpoint. 2010-10-06 00:25:07 -04:00
Tom Rothamel 82c695a199 make buildable 2010-10-05 23:09:11 -04:00
Tom Rothamel 09ff58a1a6 Add a gc-based to checking for memory leakes in Renders. 2010-10-05 22:58:53 -04:00
Tom Rothamel 0fbe522235 More speedup of transform_render. 2010-10-03 23:57:21 -04:00
Tom Rothamel cc38b5e5c3 Add missing files. 2010-10-03 23:09:32 -04:00
Tom Rothamel c6101f5565 More improvements. 2010-10-03 23:09:18 -04:00
Tom Rothamel f4e50ae4d8 Add config.imagereference_respects_position. When set to False, ImageReference
ignores positions in its styles - much faster.
2010-10-03 18:21:37 -04:00
Tom Rothamel 3f42edbb08 Add some types to draw_render_textures. 2010-10-03 18:04:18 -04:00
Tom Rothamel c63ff665b2 Checkpointing work. 2010-10-03 17:06:23 -04:00
Tom Rothamel 230ef6d4ca Add pxds. 2010-10-02 20:52:43 -04:00
Tom Rothamel 9d1783f4d6 Checkpoint progress. 2010-10-02 20:52:23 -04:00
Tom Rothamel 99d14d9521 Improve the speed of the render function. 2010-10-02 15:30:24 -04:00
Tom Rothamel 57ed7e692e Annotate render fields, implement mark-sweep render gc. 2010-10-02 14:40:43 -04:00
Tom Rothamel 6aaf974049 Make sure everything can build with the latest cython, and remove
cython-generated code from the tree.
2010-09-27 23:03:17 -04:00
Tom Rothamel 1fce0f5557 Add infrastructure for automatically building and loading cython
Ren'Py modules, when they change.
2010-09-27 22:38:12 -04:00
186 changed files with 10647 additions and 31323 deletions
+31
View File
@@ -67,3 +67,34 @@ lib/windows-x86
sphinx/source/inc/*
doc/*
updates/prerelease
module/render.c
module/_renpy.c
module/_renpy_pysdlgl.c
module/_renpybidi.c
module/sound.c
module/winmixer.c
module/accelerator.html
module/gldraw.html
module/glenviron_fixed.html
module/glenviron.html
module/glenviron_limited.html
module/glenviron_shader.html
module/glrtt_copy.html
module/glshader.html
module/gltexture.html
module/render.html
module/accelerator.c
module/gldraw.c
module/glenviron.c
module/glenviron_fixed.c
module/glenviron_limited.c
module/glenviron_shader.c
module/glrtt_copy.c
module/glshader.c
module/gltexture.c
log.txt
lib/linux-x86
lib/python
lib/update-version.txt
sphinx/game/saves
tutorial/game/saves
+10 -5
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env python
import modulefinder
import shutil
from distutils.core import setup
import py2exe
@@ -24,7 +25,9 @@ def move_from_dist(fn):
os.unlink(fn)
os.rename("dist/" + fn, fn)
import renpy
renpy.setup_modulefinder(modulefinder)
def main():
@@ -70,7 +73,11 @@ def main():
for fn in zfold.namelist():
if fn.startswith("renpy/"):
continue
# Keep around .pyo files that load pyd files.
pydfn = fn.replace("/", ".").replace(".pyo", ".pyd")
if not os.path.exists("dist/lib/windows-x86/" + pydfn):
continue
if fn in seen:
continue
@@ -102,6 +109,4 @@ try:
except:
traceback.print_exc()
print
print "Press return to quit."
raw_input()
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file contains warpers that are used by ATL. They need to be defined
+7 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init -1210 python:
@@ -44,7 +44,13 @@ init -1210 python:
if version <= (6, 11, 0):
config.movetransition_respects_offsets = False
if version <= (6, 11, 2):
config.imagereference_respects_position = True
config.predict_screens = False
config.choice_screen_ids = False
init 1210 python hide::
# This returns true if the script_version is <= the
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file contains a number of definitions of standard
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This contains code to choose between OpenGL and Software rendering, when
+2 -13
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init -1105 python:
@@ -14,17 +14,6 @@ init -1105 python:
layout.compat_funcs = [ ]
layout.provided = set()
# 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 ]
if narration:
renpy.say(None, "\n".join(narration), interact=False)
return renpy.display_menu(menuitems)
init -1105 python hide:
# Called to indicate that the given kind of layout has been
@@ -211,7 +200,7 @@ init -1105 python hide:
@layout
def button_menu():
store.menu = _display_button_menu
config.narrator_menu = True
style.menu.box_spacing = 2
style.menu_window.set_parent(style.default)
+75 -40
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file consists of renpy functions that aren't expected to be
@@ -67,6 +67,10 @@ init -1180 python:
# Should we start the game with scene black or just scene?
config.start_scene_black = False
# Voice and Sound samples.
config.sample_sound = None
config.sample_voice = None
# This is updated to give the user an idea of where a save is
# taking place.
@@ -117,7 +121,6 @@ init -1180 python:
_intra_jumps = renpy.curry(_intra_jumps_core)
# The function that's used to translate strings in the game menu.
def _(s):
"""
@@ -132,11 +135,33 @@ init -1180 python:
return s
config.extend_interjection = "{fast}"
def extend(what, interact=True):
who = _last_say_who
if who is not None:
who = eval(who)
if who is None:
who = narrator
if isinstance(who, basestring):
who = unknown.copy(who)
# This ensures extend works even with NVL mode.
who.do_extend()
what = _last_say_what + config.extend_interjection + what
renpy.exports.say(who, what, interact=interact)
store._last_say_what = what
extend.record_say = False
# Are the windows currently hidden?
_windows_hidden = False
init -1180 python:
def toggle_skipping():
if not config.skipping:
@@ -170,7 +195,8 @@ init -1180 python:
webbrowser.open_new("file:///" + config.basedir + "/" + help)
except:
pass
# Called to make a screenshot happen.
def _screenshot():
import os.path
@@ -204,6 +230,14 @@ init -1180 python:
import traceback
traceback.print_exc()
if config.screenshot_callback is not None:
config.screenshot_callback(fn)
def _screenshot_callback(fn):
renpy.notify(_("Saved screenshot as %s.") % fn)
config.screenshot_callback = _screenshot_callback
init -1180 python hide:
@@ -315,32 +349,36 @@ init -1180 python hide:
config.hyperlink_styler = hyperlink_styler
config.hyperlink_callback = hyperlink_function
# Prediction of screens.
def predict():
s = _game_menu_screen
if s is None:
return
if renpy.has_screen(s):
renpy.predict_screen(s)
return
if s.endswith("_screen"):
s = s[:-7]
if renpy.has_screen(s):
renpy.predict_screen(s)
return
config.predict_callbacks.append(predict)
def imagemap_auto_function(auto_param, variant):
rv = auto_param % variant
if renpy.loadable(rv):
return rv
else:
return None
config.extend_interjection = "{fast}"
init -1180 python:
def extend(what, interact=True):
who = _last_say_who
if who is not None:
who = eval(who)
if who is None:
who = narrator
if isinstance(who, basestring):
who = unknown.copy(who)
# This ensures extend works even with NVL mode.
who.do_extend()
what = _last_say_what + config.extend_interjection + what
renpy.exports.say(who, what, interact=interact)
store._last_say_what = what
extend.record_say = False
config.imagemap_auto_function = imagemap_auto_function
label _hide_windows:
@@ -365,17 +403,15 @@ label _hide_windows:
label _save_reload_game:
python hide:
renpy.take_screenshot((config.thumbnail_width, config.thumbnail_height))
renpy.music.stop()
ui.add(Solid((0, 0, 0, 255)))
ui.text("Saving game...",
size=32, xalign=0.5, yalign=0.5, color=(255, 255, 255, 255))
renpy.pause(0)
renpy.save("reload", "reload save game")
renpy.music.stop()
persistent._reload_save = "reload"
renpy.save("_reload-1", "reload save game")
ui.add(Solid((0, 0, 0, 255)))
ui.text("Reloading script...",
@@ -386,13 +422,12 @@ label _save_reload_game:
renpy.utter_restart()
label _load_reload_game:
if not persistent._reload_save:
return
if not renpy.can_load("_reload-1"):
return
python hide:
save = persistent._reload_save
persistent._reload_save = 0
renpy.rename_save("_reload-1", "_reload-2")
ui.add(Solid((0, 0, 0, 255)))
ui.text("Reloading game...",
@@ -401,7 +436,7 @@ label _load_reload_game:
ui.pausebehavior(0)
ui.interact(suppress_underlay=True, suppress_overlay=True)
renpy.load(save)
renpy.load("_reload-2")
return
+3 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Common stuff that's used by the various Ren'Py menus. This includes
@@ -35,6 +35,8 @@ label _quit_prompt:
return
label _main_menu_prompt:
$ renpy.loadsave.force_autosave()
if layout.yesno_prompt(None, layout.MAIN_MENU):
$ renpy.full_restart(transition=config.game_main_transition)
else:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file contains code that sets up the various mixers, based on how
+55 -27
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This is an implementation of NVL-mode, which can be used to show
@@ -80,9 +80,10 @@ init -1100 python:
else:
return s
def nvl_show_screen(screen_name, **scope):
def __nvl_screen_dialogue():
"""
Shows an nvl-mode screen. Returns the "who" widget.
Returns widget_properties and dialogue for the current NVL
mode screen.
"""
widget_properties = { }
@@ -110,6 +111,14 @@ init -1100 python:
dialogue.append((who, what, who_id, what_id, window_id))
return widget_properties, dialogue
def __nvl_show_screen(screen_name, **scope):
"""
Shows an nvl-mode screen. Returns the "what" widget.
"""
widget_properties, dialogue = __nvl_screen_dialogue()
renpy.show_screen(screen_name, _transient=True, _widget_properties=widget_properties, dialogue=dialogue, **scope)
renpy.shown_window()
@@ -119,7 +128,7 @@ init -1100 python:
# Screen version.
if renpy.has_screen("nvl"):
return nvl_show_screen("nvl")
return __nvl_show_screen("nvl", items=[ ])
if renpy.in_rollback():
nvl_window = __s(style.nvl_window)['rollback']
@@ -264,7 +273,8 @@ init -1100 python:
# Run clear at the start of the game.
config.start_callbacks.append(nvl_clear)
def nvl_menu(items):
renpy.mode('nvl_menu')
@@ -272,37 +282,55 @@ init -1100 python:
if nvl_list is None:
store.nvl_list = [ ]
screen = None
if renpy.has_screen("nvl_choice"):
screen = "nvl_choice"
elif renpy.has_screen("nvl"):
screen = "nvl"
if screen is not None:
# Screen version.
nvl_show_screen("nvl_choice", items=items)
widget_properties, dialogue = __nvl_screen_dialogue()
else:
return renpy.display_menu(
items,
widget_properties=widget_properties,
screen=screen,
scope={ "dialogue" : dialogue },
window_style=__s(style.nvl_menu_window),
choice_style=__s(style.nvl_menu_choice),
choice_chosen_style=__s(style.nvl_menu_choice_chosen),
choice_button_style=__s(style.nvl_menu_choice_button),
choice_chosen_button_style=__s(style.nvl_menu_choice_chosen_button),
type="nvl",
)
# Traditional version.
ui.layer("transient")
ui.clear()
ui.close()
ui.window(style=__s(style.nvl_window))
ui.vbox(style=__s(style.nvl_vbox))
# Traditional version.
ui.layer("transient")
ui.clear()
ui.close()
for i in nvl_list:
if not i:
continue
ui.window(style=__s(style.nvl_window))
ui.vbox(style=__s(style.nvl_vbox))
who, what, kw = i
rv = renpy.show_display_say(who, what, **kw)
for i in nvl_list:
if not i:
continue
renpy.display_menu(items, interact=False,
window_style=__s(style.nvl_menu_window),
choice_style=__s(style.nvl_menu_choice),
choice_chosen_style=__s(style.nvl_menu_choice_chosen),
choice_button_style=__s(style.nvl_menu_choice_button),
choice_chosen_button_style=__s(style.nvl_menu_choice_chosen_button),
)
who, what, kw = i
rv = renpy.show_display_say(who, what, **kw)
ui.close()
renpy.display_menu(items, interact=False,
window_style=__s(style.nvl_menu_window),
choice_style=__s(style.nvl_menu_choice),
choice_chosen_style=__s(style.nvl_menu_choice_chosen),
choice_button_style=__s(style.nvl_menu_choice_button),
choice_chosen_button_style=__s(style.nvl_menu_choice_chosen_button),
)
ui.close()
roll_forward = renpy.roll_forward_info()
+23 -1
View File
@@ -59,6 +59,9 @@ init -1140 python:
self.screen = screen
self.kwargs = kwargs
self.transition = transition
def predict(self):
renpy.predict_screen(self.scren, **self.kwargs)
def __call__(self):
renpy.show_screen(self.screen, **self.kwargs)
@@ -150,6 +153,9 @@ init -1140 python:
def __init__(self, message):
self.message = message
def predict(self):
renpy.predict_screen("notify")
def __call__(self):
renpy.notify(self.message)
@@ -177,6 +183,9 @@ init -1140 python:
def periodic(self, st):
return self.action.periodic(st)
def predict(self):
self.action.predict()
def If(expression, true=None, false=None):
"""
@@ -228,6 +237,10 @@ init -1140 python:
def __init__(self, screen=None):
self.screen = screen
def predict(self):
renpy.predict_screen(self.screen)
def __call__(self):
if not self.get_sensitive():
@@ -862,6 +875,8 @@ init -1140 python:
##########################################################################
# File functions
config.linear_saves_page_size = None
if persistent._file_page is None:
persistent._file_page = "1"
@@ -869,8 +884,15 @@ init -1140 python:
if page is None:
page = persistent._file_page
if config.linear_saves_page_size is not None:
try:
page = int(page)
name = int(name)
return str((page - 1) * config.linear_saves_page_size + name)
except ValueError:
pass
return str(page) + "-" + str(name)
def FileLoadable(name, page=None):
+9 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file contains code that creates a few new statements. We'll
@@ -503,7 +503,11 @@ python early hide:
l.expect_eol()
return dict(name=name)
def predict_screen(p):
if not p["parameters"]:
renpy.predict_screen(p["name"])
def execute_show_screen(p):
name = p["name"]
@@ -523,7 +527,7 @@ python early hide:
kwargs = { }
for k, v in parameters.iteritems():
kwargs[k] = eval(v)
kwargs[str(k)] = eval(v)
store._return = renpy.call_screen(name, **kwargs)
@@ -540,11 +544,13 @@ python early hide:
renpy.statements.register("show screen",
parse=parse_show_call_screen,
execute=execute_show_screen,
predict=predict_screen,
lint=lint_screen)
renpy.statements.register("call screen",
parse=parse_show_call_screen,
execute=execute_call_screen,
predict=predict_screen,
lint=lint_screen)
renpy.statements.register("hide screen",
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file is responsible for creating and defining the default styles
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init -1110 python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This extra contains a basic implementation of voice support. Right
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init -1170 python hide:
+2 -2
View File
@@ -1,7 +1,7 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Copyright 2004-2006 PyTom
# Copyright 2004-2011 Tom Rothamel
#
# Please see the LICENSE.txt distributed with Ren'Py for permission to
# copy and modify.
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python hide:
+2 -2
View File
@@ -1,7 +1,7 @@
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# Copyright 2004-2007 PyTom
# Copyright 2004-2011 Tom Rothamel
#
# Please see the LICENSE.txt distributed with Ren'Py for permission to
# copy and modify.
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python hide:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python hide:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python hide:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python:
+9 -31
View File
@@ -11,6 +11,7 @@ import compileall
import shutil
import subprocess
import makeupdate
import glob
import time
zlib.Z_DEFAULT_COMPRESSION = 9
@@ -120,6 +121,8 @@ def main():
prefix = sys.argv[1]
shutil.copy("tutorial/game/screens.rpy", "template/game/screens.rpy")
# Update the update-version.txt file.
p = subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE)
revno = p.stdout.read().strip() + "-" + str(time.time())
@@ -159,41 +162,16 @@ def main():
more_files.extend(tree("lib/linux-x86"))
module_files = [
"lib/pysdlsound/linmixer.py",
"lib/pysdlsound/__init__.py",
"core.c",
"ffdecode.c",
"IMG_savepng.c",
"IMG_savepng.h",
"mmx.h",
"pss.c",
"pss.h",
"*.c",
"*.h",
"*.py",
"*.pyx",
"README.txt",
"_renpy.c",
"renpy_font.c",
"renpy.h",
"_renpy.pyx",
"renpy_ttf.c",
"renpy_ttf.h",
"rwobject.c",
"setup.py",
"sound.c",
"sound.pyx",
"subpixel.c",
"winmixer.c",
"winmixer.pyx",
"_renpybidi.c",
"renpybidicore.c",
"_renpybidi.pyx",
"_renpy_pysdlgl.c",
"_renpy_pysdlgl.pyx",
"_renpy_tegl.c",
"maketegl.py",
"maketegl.txt",
"lib/pysdlsound/*.py",
]
for i in module_files:
files.append('module/' + i)
files.extend(glob.glob('module/' + i))
files.extend(tree('renpy'))
files.append('renpy.py')
+1 -1
View File
@@ -1,3 +1,3 @@
init -999:
$ config.script_version = (6, 11, 2)
$ config.script_version = (6, 12, 0)
-5742
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,5 +1,5 @@
# -*- python -*-
# Copyright 2005 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -20,6 +20,9 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
def version():
return (6, 12, 0)
cdef extern from "renpy.h":
cdef struct SDL_RWops:
@@ -95,9 +98,6 @@ import pygame
PygameSurface = pygame.Surface
def version():
return (6, 10, 1)
def save_png(surf, file, compress=-1):
if not isinstance(surf, PygameSurface):
File diff suppressed because it is too large Load Diff
-425
View File
@@ -1,425 +0,0 @@
# This file contains bindings to integrate pygame (SDL) and OpenGL.
cdef extern from "pygame/pygame.h":
struct SDL_Surface:
int w
int h
int pitch
void *pixels
SDL_Surface *PySurface_AsSurface(object)
cdef extern from "GL/glew.h":
ctypedef unsigned int GLenum
ctypedef unsigned char GLboolean
ctypedef unsigned int GLbitfield
ctypedef void GLvoid
ctypedef signed char GLbyte
ctypedef short GLshort
ctypedef int GLint
ctypedef unsigned char GLubyte
ctypedef unsigned short GLushort
ctypedef unsigned int GLuint
ctypedef int GLsizei
ctypedef float GLfloat
ctypedef float GLclampf
ctypedef double GLdouble
ctypedef double GLclampd
GLenum GLEW_OK
GLenum glewInit()
GLubyte *glewGetErrorString(GLenum)
int GL_UNPACK_ROW_LENGTH
int GL_PACK_ROW_LENGTH
void glPixelStorei(
GLint pname,
GLint param)
int GL_TEXTURE_2D
int GL_RGBA8
int GL_RGBA
int GL_BGRA
int GL_ALPHA
int GL_UNSIGNED_BYTE
void glTexImage2D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
void *pixels)
void glTexSubImage2D(
int target,
int level,
int xoffset,
int yoffset,
int width,
int height,
int format,
int type,
void *pixels)
GLenum GL_TEXTURE0_ARB
GLenum GL_TEXTURE1_ARB
GLenum GL_TEXTURE2_ARB
GLenum GL_TRIANGLE_STRIP
void glMultiTexCoord2fARB(GLenum, GLfloat, GLfloat)
void glVertex2f(GLfloat, GLfloat)
void glBegin(GLenum)
void glEnd()
void glActiveTextureARB(GLenum)
void glBindTexture(GLenum, GLuint texture)
GLubyte *glGetString(GLenum)
void glReadPixels(
GLint,
GLint,
GLsizei,
GLsizei,
GLenum,
GLenum,
void *)
def init_glew():
err = glewInit()
if err != GLEW_OK:
raise Exception("Glew init failed: %s" % <char *> glewGetErrorString(err))
def premultiply(
object pysurf,
int x,
int y,
int w,
int h,
border_left, border_top, border_right, border_bottom):
"""
Creates a string containing the premultiplied image data for
for the (x, y, w, h) box inside pysurf. The various border_
parameters control the addition of a border on the sides.
"""
# Adjust the alpha if we have an alpha-free image.
cdef unsigned char alpha_and
cdef unsigned char alpha_or
if pysurf.get_masks()[3]:
alpha_and = 255
alpha_or = 0
else:
alpha_and = 0
alpha_or = 255
# Allocate an uninitialized string.
cdef unsigned char *null = NULL
rv = null[:w*h*4]
# Out is where we put the output.
cdef unsigned char *out = rv
# The pixels in the source image.
cdef unsigned char *pixels = NULL
cdef SDL_Surface *surf
# Pointer to the current pixel.
cdef unsigned char *p
# Pointer to the current output pixel.
cdef unsigned char *op
# Pointer to the row end.
cdef unsigned char *pend
# alpha value.
cdef unsigned int a
# pixel pointer.
cdef unsigned int *pp
surf = PySurface_AsSurface(pysurf)
pixels = <unsigned char *> surf.pixels
pixels += y * surf.pitch
pixels += x * 4
op = out
for y from 0 <= y < h:
p = pixels + y * surf.pitch
pend = p + w * 4
while p < pend:
a = (p[3] & alpha_and) | alpha_or
op[0] = p[0] * a / 255
op[1] = p[1] * a / 255
op[2] = p[2] * a / 255
op[3] = a
p += 4
op += 4
if border_left:
pp = <unsigned int *> (out)
for y from 0 <= y < h:
pp[0] = pp[1]
pp += w
if border_right:
pp = <unsigned int *> (out)
pp += w - 2
for y from 0 <= y < h:
pp[1] = pp[0]
pp += w
if border_top:
pp = <unsigned int *> (out)
for x from 0 <= x < w:
pp[0] = pp[w]
pp += 1
if border_top:
pp = <unsigned int *> (out)
pp += (y - 2) * w
for x from 0 <= x < w:
pp[w] = pp[0]
pp += 1
return rv
def load_premultiplied(
data, width, height, update, format,
):
cdef char *pixels
if data:
pixels = data
else:
pixels = NULL
if update:
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
width,
height,
format,
GL_UNSIGNED_BYTE,
pixels)
else:
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
width,
height,
0,
format,
GL_UNSIGNED_BYTE,
pixels)
def store_framebuffer(
object pysurf,
int format,
):
"""
This loads the supplied pygame surface into the numbered
texture. The created texture will be of size (width, height),
and at position (xoffset, yoffset) relative to the containing
image.
"""
cdef unsigned char *pixels = NULL
cdef SDL_Surface *surf
surf = PySurface_AsSurface(pysurf)
pixels = <unsigned char *> surf.pixels
glPixelStorei(GL_PACK_ROW_LENGTH, surf.pitch / 4)
glReadPixels(
0,
0,
surf.w,
surf.h,
format,
GL_UNSIGNED_BYTE,
pixels)
def draw_rectangle(
float sx,
float sy,
float x,
float y,
float w,
float h,
transform,
tex0, int tex0x, int tex0y,
tex1, int tex1x, int tex1y,
tex2, int tex2x, int tex2y,
):
"""
This draws a rectangle (textured with up to four textures) to the
screen.
"""
# Do we have the given texture?
cdef int has_tex0, has_tex1, has_tex2
# Texture coordinates.
cdef float t0u0, t0v0, t0u1, t0v1
cdef float t1u0, t1v0, t1u1, t1v1
cdef float t2u0, t2v0, t2u1, t2v1
# Pull apart the transform.
cdef float xdx = transform.xdx
cdef float xdy = transform.xdy
cdef float ydx = transform.ydx
cdef float ydy = transform.ydy
# Transform the vertex coordinates to screen-space.
cdef float x0 = (x + 0) * xdx + (y + 0) * xdy + sx
cdef float y0 = (x + 0) * ydx + (y + 0) * ydy + sy
cdef float x1 = (x + w) * xdx + (y + 0) * xdy + sx
cdef float y1 = (x + w) * ydx + (y + 0) * ydy + sy
cdef float x2 = (x + 0) * xdx + (y + h) * xdy + sx
cdef float y2 = (x + 0) * ydx + (y + h) * ydy + sy
cdef float x3 = (x + w) * xdx + (y + h) * xdy + sx
cdef float y3 = (x + w) * ydx + (y + h) * ydy + sy
# Compute the texture coordinates, and set up the textures.
cdef float xadd, yadd, xmul, ymul
if tex0 is not None:
has_tex0 = 1
glActiveTextureARB(GL_TEXTURE0_ARB)
glBindTexture(GL_TEXTURE_2D, tex0.number)
xadd = tex0.xadd
yadd = tex0.yadd
xmul = tex0.xmul
ymul = tex0.ymul
t0u0 = xadd + xmul * (tex0x + 0)
t0u1 = xadd + xmul * (tex0x + w)
t0v0 = yadd + ymul * (tex0y + 0)
t0v1 = yadd + ymul * (tex0y + h)
else:
has_tex0 = 0
if tex1 is not None:
has_tex1 = 1
glActiveTextureARB(GL_TEXTURE1_ARB)
glBindTexture(GL_TEXTURE_2D, tex1.number)
xadd = tex1.xadd
yadd = tex1.yadd
xmul = tex1.xmul
ymul = tex1.ymul
t1u0 = xadd + xmul * (tex1x + 0)
t1u1 = xadd + xmul * (tex1x + w)
t1v0 = yadd + ymul * (tex1y + 0)
t1v1 = yadd + ymul * (tex1y + h)
else:
has_tex1 = 0
if tex2 is not None:
has_tex2 = 1
glActiveTextureARB(GL_TEXTURE2_ARB)
glBindTexture(GL_TEXTURE_2D, tex2.number)
xadd = tex2.xadd
yadd = tex2.yadd
xmul = tex2.xmul
ymul = tex2.ymul
t2u0 = xadd + xmul * (tex2x + 0)
t2u1 = xadd + xmul * (tex2x + w)
t2v0 = yadd + ymul * (tex2y + 0)
t2v1 = yadd + ymul * (tex2y + h)
else:
has_tex2 = 0
# Now, actually draw the textured rectangle.
glBegin(GL_TRIANGLE_STRIP)
if has_tex0:
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, t0u0, t0v0)
if has_tex1:
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, t1u0, t1v0)
if has_tex2:
glMultiTexCoord2fARB(GL_TEXTURE2_ARB, t2u0, t2v0)
glVertex2f(x0, y0)
if has_tex0:
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, t0u1, t0v0)
if has_tex1:
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, t1u1, t1v0)
if has_tex2:
glMultiTexCoord2fARB(GL_TEXTURE2_ARB, t2u1, t2v0)
glVertex2f(x1, y1)
if has_tex0:
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, t0u0, t0v1)
if has_tex1:
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, t1u0, t1v1)
if has_tex2:
glMultiTexCoord2fARB(GL_TEXTURE2_ARB, t2u0, t2v1)
glVertex2f(x2, y2)
if has_tex0:
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, t0u1, t0v1)
if has_tex1:
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, t1u1, t1v1)
if has_tex2:
glMultiTexCoord2fARB(GL_TEXTURE2_ARB, t2u1, t2v1)
glVertex2f(x3, y3)
glEnd()
def get_string(name):
return <char *> glGetString(name)
-10266
View File
File diff suppressed because it is too large Load Diff
-1446
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
A="$RENPY_ANDROID"
CFLAGS="$CFLAGS -DANDROID"
CFLAGS="$CFLAGS -I$A/android-sdl/sdl/sdl-1.2/include"
CFLAGS="$CFLAGS -I$A/android-sdl/jni/png"
CFLAGS="$CFLAGS -I$A/android-sdl/jni/freetype/include"
LDFLAGS="$LDFLAGS -L$A/android-sdl/libs/armeabi -L$A/android-sdl/obj/local/armeabi"
export CFLAGS
export LDFLAGS
$A/python-install/bin/python.host setup.py build_ext -b build/lib.android -t build/tmp.android build_ext
+12 -6
View File
@@ -1,9 +1,15 @@
#!/bin/sh
. ~/newbuild.i386/env.sh
./build.sh
. ~/newbuild.ppc/env.sh
./build.sh
try () {
"$@" || exit -1
}
chmod -R a+rX ~/newbuild.i386/install
chmod -R a+rX ~/newbuild.ppc/install
BASE=/Users/tom
. $BASE/newbuild.i386/env.sh
try ./build.sh
. $BASE/newbuild.ppc/env.sh
try ./build.sh
try chmod -R a+rX $BASE/newbuild.i386/install
try chmod -R a+rX $BASE/newbuild.ppc/install
+9 -7
View File
@@ -1028,8 +1028,8 @@ int transform32_std(PyObject *pysrc, PyObject *pydst,
unsigned int amul = (unsigned int) (a * 256);
// Compute the maximum x and y coordinates.
double maxsx = srcw - 1;
double maxsy = srch - 1;
double maxsx = srcw;
double maxsy = srch;
// Deal with pre-6.10.1 versions of Ren'Py, which didn't give us
// that 1px border that allows us to be precise.
@@ -1059,7 +1059,7 @@ int transform32_std(PyObject *pysrc, PyObject *pydst,
// The source coordinates of the leftmost pixel in the line.
double leftsx = corner_x + y * xdy;
double leftsy = corner_y + y * ydy;
// Min and max x-extent to draw on the current line.
double minx = 0;
double maxx = dstw - 1;
@@ -1115,7 +1115,7 @@ int transform32_std(PyObject *pysrc, PyObject *pydst,
// Advance start of line by 4.
d += 4 * (int) minx;
// Starting coordinates and deltas.
sxi = (int) ((leftsx + minx * xdx) * 65536);
syi = (int) ((leftsy + minx * ydx) * 65536);
@@ -1230,8 +1230,8 @@ int transform32_mmx(PyObject *pysrc, PyObject *pydst,
unsigned int amul = (unsigned int) (a * 256);
// Compute the maximum x and y coordinates.
double maxsx = srcw - 1;
double maxsy = srch - 1;
double maxsx = srcw;
double maxsy = srch;
// Deal with pre-6.10.1 versions of Ren'Py, which didn't give us
// that 1px border that allows us to be precise.
@@ -1438,11 +1438,13 @@ void transform32_core(PyObject *pysrc, PyObject *pydst,
float a,
int precise
) {
#ifdef GCC_MMX
static int checked_mmx = 0;
static int has_mmx = 0;
if (! checked_mmx) {
has_mmx = SDL_HasMMX();
checked_mmx = 1;
+62
View File
@@ -0,0 +1,62 @@
/**
* This takes care of abstracting between OpenGL and OpenGL ES, by
* choosing the appropriate header file, and renaming various names
* in the ES case.
*/
#ifndef GL_COMPAT_H
#define GL_COMPAT_H
// Environ is defined on windows, but our GL code uses it as an
// identifier.
#undef environ
#ifdef ANDROID
#include <GLES/gl.h>
#include <GLES/glext.h>
typedef GLfloat GLdouble;
#define glewInit() (1)
#define GLEW_OK (1)
#define glewGetErrorString(x) ("Unknown Error")
#define glewIsSupported(x) (1)
#define glOrtho glOrthof
#define glClipPlane glClipPlanef
#define GL_SOURCE0_ALPHA GL_SRC0_ALPHA
#define GL_SOURCE1_ALPHA GL_SRC1_ALPHA
#define GL_SOURCE2_ALPHA GL_SRC2_ALPHA
#define GL_SOURCE0_RGB GL_SRC0_RGB
#define GL_SOURCE1_RGB GL_SRC1_RGB
#define GL_SOURCE2_RGB GL_SRC2_RGB
// This isn't defined on GL ES, but that's okay, since we'll disable
// screenshots on Android.
#define GL_PACK_ROW_LENGTH 0
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER_OES
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0_OES
#define glBindFramebufferEXT glBindFramebufferOES
#define glFramebufferTexture2DEXT glFramebufferTexture2DOES
#define glGenFramebuffersEXT glGenFramebuffersOES
#define glDeleteFramebuffersEXT glDeleteFramebuffersOES
#define glCheckFramebufferStatusEXT glCheckFramebufferStatusOES
#else
#include <GL/glew.h>
#undef glClientActiveTexture
#define glClientActiveTexture glClientActiveTextureARB
#undef glActiveTexture
#define glActiveTexture glActiveTextureARB
#define GL_RGB565_OES 0
#endif
#endif
+127 -1005
View File
File diff suppressed because it is too large Load Diff
-275
View File
@@ -1,275 +0,0 @@
TEGL
----
Tegl is Python script for generating OpenGL extenstions. I wrote it
because I was disappointed with some other OpenGL solutions for
Python.
Tegl generates a C extension that can be compiled into module to make
OpenGL available to Python programs. (You're on your own compiling
it, though.)
Unlike PyOpenGL, the C extension is a thin wrapper around OpenGL. It
performs only minor argument checking. Nevertheless, it is mostly
compatible with PyOpenGL, and depending on how the module is
generated, it should only need minor changes to migrate from PyOpenGL.
(In fact, I was able to migrate a recent application simply by adding
a couple wrapper functions that mimicked PyOpenGL semantics.)
This is version 002.
USAGE
-----
To use, simply run maketegl.py. It will generate two files, tegl.c
and teglu.c in the current directory, which you can compile it to
create Python GL and GLU modules. The modules comprise (most of)
OpenGL 1.1.
For more control, open maketegl.py with a text editor. At the top are
some options for controlling the generated code. You can change the
names of the modules, and even combine them into one. You can control
whether the "gl" and "GL_" prefixes appear on the exported symbols.
You can choose to include or exclude various OpenGL extensions, or use
more recent versions of OpenGL. I recommend plain OpenGL 1.1 for
maximum portability, and selected ARB extensions if you need more.
There are some other switches I will cover below.
If you really want fine-tuned control, you can scroll past the options
and comment out any functions and constants you don't want. This may
be a good idea since currently Tegl modules are quite large when
compiled.
USING THE MODULE
----------------
Calling OpenGL functions is simple. Just import the module with "from
tegl import *" (or just "import tegl as gl" if you have built it
without prefixes, or whatever else suits you).
Most OpenGL functions can be called just as in C:
glBegin(GL_COMPILE) or gl.Begin(gl.COMPILE)
glVertex3d(1.0,2.0,3.0) or gl.Vertex3d(1.0,2.0,3.0)
glEnable(GL_CULL_FACE)
glRotated(1.0,90.0,0.0,0.0)
texon = glIsEnabled(GL_TEXTURE_2D)
It's usually pretty straightforward to use OpenGL functions that
accept data through a pointer: you just pass it a list (or tuple, or
numpy array, or any sequence).
glVertex3dv([1.0,2.0,3.0])
glMaterialfv(GL_FRONT,GL_AMBIENT,[0.2,0.2,0.2,1.0])
OpenGL functions that return data through a pointer are somewhat
trickier, you have to pass it an empty sequence that is large enough
to contain the data the function returns. The sequence type has to be
mutable, of course.
retval = [None]*4
glGetMaterialfv(GL_FRONT,GL_AMBIENT,retval)
(This is a departure from how PyOpenGL operates; it will simply create
an array and return it. But Tegl is intended to be a thin wrapper, so
it follows the C usage closely.)
In many cases, it's preferrable to use a buffer object instead of a
Python sequence to pass data to the function; for instance, texture
data. In these cases, you would pass in an object that supports
buffer protocol, such as a string, a numpy array, or an array from the
array module.
imagedata = Image.open(imgfile).tostring()
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,256,256,0,GL_RGBA,
GL_UNSIGNED_BYTE,imagedata)
To use an OpenGL function that returns image data, you need to pass in
a object that supports writable buffer protocol. The buffer must be
large enough to hold the output of the function, otherwise Bad Things
can happen. Strings are not mutable so you'll have to use some other
type. Arrays from the array module can be your friend here.
retval = array.array("B",[0])*640*480*4
glReadPixels(0,0,640,480,GL_RGBA,GL_UNSIGNED_BYTE,retval)
The question is, how do you know whether you should pass a buffer type
or a sequence type to OpenGL? (Currently, you can only pass one or
the other; this may change in a future version.) Here is the general
rule of thumb:
You need to use a buffer if:
* The type of the argument in C is GLvoid* (or just void*)
* OR the size of the data is theoretically unbounded.
You need to use a sequence if:
* The type if te argument is not GLvoid*
* AND the size of the data is fixed or bounded.
So glMaterialfv takes a sequence argument because it has a type
(GLfloat*) and has a size of 4 at most (it's bounded). On the other
hand, glTexImage2D uses a buffer argument because the type of the data
is GLvoid*, and the image can be arbitrarily large.
This rule of thumb does not always hold, however. I decided to go
against it where it seemed useful.
Several functions for modifying textures (glGenTextures,
glDeleteTextures, glPrioritizeTextures, and glAreTexturesResident)
accept arrays of unbounded size, but I felt that sequence types were
far more useful here, so I defined a constant (MAX_TEXTURE_ARRAY_SIZE)
that lets the user specify a bound on the size. (Otherwise I would
have had to muck around with malloc, and I did not want to do that.)
Functions for creating and destroying buffer object, occlusion
queries, and shader programs (ARB only) are treated likewise.
glCallList accepts buffer objects. Even though the size of the call
list is unbounded, it seemed as if a sequence would be more
appropriate. However, a common use case of glCallList (in conjunction
with glListBase) is to pass it a string, where each character is the
name of a display list that draws that character. Thus I left is as a
buffer.
If I chose wrongly for your application, I apologize. Numpy arrays
and arrays from the array module implement both the sequence and
buffer protocols; these may be of assistence to you. (Be careful
about numpy strides, though.)
If worse comes to worst, you can change the definition inside the
maketegl.py script to suit you.
ADVANCED: THE GIL
-----------------
It's possible that if you send a lot of data to the OpenGL pipeline
quickly enough, the OpenGL pipeline could fill up, an an OpenGL call
in progress would block until the pipeline clears up. This is
possible with functions like glCallList, which runs a display list
that could be enormous.
In threaded programs, the time spent waiting for an OpenGL block could
be used for other tasks. In Python, only a single thread can run
Python code at a given time (a thread has to have the GIL, global
interpreter lock, to run Python code). However, extensions may
release the GIL while not manipulating Python objects (which is the
case during an OpenGL call).
Therefore, there is an option in Tegl for releasing the GIL around
certain OpenGL calls, thus allowing other Python code to run if it
should happen to block. Simply add the name of the function (without
the "gl") to the set of functions to release the GIL for at the top of
maketegl.py.
UNSUPPORTED FUNCTIONS
---------------------
There are a few OpenGL functions that aren't supported by Tegl simply
because they have an unusual signature that the machinery doesn't
easily support. In this early release, I didn't bother. Here's the
list:
glGetString
glGetPointerv
glMultiDrawArrays(ARB)
glMultiDrawElements(ARB)
glGetBufferPointerv(ARB)
glGetVertexAttribPointerv(ARB)
glShaderSource(ARB)
All glu* functions that implement nurbs, tesselators, and quadrics.
Additionally, a couple functions are supported with limited
functionality:
glMapBuffer(ARB) returns a CObject. This is not too useful from
Python; however, you can get at it from a C extension. Also, ctypes
and numpy wizards should be able to map a numpy array to the pointer
location.
glShaderSource(ARB) is handcoded, and only supports passing it a
single string. (You must still pass a singleton sequence of strings;
this is to preserve upward compatibility.) For instance, you'd call
it like this:
glShaderSourceARB(shaderobj,1,[source],[len(source)])
IMPROVEMENTS
------------
The two main improvements I have in mind (aside from fixing up bugs
and adding stuff) are these:
* To take advantage of the parallelism of OpenGL to make the tegl
module a lot smaller. Many OpenGL function have the same signature
(same argument and return types) and I can save a lot of code by
generating one function with that signature, and calling it with a
function pointer (and maybe a size index or two).
* To support sequences and buffers for the same argument at the same
time. This isn't as straightforward as it looks, though, since for
objects that support both protocols, the results could be different
depending on whether it's treated as a buffer or a sequence. I have
to figure out what the most reasonable behavior is.
BUGS
----
Yes.
CHANGES FROM 001
----------------
Added #define GL_EXT_PROTOTYPES. Since Tegl depends on the C compiler
having prototypes available for typecasting arguments, this is pretty
important.
Added handcoded version of glShaderSource(ARB) that only accepts a
single string in the source.
Fixed specification of gluUnProject4.
LICENCE AND COPYRIGHT
---------------------
maketegl.py and maketegl.txt are copyrighted by Carl Banks.
These files, which comprise the tegl package, are released under a BSD
style license. See the file copying for details.
WHY NOT PYOPENGL
----------------
The standard OpenGL package in Python, PyOpenGL, has some limitations
(mostly speedwise) that made it undesirable for me.
Probably the biggest bottleneck is that PyOpenGL calls glGetError
after every call. I understand the rationale for this, but its cost
is too high for my needs. Another problem is, as far as I know, it
does not allow the user to release the GIL around some GL calls.
Thirdly, PyOpenGL 3 is based on ctypes. There's nothing wrong with
ctypes, but for a usage where speed really does matter, it's much too
slow. PyOpenGL 2 is a C extension, and is much faster than PyOpenGL
3, but doesn't support recent OpenGL extensions.
A minor thing I didn't like was that PyOpenGL didn't get rid of the gl
prefixes. I prefer namespaces, and would prefer to simply import a gl
module and call functions this way: "gl.End()". But PyOpenGL did not
support that; I had to write wrappers to pull the symbols apart.
But the most irritating thing about PyOpenGL is the setuptools entry
points, which mean that you cannot simply import the OpenGL modules;
you have to go through setuptools. This, among other things, makes
distributing programs using PyOpenGL (such as with py2exe) a pain.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
Copyright 2005-2009 PyTom <pytom@bishoujo.us>
Copyright 2004-2011 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
+89 -60
View File
@@ -6,31 +6,30 @@ import platform
import sys
import subprocess
try:
import bdist_mpkg
except:
pass
# These control the level of optimization versus debugging.
extra_compile_args = [ "-O3", "-funroll-loops" ]
extra_compile_args = [ "-O3", "-Wno-unused-function" ]
# extra_compile_args = [ "-O3", "-funroll-loops", "-ggdb" ]
# extra_compile_args = [ "-O0", "-ggdb" ]
# extra_compile_args = [ "-O0", "-gstabs" ]
extra_link_args = [ ]
android = "RENPY_ANDROID" in os.environ
# This environment variable should have the full path to the installed
# Ren'Py dependencies.
install = os.environ.get("RENPY_DEPS_INSTALL", None)
if install is None:
print """
The RENPY_DEPS_INSTALL environment variable has not been set. This
should be set to a double-colon-delimited list of places where the
Ren'Py dependencies can be found. (To use system libraries, this can
be set to a system directory, like /usr.)
"""
sys.exit(-1)
if not android:
if install is None:
print """
The RENPY_DEPS_INSTALL environment variable has not been set. This
should be set to a double-colon-delimited list of places where the
Ren'Py dependencies can be found. (To use system libraries, this can
be set to a system directory, like /usr.)
"""
sys.exit(-1)
install = install.split("::")
install = install.split("::")
include_dirs = [ ]
library_dirs = [ ]
@@ -42,6 +41,9 @@ def add_include(prefix, file):
in into include_dirs.
"""
if android:
return False
checked = [ ]
for i in install:
@@ -81,6 +83,9 @@ def add_library(name, optional=False):
<i> in install. When found, it adds it to library_dirs.
"""
if android:
return False
checked = [ ]
for i in install:
@@ -150,16 +155,16 @@ add_library("libz")
has_libglew = add_library("libGLEW", True)
has_libglew32 = add_library("libglew32", True)
cython("_renpy")
cython("_renpybidi")
cython("_renpy_pysdlgl")
cython("sound")
cython("winmixer")
extra_link_args = [ ]
if android:
sdl_libraries = [ 'sdl', 'GLESv1_CM', 'log' ]
else:
sdl_libraries = [ 'SDL' ]
sdl_libraries = [ 'SDL' ]
png_libraries = [ 'png', "z" ]
sound_libraries = [ "avformat", "avcodec", "avutil", "z" ]
@@ -192,7 +197,7 @@ extensions.append(distutils.core.Extension(
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
libraries=sdl_libraries + png_libraries,
libraries=sdl_libraries + png_libraries + [ 'm' ],
))
extensions.append(distutils.core.Extension(
@@ -202,63 +207,87 @@ extensions.append(distutils.core.Extension(
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
libraries=sdl_libraries + [ 'freetype', 'z' ],
libraries=sdl_libraries + [ 'freetype', 'z', 'm' ],
))
extensions.append(distutils.core.Extension(
"pysdlsound.sound",
[ "pss.c", "rwobject.c", "sound.c", "ffdecode.c" ],
include_dirs=include_dirs,
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
libraries=sound_libraries + sdl_libraries,
))
if not android:
if winmixer:
extensions.append(distutils.core.Extension(
"pysdlsound.winmixer",
[ 'winmixer.c' ],
libraries=['winmm'],
"pysdlsound.sound",
[ "pss.c", "rwobject.c", "sound.c", "ffdecode.c" ],
include_dirs=include_dirs,
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
libraries=sound_libraries + sdl_libraries,
))
if linmixer:
py_modules.append('pysdlsound.linmixer')
extensions.append(distutils.core.Extension(
"_renpybidi",
["_renpybidi.c", "renpybidicore.c"],
include_dirs=include_dirs,
library_dirs=library_dirs,
libraries=['fribidi'],
))
if winmixer:
extensions.append(distutils.core.Extension(
"pysdlsound.winmixer",
[ 'winmixer.c' ],
libraries=['winmm'],
))
if linmixer:
py_modules.append('pysdlsound.linmixer')
if not android:
extensions.append(distutils.core.Extension(
"_renpybidi",
["_renpybidi.c", "renpybidicore.c"],
include_dirs=include_dirs,
library_dirs=library_dirs,
libraries=['fribidi'],
))
if has_libglew:
glew_libs = [ 'GLEW' ]
elif android:
glew_libs = [ 'GLESv1_CM', 'z', 'm' ]
else:
glew_libs = [ 'glew32', "opengl32" ]
def display(name, libs=[]):
"""
Adds code to compile a module that's defined by a cython file in
the display directory, and turned into a cython file in this
directory by the run.sh script.
"""
extensions.append(distutils.core.Extension(
"_renpy_tegl",
["_renpy_tegl.c"],
extra_compile_args=extra_compile_args,
include_dirs=include_dirs,
library_dirs=library_dirs,
libraries=glew_libs))
extensions.append(distutils.core.Extension(
"renpy.display." + name,
[name + ".c"],
extra_compile_args=extra_compile_args,
include_dirs=include_dirs,
library_dirs=library_dirs,
libraries=libs))
extensions.append(distutils.core.Extension(
"_renpy_pysdlgl",
["_renpy_pysdlgl.c"],
extra_compile_args=extra_compile_args,
include_dirs=include_dirs,
library_dirs=library_dirs,
libraries=glew_libs))
display("render", [ 'z', 'm' ])
display("accelerator", [ 'z', 'm' ])
display("gldraw", glew_libs )
display("gltexture", glew_libs)
display("glenviron", glew_libs)
if not android:
display("glenviron_fixed", glew_libs)
display("glenviron_shader", glew_libs)
display("glshader", glew_libs)
display("glenviron_limited", glew_libs)
display("glrtt_copy", glew_libs)
display("glrtt_fbo", glew_libs)
sys.path.append('..')
import renpy
distutils.core.setup(
name = "renpy_module",
version = "6.11.0",
version = renpy.version[7:],
ext_modules = extensions,
py_modules = py_modules,
package_dir = { '' : 'lib' },
-3453
View File
File diff suppressed because it is too large Load Diff
+4 -3
View File
@@ -1,5 +1,5 @@
# -*- python -*-
# Copyright 2005 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -52,8 +52,9 @@ cdef extern from "pss.h":
def check_error():
e = PSS_get_error();
if e:
raise Exception, e
if str(e):
raise Exception(e)
def play(channel, file, name, paused=False, fadein=0, tight=False):
cdef SDL_RWops *rw
-1825
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2005 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -45,7 +45,7 @@ cdef uint_to_vol(unsigned int u):
v1 = u & 0xffff
v2 = u >> 16
return (v1 + v2) / 2.0 / 0xffff
return (v1 + v2) / 2.0 / 65535
midi_dev = None
wave_dev = None
+29 -23
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -29,6 +29,8 @@ import warnings
# Functions to be customized by distributors. ################################
android = ("ANDROID_PRIVATE" in os.environ)
# Given the Ren'Py base directory (usually the directory containing
# this file), this is expected to return the path to the common directory.
def path_to_common(renpy_base):
@@ -56,15 +58,20 @@ def path_to_saves(gamedir):
path = newpath
# Otherwise, put the saves in a standard place.
if platform.mac_ver()[0]:
if android:
return gamedir + "/saves"
elif platform.mac_ver()[0]:
rv = "~/Library/RenPy/" + renpy.config.save_directory
return os.path.expanduser(rv)
elif sys.platform == "win32":
if 'APPDATA' in os.environ:
return os.environ['APPDATA'] + "/RenPy/" + renpy.config.save_directory
else:
rv = "~/RenPy/" + renpy.config.save_directory
return os.path.expanduser(rv)
else:
rv = "~/.renpy/" + renpy.config.save_directory
return os.path.expanduser(rv)
@@ -94,26 +101,19 @@ except:
raise
print "Ren'Py requires at least python 2.6."
sys.exit(0)
# Android requires us to add code to the main module, and to command some
# renderers.
if android:
__main__ = sys.modules["__main__"]
__main__.path_to_renpy_base = path_to_renpy_base
__main__.path_to_common = path_to_common
__main__.path_to_saves = path_to_saves
os.environ["RENPY_RENDERER"] = "gl"
os.environ["RENPY_GL_ENVIRON"] = "limited"
def main():
if __name__ == "__main__":
if not 'RENPY_NO_VERSION_CHECK' in os.environ:
# Check for mac compatibility.
if "mac_version" in globals():
globals()["mac_version"](macos_version)
# Check py4renpy compatibility.
try:
import py4renpy
if py4renpy.version < linux_version:
print "The version of py4renpy that you are using is too old. Please go to"
print "http://www.bishoujo.us/renpy/linux.html, and download the latest"
print "version."
sys.exit(-1)
except ImportError:
pass
renpy_base = path_to_renpy_base()
# Add paths.
@@ -128,8 +128,7 @@ if __name__ == "__main__":
# Ignore warnings that happen.
warnings.simplefilter("ignore", DeprecationWarning)
# Start Ren'Py proper.
try:
import renpy.bootstrap
@@ -138,4 +137,11 @@ if __name__ == "__main__":
print >>sys.stderr, "correctly, preserving the directory structure."
raise
renpy.android = android
renpy.bootstrap.bootstrap(renpy_base)
if __name__ == "__main__":
main()
+55 -6
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -22,19 +22,53 @@
# This file ensures that renpy packages will be imported in the right
# order.
import os
# Some version numbers and things.
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
# 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.11.2a"
# Be sure to change _renpy.pyx and module.py, if necessary.
version = "Ren'Py 6.12.0a"
# Other versions.
script_version = 5003000
savegame_suffix = "-LT1.save"
bytecode_version = 1
# True if this is the first time we've started - even including
# utter restarts.
first_utter_start = True
def setup_modulefinder(modulefinder):
import _renpy
libexec = os.path.dirname(_renpy.__file__)
displaypath = os.path.join(libexec, "renpy", "display")
modulefinder.AddPackagePath('renpy.display', displaypath)
def import_cython():
"""
Never called, but necessary to ensure that modulefinder will properly
grab the various cython modules.
"""
import renpy.display.accelerator
import renpy.display.gldraw
import renpy.display.glenviron
import renpy.display.glenviron_fixed
import renpy.display.glenviron_limited
import renpy.display.glenviron_shader
import renpy.display.glrtt_copy
import renpy.display.glrtt_fbo
import renpy.display.glshader
import renpy.display.gltexture
import renpy.display.render
# Prevent a pyflakes warning.
renpy
def import_all():
# Should probably be early, as we will add it as a base to serialized things.
@@ -64,6 +98,18 @@ def import_all():
import renpy.display.pgrender
import renpy.display.scale # Must be before module.
import renpy.display.module
# Now that render is pre-compiled, we want to use the
# location of renpy.display.module to find it.
import _renpy
libexec = os.path.dirname(_renpy.__file__)
renpy.display.__path__.insert(0, os.path.join(libexec, "renpy", "display"))
# Also find encodings, to deal with the way py2exe lays things out.
import encodings
libexec = os.path.dirname(encodings.__path__[0])
renpy.display.__path__.insert(1, os.path.join(libexec, "renpy", "display"))
import renpy.display.render # Most display stuff depends on this.
import renpy.display.core # object
@@ -82,10 +128,11 @@ def import_all():
import renpy.display.joystick
import renpy.display.minigame
import renpy.display.screen
import renpy.display.error
import renpy.display.dragdrop
import renpy.display.imagemap
import renpy.display.predict
import renpy.display.swdraw
import renpy.display.gldraw
import renpy.display.error
# Note: For windows to work, renpy.audio.audio needs to be after
# renpy.display.module.
@@ -115,6 +162,7 @@ def import_all():
def reload_all():
import renpy
renpy.log.info("Reloading.")
# Shut down the cache thread.
renpy.display.im.cache.quit()
@@ -124,6 +172,7 @@ def reload_all():
sys.meta_path.pop()
blacklist = [ "renpy",
"renpy.log",
"renpy.bootstrap",
"renpy.display",
"renpy.display.iliad",
+57 -41
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -29,6 +29,7 @@
import renpy
import re
import time
import md5
# Called to set the state of a Node, when necessary.
def setstate(node, state):
@@ -94,7 +95,6 @@ class PyExpr(unicode):
def __getnewargs__(self):
return (unicode(self), self.filename, self.linenumber) # E1101
class PyCode(object):
__slots__ = [
@@ -102,6 +102,7 @@ class PyCode(object):
'location',
'mode',
'bytecode',
'hash',
]
def __getstate__(self):
@@ -133,6 +134,23 @@ class PyCode(object):
if renpy.game.script.record_pycode:
renpy.game.script.all_pycode.append(self)
self.hash = None
def get_hash(self):
try:
if self.hash is not None:
return self.hash
except:
pass
code = self.source
if isinstance(code, renpy.python.ast.AST):
code = renpy.python.ast.dump(code)
self.hash = chr(renpy.bytecode_version) + md5.md5(code).digest()
return self.hash
def chain_block(block, next):
"""
This is called to chain together all of the nodes in a block. Node
@@ -245,13 +263,11 @@ class Node(object):
assert False, "Node subclass forgot to define execute."
def predict(self, callback):
def predict(self):
"""
This is called to predictively load images from this node. The
callback needs to be passed into the predict method of any
images this ast node will probably load, and the method should
return a list containing the nodes that this node will
probably execute next.
This is called to predictively load images from this node. It
should cause renpy.display.predict.image and
renpy.display.predict.screen to be called as necessary.
"""
if self.next:
@@ -352,7 +368,7 @@ class Say(Node):
return self.next
def predict(self, callback):
def predict(self):
if self.who is not None:
if self.who_fast:
@@ -363,7 +379,7 @@ class Say(Node):
who = None
def predict_with(trans):
trans(old_widget=None, new_widget=None).predict(callback)
renpy.display.predict.displayable(trans(old_widget=None, new_widget=None))
say_menu_with(self.with_, predict_with)
@@ -371,9 +387,7 @@ class Say(Node):
if renpy.config.say_menu_text_filter:
what = renpy.config.say_menu_text_filter(what)
for i in renpy.exports.predict_say(who, what):
if i is not None:
i.predict(callback)
renpy.exports.predict_say(who, what)
return [ self.next ]
@@ -695,7 +709,7 @@ class Transform(Node):
return self.next
def predict_imspec(imspec, callback, scene=False):
def predict_imspec(imspec, scene=False):
"""
Call this to use the given callback to predict the image named
in imspec.
@@ -732,7 +746,7 @@ def predict_imspec(imspec, callback, scene=False):
renpy.game.context().predict_info.images.predict_show(tag or name, layer)
img.predict(callback)
renpy.display.predict.displayable(img)
def show_imspec(imspec, atl=None):
@@ -798,8 +812,8 @@ class Show(Node):
return self.next
def predict(self, callback):
predict_imspec(self.imspec, callback)
def predict(self):
predict_imspec(self.imspec)
return [ self.next ]
@@ -842,10 +856,10 @@ class Scene(Node):
return self.next
def predict(self, callback):
def predict(self):
if self.imspec:
predict_imspec(self.imspec, callback, scene=True)
predict_imspec(self.imspec, scene=True)
return [ self.next ]
@@ -870,7 +884,7 @@ class Hide(Node):
def diff_info(self):
return (Hide, tuple(self.imspec[0]))
def predict(self, callback):
def predict(self):
if len(self.imspec) == 3:
name, at_list, layer = self.imspec
@@ -943,13 +957,14 @@ class With(Node):
return self.next
def predict(self, callback):
def predict(self):
try:
trans = renpy.python.py_eval(self.expr)
if trans:
trans(old_widget=None, new_widget=None).predict(callback)
renpy.display.predict.displayable(trans(old_widget=None, new_widget=None))
except:
pass
@@ -1023,7 +1038,7 @@ class Call(Node):
return rv
def predict(self, callback):
def predict(self):
if self.expression:
return [ ]
else:
@@ -1066,7 +1081,7 @@ class Return(Node):
return renpy.game.context().lookup_return(pop=True)
def predict(self, callback):
def predict(self):
site = renpy.game.context().lookup_return(pop=False)
if site:
return [ site ]
@@ -1118,17 +1133,24 @@ class Menu(Node):
def execute(self):
choices = [ ]
narration = [ ]
for i, (label, condition, block) in enumerate(self.items):
if renpy.config.say_menu_text_filter:
label = renpy.config.say_menu_text_filter(label)
if block is None:
choices.append((label, condition, None))
if renpy.config.narrator_menu and label:
narration.append(label)
else:
choices.append((label, condition, None))
else:
choices.append((label, condition, i))
if narration:
renpy.exports.say(None, "\n".join(narration), interact=False)
say_menu_with(self.with_, renpy.game.interface.set_transition)
choice = renpy.exports.menu(choices, self.set)
@@ -1138,18 +1160,16 @@ class Menu(Node):
return self.items[choice][2][0]
def predict(self, callback):
def predict(self):
rv = [ ]
def predict_with(trans):
trans(old_widget=None, new_widget=None).predict(callback)
renpy.display.predict.displayable(trans(old_widget=None, new_widget=None))
say_menu_with(self.with_, predict_with)
for i in renpy.store.predict_menu():
if i is not None:
i.predict(callback)
renpy.store.predict_menu()
for label, condition, block in self.items:
if block:
rv.append(block[0])
@@ -1198,7 +1218,7 @@ class Jump(Node):
renpy.game.context().abnormal = True
return rv
def predict(self, callback):
def predict(self):
if self.expression:
return [ ]
@@ -1257,7 +1277,7 @@ class While(Node):
else:
return self.next
def predict(self, callback):
def predict(self):
return [ self.block[0], self.next ]
def scry(self):
@@ -1303,7 +1323,7 @@ class If(Node):
return self.next
def predict(self, callback):
def predict(self):
return [ block[0] for condition, block in self.entries ] + \
[ self.next ]
@@ -1334,12 +1354,8 @@ class UserStatement(Node):
self.call("execute")
return self.get_next()
def predict(self, callback):
predicted = self.call("predict") or [ ]
for i in predicted:
callback(i)
def predict(self):
self.call("predict")
return [ self.get_next() ]
def call(self, method, *args, **kwargs):
+16 -22
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -368,11 +368,9 @@ class ATLTransformBase(renpy.object.Object):
self.done = True
return pause
def predict(self, callback):
self.atl.predict(self.context, callback)
def predict_one(self):
self.atl.predict(self.context)
def visit(self):
if not self.block:
@@ -394,9 +392,8 @@ class RawStatement(renpy.object.Object):
raise Exception("Compile not implemented.")
# Predicts the images used by this statement.
def predict(self, ctx, callback):
def predict(self, ctx):
return
# The base class for compiled ATL Statements.
class Statement(renpy.object.Object):
@@ -459,9 +456,9 @@ class RawBlock(RawStatement):
return Block(self.loc, statements)
def predict(self, ctx, callback):
def predict(self, ctx):
for i in self.statements:
i.predict(ctx, callback)
i.predict(ctx)
# A compiled ATL block.
@@ -717,7 +714,7 @@ class RawMultipurpose(RawStatement):
return Interpolation(self.loc, warper, duration, properties, self.revolution, circles, splines)
def predict(self, ctx, callback):
def predict(self, ctx):
for i, j in self.expressions:
@@ -727,17 +724,14 @@ class RawMultipurpose(RawStatement):
continue
if isinstance(i, ATLTransformBase):
i.atl.predict(ctx, callback)
i.atl.predict(ctx)
return
try:
i = renpy.easy.displayable(i)
renpy.easy.predict(i)
except:
continue
if isinstance(i, renpy.display.core.Displayable):
i.predict(callback)
# This lets us have an ATL transform as our child.
class RawContainsExpr(RawStatement):
@@ -980,9 +974,9 @@ class RawParallel(RawStatement):
def compile(self, ctx):
return Parallel(self.loc, [i.compile(ctx) for i in self.blocks])
def predict(self, ctx, callback):
def predict(self, ctx):
for i in self.blocks:
i.predict(ctx, callback)
i.predict(ctx)
class Parallel(Statement):
@@ -1043,9 +1037,9 @@ class RawChoice(RawStatement):
compiling(self.loc)
return Choice(self.loc, [ (ctx.eval(chance), block.compile(ctx)) for chance, block in self.choices])
def predict(self, ctx, callback):
def predict(self, ctx):
for i, j in self.choices:
j.predict(ctx, callback)
j.predict(ctx)
class Choice(Statement):
@@ -1132,9 +1126,9 @@ class RawOn(RawStatement):
return On(self.loc, handlers)
def predict(self, ctx, callback):
def predict(self, ctx):
for i in self.handlers.itervalues():
i.predict(ctx, callback)
i.predict(ctx)
class On(Statement):
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
+11 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -44,8 +44,16 @@ if 'pss' not in disable:
pss.check_version(4)
atexit.register(pss.quit)
except:
pss = None
pass
if pss is None:
try:
import android_sound as pss
print "Imported android_sound."
except:
pass
if 'mix' not in disable:
try:
import winmixer as mix; mix
@@ -739,7 +747,7 @@ def periodic():
if vol != 0:
anything_playing = True
if max_volume == -1.0:
if max_volume <= 0:
return
if not anything_playing:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
+14 -6
View File
@@ -34,6 +34,7 @@ def extra_imports():
import encodings.string_escape
import encodings.raw_unicode_escape
import encodings.mbcs
import encodings.utf_16
import encodings.utf_16_be
import encodings.utf_16_le; encodings.utf_16_le
import math; math
@@ -96,6 +97,9 @@ def popen_del(self, *args, **kwargs):
def bootstrap(renpy_base):
global renpy # W0602
import renpy.log
renpy.log.init(renpy_base)
os.environ["RENPY_BASE"] = os.path.abspath(renpy_base)
@@ -119,10 +123,7 @@ def bootstrap(renpy_base):
for k, v in evars.iteritems():
if k not in os.environ:
os.environ[k] = str(v)
# Get a working name for the game.
name = os.path.basename(sys.argv[0])
@@ -175,6 +176,12 @@ def bootstrap(renpy_base):
op.add_option('--presplash', dest='presplash', default=None,
help="Used internally to display the presplash screen.")
op.add_option('--log-startup', dest='log_startup', action='store_true', default=os.environ.get("RENPY_LOG_STARTUP", None),
help="Causes Ren'Py to log startup timings to its log.")
op.add_option('--debug-image-cache', dest='debug_image_cache', action='store_true', default=False,
help="Causes Ren'Py to log startup timings to its log.")
options, args = op.parse_args()
@@ -260,8 +267,7 @@ def bootstrap(renpy_base):
try:
while keep_running:
try:
renpy.game.options = options
renpy.game.options = options
renpy.config.renpy_base = renpy_base
renpy.config.basedir = basedir
renpy.config.gamedir = gamedir
@@ -408,6 +414,8 @@ def report_exception(e):
f.close()
renpy.log.info_exception()
try:
if renpy.config.editor:
renpy.exports.launch_editor([ 'traceback.txt' ], 1, transient=1)
+242 -55
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -96,7 +96,7 @@ class DialogueTextTags(object):
self.pause_delay.append(None)
def predict_show_display_say(who, what, who_args, what_args, window_args, image=False, two_window=False, side_image=None, **kwargs):
def predict_show_display_say(who, what, who_args, what_args, window_args, image=False, two_window=False, side_image=None, screen=None, **kwargs):
"""
This is the default function used by Character to predict images that
will be used by show_display_say. It's called with more-or-less the
@@ -104,24 +104,71 @@ def predict_show_display_say(who, what, who_args, what_args, window_args, image=
list of images used by show_display_say.
"""
rv = [ ]
if "background" in window_args:
rv.append(window_args["background"])
else:
rv.append(getattr(renpy.game.style, window_args["style"]).background)
if two_window:
rv.append(renpy.game.style.say_who_window.background)
if screen:
props = compute_widget_properties(who_args, what_args, window_args)
renpy.display.screen.predict_screen(
screen,
_widget_properties=props,
who=who,
what=what,
image=image,
two_window=two_window,
side_image=side_image,
**kwargs)
return
if image:
if image != "<Dynamic>":
rv.append(renpy.display.im.image(who, True))
renpy.easy.predict(who)
if side_image:
rv.append(renpy.display.im.image(side_image, True))
renpy.easy.predict(side_image)
def compute_widget_properties(who_args, what_args, window_args, variant=None):
"""
Computes and returns the widget properties.
"""
def style_args(d):
if not "style" in d:
return d
in_rollback = renpy.exports.in_rollback()
if (not in_rollback) and (not variant):
return d
d = d.copy()
style = d["style"]
if isinstance(style, basestring):
style = getattr(renpy.store.style, style)
if variant is not None:
style = style[variant]
if in_rollback:
style = style["rollback"]
d["style"] = style
return d
who_args = style_args(who_args)
what_args = style_args(what_args)
window_args = style_args(window_args)
return {
"window" : window_args,
"what" : what_args,
"who" : who_args,
}
return rv
def show_display_say(who, what, who_args={}, what_args={}, window_args={},
image=False, side_image=None, two_window=False,
@@ -165,10 +212,12 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
displaying the what text.
"""
props = compute_widget_properties(who_args, what_args, window_args, variant=variant)
def handle_who():
if who:
if image:
renpy.ui.add(renpy.display.im.image(who, loose=True, **who_args))
renpy.ui.add(renpy.display.im.image(who, loose=True, **props["who"]))
else:
renpy.ui.text(who, **who_args)
@@ -187,43 +236,7 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
rv.update(properties)
return rv
def style_args(d):
if not "style" in d:
return d
in_rollback = renpy.exports.in_rollback()
if (not in_rollback) and (not variant):
return d
d = d.copy()
style = d["style"]
if isinstance(style, basestring):
style = getattr(renpy.store.style, style)
if variant is not None:
style = style[variant]
if in_rollback:
style = style["rollback"]
d["style"] = style
return d
who_args = style_args(who_args)
what_args = style_args(what_args)
window_args = style_args(window_args)
if screen and renpy.display.screen.has_screen(screen):
widget_properties = {
"window" : window_args,
"what" : what_args,
"who" : who_args,
}
tag = screen
index = 0
@@ -234,11 +247,15 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
renpy.display.screen.show_screen(
screen,
_widget_properties=widget_properties,
_widget_properties=props,
_transient = True,
_tag = tag,
image=image,
side_image=side_image,
two_window=two_window,
who=who,
what=what)
what=what,
**kwargs)
renpy.exports.shown_window()
@@ -257,14 +274,14 @@ def show_display_say(who, what, who_args={}, what_args={}, window_args={},
renpy.ui.window(**merge_style('say_who_window', who_window_properties))
handle_who()
renpy.ui.window(**window_args)
renpy.ui.window(**props["window"])
# Opens the say_vbox.
renpy.ui.vbox(**merge_style('say_vbox', say_vbox_properties))
if not two_window:
handle_who()
rv = renpy.ui.text(what, **what_args)
rv = renpy.ui.text(what, **props["what"])
# Closes the say_vbox.
renpy.ui.close()
@@ -643,6 +660,7 @@ class ADVCharacter(object):
who_args=self.who_args,
what_args=self.what_args,
window_args=self.window_args,
screen=self.screen,
**self.show_args)
def __call__(self, what, interact=True, **kwargs):
@@ -705,6 +723,175 @@ class ADVCharacter(object):
def Character(name=NotSet, kind=None, **properties):
"""
:doc: character
:args: (name, kind=adv, **args)
:name: Character
Creates and returns a Character object, which controls the look
and feel of dialogue and narration.
`name`
If a string, the name of the character for dialogue. When
`name` is ``None``, display of the name is omitted, as for
narration.
`kind`
The Character to base this Character off of. When used, the
default value of any argument not supplied to this Character
is the value of that argument supplied to `kind`. This can
be used to define a template character, and then copy that
character with changes.
**Prefixes and Suffixes.**
These allow a prefix and suffix to be applied to the name of the
character, and to the text being shown. This can be used, for
example, to add quotes before and after each line of dialogue.
`what_prefix`
A string that is prepended to the dialogue being spoken before
it is shown.
`what_suffix`
A string that is appended to the dialogue being spoken before
it is shown.
`who_prefix`
A string that is prepended to the name of the character before
it is shown.
`who_suffix`
A string that is appended to the name of the character before
it is shown.
**Changing Name Display.**
These options help to control the display of the name.
`dynamic`
If true, then `name` should be a string containing a python
expression. That string will be evaluated before each line
of dialogue, and the result used as the name of the character.
`image`
If true, then `name` is expected to name an image file. That
image is used as the name of the character.
**Controlling Interactions.**
These options control if the dialogue is displayed, if an
interaction occurs, and the mode that is entered upon display.
`condition`
If given, this should be a string containing a python
expression. If the expression is false, the dialogue
does not occur, as if the say statement did not happen.
`interact`
If true, the default, an interaction occurs whenever the
dialogue is shown. If false, an interaction will not occur,
and additional elements can be added to the screen.
`mode`
A string giving the mode to enter when this character
speaks. See the section on :ref:`modes <modes>` for more details.
`callback`
A function that is called when events occur while the
character is speaking. See the section on
:ref:`character callbacks` fore more information.
**Click-to-continue.**
A click-to-continue indicator is displayed once all the text has
finished displaying, to prompt the user to advance.
`ctc`
A Displayable to use as the click-to-continue indicator, unless
a more specific indicator is used.
`ctc_pause`
A Displayable to use a the click-to-continue indicator when the
display of text is paused by the {p} or {w} text tags.
`ctc_timedpause`
A Displayable to use a the click-to-continue indicator when the
display of text is paused by the {p=} or {w=} text tags. When
None, this takes its default from ctc_pause, use ``Null()``
when you want a ctc_pause but no ctc_timedpause.
`ctc_position`
Controls the location of the click-to-continue indicator. If
``"nestled"``, the indicator is displayed as part of the text
being shown, immediately after the last character. If ``"fixed"``,
the indicator is added to the screen, and its position is
controlled by the position style properties.
**Screens.**
The display of dialogue uses a :ref:`screen <screens>`. These arguments
allow you to select that screen, and to provide arguments to it.
`screen`
The name of the screen that is used to display the dialogue.
Keyword arguments beginning with ``show_`` have the prefix
stripped off, and are passed to the screen as arguments. For
example, the value of ``show_side_image`` will become the
value of the ``side_image`` variable in the screen.
Some useful ``show_`` variables implemented by the default screens are:
`show_side_image`
When given a Displayable, shows that displayable when the
dialogue is shown. The position of that displayable is
controlled by its position properties. This is often used
to show an image of the speaking character to the side
of the dialogue.
`show_two_window`
If true, restructures the layout so that the name of the
character is placed in one window, and the dialogue text in a
second window.
**Styling Text and Windows.**
Keyword arguments beginning with ``who_``, ``what_``, and
`window_`` have their prefix stripped, and are used to :ref:`style
<styles>` the character name, the spoken text, and the window
containing both, respectively.
For example, if a character is given the keyword argument
``who_color="#c8ffc8"``, the color of the character's name is
changed, in this case to green. ``window_background="frame.png"``
sets the background of the window containing this character's
dialogue.
The style applied to the character name, spoken text, and window
can also be set this way, using the `who_style`, `what_style`, and
`window_style` arguments, respectively.
"""
if kind is None:
kind = renpy.store.adv
+34 -2
View File
@@ -1,5 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -225,6 +224,11 @@ keymap = dict(
# Delete a save.
save_delete = [ 'K_DELETE' ],
# Draggable.
drag_activate = [ 'mousedown_1' ],
drag_deactivate = [ 'mouseup_1' ],
)
# Should we try to support joysticks?
@@ -440,6 +444,34 @@ mode_callbacks = [ ]
# Should MoveTransition take offsets into account?
movetransition_respects_offsets = True
# Do we care about the pos and anchor attributes of an ImageReference's
# style?
imagereference_respects_position = False
# Do we want to try to pretend to be android?
simulate_android = False
# Do we want to enable imagemap caching?
imagemap_cache = True
# Callbacks that are called in order to predict images.
predict_callbacks = [ ]
# Should screens be predicted?
predict_screens = True
# Should we use the new choice screen format?
choice_screen_ids = True
# Should the narrator speak menu labels?
narrator_menu = False
# A list of screen variants to use.
variants = [ None ]
# A function from (auto_parameter, variant) -> displayable.
imagemap_auto_function = None
del renpy
del os
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
+6 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -37,3 +37,8 @@ gl_giveup = None
# The renderers we prefer to use.
prefer_renderers = "gl,sw"
# Should we disable imagedissolve-type transitions?
less_imagedissolve = False
+246
View File
@@ -0,0 +1,246 @@
#cython: profile=False
# Copyright 2004-2011 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 renpy
import math
from renpy.display.render cimport Render, Matrix2D, render
cdef Matrix2D IDENTITY
IDENTITY = renpy.display.render.IDENTITY
# This file contains implementations of methods of classes that
# are found in other files, for performance reasons.
def transform_render(self, widtho, heighto, st, at):
cdef double rxdx, rxdy, rydx, rydy
cdef double nxdx, nxdy, nydx, nydy
cdef double xdx, xdy, ydx, ydy
cdef double xo, x1, x2, x3
cdef double yo, y1, y2, y3
cdef float zoom, xzoom, yzoom
cdef double cw, ch, nw, nh
cdef Render rv, cr
cdef double angle
cdef double alpha
cdef double width = widtho
cdef double height = heighto
# Should we perform clipping?
clipping = False
# Preserve the illusion of linear time.
if st == 0:
self.st_offset = self.st
if at == 0:
self.at_offset = self.at
self.st = st = st + self.st_offset
self.at = at = at + self.at_offset
# Update the state.
self.update_state()
# Render the child.
child = self.child
if child is None:
raise Exception("Transform does not have a child.")
cr = render(child, widtho, heighto, st - self.child_st_base, at)
width = cr.width
height = cr.height
# The reverse matrix.
rxdx = 1
rxdy = 0
rydx = 0
rydy = 1
xo = 0
yo = 0
state = self.state
# Cropping.
crop = state.crop
if (state.corner1 is not None) and (crop is None) and (state.corner2 is not None):
x1, y1 = state.corner1
x2, y2 = state.corner2
if x1 < x2:
minx = x1
maxx = x2
else:
minx = x2
maxx = x1
if y1 < y2:
miny = y1
maxy = y2
else:
miny = y2
maxy = y1
crop = (minx, miny, maxx - minx, maxy - miny)
if crop is not None:
negative_xo, negative_yo, width, height = crop
xo = -negative_xo
yo = -negative_yo
clipping = True
if state.rotate:
clipcr = Render(width, height)
clipcr.subpixel_blit(cr, (xo, yo))
clipcr.clipping = clipping
xo = yo = 0
cr = clipcr
clipping = False
# Size.
size = state.size
if (size is not None) and (size != (width, height)):
nw, nh = size
xzoom = 1.0 * nw / width
yzoom = 1.0 * nh / height
rxdx = xzoom
rydy = yzoom
xo = xo * xzoom
yo = yo * yzoom
width, height = size
# Rotation.
rotate = state.rotate
if rotate is not None:
cw = width
ch = height
angle = rotate * 3.1415926535897931 / 180
xdx = math.cos(angle)
xdy = -math.sin(angle)
ydx = -xdy
ydy = xdx
# reverse = Matrix2D(xdx, xdy, ydx, ydy) * reverse
# We know that at this point, rxdy and rydx are both 0, so
# we can simplify these formulae a bit.
nxdx = rxdx * xdx
rxdy = rxdx * xdy
rydx = rydy * ydx
nydy = rydy * ydy
rxdx = nxdx
rydy = nydy
if state.rotate_pad:
width = height = math.hypot(cw, ch)
xo = -cw / 2.0 * rxdx + -ch / 2.0 * rxdy
yo = -cw / 2.0 * rydx + -ch / 2.0 * rydy
else:
xo = -cw / 2.0 * rxdx + -ch / 2.0 * rxdy
yo = -cw / 2.0 * rydx + -ch / 2.0 * rydy
x2 = -cw / 2.0 * rxdx + ch / 2.0 * rxdy
y2 = -cw / 2.0 * rydx + ch / 2.0 * rydy
x3 = cw / 2.0 * rxdx + ch / 2.0 * rxdy
y3 = cw / 2.0 * rydx + ch / 2.0 * rydy
x4 = cw / 2.0 * rxdx + -ch / 2.0 * rxdy
y4 = cw / 2.0 * rydx + -ch / 2.0 * rydy
width = max(xo, x2, x3, x4) - min(xo, x2, x3, x4)
height = max(yo, y2, y3, y4) - min(yo, y2, y3, y4)
xo += width / 2.0
yo += height / 2.0
zoom = state.zoom
xzoom = zoom * <double> state.xzoom
yzoom = zoom * <double> state.yzoom
alpha = state.alpha
if xzoom != 1 or yzoom != 1:
nxdx = rxdx * xzoom
nxdy = rxdy * yzoom
nydx = rydx * xzoom
nydy = rydy * yzoom
rxdx = nxdx
rxdy = nxdy
rydx = nydx
rydy = nydy
width *= xzoom
height *= yzoom
xo *= xzoom
yo *= yzoom
rv = Render(width, height)
# Default case - no transformation matrix.
if rxdx == 1 and rxdy == 0 and rydx == 0 and rydy == 0:
self.forward = IDENTITY
else:
inv_det = rxdx * rydy - rxdy * rydx
rv.reverse = Matrix2D(rxdx, rxdy, rydx, rydy)
if not inv_det:
self.forward = rv.forward = Matrix2D(0, 0, 0, 0)
else:
self.forward = rv.forward = Matrix2D(
rydy / inv_det,
-rxdy / inv_det,
-rydx / inv_det,
rxdx / inv_det)
rv.alpha = alpha
rv.clipping = clipping
pos = (xo, yo)
if state.subpixel:
rv.subpixel_blit(cr, pos)
else:
rv.blit(cr, pos)
self.offsets = [ pos ]
return rv
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
+112 -10
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -23,7 +23,7 @@
import renpy
from renpy.display.render import render
from renpy.display.render import render, Render
import pygame
@@ -187,6 +187,22 @@ def run(var, *args, **kwargs):
return var(*args)
def predict_action(var):
"""
Predicts some of the actions that may be caused by a variable.
"""
if var is None:
return
if isinstance(var, renpy.ui.Action):
var.predict()
if isinstance(var, (list, tuple)):
for i in var:
predict_action(i)
def run_periodic(var, st):
if isinstance(var, (list, tuple)):
@@ -252,6 +268,10 @@ class Keymap(renpy.display.layout.Null):
raise renpy.display.core.IgnoreEvent()
def predict_one_action(self):
for i in self.keymap.itervalues():
predict_action(i)
class RollForward(renpy.display.layout.Null):
"""
@@ -454,6 +474,14 @@ class Button(renpy.display.layout.Window):
self.time_policy_data = None
def predict_one_action(self):
predict_action(self.clicked)
predict_action(self.hovered)
predict_action(self.unhovered)
if self.keymap:
for v in self.keymap.itervalues():
predict_action(v)
def render(self, width, height, st, at):
@@ -513,7 +541,7 @@ class Button(renpy.display.layout.Window):
def unfocus(self, default=False):
super(Button, self).unfocus()
super(Button, self).unfocus(default)
if self.activated:
return None
@@ -543,7 +571,7 @@ class Button(renpy.display.layout.Window):
# If we have a child, try passing the event to it. (For keyboard
# events, this only happens if we're focused.)
if self.is_focused() or not (ev.type == pygame.KEYDOWN and ev.type == pygame.KEYUP):
if self.is_focused() or not (ev.type == pygame.KEYDOWN or ev.type == pygame.KEYUP):
rv = super(Button, self).event(ev, x, y, st)
if rv is not None:
return rv
@@ -910,6 +938,8 @@ class Bar(renpy.display.core.Displayable):
style=None,
vertical=False,
replaces=None,
hovered=None,
unhovered=None,
**properties):
self.value = None
@@ -954,14 +984,41 @@ class Bar(renpy.display.core.Displayable):
self.height = 0
self.width = 0
self.hidden = False
def visit(self):
return [ self.style.fore_bar, self.style.aft_bar, self.style.thumb, self.style.thumb_shadow ]
self.hovered = hovered
self.unhovered = unhovered
def per_interact(self):
self.focusable = self.adjustment.adjustable
self.adjustment.register(self)
def predict_one(self):
pd = renpy.display.predict.displayable
style = self.style
pd(style.insensitive_fore_bar)
pd(style.idle_fore_bar)
pd(style.hover_fore_bar)
pd(style.selected_idle_fore_bar)
pd(style.selected_hover_fore_bar)
pd(style.insensitive_aft_bar)
pd(style.idle_aft_bar)
pd(style.hover_aft_bar)
pd(style.selected_idle_aft_bar)
pd(style.selected_hover_aft_bar)
pd(style.insensitive_thumb)
pd(style.idle_thumb)
pd(style.hover_thumb)
pd(style.selected_idle_thumb)
pd(style.selected_hover_thumb)
pd(style.insensitive_thumb_shadow)
pd(style.idle_thumb_shadow)
pd(style.hover_thumb_shadow)
pd(style.selected_idle_thumb_shadow)
pd(style.selected_hover_thumb_shadow)
def render(self, width, height, st, at):
# Handle redrawing.
@@ -1081,12 +1138,13 @@ class Bar(renpy.display.core.Displayable):
def focus(self, default=False):
super(Bar, self).focus(default)
self.set_transform_event("hover")
run(self.hovered)
def unfocus(self, default=False):
super(Bar, self).unfocus()
self.set_transform_event("idle")
run(self.unhovered)
def event(self, ev, x, y, st):
@@ -1260,4 +1318,48 @@ class Timer(renpy.display.layout.Null):
return self.function(*self.args, **self.kwargs)
class MouseArea(renpy.display.core.Displayable):
def __init__(self, hovered=None, unhovered=None, replaces=None, **properties):
super(MouseArea, self).__init__(**properties)
self.hovered = hovered
self.unhovered = unhovered
# Are we hovered right now?
self.is_hovered = False
if replaces is not None:
self.is_hovered = replaces.is_hovered
# Taken from the render.
self.width = 0
self.height = 0
def render(self, width, height, st, at):
self.width = width
self.height = height
return Render(width, height)
def event(self, ev, x, y, st):
if 0 <= x < self.width and 0 <= y < self.height:
is_hovered = True
else:
is_hovered = False
if is_hovered and not self.is_hovered:
self.is_hovered = True
return run(self.hovered)
elif not is_hovered and self.is_hovered:
self.is_hovered = False
run(self.unhovered)
+146 -101
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -38,6 +38,11 @@ try:
except:
pass
try:
import android
except:
android = None
# Is the cpu idle enough to do other things?
cpu_idle = threading.Event()
cpu_idle.clear()
@@ -97,6 +102,14 @@ class Displayable(renpy.object.Object):
their fields.
"""
# Some invariants about method call order:
#
# per_interact is called before render.
# render is called before event.
#
# get_placement can be called at any time, so can't
# assume anything.
activated = False
focusable = False
full_focus_name = None
@@ -188,7 +201,7 @@ class Displayable(renpy.object.Object):
that this drawable can be drawn to without overflowing some
bounding box. It's also given two times. It returns a Surface
that is the current image of this drawable.
@param st: The time since this widget was first shown, in seconds.
@param at: The time since a similarly named widget was first shown,
in seconds.
@@ -225,18 +238,13 @@ class Displayable(renpy.object.Object):
displayable.
"""
worklist = [ self ]
while worklist:
d = worklist.pop(0)
if d is None:
for d in self.visit():
if not d:
continue
d.visit_all(callback)
callback(d)
worklist.extend(d.visit())
callback(self)
def visit(self):
"""
Called to ask the displayable to return a list of its children
@@ -253,15 +261,7 @@ class Displayable(renpy.object.Object):
return None
def predict(self, callback):
"""
Called to ask this displayable to call the callback with all
the images it, and its children, may want to load.
"""
self.visit_all(lambda i : i.predict_one(callback))
def predict_one(self, callback):
def predict_one(self):
"""
Called to ask this displayable to call the callback with all
the images it may want to load.
@@ -269,7 +269,15 @@ class Displayable(renpy.object.Object):
return
def place(self, dest, x, y, width, height, surf, xoff=None, yoff=None, main=True):
def predict_one_action(self):
"""
Called to ask this displayable to cause image prediction
to occur for images that may be loaded by its actions.
"""
return
def place(self, dest, x, y, width, height, surf, main=True):
"""
This draws this Displayable onto a destination surface, using
the placement style information returned by this object's
@@ -295,7 +303,6 @@ class Displayable(renpy.object.Object):
"""
xpos, ypos, xanchor, yanchor, xoffset, yoffset, subpixel = self.get_placement()
if xpos is None:
xpos = 0
@@ -310,53 +317,32 @@ class Displayable(renpy.object.Object):
if yoffset is None:
yoffset = 0
sw, sh = surf.get_size()
# We need to use type, since isinstance(absolute(0), float).
if xpos.__class__ is float:
xpos *= width
# x
if xoff is None:
xoff = xpos
if xanchor.__class__ is float:
xanchor *= surf.width
if type(xoff) is float:
xoff_mul = width
else:
xoff_mul = 1
if type(xanchor) is float:
xanchor_mul = sw
else:
xanchor_mul = 1
xoff = xoff * xoff_mul - xanchor * xanchor_mul
xoff += x
# y
if yoff is None:
yoff = ypos
if type(yoff) is float:
yoff_mul = height
else:
yoff_mul = 1
if type(yanchor) is float:
yanchor_mul = sh
else:
yanchor_mul = 1
yoff = yoff * yoff_mul - yanchor * yanchor_mul
yoff += y
# Add in offsets.
xoff += xoffset
yoff += yoffset
if subpixel:
dest.subpixel_blit(surf, (xoff, yoff), main=main)
else:
dest.blit(surf, (xoff, yoff), main=main)
xpos += x + xoffset - xanchor
# y
return xoff, yoff
if ypos.__class__ is float:
ypos *= height
if yanchor.__class__ is float:
yanchor *= surf.height
ypos += y + yoffset - yanchor
if dest is not None:
if subpixel:
dest.subpixel_blit(surf, (xpos, ypos), main, main, None)
else:
dest.blit(surf, (xpos, ypos), main, main, None)
return xpos, ypos
def set_transform_event(self, event):
"""
@@ -491,7 +477,7 @@ class SceneLists(renpy.object.Object):
things to the user.
"""
__version__ = 4
__version__ = 5
def after_setstate(self):
for i in renpy.config.layers + renpy.config.top_layers:
@@ -519,7 +505,10 @@ class SceneLists(renpy.object.Object):
self.layers[k] = [ SceneListEntry(*(i + (None,)) ) for i in self.layers[k] ]
self.additional_transient = [ ]
if version < 5:
self.drag_group = None
def __init__(self, oldsl, ipi):
super(SceneLists, self).__init__()
@@ -543,6 +532,11 @@ class SceneLists(renpy.object.Object):
# A list of (layer, tag) pairs that are considered to be
# transient.
self.additional_transient = [ ]
# Either None, or a DragGroup that's used as the default for
# drags with names.
self.drag_group = None
if oldsl:
@@ -562,6 +556,8 @@ class SceneLists(renpy.object.Object):
self.replace_transient()
self.focused = None
self.drag_group = oldsl.drag_group
else:
for i in renpy.config.layers + renpy.config.top_layers:
@@ -1122,7 +1118,7 @@ class Interface(object):
# Initialize pygame.
if pygame.version.vernum < (1, 8, 1):
raise Exception("Ren'Py requires pygame 1.8.1 to run.")
try:
pygame.macosx.init()
except:
@@ -1132,7 +1128,7 @@ class Interface(object):
renpy.audio.audio.init()
renpy.display.joystick.init()
pygame.display.init()
# Init timing.
init_time()
self.profile_time = get_time()
@@ -1152,6 +1148,11 @@ class Interface(object):
# Setup the video mode.
self.set_mode()
# Setup the android keymap.
if android is not None:
android.map_key(android.KEYCODE_BACK, pygame.K_PAGEUP)
android.map_key(android.KEYCODE_MENU, pygame.K_ESCAPE)
# Double check, since at least on Linux, we can't set safe_mode until
# the window maps.
if renpy.first_utter_start and (pygame.key.get_mods() & pygame.KMOD_SHIFT):
@@ -1225,12 +1226,22 @@ class Interface(object):
"""
Figures out the list of draw constructors to try.
"""
draws = {
"gl" : renpy.display.gldraw.GLDraw,
"sw" : renpy.display.swdraw.SWDraw,
}
draws = { }
try:
import renpy.display.gldraw as gldraw
draws["gl"] = gldraw.GLDraw
except:
renpy.log.info("Couldn't import gl renderer.")
try:
import renpy.display.swdraw as swdraw
draws["sw"] = swdraw.SWDraw
except:
renpy.log.info("Couldn't import sw renderer.")
default = renpy.display.prefer_renderers
dl = os.environ.get("RENPY_RENDERER", default).split(",")
@@ -1242,11 +1253,16 @@ class Interface(object):
"""
This sets the video mode. It also picks the draw object.
"""
if self.display_reset:
renpy.display.draw.deinit()
renpy.display.draw.quit()
renpy.display.draw = None
renpy.display.render.free_memory()
renpy.display.im.cache.clear()
renpy.display.module.bo_cache = None
self.display_reset = False
@@ -1260,7 +1276,7 @@ class Interface(object):
# Setup screen.
fullscreen = renpy.game.preferences.fullscreen
# If we're in fullscreen mode, and changing to another mode, go to
# windowed mode first.
s = pygame.display.get_surface()
@@ -1310,7 +1326,7 @@ class Interface(object):
renpy.display.draw.draw_screen(surftree, fullscreen_video)
renpy.display.render.kill_old_screen()
renpy.display.render.mark_sweep()
renpy.display.focus.take_focuses()
self.surftree = surftree
@@ -1375,11 +1391,11 @@ class Interface(object):
rv = self.screenshot
if not rv:
self.take_screenshot()
rv = self.screenshot()
self.take_screenshot((renpy.config.thumbnail_width, renpy.config.thumbnail_height))
rv = self.screenshot
self.lose_screenshot()
return self.screenshot
return rv
def lose_screenshot(self):
@@ -1564,7 +1580,7 @@ class Interface(object):
This is called to handle the user invoking a quit.
"""
if self.quit_time > (time.time() - 3.0):
if self.quit_time > (time.time() - .75):
raise renpy.game.QuitException()
if renpy.config.quit_action is not None:
@@ -1669,6 +1685,31 @@ class Interface(object):
return (get_time() - self.frame_time) <= seconds_ago
def android_check_suspend(self):
if android.check_pause():
import android_sound
android_sound.pause_all()
pygame.time.set_timer(PERIODIC, 0)
pygame.time.set_timer(REDRAW, 0)
pygame.time.set_timer(TIMEEVENT, 0)
# The game has to be saved.
renpy.loadsave.save("_reload-1")
android.wait_for_resume()
# Since we came back to life, we can get rid of the
# auto-reload.
renpy.loadsave.unlink_save("_reload-1")
pygame.time.set_timer(PERIODIC, PERIODIC_INTERVAL)
android_sound.unpause_all()
def interact_core(self,
show_mouse=True,
trans_pause=False,
@@ -1748,7 +1789,8 @@ class Interface(object):
# Tick time forward.
renpy.display.im.cache.tick()
renpy.display.predict.reset()
# Cleare the size groups.
renpy.display.layout.size_groups.clear()
@@ -1797,9 +1839,8 @@ class Interface(object):
scene = self.compute_scene(scene_lists)
# If necessary, load all images here.
if renpy.config.load_before_transition:
for w in scene.itervalues():
w.predict(renpy.display.im.cache.get)
for w in scene.itervalues():
renpy.display.predict.displayable(w)
# The root widget of all of the layers.
layers_root = renpy.display.layout.MultiBox(layout='fixed')
@@ -1873,6 +1914,8 @@ class Interface(object):
for layer in renpy.config.top_layers:
add_layer(root_widget, layer)
prediction_coroutine = renpy.display.predict.prediction_coroutine(root_widget)
# Clean out the registered adjustments.
renpy.display.behavior.adj_registered.clear()
@@ -1902,10 +1945,6 @@ class Interface(object):
# We don't yet know when the interaction began.
self.interact_time = None
# We only want to do prediction once, but we will defer it as
# long as possible.
did_prediction = False
# We only want to do autosave once.
did_autosave = False
@@ -1928,8 +1967,11 @@ class Interface(object):
self.set_mode()
needs_redraw = True
# Redraw the screen.
# Check for suspend.
if android:
self.android_check_suspend()
# Redraw the screen.
if (self.force_redraw or
((first_pass or not pygame.event.peek(ALL_EVENTS)) and
renpy.display.draw.should_redraw(needs_redraw, first_pass))):
@@ -1989,16 +2031,15 @@ class Interface(object):
needs_redraw = needs_redraw or renpy.display.render.process_redraws()
# Predict images, if we haven't done so already.
if not did_prediction and not self.event_peek():
if not renpy.config.load_before_transition:
root_widget.predict(renpy.display.im.cache.preload_image)
for w in preloads:
w.predict(renpy.display.im.cache.preload_image)
renpy.game.context().predict(renpy.display.im.cache.preload_image)
renpy.display.im.cache.preload()
did_prediction = True
while (prediction_coroutine is not None) \
and not needs_redraw \
and not self.event_peek():
result = prediction_coroutine.next()
if not result:
prediction_coroutine = None
break
# If we need to redraw again, do it if we don't have an
# event going on.
@@ -2146,7 +2187,11 @@ class Interface(object):
# This returns the event location. It also updates the
# mouse state as necessary.
x, y = renpy.display.draw.mouse_event(ev)
if not self.focused:
x = -1
y = -1
self.event_time = end_time = get_time()
# Handle the event normally.
+730
View File
@@ -0,0 +1,730 @@
# Copyright 2004-2011 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.
# TODO: Use overlap (rather than simple pointer location) to determine
# drag and drop.
import renpy
from renpy.display.render import render, Render, redraw
from renpy.display.core import absolute
from renpy.display.behavior import map_event, run
import pygame
def default_drag_group():
"""
Gets the default drag group. If it doesn't exist yet, creates it.
"""
sls = renpy.game.context().scene_lists
rv = sls.drag_group
if rv is None:
rv = DragGroup()
sls.drag_group = rv
return rv
def default_drag_joined(drag):
return [ (drag, 0, 0) ]
class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
"""
:doc: drag_drop class
A displayable that represents an object that can be dragged around
its enclosing area. A Drag can also represent an area that
other Drags can be dropped on.
A Drag can be moved around inside is parent. Generally, its parent
should be either a :func:`Fixed` or :class:`DragGroup`.
A Drag has one child. The child's state reflects the status
of the drag and drop operation:
* ``selected_hover`` - when it is being dragged.
* ``selected_idle`` - when it can be dropped on.
* ``hover`` - when the draggable will be dragged when the mouse is
clicked.
* ``idle`` - otherwise.
The drag handle is a rectangle inside the child. The mouse must be over
a non-transparent pixel inside the drag handle for dragging or clicking
to occur.
A newly-created draggable is added to the default DragGroup. A draggable
can only be in a single DragGroup - if it's added to a second group,
it's removed from the first.
When a Drag is first rendered, if it's position cannot be determined
from the DragGroup it is in, the position of its upper-left corner
is computed using the standard layout algorithm. Once that position
`d`
If present, the child of this Drag. Drags use the child style
in preference to this, if it's not None.
`drag_name`
If not None, the name of this draggable. This is available
as the `name` property of draggable objects. If a Drag
with the same name is or was in the DragGroup, the starting
position of this Drag is taken from that Draggable.
`draggable`
If true, the Drag can be dragged around the screen with
the mouse.
`droppable`
If true, other Drags can be dropped on this Drag.
`drag_raise`
If true, this Drag is raised to the top when it is dragged. If
it is joined to other Drags, all joined drags are raised.
`dragged`
A callback (or list of callbacks) that is called when the Drag
has been dragged. It is called with two arguments. The first is
a list of Drags that are being dragged. The second is either
a Drag that is being dropped onto, or None of a drop did not
occur. If the callback returns a value other than None, that
value is returned as the result of the interaction.
`dropped`
A callback (or list of callbacks) that is called when this Drag
is dropped onto. It is called with two arguments. The first
is the Drag being dropped onto. The second is a list of Drags that
are being dragged. If the callback returns a value other than None,
that value is returned as the result of the interaction.
When a dragged and dropped callback are triggered for the same
event, the dropped callback is only called if dragged returns
None.
`clicked`
A callback this is called, with no arguments, when the Drag is
clicked without being moved. A droppable can also be focused
and clicked. If the callback returns a value othe than None,
that value is returned as the result of the interaction.
`drag_handle`
A (x, y, width, height) tuple, giving the position of the drag
handle within the child. In this tuple, integers are considered
to be a literal number of pixels, while floats are relative to
the size of the child.
`drag_joined`
This is called with the current Drag as an argument. It's
expected to return a list of [ (drag, x, y) ] tuples, giving
the draggables to drag as a unit. `x` and `y` are the offsets
of the drags relative to each other, they are not relative
to the corner of this drag.
Except for `d`, all of the parameters are available as fields (with
the same name) on the Drag object. In addition, after the drag has
been rendered, the following fields become available:
`x`, `y`
The position of the Drag relative to its parent, in pixels.
`w`, `h`
The width and height of the Drag's child, in pixels.
"""
def __init__(self,
d=None,
drag_name=None,
draggable=True,
droppable=True,
drag_raise=True,
dragged=None,
dropped=None,
drag_handle=(0.0, 0.0, 1.0, 1.0),
drag_joined=default_drag_joined,
clicked=None,
hovered=None,
unhovered=None,
replaces=None,
**properties):
super(Drag, self).__init__(self, **properties)
self.drag_name = drag_name
self.draggable = draggable
self.droppable = droppable
self.drag_raise = drag_raise
self.dragged = dragged
self.dropped = dropped
self.drag_handle = drag_handle
self.drag_joined = drag_joined
self.clicked = clicked
self.hovered = hovered
self.unhovered = unhovered
self.child = None
# Add us to a drag group on creation.
if drag_name:
self.drag_group = default_drag_group()
# The current x and y coordinates of this displayable.
self.x = None
self.y = None
# The width and height of the child.
self.w = None
self.h = None
# The width and height of our parent.
self.parent_width = None
self.parent_height = None
# The target x and y coordinates of this displayable. (The
# coordinates that we're snapping to.)
self.target_x = None
self.target_y = None
# The offset from the location of the mouse to the "grab point",
# which is where the things that are being moved are offset from.
self.grab_x = None
self.grab_y = None
# x and y from the last time we rendered.
self.last_x = None
self.last_y = None
# The abs_x and abs_y from when we started the grab.
self.start_x = 0
self.start_y = 0
# The last time we were shown, using the animation timebases.
self.at = 0
# The (animation timebase) time at which we should reach
# the target coordinates.
self.target_at = 0
# The displayable we were last dropping on.
self.last_drop = None
# Did we move over the course of this drag?
self.drag_moved = False
if replaces is not None:
self.x = replaces.x
self.y = replaces.y
self.at = replaces.at
self.target_x = replaces.target_x
self.target_y = replaces.target_y
self.target_at = replaces.target_at
if d is not None:
self.add(d)
def snap(self, x, y, delay=0):
"""
:doc: drag_drop method
Changes the position of the drag. If the drag is not showing,
then the position change is instantaneous. Otherwise, the
position change takes `delay` seconds, and is animated as a
linear move.
"""
self.target_x = x
self.target_y = y
if self.x is not None:
self.target_at = self.at + delay
else:
self.target_at = self.at
self.x = x
self.y = y
redraw(self, 0)
def set_style_prefix(self, prefix, root):
super(Drag, self).set_style_prefix(prefix, root)
if self.child is not None:
self.child.set_style_prefix(prefix, False)
def add(self, d):
if self.child is not None:
raise Exception("Drag expects either zero or one children.")
self.child = renpy.easy.displayable(d)
def set_child(self, d):
"""
:doc: drag_drop method
Changes the child of this drag to `d`.
"""
d.per_interact()
self.child = renpy.easy.displayable(d)
def top(self):
"""
:doc: drag_drop method
Raises this displayable to the top of its drag_group.
"""
if self.drag_group is not None:
self.drag_group.raise_children([ self ])
def visit(self):
return [ self.child ]
def focus(self, default=False):
super(Drag, self).focus(default)
rv = None
if not default:
rv = run(self.hovered)
return rv
def unfocus(self, default=False):
super(Drag, self).unfocus(default)
if not default:
run(self.unhovered)
def render(self, width, height, st, at):
child = self.style.child
if child is None:
child = self.child
self.parent_width = width
self.parent_height = height
cr = render(child, width, height, st, at)
cw, ch = cr.get_size()
rv = Render(cw, ch)
rv.blit(cr, (0, 0))
self.w = cw
self.h = ch
# If we don't have a position, then look for it in a drag group.
if (self.x is None) and (self.drag_group is not None) and (self.drag_name is not None):
if self.drag_name in self.drag_group.positions:
self.x, self.y = self.drag_group.positions[self.drag_name]
# If we don't have a position, run the placement code and use
# that to compute our placement.
if self.x is None:
self.x, self.y = self.place(None, 0, 0, width, height, rv)
self.x = int(self.x)
self.y = int(self.y)
if self.target_x is None:
self.target_x = self.x
self.target_y = self.y
self.target_at = at
# Determine if we need to do the snap animation.
if at >= self.target_at:
self.x = self.target_x
self.y = self.target_y
else:
done = (at - self.at) / (self.target_at - self.at)
self.x = absolute(self.x + done * (self.target_x - self.x))
self.y = absolute(self.y + done * (self.target_y - self.y))
redraw(self, 0)
if self.draggable or self.clicked is not None:
fx, fy, fw, fh = self.drag_handle
if isinstance(fx, float):
fx = int(fx * cw)
if isinstance(fy, float):
fy = int(fy * ch)
if isinstance(fw, float):
fw = int(fw * cw)
if isinstance(fh, float):
fh = int(fh * ch)
rv.add_focus(self, None, fx, fy, fw, fh, fx, fy, cr.subsurface((fx, fy, fw, fh)))
self.last_x = self.x
self.last_y = self.y
self.at = at
return rv
def event(self, ev, x, y, st):
if not self.is_focused():
return self.child.event(ev, x, y, st)
# if not self.draggable:
# return self.child.event(ev, x, y, st)
# Mouse, in parent-relative coordinates.
par_x = self.last_x + x
par_y = self.last_y + y
grabbed = (renpy.display.focus.get_grab() is self)
if grabbed:
joined_offsets = self.drag_joined(self)
joined = [ i[0] for i in joined_offsets ]
elif self.draggable and map_event(ev, "drag_activate"):
joined_offsets = self.drag_joined(self)
joined = [ i[0] for i in joined_offsets ]
if not joined:
raise renpy.display.core.IgnoreEvent()
renpy.display.focus.set_grab(self)
self.grab_x = x
self.grab_y = y
# If we're not the only thing we're joined with, we
# might need to adjust our grab point.
for i, xo, yo in joined_offsets:
if i is self:
self.grab_x += xo
self.grab_y += yo
break
self.drag_moved = False
self.start_x = par_x
self.start_y = par_y
grabbed = True
# Handle clicking on droppables.
if not grabbed:
if self.clicked is not None and map_event(ev, "drag_deactivate"):
rv = run(self.clicked)
if rv is not None:
return rv
raise renpy.display.core.IgnoreEvent()
return self.child.event(ev, x, y, st)
# Handle moves by moving things relative to the grab point.
if ev.type in (pygame.MOUSEMOTION, pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN):
if not self.drag_moved and (self.start_x != par_x or self.start_y != par_y):
self.drag_moved = True
# We may not be in the drag_joined group.
self.set_style_prefix("idle_", True)
# Set the style.
for i in joined:
i.set_style_prefix("selected_hover_", True)
# Raise the joined items.
if self.drag_raise and self.drag_group is not None:
self.drag_group.raise_children(joined)
if self.drag_moved:
for i, xo, yo in joined_offsets:
new_x = par_x - self.grab_x + xo
new_y = par_y - self.grab_y + yo
new_x = max(new_x, 0)
new_x = min(new_x, i.parent_width - i.w)
new_y = max(new_y, 0)
new_y = min(new_y, i.parent_height - i.h)
if i.drag_group is not None and i.drag_name is not None:
i.drag_group.positions[i.drag_name] = (new_x, new_y)
i.x = new_x
i.y = new_y
i.target_x = new_x
i.target_y = new_y
i.target_at = self.at
redraw(i, 0)
if (self.drag_group is not None) and self.drag_moved:
drop = self.drag_group.get_best_drop(joined)
else:
drop = None
if drop is not self.last_drop:
if self.last_drop is not None:
self.last_drop.set_style_prefix("idle_", True)
if drop is not None:
drop.set_style_prefix("selected_idle_", True)
self.last_drop = drop
if map_event(ev, 'drag_deactivate'):
renpy.display.focus.set_grab(None)
if drop is not None:
drop.set_style_prefix("idle_", True)
for i in joined:
i.set_style_prefix("idle_", True)
self.set_style_prefix("hover_", True)
self.grab_x = None
self.grab_y = None
self.last_drop = None
if self.drag_moved:
# Call the drag callback.
drag = joined[0]
if drag.dragged is not None:
rv = run(drag.dragged, joined, drop)
if rv is not None:
return rv
# Call the drop callback.
if drop is not None and drop.dropped is not None:
rv = run(drop.dropped, drop, joined)
if rv is not None:
return rv
else:
# Call the clicked callback.
if self.clicked:
rv = run(self.clicked)
if rv is not None:
return rv
raise renpy.display.core.IgnoreEvent()
def get_placement(self):
if self.x is not None:
return self.x, self.y, 0, 0, 0, 0, True
else:
return super(Drag, self).get_placement()
def per_interact(self):
self.set_style_prefix("idle_", True)
super(Drag, self).per_interact()
class DragGroup(renpy.display.layout.MultiBox):
"""
:doc: drag_drop class
Represents a group of Drags. A Drag is limited to the boundary of
its DragGroup. Dropping only works between Drags that are in the
same DragGroup. Drags may only be raised when they are inside a
DragGroup.
A DragGroup is laid out like a :func:`Fixed`.
All positional parameters to the DragGroup constructor should be
Drags, that are added to the DragGroup.
"""
_list_type = renpy.python.RevertableList
def __init__(self, *children, **properties):
properties.setdefault("style", "fixed")
properties.setdefault("layout", "fixed")
replaces = properties.pop("replaces", None)
super(DragGroup, self).__init__(**properties)
if replaces is not None:
self.positions = renpy.python.RevertableDict(replaces.positions)
self.sensitive = replaces.sensitive
else:
self.positions = renpy.python.RevertableDict()
self.sensitive = True
for i in children:
self.add(i)
def add(self, child):
"""
:doc: drag_drop method
Adds `child`, which must be a Drag, to this DragGroup.
"""
if not isinstance(child, Drag):
raise Exception("Only drags can be added to a drag group.")
child.drag_group = self
super(DragGroup, self).add(child)
def remove(self, child):
"""
:doc: drag_drop method
Removes `child` from this DragGroup.
"""
if not isinstance(child, Drag):
raise Exception("Only drags can be removed from a drag group.")
child.x = None
super(DragGroup, self).remove(child)
def event(self, ev, x, y, st):
if not self.sensitive:
return None
return super(DragGroup, self).event(ev, x, y, st)
def raise_children(self, l):
"""
Raises the children in `l` to the top of this drag_group, using the
order given in l for those children.
"""
s = set(l)
offset_map = { }
children = [ ]
offsets = [ ]
for i, c in enumerate(self.children):
if i < len(self.offsets):
o = self.offsets[i]
else:
o = (0, 0)
if c not in s:
children.append(c)
offsets.append(o)
else:
offset_map[c] = o
for c in l:
if c in offset_map:
children.append(c)
offsets.append(offset_map[c])
self.children = self._list_type(children)
self.offsets = self._list_type(offsets)
def get_best_drop(self, joined):
"""
Returns the droppable that the members of joined overlap the most.
"""
max_overlap = 0
rv = 0
joined_set = set(joined)
for d in joined:
r1 = (d.x, d.y, d.w, d.h)
for c in self.children:
if c in joined_set:
continue
if not c.droppable:
continue
r2 = (c.x, c.y, c.w, c.h)
overlap = rect_overlap_area(r1, r2)
if overlap >= max_overlap:
rv = c
max_overlap = overlap
if max_overlap <= 0:
return None
else:
return rv
def get_children(self):
"""
Returns a list of Drags that are the children of
this DragGroup.
"""
return renpy.python.RevertableList(self.children)
def get_child_by_name(self, name):
"""
:doc: drag_drop method
Returns the first child of this DragGroup that has a drag_name
of name.
"""
for i in self.children:
if i.drag_name == name:
return i
return None
def rect_overlap_area(r1, r2):
"""
Returns the number of pixels by which rectangles r1 and r2 overlap.
"""
x1, y1, w1, h1 = r1
x2, y2, w2, h2 = r2
maxleft = max(x1, x2)
minright = min(x1 + w1, x2 + w2)
maxtop = max(y1, y2)
minbottom = min(y1 + h1, y2 + h2)
if minright < maxleft:
return 0
if minbottom < maxtop:
return 0
return (minright - maxleft) * (minbottom - maxtop)
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
+2 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -230,7 +230,7 @@ def mouse_handler(ev, x, y, default=False):
if ev.type not in (pygame.MOUSEMOTION, pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN):
return
new_focus = renpy.display.render.focus_at_point(x, y)
if new_focus is None:
+6 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -21,8 +21,11 @@
import pygame
import xml.etree.ElementTree as etree
try:
import xml.etree.ElementTree as etree
except:
pass
import _renpy_font
pygame.font = _renpy_font
+1373
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
cimport render
cdef class GLDraw:
cdef bint did_init
cdef object environ
cdef object rtt
cdef object window
cdef tuple virtual_size
cdef public tuple physical_size
cdef tuple virtual_box
cdef tuple physical_box
cdef object mouse_old_visible
cdef object mouse_info
cdef object texture_cache
cdef double last_redraw_time
cdef double redraw_period
cdef public dict info
cdef object old_fullscreen
cdef public object fullscreen_surface
cdef object display_info
cdef double upscale_factor
cdef tuple clip_cache
cdef bint fast_dissolve
cdef bint use_clipping_planes
cdef bint always_opaque
cdef tuple clip_rtt_box
cpdef set_clip(GLDraw self, tuple clip)
cpdef int draw_render_textures(
GLDraw self,
object what,
bint non_aligned)
cpdef int draw_transformed(
GLDraw self,
object what,
tuple clip,
double xo,
double yo,
double alpha,
render.Matrix2D reverse)
File diff suppressed because it is too large Load Diff
-588
View File
@@ -1,588 +0,0 @@
# Copyright 2004-2010 PyTom <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.
# This file contains the code required to set up (and change) OpenGL texture
# environments to implement various effects.
try:
import _renpy_tegl as gl; gl
import _renpy_pysdlgl as pysdlgl; pysdlgl
except ImportError:
gl = None
pysdlgl = None
import glshader
# Constants, that are used to store the last kind of blend a class was
# used for. (So we can avoid changing the GL state unnecessarily.)
NONE = 0
BLIT = 1
BLEND = 2
IMAGEBLEND = 3
class Environ(object):
def blit(self):
"""
Set up a normal blit environment. The texture to be blitted should
be TEXTURE0.
"""
raise Exception("Not implemented.")
def blend(self, fraction):
"""
Set up an environment that blends from TEXTURE0 to TEXTURE1.
`fraction` is the fraction of the blend complete.
"""
raise Exception("Not implemented.")
def imageblend(self, fraction, ramp):
"""
Setup an environment that does an imageblend from TEXTURE1 to TEXTURE2.
The controlling image is TEXTURE0.
`fraction` is the fraction of the blend complete.
`ramp` is the length of the ramp.
"""
raise Exception("Not implemented.")
class FixedFunctionEnviron(Environ):
"""
This is an OpenGL environment that uses the fixed-function pipeline.
It requires ARB_texture_env_combine and ARB_texture_env_crossbar to
work.
"""
def init(self):
# The last blend environ used.
self.last = NONE
# The last ramp length asked for.
self.last_ramp = -1
# The last ramplen actually used.
self.last_ramplen = -1
# A table that maps ramp lengths to the setup of the fixed-function
# units.
self.ramp_setup = [
# Fields are:
# ramp length,
# unit 1 scale,
# unit 2 function,
# unit 2 scale,
(256, 1.0, gl.REPLACE, 1.0),
(128, 1.0, gl.REPLACE, 2.0),
(64, 1.0, gl.REPLACE, 4.0),
(32, 1.0, gl.ADD, 4.0),
(16, 2.0, gl.ADD, 4.0),
(8, 4.0, gl.ADD, 4.0),
]
def deinit(self):
"""
Called before changing the GL context.
"""
return
def disable(self, unit):
"""
Disables the given texture combiner.
"""
gl.ActiveTextureARB(unit)
gl.Disable(gl.TEXTURE_2D)
def combine_mode(self, unit,
color_function=gl.MODULATE,
color_arg0=gl.TEXTURE,
color_arg1=gl.PREVIOUS_ARB,
color_arg2=gl.CONSTANT_ARB,
color_source0=gl.SRC_COLOR,
color_source1=gl.SRC_COLOR,
color_source2=gl.SRC_COLOR,
color_scale=1.0,
alpha_function=gl.MODULATE,
alpha_arg0=gl.TEXTURE,
alpha_arg1=gl.PREVIOUS_ARB,
alpha_arg2=gl.CONSTANT_ARB,
alpha_source0=gl.SRC_ALPHA,
alpha_source1=gl.SRC_ALPHA,
alpha_source2=gl.SRC_ALPHA,
alpha_scale=1.0,
enable=True):
gl.ActiveTextureARB(unit)
if enable:
gl.Enable(gl.TEXTURE_2D)
else:
gl.Disable(gl.TEXTURE_2D)
gl.TexEnvi(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.COMBINE_ARB)
gl.TexEnvi(gl.TEXTURE_ENV, gl.COMBINE_RGB_ARB, color_function)
gl.TexEnvi(gl.TEXTURE_ENV, gl.COMBINE_ALPHA_ARB, alpha_function)
gl.TexEnvi(gl.TEXTURE_ENV, gl.SOURCE0_RGB_ARB, color_arg0)
gl.TexEnvi(gl.TEXTURE_ENV, gl.OPERAND0_RGB_ARB, color_source0)
gl.TexEnvi(gl.TEXTURE_ENV, gl.SOURCE1_RGB_ARB, color_arg1)
gl.TexEnvi(gl.TEXTURE_ENV, gl.OPERAND1_RGB_ARB, color_source1)
gl.TexEnvi(gl.TEXTURE_ENV, gl.SOURCE2_RGB_ARB, color_arg2)
gl.TexEnvi(gl.TEXTURE_ENV, gl.OPERAND2_RGB_ARB, color_source2)
gl.TexEnvi(gl.TEXTURE_ENV, gl.SOURCE0_ALPHA_ARB, alpha_arg0)
gl.TexEnvi(gl.TEXTURE_ENV, gl.OPERAND0_ALPHA_ARB, alpha_source0)
gl.TexEnvi(gl.TEXTURE_ENV, gl.SOURCE1_ALPHA_ARB, alpha_arg1)
gl.TexEnvi(gl.TEXTURE_ENV, gl.OPERAND1_ALPHA_ARB, alpha_source1)
gl.TexEnvi(gl.TEXTURE_ENV, gl.SOURCE2_ALPHA_ARB, alpha_arg2)
gl.TexEnvi(gl.TEXTURE_ENV, gl.OPERAND2_ALPHA_ARB, alpha_source2)
gl.TexEnvf(gl.TEXTURE_ENV, gl.RGB_SCALE_ARB, color_scale)
gl.TexEnvf(gl.TEXTURE_ENV, gl.ALPHA_SCALE, alpha_scale)
def blit(self):
if self.last != BLIT:
# Set unit 0 to modulate.
self.combine_mode(gl.TEXTURE0_ARB,
color_function=gl.MODULATE,
alpha_function=gl.MODULATE)
# Disable units 1, 2 and 3.
self.disable(gl.TEXTURE1_ARB)
self.disable(gl.TEXTURE2_ARB)
self.disable(gl.TEXTURE3_ARB)
self.last = BLIT
def blend(self, fraction):
if self.last != BLEND:
# Get texture 0.
self.combine_mode(gl.TEXTURE0_ARB,
color_function=gl.REPLACE,
alpha_function=gl.REPLACE)
# Use interpolate to combine texture 0 with texture 1, as
# controlled by the constant of texture unit 1.
self.combine_mode(gl.TEXTURE1_ARB,
color_function=gl.INTERPOLATE_ARB,
color_arg0=gl.TEXTURE1_ARB,
color_arg1=gl.TEXTURE0_ARB,
alpha_function=gl.INTERPOLATE_ARB,
alpha_arg0=gl.TEXTURE1_ARB,
alpha_arg1=gl.TEXTURE0_ARB)
# Combine the interpolated result with the primary color, to
# allow for tinting and alpha adjustments.
self.combine_mode(gl.TEXTURE2_ARB,
color_function=gl.MODULATE,
color_arg0=gl.PREVIOUS_ARB,
color_arg1=gl.PRIMARY_COLOR_ARB,
alpha_function=gl.MODULATE,
alpha_arg0=gl.PREVIOUS_ARB,
alpha_arg1=gl.PRIMARY_COLOR_ARB,
enable=False)
# Disable texture unit 3.
self.disable(gl.TEXTURE3_ARB)
self.last = BLEND
gl.ActiveTextureARB(gl.TEXTURE1_ARB)
gl.TexEnvfv(gl.TEXTURE_ENV, gl.TEXTURE_ENV_COLOR, (fraction, fraction, fraction, fraction))
def imageblend(self, fraction, ramp):
if self.last != IMAGEBLEND or self.last_ramp != ramp:
# Figure out the details of the ramp.
for i in self.ramp_setup:
ramplen, t0scale, t1function, t1scale = i
# We round the ramplen down, unless we're below the
# smallest size, in which case we increase it.
if ramplen <= ramp:
break
# Unit 0 loads in the control image, and adds/subtracts an
# offset to/from it. (We'll set it up to subtract here,
# and change this later on as necessary.)
#
# It multiplies this result by up to 4.
self.combine_mode(gl.TEXTURE0_ARB,
color_function=gl.SUBTRACT_ARB,
alpha_function=gl.SUBTRACT_ARB,
color_arg1=gl.CONSTANT_ARB,
alpha_arg1=gl.CONSTANT_ARB,
color_scale=t0scale,
alpha_scale=t0scale)
# Unit 1 will multiply the result of stage 1 by up to 8.
#
# It also takes the first source texture, but we don't
# access it directly yet.
self.combine_mode(gl.TEXTURE1_ARB,
color_function=t1function,
alpha_function=t1function,
color_arg0=gl.PREVIOUS_ARB,
color_arg1=gl.PREVIOUS_ARB,
alpha_arg0=gl.PREVIOUS_ARB,
alpha_arg1=gl.PREVIOUS_ARB,
color_scale=t1scale,
alpha_scale=t1scale)
# Unit 2 uses the result of unit 1 to interpolate between the
# unit 1 and unit 2 textures.
self.combine_mode(gl.TEXTURE2_ARB,
color_function=gl.INTERPOLATE_ARB,
alpha_function=gl.INTERPOLATE_ARB,
color_arg0=gl.TEXTURE2_ARB,
color_arg1=gl.TEXTURE1_ARB,
color_arg2=gl.PREVIOUS_ARB,
alpha_arg0=gl.TEXTURE2_ARB,
alpha_arg1=gl.TEXTURE1_ARB,
alpha_arg2=gl.PREVIOUS_ARB)
# Finally, Unit 3 modulates the result of unit 2 with the color.
self.combine_mode(gl.TEXTURE3_ARB,
color_function=gl.MODULATE,
color_arg0=gl.PREVIOUS_ARB,
color_arg1=gl.PRIMARY_COLOR_ARB,
alpha_function=gl.MODULATE,
alpha_arg0=gl.PREVIOUS_ARB,
alpha_arg1=gl.PRIMARY_COLOR_ARB,
enable=False)
self.last = IMAGEBLEND
self.last_ramp = ramp
self.last_ramplen = ramplen
# Compute the offset to apply to the alpha.
start = -1.0
end = self.last_ramplen / 256.0
offset = start + ( end - start) * fraction
# Decide if we're adding or subtracting.
if offset < 0:
function = gl.SUBTRACT_ARB
offset = -offset
else:
function = gl.ADD
# Setup unit 0 as appropriate.
gl.ActiveTextureARB(gl.TEXTURE0_ARB)
gl.TexEnvi(gl.TEXTURE_ENV, gl.COMBINE_RGB_ARB, function)
gl.TexEnvi(gl.TEXTURE_ENV, gl.COMBINE_ALPHA_ARB, function)
gl.TexEnvfv(gl.TEXTURE_ENV, gl.TEXTURE_ENV_COLOR, (offset, offset, offset, offset))
class ShaderEnviron(object):
"""
This is an environment that uses shaders.
"""
def init(self):
self.blit_program = glshader.blit_program()
self.blit_tex0_uniform = gl.GetUniformLocationARB(
self.blit_program,
"tex0")
self.blend_program = glshader.blend_program()
self.blend_done_uniform = gl.GetUniformLocationARB(
self.blend_program,
"done")
self.blend_tex0_uniform = gl.GetUniformLocationARB(
self.blend_program,
"tex0")
self.blend_tex1_uniform = gl.GetUniformLocationARB(
self.blend_program,
"tex1")
self.imageblend_program = glshader.imageblend_program()
self.imageblend_tex0_uniform = gl.GetUniformLocationARB(
self.imageblend_program,
"tex0")
self.imageblend_tex1_uniform = gl.GetUniformLocationARB(
self.imageblend_program,
"tex1")
self.imageblend_tex2_uniform = gl.GetUniformLocationARB(
self.imageblend_program,
"tex2")
self.imageblend_offset_uniform = gl.GetUniformLocationARB(
self.imageblend_program,
"offset")
self.imageblend_multiplier_uniform = gl.GetUniformLocationARB(
self.imageblend_program,
"multiplier")
self.last = NONE
def deinit(self):
"""
Called before changing the GL context.
"""
gl.DeleteObjectARB(self.blit_program)
gl.DeleteObjectARB(self.blend_program)
gl.DeleteObjectARB(self.imageblend_program)
return
def blit(self):
if self.last != BLIT:
gl.UseProgramObjectARB(self.blit_program)
gl.Uniform1iARB(self.blit_tex0_uniform, 0)
self.last = BLIT
def blend(self, fraction):
if self.last != BLEND:
gl.UseProgramObjectARB(self.blend_program)
gl.Uniform1iARB(self.blend_tex0_uniform, 0)
gl.Uniform1iARB(self.blend_tex1_uniform, 1)
self.last = BLEND
gl.Uniform1fARB(self.blend_done_uniform, fraction)
def imageblend(self, fraction, ramp):
if self.last != IMAGEBLEND:
gl.UseProgramObjectARB(self.imageblend_program)
gl.Uniform1iARB(self.imageblend_tex0_uniform, 0)
gl.Uniform1iARB(self.imageblend_tex1_uniform, 1)
gl.Uniform1iARB(self.imageblend_tex2_uniform, 2)
self.last = IMAGEBLEND
# Prevent a DBZ if the user gives us a 0 ramp.
if ramp < 1:
ramp = 1
# Compute the offset to apply to the alpha.
start = -1.0
end = ramp / 256.0
offset = start + ( end - start) * fraction
# Setup the multiplier and the offset.
gl.Uniform1fARB(self.imageblend_multiplier_uniform, 256.0 / ramp)
gl.Uniform1fARB(self.imageblend_offset_uniform, offset)
class Rtt(object):
"""
Subclasses of this class handle rendering to a texture.
"""
def begin(self):
"""
This function should be called when a Render-to-texture
session begins. It's responsible for setting the GPU to
RTT mode.
"""
raise Exception("Not implemented.")
def render(self, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
raise Exception("Not implemented.")
def end(self):
"""
This is called when a Render-to-texture session ends.
"""
raise Exception("Not implemented.")
class CopyRtt(object):
"""
This class uses texture copying to implement Render-to-texture.
"""
def init(self):
pass
def deinit(self):
"""
Called before changing the GL context.
"""
return
def begin(self):
"""
This function should be called when a Render-to-texture
session begins. It's responsible for setting the GPU to
RTT mode.
"""
def render(self, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
gl.Viewport(0, 0, w, h)
gl.MatrixMode(gl.PROJECTION)
gl.LoadIdentity()
gl.Ortho(x, x + w, y, y + h, -1, 1)
gl.MatrixMode(gl.MODELVIEW)
draw_func()
gl.BindTexture(gl.TEXTURE_2D, texture)
gl.CopyTexSubImage2D(
gl.TEXTURE_2D,
0,
0,
0,
0,
0,
w,
h)
def end(self):
"""
This is called when a Render-to-texture session ends.
"""
class FramebufferRtt(object):
"""
This class uses the framebuffer object to do RTT.
"""
def init(self):
# This maps a texture to the framebuffer object that
# can write to that texture.
self.texture_to_fbo = { }
def deinit(self):
"""
Called before changing the GL context.
"""
for i in self.texture_to_fbo.itervalues():
gl.DeleteFramebuffersEXT(1, [ i ])
self.texture_to_fbo.clear()
def get_fbo(self, texture):
if texture in self.texture_to_fbo:
return self.texture_to_fbo[texture]
fbos = [ 0 ]
gl.GenFramebuffersEXT(1, fbos)
fbo = fbos[0]
gl.BindFramebufferEXT(gl.FRAMEBUFFER_EXT, fbo)
gl.FramebufferTexture2DEXT(
gl.FRAMEBUFFER_EXT,
gl.COLOR_ATTACHMENT0_EXT,
gl.TEXTURE_2D,
texture,
0)
self.texture_to_fbo[texture] = fbo
return fbo
def begin(self):
"""
This function should be called when a Render-to-texture
session begins. It's responsible for setting the GPU to
RTT mode.
"""
def render(self, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
fbo = self.get_fbo(texture)
gl.BindFramebufferEXT(gl.FRAMEBUFFER_EXT, fbo)
gl.Viewport(0, 0, w, h)
gl.MatrixMode(gl.PROJECTION)
gl.LoadIdentity()
gl.Ortho(x, x + w, y, y + h, -1, 1)
gl.MatrixMode(gl.MODELVIEW)
draw_func()
def end(self):
"""
This is called when a Render-to-texture session ends.
"""
gl.BindFramebufferEXT(gl.FRAMEBUFFER_EXT, 0)
+94
View File
@@ -0,0 +1,94 @@
#cython: profile=False
# Copyright 2004-2011 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.
# This file contains the code required to set up (and change) OpenGL texture
# environments to implement various effects.
from gl cimport *
# Constants, that are used to store the last kind of blend a class was
# used for. (So we can avoid changing the GL state unnecessarily.)
NONE = 0
BLIT = 1
BLEND = 2
IMAGEBLEND = 3
class Environ(object):
def blit(self):
"""
Set up a normal blit environment. The texture to be blitted should
be TEXTURE0.
"""
raise Exception("Not implemented.")
def blend(self, fraction):
"""
Set up an environment that blends from TEXTURE0 to TEXTURE1.
`fraction` is the fraction of the blend complete.
"""
raise Exception("Not implemented.")
def imageblend(self, fraction, ramp):
"""
Setup an environment that does an imageblend from TEXTURE1 to TEXTURE2.
The controlling image is TEXTURE0.
`fraction` is the fraction of the blend complete.
`ramp` is the length of the ramp.
"""
raise Exception("Not implemented.")
class Rtt(object):
"""
Subclasses of this class handle rendering to a texture.
"""
def init(self):
return
def deinit(self):
return
def render(self, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
raise Exception("Not implemented.")
def get_size_limit(self, dimension):
"""
Get the maximum size of a texture.
"""
raise Exception("Not implemented.")
+272
View File
@@ -0,0 +1,272 @@
#cython: profile=False
# Copyright 2004-2011 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.
from gl cimport *
from renpy.display.glenviron import *
class FixedFunctionEnviron(Environ):
"""
This is an OpenGL environment that uses the fixed-function pipeline.
It requires ARB_texture_env_combine and ARB_texture_env_crossbar to
work.
"""
def init(self):
# The last blend environ used.
self.last = NONE
# The last ramp length asked for.
self.last_ramp = -1
# The last ramplen actually used.
self.last_ramplen = -1
# A table that maps ramp lengths to the setup of the fixed-function
# units.
self.ramp_setup = [
# Fields are:
# ramp length,
# unit 1 scale,
# unit 2 function,
# unit 2 scale,
(256, 1.0, GL_REPLACE, 1.0),
(128, 1.0, GL_REPLACE, 2.0),
(64, 1.0, GL_REPLACE, 4.0),
(32, 1.0, GL_ADD, 4.0),
(16, 2.0, GL_ADD, 4.0),
(8, 4.0, GL_ADD, 4.0),
]
def deinit(self):
"""
Called before changing the GL context.
"""
return
def disable(self, unit):
"""
Disables the given texture combiner.
"""
glActiveTextureARB(unit)
glDisable(GL_TEXTURE_2D)
def combine_mode(self, unit,
color_function=GL_MODULATE,
color_arg0=GL_TEXTURE,
color_arg1=GL_PREVIOUS_ARB,
color_arg2=GL_CONSTANT_ARB,
color_source0=GL_SRC_COLOR,
color_source1=GL_SRC_COLOR,
color_source2=GL_SRC_COLOR,
color_scale=1.0,
alpha_function=GL_MODULATE,
alpha_arg0=GL_TEXTURE,
alpha_arg1=GL_PREVIOUS_ARB,
alpha_arg2=GL_CONSTANT_ARB,
alpha_source0=GL_SRC_ALPHA,
alpha_source1=GL_SRC_ALPHA,
alpha_source2=GL_SRC_ALPHA,
alpha_scale=1.0,
enable=True):
glActiveTextureARB(unit)
if enable:
glEnable(GL_TEXTURE_2D)
else:
glDisable(GL_TEXTURE_2D)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, color_function)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, alpha_function)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, color_arg0)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, color_source0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, color_arg1)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, color_source1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, color_arg2)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, color_source2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, alpha_arg0)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, alpha_source0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, alpha_arg1)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, alpha_source1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, alpha_arg2)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, alpha_source2)
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, color_scale)
glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, alpha_scale)
def blit(self):
if self.last != BLIT:
# Set unit 0 to modulate.
self.combine_mode(GL_TEXTURE0_ARB,
color_function=GL_MODULATE,
alpha_function=GL_MODULATE)
# Disable units 1, 2 and 3.
self.disable(GL_TEXTURE1_ARB)
self.disable(GL_TEXTURE2_ARB)
self.disable(GL_TEXTURE3_ARB)
self.last = BLIT
def blend(self, fraction):
if self.last != BLEND:
# Get texture 0.
self.combine_mode(GL_TEXTURE0_ARB,
color_function=GL_REPLACE,
alpha_function=GL_REPLACE)
# Use interpolate to combine texture 0 with texture 1, as
# controlled by the constant of texture unit 1.
self.combine_mode(GL_TEXTURE1_ARB,
color_function=GL_INTERPOLATE_ARB,
color_arg0=GL_TEXTURE1_ARB,
color_arg1=GL_TEXTURE0_ARB,
alpha_function=GL_INTERPOLATE_ARB,
alpha_arg0=GL_TEXTURE1_ARB,
alpha_arg1=GL_TEXTURE0_ARB)
# Combine the interpolated result with the primary color, to
# allow for tinting and alpha adjustments.
self.combine_mode(GL_TEXTURE2_ARB,
color_function=GL_MODULATE,
color_arg0=GL_PREVIOUS_ARB,
color_arg1=GL_PRIMARY_COLOR_ARB,
alpha_function=GL_MODULATE,
alpha_arg0=GL_PREVIOUS_ARB,
alpha_arg1=GL_PRIMARY_COLOR_ARB,
enable=False)
# Disable texture unit 3.
self.disable(GL_TEXTURE3_ARB)
self.last = BLEND
cdef float *fractions = [ fraction, fraction, fraction, fraction ]
glActiveTextureARB(GL_TEXTURE1_ARB)
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fractions)
def imageblend(self, fraction, ramp):
if self.last != IMAGEBLEND or self.last_ramp != ramp:
# Figure out the details of the ramp.
for i in self.ramp_setup:
ramplen, t0scale, t1function, t1scale = i
# We round the ramplen down, unless we're below the
# smallest size, in which case we increase it.
if ramplen <= ramp:
break
# Unit 0 loads in the control image, and adds/subtracts an
# offset to/from it. (We'll set it up to subtract here,
# and change this later on as necessary.)
#
# It multiplies this result by up to 4.
self.combine_mode(GL_TEXTURE0_ARB,
color_function=GL_SUBTRACT_ARB,
alpha_function=GL_SUBTRACT_ARB,
color_arg1=GL_CONSTANT_ARB,
alpha_arg1=GL_CONSTANT_ARB,
color_scale=t0scale,
alpha_scale=t0scale)
# Unit 1 will multiply the result of stage 1 by up to 8.
#
# It also takes the first source texture, but we don't
# access it directly yet.
self.combine_mode(GL_TEXTURE1_ARB,
color_function=t1function,
alpha_function=t1function,
color_arg0=GL_PREVIOUS_ARB,
color_arg1=GL_PREVIOUS_ARB,
alpha_arg0=GL_PREVIOUS_ARB,
alpha_arg1=GL_PREVIOUS_ARB,
color_scale=t1scale,
alpha_scale=t1scale)
# Unit 2 uses the result of unit 1 to interpolate between the
# unit 1 and unit 2 textures.
self.combine_mode(GL_TEXTURE2_ARB,
color_function=GL_INTERPOLATE_ARB,
alpha_function=GL_INTERPOLATE_ARB,
color_arg0=GL_TEXTURE2_ARB,
color_arg1=GL_TEXTURE1_ARB,
color_arg2=GL_PREVIOUS_ARB,
alpha_arg0=GL_TEXTURE2_ARB,
alpha_arg1=GL_TEXTURE1_ARB,
alpha_arg2=GL_PREVIOUS_ARB)
# Finally, Unit 3 modulates the result of unit 2 with the color.
self.combine_mode(GL_TEXTURE3_ARB,
color_function=GL_MODULATE,
color_arg0=GL_PREVIOUS_ARB,
color_arg1=GL_PRIMARY_COLOR_ARB,
alpha_function=GL_MODULATE,
alpha_arg0=GL_PREVIOUS_ARB,
alpha_arg1=GL_PRIMARY_COLOR_ARB,
enable=False)
self.last = IMAGEBLEND
self.last_ramp = ramp
self.last_ramplen = ramplen
# Compute the offset to apply to the alpha.
start = -1.0
end = self.last_ramplen / 256.0
offset = start + ( end - start) * fraction
# Decide if we're adding or subtracting.
if offset < 0:
function = GL_SUBTRACT_ARB
offset = -offset
else:
function = GL_ADD
# Setup unit 0 as appropriate.
glActiveTextureARB(GL_TEXTURE0_ARB)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, function)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, function)
cdef float *offsets = [ offset, offset, offset, offset ]
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, offsets)
+154
View File
@@ -0,0 +1,154 @@
#cython: profile=False
# Copyright 2004-2011 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.
from gl cimport *
from renpy.display.glenviron import *
import renpy
class LimitedEnviron(Environ):
"""
This is an OpenGL environment that uses a limited fixed-function
pipeline. This will work with any GL or GLES system that has at
least 2 texture units.
(It's missing some functionality, like the ability to change the
alpha of an imagedissolve or dissolve, and the ability to
imagedissolve.)
"""
def init(self):
# The last blend environ used.
self.last = NONE
# Disable imagedissolve.
renpy.display.less_imagedissolve = True
def deinit(self):
"""
Called before changing the GL context.
"""
return
def disable(self, unit):
"""
Disables the given texture combiner.
"""
glActiveTexture(unit)
glDisable(GL_TEXTURE_2D)
def combine_mode(self, unit,
color_function=GL_MODULATE,
color_arg0=GL_TEXTURE,
color_arg1=GL_PREVIOUS,
color_arg2=GL_CONSTANT,
color_source0=GL_SRC_COLOR,
color_source1=GL_SRC_COLOR,
color_source2=GL_SRC_COLOR,
color_scale=1.0,
alpha_function=GL_MODULATE,
alpha_arg0=GL_TEXTURE,
alpha_arg1=GL_PREVIOUS,
alpha_arg2=GL_CONSTANT,
alpha_source0=GL_SRC_ALPHA,
alpha_source1=GL_SRC_ALPHA,
alpha_source2=GL_SRC_ALPHA,
alpha_scale=1.0,
enable=True):
glActiveTexture(unit)
if enable:
glEnable(GL_TEXTURE_2D)
else:
glDisable(GL_TEXTURE_2D)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, color_function)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, alpha_function)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, color_arg0)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, color_source0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, color_arg1)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, color_source1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, color_arg2)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, color_source2)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, alpha_arg0)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, alpha_source0)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, alpha_arg1)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, alpha_source1)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, alpha_arg2)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, alpha_source2)
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, color_scale)
glTexEnvf(GL_TEXTURE_ENV, GL_ALPHA_SCALE, alpha_scale)
def blit(self):
if self.last != BLIT:
# Set unit 0 to modulate.
self.combine_mode(GL_TEXTURE0,
color_function=GL_MODULATE,
alpha_function=GL_MODULATE)
# Disable unit 1.
self.disable(GL_TEXTURE1)
self.last = BLIT
def blend(self, fraction):
if self.last != BLEND:
# Get texture 0.
self.combine_mode(GL_TEXTURE0,
color_function=GL_REPLACE,
alpha_function=GL_REPLACE)
# Use interpolate to combine texture 0 with texture 1, as
# controlled by the constant of texture unit 1.
self.combine_mode(GL_TEXTURE1,
color_function=GL_INTERPOLATE,
color_arg0=GL_TEXTURE1,
color_arg1=GL_TEXTURE0,
alpha_function=GL_INTERPOLATE,
alpha_arg0=GL_TEXTURE1,
alpha_arg1=GL_TEXTURE0)
self.last = BLEND
cdef float *fractions = [ fraction, fraction, fraction, fraction ]
glActiveTexture(GL_TEXTURE1)
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fractions)
def imageblend(self, fraction, ramp):
# Imageblend doesn't work on GLES.
pass
+125
View File
@@ -0,0 +1,125 @@
#cython: profile=False
# Copyright 2004-2011 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.
from gl cimport *
from renpy.display.glenviron import *
import renpy.display.glshader as glshader
class ShaderEnviron(Environ):
"""
This is an environment that uses shaders.
"""
def init(self):
self.blit_program = glshader.blit_program()
self.blit_tex0_uniform = glGetUniformLocationARB(
self.blit_program,
"tex0")
self.blend_program = glshader.blend_program()
self.blend_done_uniform = glGetUniformLocationARB(
self.blend_program,
"done")
self.blend_tex0_uniform = glGetUniformLocationARB(
self.blend_program,
"tex0")
self.blend_tex1_uniform = glGetUniformLocationARB(
self.blend_program,
"tex1")
self.imageblend_program = glshader.imageblend_program()
self.imageblend_tex0_uniform = glGetUniformLocationARB(
self.imageblend_program,
"tex0")
self.imageblend_tex1_uniform = glGetUniformLocationARB(
self.imageblend_program,
"tex1")
self.imageblend_tex2_uniform = glGetUniformLocationARB(
self.imageblend_program,
"tex2")
self.imageblend_offset_uniform = glGetUniformLocationARB(
self.imageblend_program,
"offset")
self.imageblend_multiplier_uniform = glGetUniformLocationARB(
self.imageblend_program,
"multiplier")
self.last = NONE
def deinit(self):
"""
Called before changing the GL context.
"""
glDeleteObjectARB(self.blit_program)
glDeleteObjectARB(self.blend_program)
glDeleteObjectARB(self.imageblend_program)
return
def blit(self):
if self.last != BLIT:
glUseProgramObjectARB(self.blit_program)
glUniform1iARB(self.blit_tex0_uniform, 0)
self.last = BLIT
def blend(self, fraction):
if self.last != BLEND:
glUseProgramObjectARB(self.blend_program)
glUniform1iARB(self.blend_tex0_uniform, 0)
glUniform1iARB(self.blend_tex1_uniform, 1)
self.last = BLEND
glUniform1fARB(self.blend_done_uniform, fraction)
def imageblend(self, fraction, ramp):
if self.last != IMAGEBLEND:
glUseProgramObjectARB(self.imageblend_program)
glUniform1iARB(self.imageblend_tex0_uniform, 0)
glUniform1iARB(self.imageblend_tex1_uniform, 1)
glUniform1iARB(self.imageblend_tex2_uniform, 2)
self.last = IMAGEBLEND
# Prevent a DBZ if the user gives us a 0 ramp.
if ramp < 1:
ramp = 1
# Compute the offset to apply to the alpha.
start = -1.0
end = ramp / 256.0
offset = start + ( end - start) * fraction
# Setup the multiplier and the offset.
glUniform1fARB(self.imageblend_multiplier_uniform, 256.0 / ramp)
glUniform1fARB(self.imageblend_offset_uniform, offset)
+73
View File
@@ -0,0 +1,73 @@
#cython: profile=False
# Copyright 2004-2011 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.
from gl cimport *
from renpy.display.glenviron import *
class CopyRtt(Rtt):
"""
This class uses texture copying to implement Render-to-texture.
"""
def init(self):
return
def deinit(self):
return
def render(self, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(x, x + w, y, y + h, -1, 1)
glMatrixMode(GL_MODELVIEW)
draw_func(x, y, w, h)
glBindTexture(GL_TEXTURE_2D, texture)
glCopyTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
0,
0,
w,
h)
def end(self):
"""
This is called when a Render-to-texture session ends.
"""
def get_size_limit(self, dimension):
return dimension
+89
View File
@@ -0,0 +1,89 @@
#cython: profile=False
# Copyright 2004-2011 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.
from gl cimport *
from renpy.display.glenviron import *
import renpy
# The framebuffer object we use.
cdef GLuint fbo
class FboRtt(Rtt):
"""
This class uses texture copying to implement Render-to-texture.
"""
def init(self):
glGenFramebuffersEXT(1, &fbo)
cdef int i
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &i)
self.size_limit = i
renpy.log.info("FBO Maximum Texture Size: %d", i)
def deinit(self):
"""
Called before changing the GL context.
"""
glDeleteFramebuffersEXT(1, &fbo)
def begin(self):
"""
This function should be called when a Render-to-texture
session begins. It's responsible for setting the GPU to
RTT mode.
"""
def render(self, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)
glFramebufferTexture2DEXT(
GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D,
texture,
0)
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(x, x + w, y, y + h, -1, 1)
glMatrixMode(GL_MODELVIEW)
draw_func(x, y, w, h)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)
def get_size_limit(self, dimension):
return self.size_limit
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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
@@ -22,13 +22,7 @@
# This file contains GLSL shader code, and code to load shaders.
import array
try:
import _renpy_tegl as gl; gl
import _renpy_pysdlgl as pysdlgl; pysdlgl
except ImportError:
gl = None
pysdlgl = None
from gl cimport *
VERTEX_SHADER = """
void main() {
@@ -91,34 +85,36 @@ def check_status(handle, type):
Checks the status of a shader or program. If it fails, then an
exception is raised.
"""
cdef GLint status = 0
cdef GLint log_length = 0
status = [ 0 ]
gl.GetObjectParameterivARB(handle, type, status)
glGetObjectParameterivARB(handle, type, &status)
if status[0] == 0:
log_length_list = [ 0 ]
gl.GetObjectParameterivARB(handle, gl.OBJECT_INFO_LOG_LENGTH_ARB, log_length_list)
log_length = log_length_list[0]
log = array.array('c', ' ' * log_length)
if status == 1: # 0 for problems.
return
gl.GetInfoLogARB(handle, log_length, [ 0 ], log)
glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_length)
log = ' ' * log_length
glGetInfoLogARB(handle, log_length, &log_length, <char *> log)
raise Exception("Shader error: %s" % log)
raise Exception("Shader error: %s" % log.tostring())
def compile_shader(kind, source):
"""
Allocates and compiles a shader.
"""
cdef char *sourceptr = <char *> source
cdef int lensource = len(source)
handle = gl.CreateShaderObjectARB(kind)
gl.ShaderSourceARB(handle, 1, [ source ], [ len(source) ])
gl.CompileShaderARB(handle)
handle = glCreateShaderObjectARB(kind)
glShaderSourceARB(handle, 1, <GLcharARB **> &sourceptr, &lensource)
glCompileShaderARB(handle)
check_status(handle, gl.OBJECT_COMPILE_STATUS_ARB)
check_status(handle, GL_OBJECT_COMPILE_STATUS_ARB)
return handle
@@ -127,24 +123,23 @@ def compile_program(vertex, fragment):
"""
Compiles a pair of shaders into a program.
"""
vertex_shader = compile_shader(gl.VERTEX_SHADER_ARB, vertex)
fragment_shader = compile_shader(gl.FRAGMENT_SHADER_ARB, fragment)
vertex_shader = compile_shader(GL_VERTEX_SHADER_ARB, vertex)
fragment_shader = compile_shader(GL_FRAGMENT_SHADER_ARB, fragment)
program = gl.CreateProgramObjectARB()
program = glCreateProgramObjectARB()
gl.AttachObjectARB(program, vertex_shader)
gl.AttachObjectARB(program, fragment_shader)
glAttachObjectARB(program, vertex_shader)
glAttachObjectARB(program, fragment_shader)
gl.LinkProgramARB(program)
glLinkProgramARB(program)
check_status(program, gl.OBJECT_LINK_STATUS_ARB)
check_status(program, GL_OBJECT_LINK_STATUS_ARB)
gl.UseProgramObjectARB(program)
glUseProgramObjectARB(program)
gl.DeleteObjectARB(vertex_shader)
gl.DeleteObjectARB(fragment_shader)
glDeleteObjectARB(vertex_shader)
glDeleteObjectARB(fragment_shader)
return program
@@ -159,10 +154,3 @@ def blend_program():
def imageblend_program():
return compile_program(VERTEX_SHADER, IMAGEBLEND_SHADER)
+67
View File
@@ -0,0 +1,67 @@
cimport renpy.display.render as render
cdef class TextureCore:
cdef public int width
cdef public int height
cdef public int generation
cdef public unsigned int number
cdef int format
cdef double xmul
cdef double xadd
cdef double ymul
cdef double yadd
cdef object premult
cdef tuple premult_size
cdef int premult_left
cdef int premult_right
cdef int premult_top
cdef int premult_bottom
cdef bint nearest
cdef public list free_list
cdef void make_ready(TextureCore)
cdef void make_nearest(TextureCore)
cdef void make_linear(TextureCore)
cpdef int allocate(TextureCore)
cdef class TextureGrid:
cdef public int width
cdef public int height
cdef list rows
cdef list columns
cdef list tiles # list of lists.
cdef public TextureGrid half_cache
cdef void make_ready(self, bint nearest)
cpdef blit(
TextureGrid tg,
double sx,
double sy,
render.Matrix2D transform,
double alpha,
environ,
bint nearest)
cpdef blend(
TextureGrid tg0,
TextureGrid tg1,
double sx,
double sy,
render.Matrix2D transform,
double alpha,
double fraction,
environ)
cpdef imageblend(
TextureGrid tg0,
TextureGrid tg1,
TextureGrid tg2,
double sx,
double sy,
render.Matrix2D transform,
double alpha,
double fraction,
int ramp,
environ)
@@ -1,4 +1,5 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
#cython: profile=False
# Copyright 2004-2011 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
@@ -19,45 +20,41 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from gl cimport *
from pygame cimport *
import collections
import pygame; pygame # other modules might depend on pygame.
try:
import _renpy_tegl as gl; gl
import _renpy_pysdlgl as pysdlgl; pysdlgl
except ImportError:
gl = None
pysdlgl = None
import renpy
# The maximum size of a texture.
MAX_SIZE = 512
# Possible sizes for a texture.
SIZES = [ 512, 256, 128, 64 ]
def check_error():
"""
This checks for an opengl error, and throws an exception if it occurs.
"""
err = gl.GetError()
if err:
raise Exception("GL Error: 0x%x" % err)
SIZES = [ 1024, 512, 256, 128, 64 ]
# A list of texture number allocated.
texture_numbers = [ ]
cdef int rtt_format = GL_RGBA
cdef int rtt_internalformat = GL_RGBA
def use_gles():
"""
Called to trigger gles mode.
"""
global rtt_format
global rtt_internalformat
class Texture(object):
rtt_format = GL_RGB
rtt_internalformat = GL_RGB
cdef class TextureCore:
"""
This object stores information about an OpenGL texture.
"""
def __init__(self, width, height):
def __init__(TextureCore self, int width, int height):
# The width and height of this texture.
self.width = width
@@ -66,10 +63,10 @@ class Texture(object):
# The number of the OpenGL texture this texture object
# represents.
self.generation = 0
self.number = None
self.number = -1
# True if the texture has been created inside the GPU.
self.created = False
# The format of this texture in the GPU (or 0 if not known).
self.format = 0
# These are used to map an index into texture coordinates.
self.xmul = 0
@@ -83,10 +80,10 @@ class Texture(object):
self.premult = None
self.premult_size = None
self.premult_left = None
self.premult_right = None
self.premult_top = None
self.premult_bottom = None
self.premult_left = 0
self.premult_right = 0
self.premult_top = 0
self.premult_bottom = 0
# True if we're in NEAREST mode. False if we're in LINEAR mode.
self.nearest = False
@@ -98,14 +95,16 @@ class Texture(object):
def __del__(self):
cdef unsigned int num
# Release the surface.
self.premult = None
self.premult_size = None
self.premult_left = None
self.premult_right = None
self.premult_top = None
self.premult_bottom = None
self.premult_left = 0
self.premult_right = 0
self.premult_top = 0
self.premult_bottom = 0
# The test needs to be here so we don't try to append during
# interpreter shutdown.
if self.free_list is not None:
@@ -127,14 +126,14 @@ class Texture(object):
# occurs when the texture is first needed. This ensures that the
# texture loading only occurs in the GL thread.
self.premult = pysdlgl.premultiply(
self.premult = premultiply(
surf, x, y, w, h,
border_left, border_top, border_right, border_bottom)
self.premult_size = (w, h)
def make_nearest(self):
cdef void make_nearest(TextureCore self):
"""
Causes this texture to be rendered in nearest-neighbor mode.
"""
@@ -142,14 +141,14 @@ class Texture(object):
if self.nearest:
return
gl.BindTexture(gl.TEXTURE_2D, self.number)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
glBindTexture(GL_TEXTURE_2D, self.number)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
self.nearest = True
def make_linear(self):
cdef void make_linear(TextureCore self):
"""
Causes this texture to be rendered in linear interpolation mode.
"""
@@ -157,14 +156,14 @@ class Texture(object):
if not self.nearest:
return
gl.BindTexture(gl.TEXTURE_2D, self.number)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
glBindTexture(GL_TEXTURE_2D, self.number)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
self.nearest = False
def make_ready(self):
cdef void make_ready(TextureCore self):
"""
Makes the texture ready for use.
"""
@@ -175,9 +174,9 @@ class Texture(object):
w, h = self.premult_size
gl.BindTexture(gl.TEXTURE_2D, self.number)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
glBindTexture(GL_TEXTURE_2D, self.number)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
self.nearest = False
@@ -185,27 +184,29 @@ class Texture(object):
# smaller than it, load in the empty texture.
if w < self.width or h < self.height:
if not self.created:
pysdlgl.load_premultiplied(
if self.format != GL_RGBA:
load_premultiplied(
None,
self.width,
self.height,
0,
gl.BGRA)
GL_RGBA,
GL_RGBA)
self.created = True
self.format = GL_RGBA
# Otherwise, either load or replace the texture.
pysdlgl.load_premultiplied(
load_premultiplied(
self.premult,
w,
h,
self.created,
gl.BGRA)
(self.format == GL_RGBA),
GL_RGBA,
GL_RGBA)
# Needs to be here twice, since we may not go through the w < SIDE
# h < SIDE thing all the time.
self.created = True
self.format = GL_RGBA
# Finally, load in the default math.
self.xadd = self.yadd = 0
@@ -221,22 +222,23 @@ class Texture(object):
self.allocate()
if not self.created:
if self.format != rtt_format:
gl.BindTexture(gl.TEXTURE_2D, self.number)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
glBindTexture(GL_TEXTURE_2D, self.number)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
self.nearest = False
pysdlgl.load_premultiplied(
load_premultiplied(
None,
self.width,
self.height,
0,
gl.BGRA)
rtt_format,
rtt_internalformat)
self.created = True
self.format = rtt_format
rtt.render(self.number, x, y, self.width, self.height, draw_func)
@@ -244,24 +246,35 @@ class Texture(object):
self.yadd = 0
self.xmul = 1.0 / self.width
self.ymul = 1.0 / self.height
def allocate(self):
cpdef int allocate(self):
"""
This allocates a texture number, if necessary.
"""
if self.number is not None:
return
cdef unsigned int texnums[1]
texnums = [ 0 ]
gl.GenTextures(1, texnums)
if self.number != -1:
return 0
glGenTextures(1, texnums)
self.number = texnums[0]
self.created = False
self.format = 0
texture_numbers.append(texnums[0])
return 0
class Texture(TextureCore):
"""
We need to be a real python class, not a C extension, to ensure that
the __del__ method is called.
"""
pass
# This is a map from texture sizes to a list of free textures of that
# size.
@@ -280,7 +293,6 @@ def alloc_texture(width, height):
"""
global total_texture_size
l = free_textures[width, height]
@@ -297,9 +309,13 @@ def alloc_texture(width, height):
def dealloc_textures():
global texture_numbers
cdef GLuint texnums[1]
for t in texture_numbers:
gl.DeleteTextures(1, [ t ])
texnums[0] = t
glDeleteTextures(1, texnums)
texture_numbers = [ ]
free_textures.clear()
@@ -362,7 +378,7 @@ def compute_subrow(row, offset, width):
return outrow, tiles
class TextureGrid(object):
cdef class TextureGrid(object):
"""
This represents one or more textures that cover a rectangular
area.
@@ -400,12 +416,14 @@ class TextureGrid(object):
return self.width, self.height
def subsurface(self, (x, y, w, h)):
def subsurface(self, rect):
"""
This produces a texture grid containing a rectangle "cut out"
of this texture grid.
"""
(x, y, w, h) = rect
rv = TextureGrid(w, h)
rv.rows, rowtiles = compute_subrow(self.rows, y, h)
@@ -421,11 +439,14 @@ class TextureGrid(object):
return rv
def make_ready(self, nearest=False):
cdef void make_ready(self, bint nearest):
"""
Makes ready all the tile-textures in this texture grid.
"""
cdef list row
cdef TextureCore t
for row in self.tiles:
for t in row:
t.make_ready()
@@ -440,7 +461,7 @@ class TextureGrid(object):
# This is a cache from (width, size) to the results of compute_tiling.
tiling_cache = { }
def compute_tiling(width, max_size=MAX_SIZE):
def compute_tiling(width, max_size, min_fill_factor):
"""
This computes a tiling for an image with the given width (or
height). It takes a width as an argument, and returns two lists.
@@ -487,9 +508,8 @@ def compute_tiling(width, max_size=MAX_SIZE):
if size > max_size:
continue
# Ensure each texture is at least 2/3rds full. (Except the
# smallest.)
if size * .66 <= width + left_border:
# Ensure each texture is full enough.
if size * min_fill_factor <= width + left_border + right_border:
break
# The number of pixels to display to the user from this tile.
@@ -509,20 +529,6 @@ def compute_tiling(width, max_size=MAX_SIZE):
return row, tiles
def first_last(l):
"""
Iterates over list l. Yields (first, last, item) triples, where first
and last are true if the item is the first or last element in l,
respectively.
"""
n = len(l)
for i in range(n):
first = (i == 0)
last = (i == n - 1)
yield first, last, l[i]
def texture_grid_from_surface(surf):
"""
This takes a Surface and turns it into a TextureGrid.
@@ -532,14 +538,29 @@ def texture_grid_from_surface(surf):
rv = TextureGrid(width, height)
rv.columns, texcolumns = compute_tiling(width)
rv.rows, texrows = compute_tiling(height)
rv.columns, texcolumns = compute_tiling(width, MAX_SIZE, .66)
rv.rows, texrows = compute_tiling(height, MAX_SIZE, .66)
for border_top, border_bottom, (y, height, texheight) in first_last(texrows):
rownum = 0
lastrow = len(texrows) - 1
lastcol = len(texcolumns) - 1
for y, height, texheight in texrows:
border_top = (rownum == 0)
border_bottom = (rownum == lastrow)
rownum += 1
row = [ ]
for border_left, border_right, (x, width, texwidth) in first_last(texcolumns):
colnum = 0
for x, width, texwidth in texcolumns:
border_left = (colnum == 0)
border_right = (colnum == lastcol)
colnum += 1
tex = alloc_texture(texwidth, texheight)
tex.load_surface(surf, x, y, width, height,
border_left, border_top, border_right, border_bottom)
@@ -557,15 +578,14 @@ def texture_grid_from_drawing(width, height, draw_func, rtt):
draw_func to draw to the screen.
"""
rtt.begin()
rv = TextureGrid(width, height)
pwidth, pheight = renpy.display.draw.physical_size
gldraw = renpy.display.draw
pwidth, pheight = gldraw.physical_size
rv.columns, texcolumns = compute_tiling(width, rtt.get_size_limit(pwidth), .5)
rv.rows, texrows = compute_tiling(height, rtt.get_size_limit(pheight), .5)
rv.columns, texcolumns = compute_tiling(width, pwidth)
rv.rows, texrows = compute_tiling(height, pheight)
for y, height, texheight in texrows:
row = [ ]
@@ -577,8 +597,6 @@ def texture_grid_from_drawing(width, height, draw_func, rtt):
row.append(tex)
rv.tiles.append(row)
rtt.end()
return rv
@@ -638,7 +656,7 @@ def align_axes(*args):
return rv
def blit(tg, sx, sy, transform, alpha, environ, nearest=False):
cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, double alpha, environ, bint nearest):
"""
This draws texgrid `tg` to the screen. `sx` and `sy` are offsets from
the upper-left corner of the screen.
@@ -649,11 +667,14 @@ def blit(tg, sx, sy, transform, alpha, environ, nearest=False):
`alpha` is the alpha multiplier applied, from 0.0 to 1.0.
"""
cdef int x, y
cdef int texx, texy, texw, texh
tg.make_ready(nearest)
environ.blit()
gl.Color4f(alpha, alpha, alpha, alpha)
glColor4f(alpha, alpha, alpha, alpha)
y = 0
for texy, texh, rowindex in tg.rows:
@@ -676,9 +697,8 @@ def blit(tg, sx, sy, transform, alpha, environ, nearest=False):
x += texw
y += texh
def blend(tg0, tg1, sx, sy, transform, alpha, fraction, environ):
cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matrix2D transform, double alpha, double fraction, environ):
"""
Blends two textures to the screen.
@@ -694,11 +714,11 @@ def blend(tg0, tg1, sx, sy, transform, alpha, fraction, environ):
`fraction` is the fraction of the second texture to show.
"""
tg0.make_ready()
tg1.make_ready()
tg0.make_ready(False)
tg1.make_ready(False)
environ.blend(fraction)
gl.Color4f(alpha, alpha, alpha, alpha)
glColor4f(alpha, alpha, alpha, alpha)
y = 0
@@ -731,8 +751,7 @@ def blend(tg0, tg1, sx, sy, transform, alpha, fraction, environ):
y += t0h
def imageblend(tg0, tg1, tg2, sx, sy, transform, alpha, fraction, ramp, environ):
cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, double sy, render.Matrix2D transform, double alpha, double fraction, int ramp, environ):
"""
This uses texture 0 to control the blending of tetures 1 and 2 to
the screen.
@@ -752,12 +771,12 @@ def imageblend(tg0, tg1, tg2, sx, sy, transform, alpha, fraction, ramp, environ)
"""
tg0.make_ready()
tg1.make_ready()
tg2.make_ready()
tg0.make_ready(False)
tg1.make_ready(False)
tg2.make_ready(False)
environ.imageblend(fraction, ramp)
gl.Color4f(alpha, alpha, alpha, alpha)
glColor4f(alpha, alpha, alpha, alpha)
y = 0
@@ -791,18 +810,161 @@ def imageblend(tg0, tg1, tg2, sx, sy, transform, alpha, fraction, ramp, environ)
y += t0h
def premultiply(
object pysurf,
int x,
int y,
int w,
int h,
border_left, border_top, border_right, border_bottom):
"""
Creates a string containing the premultiplied image data for
for the (x, y, w, h) box inside pysurf. The various border_
parameters control the addition of a border on the sides.
"""
def draw_rectangle(
sx,
sy,
x,
y,
w,
h,
transform,
tex0, tex0x, tex0y,
tex1, tex1x, tex1y,
tex2, tex2x, tex2y):
# Adjust the alpha if we have an alpha-free image.
cdef unsigned char alpha_and
cdef unsigned char alpha_or
if pysurf.get_masks()[3]:
alpha_and = 255
alpha_or = 0
else:
alpha_and = 0
alpha_or = 255
# Allocate an uninitialized string.
cdef unsigned char *null = NULL
rv = null[:w*h*4]
# Out is where we put the output.
cdef unsigned char *out = rv
# The pixels in the source image.
cdef unsigned char *pixels = NULL
cdef SDL_Surface *surf
# Pointer to the current pixel.
cdef unsigned char *p
# Pointer to the current output pixel.
cdef unsigned char *op
# Pointer to the row end.
cdef unsigned char *pend
# alpha value.
cdef unsigned int a
# pixel pointer.
cdef unsigned int *pp
surf = PySurface_AsSurface(pysurf)
pixels = <unsigned char *> surf.pixels
pixels += y * surf.pitch
pixels += x * 4
op = out
for y from 0 <= y < h:
p = pixels + y * surf.pitch
pend = p + w * 4
while p < pend:
a = (p[3] & alpha_and) | alpha_or
op[0] = p[0] * a / 255
op[1] = p[1] * a / 255
op[2] = p[2] * a / 255
op[3] = a
p += 4
op += 4
if border_left:
pp = <unsigned int *> (out)
for y from 0 <= y < h:
pp[0] = pp[1]
pp += w
if border_right:
pp = <unsigned int *> (out)
pp += w - 2
for y from 0 <= y < h:
pp[1] = pp[0]
pp += w
if border_top:
pp = <unsigned int *> (out)
for x from 0 <= x < w:
pp[0] = pp[w]
pp += 1
if border_top:
pp = <unsigned int *> (out)
pp += (y - 2) * w
for x from 0 <= x < w:
pp[w] = pp[0]
pp += 1
return rv
def load_premultiplied(
data, width, height, update, format, internalformat,
):
cdef char *pixels
if data:
pixels = data
else:
pixels = NULL
if update:
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
width,
height,
format,
GL_UNSIGNED_BYTE,
<GLubyte *> pixels)
else:
glTexImage2D(
GL_TEXTURE_2D,
0,
internalformat,
width,
height,
0,
format,
GL_UNSIGNED_BYTE,
<GLubyte *> pixels)
cdef void draw_rectangle(
double sx,
double sy,
double x,
double y,
double w,
double h,
render.Matrix2D transform,
TextureCore tex0, float tex0x, float tex0y,
TextureCore tex1, float tex1x, float tex1y,
TextureCore tex2, float tex2x, float tex2y,
):
"""
This draws a rectangle (textured with up to four textures) to the
@@ -831,35 +993,42 @@ def draw_rectangle(
Texture offset to apply to the given side of the texture.
"""
gl.Disable(gl.POLYGON_SMOOTH)
# Do we have the given texture?
cdef int has_tex0, has_tex1, has_tex2
# Texture coordinates.
cdef double t0u0, t0v0, t0u1, t0v1
cdef double t1u0, t1v0, t1u1, t1v1
cdef double t2u0, t2v0, t2u1, t2v1
# Pull apart the transform.
xdx = transform.xdx
xdy = transform.xdy
ydx = transform.ydx
ydy = transform.ydy
cdef double xdx = transform.xdx
cdef double xdy = transform.xdy
cdef double ydx = transform.ydx
cdef double ydy = transform.ydy
# Transform the vertex coordinates to screen-space.
x0 = (x + 0) * xdx + (y + 0) * xdy + sx
y0 = (x + 0) * ydx + (y + 0) * ydy + sy
cdef double x0 = (x + 0) * xdx + (y + 0) * xdy + sx
cdef double y0 = (x + 0) * ydx + (y + 0) * ydy + sy
x1 = (x + w) * xdx + (y + 0) * xdy + sx
y1 = (x + w) * ydx + (y + 0) * ydy + sy
cdef double x1 = (x + w) * xdx + (y + 0) * xdy + sx
cdef double y1 = (x + w) * ydx + (y + 0) * ydy + sy
x2 = (x + 0) * xdx + (y + h) * xdy + sx
y2 = (x + 0) * ydx + (y + h) * ydy + sy
cdef double x2 = (x + 0) * xdx + (y + h) * xdy + sx
cdef double y2 = (x + 0) * ydx + (y + h) * ydy + sy
x3 = (x + w) * xdx + (y + h) * xdy + sx
y3 = (x + w) * ydx + (y + h) * ydy + sy
cdef double x3 = (x + w) * xdx + (y + h) * xdy + sx
cdef double y3 = (x + w) * ydx + (y + h) * ydy + sy
# Compute the texture coordinates, and set up the textures.
cdef double xadd, yadd, xmul, ymul
if tex0 is not None:
has_tex0 = 1
gl.ActiveTextureARB(gl.TEXTURE0_ARB)
gl.BindTexture(gl.TEXTURE_2D, tex0.number)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, tex0.number)
xadd = tex0.xadd
yadd = tex0.yadd
@@ -878,8 +1047,8 @@ def draw_rectangle(
has_tex1 = 1
gl.ActiveTextureARB(gl.TEXTURE1_ARB)
gl.BindTexture(gl.TEXTURE_2D, tex1.number)
glActiveTexture(GL_TEXTURE1)
glBindTexture(GL_TEXTURE_2D, tex1.number)
xadd = tex1.xadd
yadd = tex1.yadd
@@ -898,8 +1067,8 @@ def draw_rectangle(
has_tex2 = 1
gl.ActiveTextureARB(gl.TEXTURE2_ARB)
gl.BindTexture(gl.TEXTURE_2D, tex2.number)
glActiveTexture(GL_TEXTURE2)
glBindTexture(GL_TEXTURE_2D, tex2.number)
xadd = tex2.xadd
yadd = tex2.yadd
@@ -914,49 +1083,76 @@ def draw_rectangle(
else:
has_tex2 = 0
# Now, actually draw the textured rectangle.
gl.Begin(gl.TRIANGLE_STRIP)
cdef GLfloat tex0coords[8]
cdef GLfloat tex1coords[8]
cdef GLfloat tex2coords[8]
cdef GLfloat vcoords[8]
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u0, t0v0)
tex0coords[0] = t0u0
tex0coords[1] = t0v0
tex0coords[2] = t0u1
tex0coords[3] = t0v0
tex0coords[4] = t0u0
tex0coords[5] = t0v1
tex0coords[6] = t0u1
tex0coords[7] = t0v1
glClientActiveTexture(GL_TEXTURE0)
glTexCoordPointer(2, GL_FLOAT, 0, <GLubyte *> tex0coords)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
else:
glClientActiveTexture(GL_TEXTURE0)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u0, t1v0)
tex1coords[0] = t1u0
tex1coords[1] = t1v0
tex1coords[2] = t1u1
tex1coords[3] = t1v0
tex1coords[4] = t1u0
tex1coords[5] = t1v1
tex1coords[6] = t1u1
tex1coords[7] = t1v1
glClientActiveTexture(GL_TEXTURE1)
glTexCoordPointer(2, GL_FLOAT, 0, <GLubyte *> tex1coords)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
else:
glClientActiveTexture(GL_TEXTURE1)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u0, t2v0)
gl.Vertex2f(x0, y0)
tex2coords[0] = t2u0
tex2coords[1] = t2v0
tex2coords[2] = t2u1
tex2coords[3] = t2v0
tex2coords[4] = t2u0
tex2coords[5] = t2v1
tex2coords[6] = t2u1
tex2coords[7] = t2v1
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u1, t0v0)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u1, t1v0)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u1, t2v0)
gl.Vertex2f(x1, y1)
glClientActiveTexture(GL_TEXTURE2)
glTexCoordPointer(2, GL_FLOAT, 0, <GLubyte *> tex2coords)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
else:
glClientActiveTexture(GL_TEXTURE2)
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u0, t0v1)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u0, t1v1)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u0, t2v1)
gl.Vertex2f(x2, y2)
vcoords[0] = x0
vcoords[1] = y0
vcoords[2] = x1
vcoords[3] = y1
vcoords[4] = x2
vcoords[5] = y2
vcoords[6] = x3
vcoords[7] = y3
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u1, t0v1)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u1, t1v1)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u1, t2v1)
gl.Vertex2f(x3, y3)
gl.End()
C_DRAW = True
if C_DRAW:
if pysdlgl:
draw_rectangle = pysdlgl.draw_rectangle
else:
print "Warning: Draw not using C code."
glVertexPointer(2, GL_FLOAT, 0, <GLubyte *> vcoords)
glEnableClientState(GL_VERTEX_ARRAY)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# Copyright 2004-2011 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

Some files were not shown because too many files have changed in this diff Show More