Compare commits
139 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cc54d1970b | |||
| e6915fffd3 | |||
| 964d746f6d | |||
| de6af43d74 | |||
| 0dc1a6e46c | |||
| 4098830804 | |||
| 304ab15b8f | |||
| 16fa9410db | |||
| 9ff69de20c | |||
| cd50f1ee86 | |||
| 195f3d6130 | |||
| 89d8622f6f | |||
| d71e054eb4 | |||
| 48a648eecd | |||
| 63268d079e | |||
| 743d5ca81a | |||
| dffb33c8e0 | |||
| a6ea0931dd | |||
| 17016c0eb2 | |||
| 67c703d934 | |||
| c163d1c936 | |||
| e3c15a2c58 | |||
| dfc149f292 | |||
| 627ba65b9a | |||
| a92170d88a | |||
| 503653cb5e | |||
| 68c277ff9a | |||
| 7b171b4f9b | |||
| 30956e4c58 | |||
| 6a956aacab | |||
| 681c845e2d | |||
| 11594ef5e8 | |||
| 28f06291db | |||
| c6937698ed | |||
| 15f85c8b80 | |||
| 7fd5695f83 | |||
| 952880287b | |||
| f76c7cf25a | |||
| 7c14b4d381 | |||
| c67389f0a3 | |||
| 219994ced2 | |||
| 274f08807e | |||
| 7601b4d3da | |||
| 05d14b4bfd | |||
| c5b63fd1c5 | |||
| 0bb6a926b2 | |||
| 0124eacb15 | |||
| 7ac06761d6 | |||
| c8c6226045 | |||
| 507d9610c7 | |||
| 5f4075fc35 | |||
| 514571cc80 | |||
| 6ff34b71cf | |||
| 37416daa53 | |||
| 6bd5401633 | |||
| ea6b9571b5 | |||
| bd7c403986 | |||
| 99417726ce | |||
| 4319e542f7 | |||
| 61d8445949 | |||
| 743095064d | |||
| efa12ab5a6 | |||
| b49b1b392c | |||
| 09e54e9915 | |||
| 373d175f2d | |||
| 5f3955a04a | |||
| 98c0e51527 | |||
| 8b3a6e8fc6 | |||
| b2d2e8ba7e | |||
| f1efced19c | |||
| 5b09dfc80c | |||
| 39f91a4368 | |||
| 3b6c9bde63 | |||
| 1df05ea53e | |||
| 3e9aee1c6f | |||
| 5231a460da | |||
| e6b3b36df9 | |||
| 060d510658 | |||
| 3b21a4aa97 | |||
| 4824b44950 | |||
| 988a92d4a5 | |||
| 378e2e61bd | |||
| eb94a7d9bb | |||
| fe2ba07a57 | |||
| 2788b12eb2 | |||
| 265b553b4e | |||
| 5f800681aa | |||
| 890c9cf591 | |||
| 2c356b80ed | |||
| cc097ba7da | |||
| 78401f1c4a | |||
| 8802363544 | |||
| 05388c3733 | |||
| 8f84301b39 | |||
| 774ba5d990 | |||
| 6bf0cd93d1 | |||
| 7f63c26348 | |||
| bce3e6ede1 | |||
| 4f642041f9 | |||
| b990b2768c | |||
| 53b8d37d8c | |||
| db9f63c2d9 | |||
| 87df4ff487 | |||
| f0fe459460 | |||
| f71a35751a | |||
| 2458d9cbb3 | |||
| 81c6d33005 | |||
| dba5c20e34 | |||
| c2eddb21e5 | |||
| de1d289670 | |||
| 623201fd75 | |||
| 2f900b6bc7 | |||
| 375af0cccd | |||
| 8ae8e887f5 | |||
| 1e6e0f0800 | |||
| b3b3c55473 | |||
| 7f2c6fd977 | |||
| 59338d3ae3 | |||
| 98a5647f97 | |||
| 5d11642776 | |||
| 297277451f | |||
| d5ec269811 | |||
| 02bbe29ccb | |||
| 3844ace955 | |||
| 3715a03598 | |||
| 82c695a199 | |||
| 09ff58a1a6 | |||
| 0fbe522235 | |||
| cc38b5e5c3 | |||
| c6101f5565 | |||
| f4e50ae4d8 | |||
| 3f42edbb08 | |||
| c63ff665b2 | |||
| 230ef6d4ca | |||
| 9d1783f4d6 | |||
| 99d14d9521 | |||
| 57ed7e692e | |||
| 6aaf974049 | |||
| 1fce0f5557 |
+31
@@ -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
@@ -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
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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):
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,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,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,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:
|
||||
|
||||
@@ -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,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:
|
||||
|
||||
@@ -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,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,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,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 hide:
|
||||
|
||||
@@ -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,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,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,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 hide:
|
||||
|
||||
@@ -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,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,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 hide:
|
||||
|
||||
@@ -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:
|
||||
|
||||
+9
-31
@@ -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,3 +1,3 @@
|
||||
init -999:
|
||||
$ config.script_version = (6, 11, 2)
|
||||
$ config.script_version = (6, 12, 0)
|
||||
|
||||
|
||||
-5742
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
-1446
File diff suppressed because it is too large
Load Diff
Executable
+15
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -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
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,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
@@ -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,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,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
@@ -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
@@ -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
@@ -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
@@ -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,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
|
||||
|
||||
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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,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,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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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)
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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,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
Reference in New Issue
Block a user