Compare commits
234 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b8bf87eaf | |||
| 857d776538 | |||
| df51f5233f | |||
| aed2625486 | |||
| 47271b7af9 | |||
| d8050e9f5d | |||
| b639171118 | |||
| 25e66d3150 | |||
| dcaa97a70e | |||
| e0fd8dc4d5 | |||
| 2cc4bdd407 | |||
| 8ccfb9abc7 | |||
| 4734fb62f4 | |||
| 8353120f55 | |||
| 5a081b6dc7 | |||
| 52cdcb699a | |||
| e190596f3d | |||
| 9352339f5b | |||
| 5c315d02d1 | |||
| 86a95abb60 | |||
| cc03f54738 | |||
| f40ff85436 | |||
| 3c6918c36f | |||
| 754aec0507 | |||
| 9f800275ad | |||
| cf05311158 | |||
| 644d24dcc4 | |||
| 87f076e78c | |||
| b0cc98cea2 | |||
| 498ea82ec9 | |||
| e587790021 | |||
| bbaf654ef9 | |||
| 44b5af95ff | |||
| 5470f86c39 | |||
| 8e04c766de | |||
| 82b396d424 | |||
| a0dad58dbf | |||
| d28ecb39ff | |||
| 6597edcada | |||
| 5c44e738e6 | |||
| 7e295d67b5 | |||
| 61eb81c79d | |||
| df32d31113 | |||
| 59587015ba | |||
| 312c49f194 | |||
| 7c75a79c13 | |||
| e6546189eb | |||
| 9500f658a3 | |||
| 6d9bcff1f6 | |||
| 3a352af1e5 | |||
| 87b323a3d4 | |||
| 1bf97965b8 | |||
| eafcbf572f | |||
| 427a1542d8 | |||
| ee53f232aa | |||
| 7c03642cb5 | |||
| 4347c89c15 | |||
| 9783a0a733 | |||
| e5252af42b | |||
| 094009fa3a | |||
| 6471986ea9 | |||
| ab97732865 | |||
| 4f90718eaa | |||
| 2aa796d418 | |||
| e62ee21922 | |||
| 218cb677cd | |||
| fe0e129ad3 | |||
| 630ed80eb5 | |||
| 2b5d40053d | |||
| 8728fd137a | |||
| 7b34ec1ba3 | |||
| 3f785ee366 | |||
| 1f9401a602 | |||
| 91a0677f67 | |||
| 1392fb9239 | |||
| ac902ee733 | |||
| 6031917511 | |||
| 0e6ad371fe | |||
| ead5c63eac | |||
| 18827a8ab3 | |||
| 8c81811177 | |||
| ce634662bd | |||
| 13c32894cf | |||
| 26e0f1617e | |||
| 6754d50c12 | |||
| ebe8264b1d | |||
| 5c9a1066e3 | |||
| 07a6f3dcbd | |||
| 3441e0e7f0 | |||
| 3bd9055c5f | |||
| 2941031b2a | |||
| 627b18a8e8 | |||
| 681d3a5772 | |||
| 39be517a0a | |||
| 8916575921 | |||
| 5288ff876d | |||
| 067d98cdf0 | |||
| 65957b3236 | |||
| 726e535f1b | |||
| 095a253bf8 | |||
| d3c36b843e | |||
| b5707d7091 | |||
| 024b0aef81 | |||
| 365913c267 | |||
| a2b8842206 | |||
| dc51db06b1 | |||
| c590c4f956 | |||
| 3871803088 | |||
| 40ec6f87ef | |||
| 6339c0dfef | |||
| 510b7cb909 | |||
| 3a011ca2c6 | |||
| d12fe12c2b | |||
| 37a128a470 | |||
| 9e8b074a16 | |||
| 3147e71c45 | |||
| 60d413f96f | |||
| 5029e6d078 | |||
| ef167433f4 | |||
| aac1f4c421 | |||
| 0ab0856e37 | |||
| 760503b124 | |||
| d16e3eea75 | |||
| 09fda5505e | |||
| 5d4bb738ef | |||
| 204a48f577 | |||
| 8889ab487d | |||
| 06684d692a | |||
| 5f4e6d4ba1 | |||
| 200af0d584 | |||
| e78828fa3b | |||
| 7e602c256e | |||
| 1a8154c78a | |||
| 2d7460bafd | |||
| ae998912f5 | |||
| e8cd034b7a | |||
| 900e291cdc | |||
| cb98d18aa9 | |||
| ef4c5aff9e | |||
| 6cdcb5dfbc | |||
| 797ef0fc25 | |||
| c132df21ca | |||
| 6ab2df60f4 | |||
| 101cb8c348 | |||
| 2f53ddc03e | |||
| 8a042fe187 | |||
| f9a61f7567 | |||
| 79c965ba5d | |||
| 340db775c5 | |||
| d1224c0707 | |||
| afeb06c1d9 | |||
| afad82b082 | |||
| 2f683b2d69 | |||
| d8ec4503a6 | |||
| bb207a7fce | |||
| 629ea6f13f | |||
| 2a78e0141f | |||
| 8da9eafd28 | |||
| 1f8e1cacf6 | |||
| 048f8fea8f | |||
| 229bd5a82d | |||
| 12405a22d9 | |||
| 3529d40ba0 | |||
| 02be00bb78 | |||
| 189e7d8e4f | |||
| 0956519365 | |||
| efbd897832 | |||
| c6d9b6e0c1 | |||
| d0bbc81ebf | |||
| 662e8227ab | |||
| 33e3174692 | |||
| dde68dd735 | |||
| 5accb1c3e4 | |||
| 77d8b9b318 | |||
| 202fc47419 | |||
| 49c0ec0504 | |||
| bc437b5e9b | |||
| b4dfcc44cf | |||
| 1a98502bdc | |||
| 977726c3ab | |||
| ed9cbfd21c | |||
| 261a0b807d | |||
| 261718967a | |||
| 3e5e77b400 | |||
| 7fa4265f15 | |||
| 995823fbcf | |||
| 663961581f | |||
| d32946ce53 | |||
| 6bd9523780 | |||
| b0b49b353e | |||
| b1b943b456 | |||
| dd5326c205 | |||
| e62cc921c7 | |||
| d343617616 | |||
| 0cf72637b2 | |||
| e9312a3604 | |||
| 39420b940a | |||
| d8655be2c5 | |||
| c276ac8ec8 | |||
| 37e7060baa | |||
| b155fa9411 | |||
| 4ef1e05dc8 | |||
| da6e5e2c73 | |||
| 95c1cd5ad8 | |||
| f8747f6e38 | |||
| 450aeb55dc | |||
| 878e2284f8 | |||
| a4291ccddb | |||
| 2091161241 | |||
| c8ac8b511f | |||
| ed3182c74c | |||
| 82b0d59f19 | |||
| 60b42fd79b | |||
| ba2c72eaac | |||
| 7751d5603e | |||
| 6e8d622282 | |||
| 30b3366168 | |||
| 736d9487c5 | |||
| 7bf7af52b1 | |||
| be7daf39d5 | |||
| 0faf7810f6 | |||
| bd333803b2 | |||
| f24e3f199e | |||
| 13a755ae93 | |||
| a907cfaa2e | |||
| b236453972 | |||
| 95fe225a8c | |||
| 621fbe9449 | |||
| f6029db185 | |||
| 38f8e1f16f | |||
| ca95350b70 | |||
| 985b54d284 | |||
| 7d655595e0 | |||
| 669a25d530 |
@@ -82,3 +82,5 @@ sphinx/source/inc
|
||||
sphinx/source/thequestion.rst
|
||||
tutorial/game/tutorial_director.rpy
|
||||
launcher/theme
|
||||
module/emscripten-static/
|
||||
web/
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ not edit the files in sphinx/source/inc directly, as they will be overwritten.
|
||||
Docstrings may include tags on the first few lines:
|
||||
|
||||
\:doc: `section` `kind`
|
||||
Indicates that this functions should be documented. `section` gives
|
||||
Indicates that this function should be documented. `section` gives
|
||||
the name of the include file the function will be documented in, while
|
||||
`kind` indicates the kind of object to be documented (one of ``function``,
|
||||
``method`` or ``class``. If omitted, `kind` will be auto-detected.
|
||||
|
||||
+24
-2
@@ -54,6 +54,7 @@ def main():
|
||||
ap.add_argument("--variant", action="store")
|
||||
ap.add_argument("--sign", action="store_true", default=True)
|
||||
ap.add_argument("--nosign", action="store_false", dest="sign")
|
||||
ap.add_argument("--notarized", action="store_true", dest="notarized")
|
||||
ap.add_argument("--vc-version-only", action="store_true")
|
||||
|
||||
args = ap.parse_args()
|
||||
@@ -175,6 +176,12 @@ def main():
|
||||
destination,
|
||||
]
|
||||
|
||||
if args.notarized:
|
||||
cmd.extend([
|
||||
"--macapp",
|
||||
"notarized/out",
|
||||
])
|
||||
|
||||
print()
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
@@ -250,8 +257,23 @@ def main():
|
||||
|
||||
print()
|
||||
|
||||
if not (args.fast or args.sign):
|
||||
print("For a final-ish release, remember to use --sign so we're signed on the mac.")
|
||||
if args.sign and not args.notarized:
|
||||
shutil.copy(sdk + ".tar.bz2", ROOT + "/notarized/in/renpy.tar.bz2")
|
||||
|
||||
print("Next steps:")
|
||||
print()
|
||||
print(" mac: ./scripts/notarize_app_1.sh")
|
||||
print(" mac: ./scripts/notarize_app_2.sh")
|
||||
print(" linux: ./distribute.py --notarized")
|
||||
print()
|
||||
|
||||
elif args.sign and args.notarized:
|
||||
|
||||
print("Next steps:")
|
||||
print()
|
||||
print(" mac: ./scripts/notarize_dmg_1.sh", args.version)
|
||||
print(" mac: ./scripts/notarize_dmg_2.sh", args.version)
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -199,12 +199,6 @@ init python:
|
||||
build.documentation('*.html')
|
||||
build.documentation('*.txt')
|
||||
|
||||
## Set this to a string containing your Apple Developer ID Application
|
||||
## to enable codesigning on the Mac. Be sure to change it to your own
|
||||
## Apple-issued ID.
|
||||
|
||||
# define build.mac_identity = "Developer ID Application: Guy Shy (XHTE5H7Z42)"
|
||||
|
||||
|
||||
## A Google Play license key is required to download expansion files and
|
||||
## perform in-app purchases. It can be found on the "Services & APIs" page
|
||||
|
||||
@@ -323,12 +323,14 @@ screen navigation():
|
||||
|
||||
textbutton _("About") action ShowMenu("about")
|
||||
|
||||
if renpy.variant("pc"):
|
||||
if renpy.variant("pc") or (renpy.variant("web") and not renpy.variant("mobile")):
|
||||
|
||||
## Help isn't necessary or relevant to mobile devices.
|
||||
textbutton _("Help") action ShowMenu("help")
|
||||
|
||||
## The quit button is banned on iOS and unnecessary on Android.
|
||||
if renpy.variant("pc"):
|
||||
|
||||
## The quit button is banned on iOS and unnecessary on Android and Web.
|
||||
textbutton _("Quit") action Quit(confirm=not main_menu)
|
||||
|
||||
|
||||
@@ -725,7 +727,7 @@ screen preferences():
|
||||
hbox:
|
||||
box_wrap True
|
||||
|
||||
if renpy.variant("pc"):
|
||||
if renpy.variant("pc") or renpy.variant("web"):
|
||||
|
||||
vbox:
|
||||
style_prefix "radio"
|
||||
|
||||
@@ -373,7 +373,7 @@ init python in distribute:
|
||||
This manages the process of building distributions.
|
||||
"""
|
||||
|
||||
def __init__(self, project, destination=None, reporter=None, packages=None, build_update=True, open_directory=False, noarchive=False, packagedest=None, report_success=True, scan=True):
|
||||
def __init__(self, project, destination=None, reporter=None, packages=None, build_update=True, open_directory=False, noarchive=False, packagedest=None, report_success=True, scan=True, macapp=None):
|
||||
"""
|
||||
Distributes `project`.
|
||||
|
||||
@@ -404,6 +404,10 @@ init python in distribute:
|
||||
|
||||
`report_success`
|
||||
If true, we report that the build succeeded.
|
||||
|
||||
`macapp`
|
||||
If given, the path to a macapp that's used instead of
|
||||
the macapp
|
||||
"""
|
||||
|
||||
# A map from a package to a unique update version hash.
|
||||
@@ -437,6 +441,9 @@ init python in distribute:
|
||||
# Logfile.
|
||||
self.log = open(self.temp_filename("distribute.txt"), "w")
|
||||
|
||||
# The path to the mac app.
|
||||
self.macapp = macapp
|
||||
|
||||
# Start by scanning the project, to get the data and build
|
||||
# dictionaries.
|
||||
data = project.data
|
||||
@@ -1059,6 +1066,9 @@ init python in distribute:
|
||||
Signs the mac app contained in appzip.
|
||||
"""
|
||||
|
||||
if self.macapp:
|
||||
return self.rescan(fl, self.macapp)
|
||||
|
||||
identity = self.build.get('mac_identity', None)
|
||||
|
||||
if identity is None:
|
||||
@@ -1094,6 +1104,7 @@ init python in distribute:
|
||||
self.build["mac_codesign_command"],
|
||||
identity=identity,
|
||||
app=os.path.join(dn, self.app),
|
||||
entitlements=os.path.join(config.gamedir, "entitlements.plist"),
|
||||
)
|
||||
|
||||
# Rescan the signed app.
|
||||
@@ -1109,7 +1120,7 @@ init python in distribute:
|
||||
identity = self.build.get('mac_identity', None)
|
||||
|
||||
if identity is None:
|
||||
raise Exception("Creating an unsigned DMG is not supported. Please set build.mac_identity.")
|
||||
identity = ''
|
||||
|
||||
self.run(
|
||||
_("Creating the Macintosh DMG..."),
|
||||
@@ -1120,14 +1131,16 @@ init python in distribute:
|
||||
dmg=dmg,
|
||||
)
|
||||
|
||||
self.run(
|
||||
_("Signing the Macintosh DMG..."),
|
||||
self.build["mac_codesign_dmg_command"],
|
||||
identity=identity,
|
||||
volname=volname,
|
||||
sourcedir=sourcedir,
|
||||
dmg=dmg,
|
||||
)
|
||||
if self.build.get("mac_codesign_dmg_command", None):
|
||||
|
||||
self.run(
|
||||
_("Signing the Macintosh DMG..."),
|
||||
self.build["mac_codesign_dmg_command"],
|
||||
identity=identity,
|
||||
volname=volname,
|
||||
sourcedir=sourcedir,
|
||||
dmg=dmg,
|
||||
)
|
||||
|
||||
def prepare_file_list(self, format, file_lists):
|
||||
"""
|
||||
@@ -1265,7 +1278,7 @@ init python in distribute:
|
||||
|
||||
file_hash, old_fl_hash = self.build_cache.get(full_filename, ("", ""))
|
||||
|
||||
if (not directory) and old_fl_hash == fl_hash:
|
||||
if (not directory) and (old_fl_hash == fl_hash) and not(self.build['renpy'] and (variant == "sdk")):
|
||||
|
||||
if file_hash:
|
||||
self.build_cache[full_filename] = (file_hash, fl_hash)
|
||||
@@ -1476,6 +1489,7 @@ init python in distribute:
|
||||
ap.add_argument("--no-update", default=True, action="store_false", dest="build_update", help="Prevents updates from being built.")
|
||||
ap.add_argument("--package", action="append", help="If given, a package to build. Defaults to building all packages.")
|
||||
ap.add_argument("--no-archive", action="store_true", help="If given, files will not be added to archives.")
|
||||
ap.add_argument("--macapp", default=None, action="store", help="If given, the path to a signed and notarized mac app.")
|
||||
ap.add_argument("project", help="The path to the project directory.")
|
||||
|
||||
args = ap.parse_args()
|
||||
@@ -1487,7 +1501,7 @@ init python in distribute:
|
||||
else:
|
||||
packages = None
|
||||
|
||||
Distributor(p, destination=args.destination, reporter=TextReporter(), packages=packages, build_update=args.build_update, noarchive=args.no_archive, packagedest=args.packagedest)
|
||||
Distributor(p, destination=args.destination, reporter=TextReporter(), packages=packages, build_update=args.build_update, noarchive=args.no_archive, packagedest=args.packagedest, macapp=args.macapp)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ init python:
|
||||
platform = "windows-amd64"
|
||||
exe = "butler.exe"
|
||||
elif renpy.macintosh:
|
||||
plaform = "darwin-amd64"
|
||||
platform = "darwin-amd64"
|
||||
exe = "butler"
|
||||
else:
|
||||
platform = "linux-amd64"
|
||||
|
||||
@@ -194,7 +194,9 @@ init -1 python:
|
||||
kwargs["stdin"] = subprocess.PIPE
|
||||
|
||||
try:
|
||||
self.process = subprocess.Popen(cmd, cwd=renpy.fsencode(RAPT_PATH), stdout=f, stderr=f, startupinfo=startupinfo, **kwargs)
|
||||
self.process = subprocess.Popen(cmd, cwd=renpy.fsencode(RAPT_PATH), stdout=f, stderr=f, stdin=subprocess.PIPE, startupinfo=startupinfo, **kwargs)
|
||||
# avoid SIGTTIN caused by e.g. gradle doing empty read on terminal stdin
|
||||
self.process.stdin.close()
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc(file=f)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
# _developer/inspector.rpym:145
|
||||
old " (no properties affect the displayable)"
|
||||
new "(디스플레이어블에 적용되는 속성이 없습니다)"
|
||||
new " (디스플레이어블에 적용되는 속성이 없습니다)"
|
||||
|
||||
# _developer/inspector.rpym:147
|
||||
old " (default properties omitted)"
|
||||
@@ -134,11 +134,11 @@
|
||||
|
||||
# 00console.rpy:413
|
||||
old " <renpy script statement>: run the statement\n"
|
||||
new "<렌파이 스크립트 명령문>: 명령문을 실행한다\n"
|
||||
new " <렌파이 스크립트 명령문>: 명령문을 실행한다\n"
|
||||
|
||||
# 00console.rpy:415
|
||||
old " <python expression or statement>: run the expression or statement"
|
||||
new "<파이썬 표현식 또는 명령문>: 표현식이나 명령문을 실행한다"
|
||||
new " <파이썬 표현식 또는 명령문>: 표현식이나 명령문을 실행한다"
|
||||
|
||||
# 00console.rpy:423
|
||||
old "clear: clear the console history"
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
# add_file.rpy:31
|
||||
old "The filename must have the .rpy extension."
|
||||
new "파일 이름에는 반드시 .rpy 확장자가 적혀있어야 합니다."
|
||||
new "파일의 확장자는 반드시 .rpy 이어야 합니다."
|
||||
|
||||
# add_file.rpy:39
|
||||
old "The file already exists."
|
||||
new "파일 이름이 이미 존재합니다."
|
||||
new "파일이 이미 존재합니다."
|
||||
|
||||
# add_file.rpy:42
|
||||
old "# Ren'Py automatically loads all script files ending with .rpy. To use this\n# file, define a label and jump to it from another file.\n"
|
||||
@@ -214,7 +214,7 @@
|
||||
|
||||
# androidstrings.rpy:17
|
||||
old "The build seems to have failed."
|
||||
new "빌드가 실패했습니다."
|
||||
new "빌드에 실패했습니다."
|
||||
|
||||
# androidstrings.rpy:18
|
||||
old "Launching app."
|
||||
@@ -594,7 +594,7 @@
|
||||
|
||||
# dmgcheck.rpy:50
|
||||
old "Ren'Py is running from a read only folder. Some functionality will not work."
|
||||
new "렌파이가 읽기 전용 폴더로부터 실행되고 있습니다. 일부 기능이 작동하지 않을 수 있습니다."
|
||||
new "렌파이가 읽기 전용 폴더에서 실행되고 있습니다. 일부 기능이 작동하지 않을 수 있습니다."
|
||||
|
||||
# dmgcheck.rpy:50
|
||||
old "This is probably because Ren'Py is running directly from a Macintosh drive image. To fix this, quit this launcher, copy the entire %s folder somewhere else on your computer, and run Ren'Py again."
|
||||
@@ -1554,7 +1554,7 @@
|
||||
|
||||
# web.rpy:194
|
||||
old "Before packaging web apps, you'll need to download RenPyWeb, Ren'Py's web support. Would you like to download RenPyWeb now?"
|
||||
new "웹 앱을 패키징하려면 렌파이 렌파이웹(RenpyWeb)이 필요하니다. 지금 내려받으시겠습니까?"
|
||||
new "웹 앱을 패키징하려면 렌파이의 웹 지원인 렌파이웹(RenpyWeb)이 필요합니다. 지금 내려받으시겠습니까?"
|
||||
|
||||
# updater.rpy:188
|
||||
old "Fetching the list of update channels"
|
||||
|
||||
@@ -190,9 +190,9 @@
|
||||
|
||||
# 00console.rpy:680
|
||||
old "short: Shorten the representation of objects on the console (default)."
|
||||
new "corto: Acorta la representación de los objetos en la consola (predeterminado)."
|
||||
new "short: Acorta la representación de los objetos en la consola (predeterminado)."
|
||||
|
||||
# 00console.rpy:685
|
||||
old "long: Print the full representation of objects on the console."
|
||||
new "largo: imprime la representación completa de los objetos en la consola."
|
||||
new "long: imprime la representación completa de los objetos en la consola."
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ init python:
|
||||
|
||||
import shutil
|
||||
import webserver
|
||||
import io
|
||||
|
||||
WEB_PATH = None
|
||||
|
||||
@@ -91,12 +92,12 @@ init python:
|
||||
shutil.copy(os.path.join(WEB_PATH, fn), os.path.join(destination, fn))
|
||||
|
||||
# Copy over index.html.
|
||||
with open(os.path.join(WEB_PATH, "index.html")) as f:
|
||||
with io.open(os.path.join(WEB_PATH, "index.html"), encoding='utf-8') as f:
|
||||
html = f.read()
|
||||
|
||||
html = html.replace("%%TITLE%%", display_name.encode("utf-8"))
|
||||
html = html.replace("%%TITLE%%", display_name)
|
||||
|
||||
with open(os.path.join(destination, "index.html"), "w") as f:
|
||||
with io.open(os.path.join(destination, "index.html"), "w", encoding='utf-8') as f:
|
||||
f.write(html)
|
||||
|
||||
webserver.start(destination)
|
||||
|
||||
+17
-6
@@ -20,7 +20,7 @@
|
||||
static int audio_equal_mono = 1;
|
||||
|
||||
/* The weight of stereo channels when audio_equal_mono is true. */
|
||||
static float stereo_matrix[] = { 1.0, 1.0 };
|
||||
static double stereo_matrix[] = { 1.0, 1.0 };
|
||||
|
||||
/* The output audio sample rate. */
|
||||
static int audio_sample_rate = 44100;
|
||||
@@ -571,19 +571,30 @@ static void decode_audio(MediaState *ms) {
|
||||
break;
|
||||
}
|
||||
|
||||
converted_frame = av_frame_alloc();
|
||||
converted_frame->sample_rate = audio_sample_rate;
|
||||
converted_frame->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
converted_frame->format = AV_SAMPLE_FMT_S16;
|
||||
|
||||
if (!ms->audio_decode_frame->channel_layout) {
|
||||
ms->audio_decode_frame->channel_layout = av_get_default_channel_layout(ms->audio_decode_frame->channels);
|
||||
|
||||
if (audio_equal_mono && (ms->audio_decode_frame->channels == 1)) {
|
||||
swr_alloc_set_opts(
|
||||
ms->swr,
|
||||
converted_frame->channel_layout,
|
||||
converted_frame->format,
|
||||
converted_frame->sample_rate,
|
||||
ms->audio_decode_frame->channel_layout,
|
||||
ms->audio_decode_frame->format,
|
||||
ms->audio_decode_frame->sample_rate,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
swr_set_matrix(ms->swr, stereo_matrix, 1);
|
||||
}
|
||||
}
|
||||
|
||||
converted_frame = av_frame_alloc();
|
||||
converted_frame->sample_rate = audio_sample_rate;
|
||||
converted_frame->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||
converted_frame->format = AV_SAMPLE_FMT_S16;
|
||||
|
||||
if(swr_convert_frame(ms->swr, converted_frame, ms->audio_decode_frame)) {
|
||||
av_frame_free(&converted_frame);
|
||||
continue;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
#include <SDL_opengl_glext.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gl2debug.h"
|
||||
|
||||
static void APIENTRY gl2_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
|
||||
printf("GL %s: 0x%x, 0x%x: %s\n", (type == GL_DEBUG_TYPE_ERROR ? "ERROR" : " "), type, severity, message);
|
||||
}
|
||||
|
||||
void gl2_enable_debug(void) {
|
||||
void APIENTRY (*debugMessageCallback)(GLDEBUGPROC callback, const void *userParam);
|
||||
void APIENTRY (*debugMessageControl)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
|
||||
void APIENTRY (*glEnable)(GLenum);
|
||||
|
||||
debugMessageCallback = SDL_GL_GetProcAddress("glDebugMessageCallback");
|
||||
|
||||
if (!debugMessageCallback) {
|
||||
debugMessageCallback = SDL_GL_GetProcAddress("glDebugMessageCallbackKHR");
|
||||
}
|
||||
|
||||
if (debugMessageCallback == NULL) {
|
||||
printf("GL: Could not get glDebugMessageCallback\n");
|
||||
return;
|
||||
}
|
||||
|
||||
debugMessageControl = SDL_GL_GetProcAddress("glDebugMessageControl");
|
||||
|
||||
if (!debugMessageControl) {
|
||||
debugMessageControl = SDL_GL_GetProcAddress("glDebugMessageControlKHR");
|
||||
}
|
||||
|
||||
if (debugMessageControl == NULL) {
|
||||
printf("GL: Could not get glDebugMessageControl\n");
|
||||
return;
|
||||
}
|
||||
|
||||
glEnable = SDL_GL_GetProcAddress("glEnable");
|
||||
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
debugMessageCallback(gl2_debug_callback, 0);
|
||||
debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, 1);
|
||||
}
|
||||
+
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef GL2DEBUG_H
|
||||
#define GL2DEBUG_H
|
||||
|
||||
void gl2_enable_debug(void);
|
||||
|
||||
#endif
|
||||
+7
-27
@@ -44,33 +44,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#if defined RENPY_GLES_1
|
||||
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
|
||||
#define glOrtho glOrthof
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
#define RENPY_THIRD_TEXTURE 0
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined RENPY_GLES_2
|
||||
|
||||
#ifdef ANGLE
|
||||
@@ -88,6 +61,12 @@ typedef GLchar GLcharARB;
|
||||
|
||||
#define GL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_IMAGE_UNITS
|
||||
|
||||
#define GL_RENDERBUFFER_EXT GL_RENDERBUFFER
|
||||
#define glGenRenderbuffersEXT glGenRenderbuffers
|
||||
#define glBindRenderbufferEXT glBindRenderbuffer
|
||||
#define glRenderbufferStorageEXT glRenderbufferStorage
|
||||
#define glDeleteRenderbuffersEXT glDeleteRenderbuffers
|
||||
|
||||
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER
|
||||
#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING
|
||||
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
|
||||
@@ -96,6 +75,7 @@ typedef GLchar GLcharARB;
|
||||
#define glGenFramebuffersEXT glGenFramebuffers
|
||||
#define glDeleteFramebuffersEXT glDeleteFramebuffers
|
||||
#define glCheckFramebufferStatusEXT glCheckFramebufferStatus
|
||||
#define glFramebufferRenderbufferEXT glFramebufferRenderbuffer
|
||||
|
||||
#define GL_OBJECT_INFO_LOG_LENGTH_ARB GL_INFO_LOG_LENGTH
|
||||
#define GL_OBJECT_COMPILE_STATUS_ARB GL_COMPILE_STATUS
|
||||
|
||||
@@ -2755,6 +2755,9 @@ def find_gl_names(dirname, gl1):
|
||||
rv = list(names)
|
||||
rv.sort()
|
||||
|
||||
for i in rv:
|
||||
print(i)
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -181,6 +181,7 @@ for p in generate_styles.prefixes:
|
||||
cython("renpy.styledata.style_{}functions".format(p), pyx=setuplib.gen + "/style_{}functions.pyx".format(p))
|
||||
|
||||
# renpy.display
|
||||
cython("renpy.display.matrix")
|
||||
cython("renpy.display.render", libs=[ 'z', 'm' ])
|
||||
cython("renpy.display.accelerator", libs=sdl + [ 'z', 'm' ])
|
||||
|
||||
@@ -218,11 +219,10 @@ cython("renpy.gl.glrtt_fbo", libs=glew_libs)
|
||||
|
||||
cython("renpy.gl2.uguugl", libs=sdl)
|
||||
cython("renpy.gl2.uguu", libs=sdl)
|
||||
cython("renpy.gl2.gl2geometry")
|
||||
cython("renpy.gl2.gl2draw", libs=sdl)
|
||||
cython("renpy.gl2.gl2texture", libs=sdl)
|
||||
cython("renpy.gl2.gl2environ_shader", libs=sdl)
|
||||
cython("renpy.gl2.gl2rtt_fbo", libs=sdl)
|
||||
|
||||
cython("renpy.gl2.gl2shader", libs=sdl)
|
||||
|
||||
if not (android or ios or emscripten):
|
||||
# renpy.angle
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
from __future__ import print_function
|
||||
from sympy import symbols, Matrix, pi, cos, sin, simplify
|
||||
|
||||
|
||||
matrix_names = [
|
||||
"xdx",
|
||||
"xdy",
|
||||
"xdz",
|
||||
"xdw",
|
||||
|
||||
"ydx",
|
||||
"ydy",
|
||||
"ydz",
|
||||
"ydw",
|
||||
|
||||
"zdx",
|
||||
"zdy",
|
||||
"zdz",
|
||||
"zdw",
|
||||
|
||||
"wdx",
|
||||
"wdy",
|
||||
"wdz",
|
||||
"wdw",
|
||||
]
|
||||
|
||||
|
||||
def prefixed_matrix(prefix):
|
||||
"""
|
||||
Returns a matrix where each entry is of the for prefix___name.
|
||||
"""
|
||||
|
||||
return Matrix(4, 4, [ symbols(prefix + "___" + i) for i in matrix_names ])
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
import cStringIO
|
||||
|
||||
generators = [ ]
|
||||
|
||||
|
||||
class Generator(object):
|
||||
|
||||
def __init__(self, name, docs):
|
||||
self.f = cStringIO.StringIO()
|
||||
|
||||
self.name = name
|
||||
self.docs = docs
|
||||
|
||||
generators.append(self)
|
||||
|
||||
self.first_let = True
|
||||
|
||||
def parameters(self, params):
|
||||
print(file=self.f)
|
||||
print(file=self.f)
|
||||
|
||||
print("def {}({}):".format(
|
||||
self.name,
|
||||
", ".join("float " + i for i in params.split())), file=self.f)
|
||||
|
||||
if self.docs:
|
||||
print(' """' + self.docs + '"""', file=self.f)
|
||||
|
||||
if params.split():
|
||||
return symbols(params)
|
||||
|
||||
def let(self, name, value):
|
||||
|
||||
if self.first_let:
|
||||
print(file=self.f)
|
||||
self.first_let = False
|
||||
|
||||
value = simplify(value, rational=True)
|
||||
|
||||
print(" cdef float {} = {}".format(name, str(value)), file=self.f)
|
||||
|
||||
return symbols(name)
|
||||
|
||||
def matrix(self, m):
|
||||
|
||||
print(file=self.f)
|
||||
|
||||
print(" cdef Matrix rv = Matrix(None)", file=self.f)
|
||||
print(file=self.f)
|
||||
|
||||
for name, value in zip(matrix_names, m):
|
||||
if value == 0.0:
|
||||
continue
|
||||
|
||||
print(" rv.{} =".format(name), simplify(value, rational=True), file=self.f)
|
||||
|
||||
print(file=self.f)
|
||||
print(" return rv", file=self.f)
|
||||
|
||||
|
||||
def generate(func):
|
||||
g = Generator(func.__name__, func.__doc__)
|
||||
func(g)
|
||||
return func
|
||||
|
||||
|
||||
def write(fn):
|
||||
with open(fn, "w") as f:
|
||||
for i in generators:
|
||||
f.write(i.f.getvalue())
|
||||
|
||||
|
||||
@generate
|
||||
def identity(g):
|
||||
"""
|
||||
Returns an identity matrix.
|
||||
"""
|
||||
|
||||
g.parameters("")
|
||||
|
||||
g.matrix(Matrix(4, 4, [
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
]))
|
||||
|
||||
|
||||
@generate
|
||||
def offset(g):
|
||||
"""
|
||||
Returns a matrix that offsets the vertex by a fixed amount.
|
||||
"""
|
||||
|
||||
x, y, z = g.parameters("x y z")
|
||||
|
||||
g.matrix(Matrix(4, 4, [
|
||||
1.0, 0.0, 0.0, x,
|
||||
0.0, 1.0, 0.0, y,
|
||||
0.0, 0.0, 1.0, z,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
]))
|
||||
|
||||
|
||||
@generate
|
||||
def rotate(g):
|
||||
"""
|
||||
Returns a matrix that rotates the displayable around the
|
||||
origin.
|
||||
|
||||
`x`, `y`, `x`
|
||||
The amount to rotate around the origin, in degrees.
|
||||
"""
|
||||
|
||||
x, y, z = g.parameters("x y z")
|
||||
|
||||
sinx = g.let("sinx", sin(x * pi / 180.0))
|
||||
cosx = g.let("cosx", cos(x * pi / 180.0))
|
||||
|
||||
siny = g.let("siny", sin(y * pi / 180.0))
|
||||
cosy = g.let("cosy", cos(y * pi / 180.0))
|
||||
|
||||
sinz = g.let("sinz", sin(z * pi / 180.0))
|
||||
cosz = g.let("cosz", cos(z * pi / 180.0))
|
||||
|
||||
rx = Matrix(4, 4, [
|
||||
1, 0, 0, 0,
|
||||
0, cosx, -sinx, 0,
|
||||
0, sinx, cosx, 0,
|
||||
0, 0, 0, 1 ])
|
||||
|
||||
ry = Matrix(4, 4, [
|
||||
cosy, 0, siny, 0,
|
||||
0, 1, 0, 0,
|
||||
-siny, 0, cosy, 0,
|
||||
0, 0, 0, 1])
|
||||
|
||||
rz = Matrix(4, 4, [
|
||||
cosz, -sinz, 0, 0,
|
||||
sinz, cosz, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1, ])
|
||||
|
||||
g.matrix(rz * ry * rx)
|
||||
|
||||
|
||||
@generate
|
||||
def perspective(g):
|
||||
"""
|
||||
Returns the Ren'Py projection matrix. This is a view into a 3d space
|
||||
where (0, 0) is the top left corner (`w`/2, `h`/2) is the center, and
|
||||
(`w`,`h`) is the bottom right, when the z coordinate is 0.
|
||||
|
||||
`w`, `h`
|
||||
The width and height of the input plane, in pixels.
|
||||
|
||||
`n`
|
||||
The distance of the near plane from the camera.
|
||||
|
||||
`p`
|
||||
The distance of the 1:1 plane from the camera. This is where 1 pixel
|
||||
is one coordinate unit.
|
||||
|
||||
`f`
|
||||
The distance of the far plane from the camera.
|
||||
"""
|
||||
|
||||
w, h, n, p, f = g.parameters('w h n p f')
|
||||
|
||||
offset = Matrix(4, 4, [
|
||||
1.0, 0.0, 0.0, -w / 2.0,
|
||||
0.0, 1.0, 0.0, -h / 2.0,
|
||||
0.0, 0.0, 1.0, -p,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
])
|
||||
|
||||
projection = Matrix(4, 4, [
|
||||
2.0 * p / w, 0.0, 0.0, 0.0,
|
||||
0.0, 2.0 * p / h, 0.0, 0.0,
|
||||
0.0, 0.0, -(f+n)/(f-n), -2 * f * n / (f - n),
|
||||
0.0, 0.0, -1.0, 0.0,
|
||||
])
|
||||
|
||||
reverse_offset = Matrix(4, 4, [
|
||||
w / 2.0, 0.0, 0.0, w / 2.0,
|
||||
0.0, h / 2.0, 0.0, h / 2.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,
|
||||
])
|
||||
|
||||
g.matrix(reverse_offset * projection * offset)
|
||||
|
||||
|
||||
@generate
|
||||
def screen_projection(g):
|
||||
"""
|
||||
This generates a matrix that projects the Ren'Py space, where (0, 0) is the
|
||||
top left and (`w`, `h`) is the bottom right, into the OpenGL viewport, where
|
||||
(-1.0, 1.0) is the top left and (1.0, -1.0) is the bottom.
|
||||
|
||||
Generates the matrix that projects the Ren'Py screen to the OpenGL screen.
|
||||
"""
|
||||
|
||||
w, h = g.parameters("w h")
|
||||
|
||||
m = Matrix(4, 4, [
|
||||
2.0 / w, 0.0, 0.0, -1.0,
|
||||
0.0, -2.0 / h, 0.0, 1.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
])
|
||||
|
||||
g.matrix(m)
|
||||
|
||||
|
||||
@generate
|
||||
def texture_projection(g):
|
||||
"""
|
||||
This generates a matrix that project the Ren'Py space, where (0, 0) is the
|
||||
top left and (`w`, `h`) is the bottom right, into the OpenGL render-to-texture
|
||||
space, where (-1.0, -1.0) is the top left and (1.0, 1.0) is the bottom.
|
||||
|
||||
Generates the matrix that projects the Ren'Py screen to the OpenGL screen.
|
||||
"""
|
||||
|
||||
w, h = g.parameters("w h")
|
||||
|
||||
m = Matrix(4, 4, [
|
||||
2.0 / w, 0.0, 0.0, -1.0,
|
||||
0.0, 2.0 / h, 0.0, -1.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
])
|
||||
|
||||
g.matrix(m)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
|
||||
RENPY = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
write(os.path.join(RENPY, "renpy", "display", "matrix_functions.pxi"))
|
||||
@@ -6,7 +6,7 @@ from libc.stdlib cimport calloc, free
|
||||
from cpython.buffer cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_CONTIG, PyBUF_CONTIG_RO
|
||||
|
||||
cimport uguugl
|
||||
from uguugl import reset_error, get_error, enable_check_error, load
|
||||
from uguugl import load
|
||||
|
||||
cdef object proxy_return_string(const GLubyte *s):
|
||||
"""
|
||||
|
||||
@@ -12,41 +12,3 @@ cdef void *find_gl_command(names):
|
||||
|
||||
raise Exception("{} not found.".format(names[0]))
|
||||
|
||||
|
||||
cdef const char *error_function
|
||||
cdef GLenum error_code
|
||||
|
||||
def reset_error():
|
||||
"""
|
||||
Resets the
|
||||
"""
|
||||
|
||||
global error_function
|
||||
error_function = NULL
|
||||
|
||||
global error_code
|
||||
error_code = GL_NO_ERROR
|
||||
|
||||
reset_error()
|
||||
|
||||
def get_error():
|
||||
|
||||
if error_function != NULL:
|
||||
return error_function.decode("utf-8"), error_code
|
||||
else:
|
||||
return None, GL_NO_ERROR
|
||||
|
||||
|
||||
cdef void check_error(const char *function) nogil:
|
||||
|
||||
global error_function
|
||||
global error_code
|
||||
|
||||
cdef GLenum error
|
||||
|
||||
error = real_glGetError()
|
||||
|
||||
if (error_function == NULL) and (error != GL_NO_ERROR):
|
||||
error_function = function
|
||||
error_code = error
|
||||
|
||||
|
||||
@@ -304,28 +304,10 @@ class XMLToPYX:
|
||||
c = self.commands[i]
|
||||
|
||||
w("")
|
||||
w(f"cdef {i}_type real_{i}")
|
||||
w(f"cdef {i}_type {i}")
|
||||
|
||||
w("")
|
||||
|
||||
param_list = c.format_param_list()
|
||||
proxy_call = c.format_proxy_call()
|
||||
|
||||
if c.return_type != "void":
|
||||
|
||||
w(f'cdef {c.return_type} check_{i}{param_list} nogil:')
|
||||
w(f' cdef {c.return_type} rv')
|
||||
w(f' rv = real_{i}{proxy_call}')
|
||||
w(f' check_error("{i}")')
|
||||
w(f' return rv')
|
||||
|
||||
else:
|
||||
|
||||
w(f'cdef {c.return_type} check_{i}{param_list} nogil:')
|
||||
w(f' real_{i}{proxy_call}')
|
||||
w(f' check_error("{i}")')
|
||||
|
||||
w("")
|
||||
w("def load():")
|
||||
|
||||
@@ -339,16 +321,8 @@ class XMLToPYX:
|
||||
names = [ i.encode("utf-8") for i in names ]
|
||||
|
||||
w(f"")
|
||||
w(f" global real_{i}, {i}")
|
||||
w(f" real_{i} = <{i}_type> find_gl_command({names!r})")
|
||||
w(f" {i} = real_{i}")
|
||||
|
||||
w("")
|
||||
w("def enable_check_error():")
|
||||
|
||||
for i in sorted(self.features.commands):
|
||||
w(f" global {i}")
|
||||
w(f" {i} = check_{i}")
|
||||
w(f" {i} = <{i}_type> find_gl_command({names!r})")
|
||||
|
||||
def generate_uguu_pyx(self, f):
|
||||
|
||||
|
||||
@@ -48,3 +48,4 @@ BLIT = int
|
||||
DISSOLVE = int
|
||||
IMAGEDISSOLVE = int
|
||||
PIXELLATE = int
|
||||
FLATTEN = int
|
||||
|
||||
+13
-2
@@ -40,7 +40,7 @@ except ImportError:
|
||||
vc_version = 0
|
||||
|
||||
# The tuple giving the version number.
|
||||
version_tuple = (7, 3, 2, vc_version)
|
||||
version_tuple = (7, 3, 3, vc_version)
|
||||
|
||||
# The name of this version.
|
||||
version_name = "The world (wide web) is not enough."
|
||||
@@ -171,6 +171,7 @@ backup_blacklist = {
|
||||
"renpy.test.testkey",
|
||||
"renpy.test.testmouse",
|
||||
"renpy.test.testparser",
|
||||
"renpy.gl2",
|
||||
"renpycoverage",
|
||||
}
|
||||
|
||||
@@ -586,7 +587,7 @@ def reload_all():
|
||||
renpy.display.render.mark_sweep()
|
||||
|
||||
# Get rid of the draw module and interface.
|
||||
renpy.display.draw.deinit()
|
||||
renpy.display.draw.quit()
|
||||
renpy.display.draw = None
|
||||
renpy.display.interface = None
|
||||
|
||||
@@ -654,6 +655,8 @@ def import_cython():
|
||||
import renpy.arguments
|
||||
|
||||
import renpy.display.accelerator
|
||||
|
||||
import renpy.display.matrix
|
||||
import renpy.display.render
|
||||
|
||||
import renpy.gl.gl
|
||||
@@ -673,6 +676,14 @@ def import_cython():
|
||||
import renpy.angle.glrtt_fbo
|
||||
import renpy.angle.gltexture
|
||||
|
||||
import renpy.gl2.gl2draw
|
||||
import renpy.gl2.gl2ftl
|
||||
import renpy.gl2.gl2geometry
|
||||
import renpy.gl2.gl2shader
|
||||
import renpy.gl2.gl2texture
|
||||
import renpy.gl2.uguu
|
||||
import renpy.gl2.uguugl
|
||||
|
||||
|
||||
if False:
|
||||
import renpy.defaultstore as store
|
||||
|
||||
@@ -1526,16 +1526,19 @@ cdef extern from "glcompat.h" nogil:
|
||||
cdef int glActiveTextureARB(GLenum) except? 0
|
||||
cdef int glAttachObjectARB(GLhandleARB, GLhandleARB) except? 0
|
||||
cdef int glBindFramebufferEXT(GLenum, GLuint) except? 0
|
||||
cdef int glBindRenderbufferEXT(GLenum, GLuint) except? 0
|
||||
cdef int glBindTexture(GLenum, GLuint) except? 0
|
||||
cdef int glBlendFunc(GLenum, GLenum) except? 0
|
||||
cdef int glClear(GLbitfield) except? 0
|
||||
cdef int glClearColor(GLclampf, GLclampf, GLclampf, GLclampf) except? 0
|
||||
cdef int glCompileShaderARB(GLhandleARB) except? 0
|
||||
cdef int glCopyTexImage2D(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) except? 0
|
||||
cdef int glCopyTexSubImage2D(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) except? 0
|
||||
cdef GLhandleARB glCreateProgramObjectARB() except? 0
|
||||
cdef GLhandleARB glCreateShaderObjectARB(GLenum) except? 0
|
||||
cdef int glDeleteFramebuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glDeleteProgram(GLuint) except? 0
|
||||
cdef int glDeleteRenderbuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glDeleteShader(GLuint) except? 0
|
||||
cdef int glDeleteTextures(GLsizei, GLuint *) except? 0
|
||||
cdef int glDisable(GLenum) except? 0
|
||||
@@ -1544,8 +1547,10 @@ cdef int glDrawArrays(GLenum, GLint, GLsizei) except? 0
|
||||
cdef int glEnable(GLenum) except? 0
|
||||
cdef int glEnableVertexAttribArrayARB(GLuint) except? 0
|
||||
cdef int glFinish() except? 0
|
||||
cdef int glFramebufferRenderbufferEXT(GLenum, GLenum, GLenum, GLuint) except? 0
|
||||
cdef int glFramebufferTexture2DEXT(GLenum, GLenum, GLenum, GLuint, GLint) except? 0
|
||||
cdef int glGenFramebuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glGenRenderbuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glGenTextures(GLsizei, GLuint *) except? 0
|
||||
cdef GLint glGetAttribLocationARB(GLhandleARB, GLchar *) except? 0
|
||||
cdef int glGetIntegerv(GLenum, GLint *) except? 0
|
||||
@@ -1557,6 +1562,7 @@ cdef GLchar * glGetString(GLenum) except? NULL
|
||||
cdef GLint glGetUniformLocationARB(GLhandleARB, GLchar *) except? 0
|
||||
cdef int glLinkProgramARB(GLhandleARB) except? 0
|
||||
cdef int glReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLubyte *) except? 0
|
||||
cdef int glRenderbufferStorageEXT(GLenum, GLenum, GLsizei, GLsizei) except? 0
|
||||
cdef int glScissor(GLint, GLint, GLsizei, GLsizei) except? 0
|
||||
cdef int glShaderSourceARB(GLhandleARB, GLsizei, GLchar * *, GLint *) except? 0
|
||||
cdef int glTexImage2D(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, GLubyte *) except? 0
|
||||
|
||||
+90
-2
@@ -1,5 +1,3 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import renpy
|
||||
|
||||
@@ -52,6 +50,21 @@ cdef int glBindFramebufferEXT(GLenum a0, GLuint a1) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glBindRenderbufferEXT(GLenum a0, GLuint a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glBindRenderbufferEXT')
|
||||
cdef GLenum error
|
||||
realGlBindRenderbufferEXT(a0, a1)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glBindRenderbufferEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glBindTexture(GLenum a0, GLuint a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glBindTexture')
|
||||
@@ -128,6 +141,21 @@ cdef int glCompileShaderARB(GLhandleARB a0) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glCopyTexImage2D(GLenum a0, GLint a1, GLenum a2, GLint a3, GLint a4, GLsizei a5, GLsizei a6, GLint a7) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glCopyTexImage2D')
|
||||
cdef GLenum error
|
||||
realGlCopyTexImage2D(a0, a1, a2, a3, a4, a5, a6, a7)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glCopyTexImage2D' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glCopyTexSubImage2D(GLenum a0, GLint a1, GLint a2, GLint a3, GLint a4, GLint a5, GLsizei a6, GLsizei a7) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glCopyTexSubImage2D')
|
||||
@@ -203,6 +231,21 @@ cdef int glDeleteProgram(GLuint a0) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glDeleteRenderbuffersEXT(GLsizei a0, GLuint * a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glDeleteRenderbuffersEXT')
|
||||
cdef GLenum error
|
||||
realGlDeleteRenderbuffersEXT(a0, a1)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glDeleteRenderbuffersEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glDeleteShader(GLuint a0) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glDeleteShader')
|
||||
@@ -323,6 +366,21 @@ cdef int glFinish() except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glFramebufferRenderbufferEXT(GLenum a0, GLenum a1, GLenum a2, GLuint a3) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glFramebufferRenderbufferEXT')
|
||||
cdef GLenum error
|
||||
realGlFramebufferRenderbufferEXT(a0, a1, a2, a3)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glFramebufferRenderbufferEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glFramebufferTexture2DEXT(GLenum a0, GLenum a1, GLenum a2, GLuint a3, GLint a4) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glFramebufferTexture2DEXT')
|
||||
@@ -353,6 +411,21 @@ cdef int glGenFramebuffersEXT(GLsizei a0, GLuint * a1) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glGenRenderbuffersEXT(GLsizei a0, GLuint * a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glGenRenderbuffersEXT')
|
||||
cdef GLenum error
|
||||
realGlGenRenderbuffersEXT(a0, a1)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glGenRenderbuffersEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glGenTextures(GLsizei a0, GLuint * a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glGenTextures')
|
||||
@@ -518,6 +591,21 @@ cdef int glReadPixels(GLint a0, GLint a1, GLsizei a2, GLsizei a3, GLenum a4, GLe
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glRenderbufferStorageEXT(GLenum a0, GLenum a1, GLsizei a2, GLsizei a3) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glRenderbufferStorageEXT')
|
||||
cdef GLenum error
|
||||
realGlRenderbufferStorageEXT(a0, a1, a2, a3)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glRenderbufferStorageEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glScissor(GLint a0, GLint a1, GLsizei a2, GLsizei a3) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glScissor')
|
||||
|
||||
+3
-1
@@ -356,9 +356,10 @@ class Node(object):
|
||||
A node in the abstract syntax tree of the program.
|
||||
|
||||
@ivar name: The name of this node.
|
||||
|
||||
@ivar filename: The filename where this node comes from.
|
||||
@ivar linenumber: The line number of the line on which this node is defined.
|
||||
@ivar next: The statement that will execute after this one.
|
||||
@ivar statement_start: If present, the first node that makes up the statement that includes this node.
|
||||
"""
|
||||
|
||||
__slots__ = [
|
||||
@@ -366,6 +367,7 @@ class Node(object):
|
||||
'filename',
|
||||
'linenumber',
|
||||
'next',
|
||||
'statement_start',
|
||||
]
|
||||
|
||||
# True if this node is translatable, false otherwise. (This can be set on
|
||||
|
||||
@@ -1828,6 +1828,7 @@ def parse_atl(l):
|
||||
if l.keyword('circles'):
|
||||
expr = l.require(l.simple_expression)
|
||||
rm.add_circles(expr)
|
||||
continue
|
||||
|
||||
# Try to parse a property.
|
||||
cp = l.checkpoint()
|
||||
|
||||
+54
-17
@@ -36,6 +36,7 @@ import os
|
||||
import re
|
||||
import threading
|
||||
import sys
|
||||
import io
|
||||
|
||||
# Import the appropriate modules, or set them to None if we cannot.
|
||||
|
||||
@@ -73,6 +74,42 @@ def load(fn):
|
||||
return rv
|
||||
|
||||
|
||||
class AudioData(unicode):
|
||||
"""
|
||||
:doc: audio
|
||||
|
||||
This class wraps a bytes object containing audio data, so it can be
|
||||
passed to the audio playback system. The audio data should be contained
|
||||
in some format Ren'Py supports. (For examples RIFF WAV format headers,
|
||||
not unadorned samples.)
|
||||
|
||||
`data`
|
||||
A bytes object containing the audio file data.
|
||||
|
||||
`filename`
|
||||
A synthetic filename associated with this data. It can be used to
|
||||
suggest the format `data` is in, and is reported as part of
|
||||
error messages.
|
||||
|
||||
Once created, this can be used wherever an audio filename is allowed. For
|
||||
example::
|
||||
|
||||
define audio.easteregg = AudioData(b'...', 'sample.wav')
|
||||
play sound easteregg
|
||||
"""
|
||||
|
||||
def __new__(cls, data, filename):
|
||||
rv = unicode.__new__(cls, filename)
|
||||
rv.data = data
|
||||
return rv
|
||||
|
||||
def __init__(self, data, filename):
|
||||
pass
|
||||
|
||||
def __reduce__(self):
|
||||
return(AudioData, (self.data, unicode(self)))
|
||||
|
||||
|
||||
class QueueEntry(object):
|
||||
"""
|
||||
A queue entry object.
|
||||
@@ -359,9 +396,6 @@ class Channel(object):
|
||||
self.queue = [ ]
|
||||
return
|
||||
|
||||
# Should we do the callback?
|
||||
do_callback = False
|
||||
|
||||
topq = None
|
||||
|
||||
# This has been modified so we only queue a single sound file
|
||||
@@ -417,7 +451,10 @@ class Channel(object):
|
||||
if (end >= 0) and ((end - start) <= 0) and self.queue:
|
||||
continue
|
||||
|
||||
topf = load(self.file_prefix + filename + self.file_suffix)
|
||||
if isinstance(topq.filename, AudioData):
|
||||
topf = io.BytesIO(topq.filename.data)
|
||||
else:
|
||||
topf = load(self.file_prefix + filename + self.file_suffix)
|
||||
|
||||
renpysound.set_video(self.number, self.movie)
|
||||
|
||||
@@ -442,20 +479,20 @@ class Channel(object):
|
||||
|
||||
break
|
||||
|
||||
if self.loop and not self.queue:
|
||||
for i in self.loop:
|
||||
if topq is not None:
|
||||
newq = QueueEntry(i, 0, topq.tight, True)
|
||||
else:
|
||||
newq = QueueEntry(i, 0, False, True)
|
||||
# Empty queue?
|
||||
if not self.queue:
|
||||
# Re-loop:
|
||||
if self.loop:
|
||||
for i in self.loop:
|
||||
if topq is not None:
|
||||
newq = QueueEntry(i, 0, topq.tight, True)
|
||||
else:
|
||||
newq = QueueEntry(i, 0, False, True)
|
||||
|
||||
self.queue.append(newq)
|
||||
else:
|
||||
do_callback = True
|
||||
|
||||
# Queue empty callback.
|
||||
if do_callback and self.callback:
|
||||
self.callback() # E1102
|
||||
self.queue.append(newq)
|
||||
# Try callback:
|
||||
elif self.callback:
|
||||
self.callback() # E1102
|
||||
|
||||
want_pause = self.context.pause or global_pause
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@ def extra_imports():
|
||||
import pstats; pstats
|
||||
import _ssl; _ssl
|
||||
import SimpleHTTPServer; SimpleHTTPServer
|
||||
import wave; wave
|
||||
import sunau; sunau
|
||||
|
||||
# Used by requests.
|
||||
import cgi; cgi
|
||||
|
||||
+2
-2
@@ -975,12 +975,10 @@ class ADVCharacter(object):
|
||||
|
||||
trans, layer = renpy.config.say_attribute_transition_callback(
|
||||
self.image_tag, mode, *delta)
|
||||
|
||||
if trans is not None:
|
||||
if layer is None:
|
||||
renpy.exports.with_statement(trans)
|
||||
else:
|
||||
renpy.exports.with_statement(None)
|
||||
renpy.exports.transition(trans, layer=layer)
|
||||
|
||||
def restore_say_attributes(self, predicting, state, interact):
|
||||
@@ -1094,6 +1092,8 @@ class ADVCharacter(object):
|
||||
if interact:
|
||||
mode = _mode or self.mode
|
||||
renpy.exports.mode(mode)
|
||||
else:
|
||||
renpy.game.context().deferred_translate_identifier = renpy.game.context().translate_identifier
|
||||
|
||||
# Figure out the arguments to display.
|
||||
display_args = self.display_args.copy()
|
||||
|
||||
@@ -74,19 +74,29 @@ init -1500 python:
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
This allows an expression to control if a button should be marked
|
||||
as selected. It should be used as part of a list with one or more
|
||||
actions. For example::
|
||||
This indicates that one action in a list of actions should be used
|
||||
to determine if a button is selected. This only makes sense
|
||||
when the button has a list of actions. For example::
|
||||
|
||||
# The button is selected if mars_flag is True
|
||||
# The button is selected only if mars_flag is True
|
||||
textbutton "Marsopolis":
|
||||
action [ Jump("mars"), SelectedIf(mars_flag) ]
|
||||
action [ SelectedIf(SetVariable("mars_flag", True)), SetVariable("on_mars", True) ]
|
||||
|
||||
The action inside SelectedIf is run normally when the button is clicked.
|
||||
"""
|
||||
|
||||
# Note: This had been documented to take a boolean.
|
||||
|
||||
def __init__(self, expression):
|
||||
self.expression = expression
|
||||
|
||||
if isinstance(expression, Action):
|
||||
for i in [ "get_selected", "get_sensitive", "get_tooltip", "periodic", "unhovered", "unhovered" ]:
|
||||
setattr(self, i, getattr(expression, i, None))
|
||||
|
||||
def __call__(self):
|
||||
if isinstance(self.expression, Action):
|
||||
return self.expression()
|
||||
return None
|
||||
|
||||
def get_selected(self):
|
||||
@@ -97,19 +107,29 @@ init -1500 python:
|
||||
"""
|
||||
:doc: other_action
|
||||
|
||||
This allows an expression to control if a button should be marked
|
||||
as sensitive. It should be used as part of a list with one or more
|
||||
actions. For example::
|
||||
This indicates that one action in a list of actions should be used
|
||||
to determine if a button is sensitive. This only makes sense
|
||||
when the button has a list of actions. For example::
|
||||
|
||||
# The button is sensitive if mars_flag is True
|
||||
# The button is sensitive only if mars_flag is True
|
||||
textbutton "Marsopolis":
|
||||
action [ Jump("mars"), SensitiveIf(mars_flag) ]
|
||||
action [ SensitiveIf(SetVariable("mars_flag", True)), SetVariable("on_mars", True) ]
|
||||
|
||||
The action inside SensitiveIf is run normally when the button is clicked.
|
||||
"""
|
||||
|
||||
# Note: This had been documented to take a boolean.
|
||||
|
||||
def __init__(self, expression):
|
||||
self.expression = expression
|
||||
|
||||
if isinstance(expression, Action):
|
||||
for i in [ "get_selected", "get_sensitive", "get_tooltip", "periodic", "unhovered", "unhovered" ]:
|
||||
setattr(self, i, getattr(expression, i, None))
|
||||
|
||||
def __call__(self):
|
||||
if isinstance(self.expression, Action):
|
||||
return self.expression()
|
||||
return None
|
||||
|
||||
def get_sensitive(self):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2004-2019 Tom Rothamel <pytom@bishoujo.us>
|
||||
# Copyright 2004-2019 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,30 +19,30 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
init -1900 python:
|
||||
config.audio_directory = 'audio'
|
||||
|
||||
# The blacklist of OpenGL cards. Fields are:
|
||||
# - A substring of the Renderer.
|
||||
# - A substring of the Version.
|
||||
# - True to allow shader rendering.
|
||||
# - True to allow fixed-function rendering.
|
||||
def _scan_audio_directory():
|
||||
|
||||
# If both of the last two entries are false, GL refuses to
|
||||
# start.
|
||||
import os
|
||||
|
||||
from __future__ import print_function
|
||||
if not config.audio_directory:
|
||||
return
|
||||
|
||||
BLACKLIST = [
|
||||
prefix = config.audio_directory.rstrip('/') + '/'
|
||||
|
||||
# Crashes for Mugenjohncel.
|
||||
("S3 Graphics DeltaChrome", "1.4 20.00", False, False),
|
||||
for fn in renpy.list_files():
|
||||
if not fn.startswith(prefix):
|
||||
continue
|
||||
|
||||
# A bug in Mesa 7.9 and 7.10 (before 7.10.3) causes the system to
|
||||
# fail to initialize the GLSL compiler.
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=35603
|
||||
("Mesa", "Mesa 7.9", False, True),
|
||||
("Mesa", "Mesa 7.10.3", True, True),
|
||||
("Mesa", "Mesa 7.10", False, True),
|
||||
basename = os.path.basename(fn)
|
||||
base, ext = os.path.splitext(basename)
|
||||
|
||||
# Default to allowing everything.
|
||||
("", "", True, True),
|
||||
]
|
||||
if not ext.lower() in [ ".wav", ".mp2", ".mp3", ".ogg", ".opus" ]:
|
||||
continue
|
||||
|
||||
base = base.lower()
|
||||
audio.__dict__.setdefault(base, fn)
|
||||
|
||||
init python:
|
||||
_scan_audio_directory()
|
||||
@@ -145,17 +145,19 @@ init -1500 python:
|
||||
|
||||
offset = 0
|
||||
action = None
|
||||
force_step = False
|
||||
|
||||
identity_fields = [ 'dict' ]
|
||||
equality_fields = [ 'key', 'range', 'max_is_zero', 'style', 'offset', 'step', 'action']
|
||||
equality_fields = [ 'key', 'range', 'max_is_zero', 'style', 'offset', 'step', 'action', 'force_step' ]
|
||||
|
||||
def __init__(self, dict, key, range, max_is_zero=False, style="bar", offset=0, step=None, action=None):
|
||||
def __init__(self, dict, key, range, max_is_zero=False, style="bar", offset=0, step=None, action=None, force_step=False):
|
||||
self.dict = dict
|
||||
self.key = key
|
||||
self.range = range
|
||||
self.max_is_zero = max_is_zero
|
||||
self.style = style
|
||||
self.offset = offset
|
||||
self.force_step = force_step
|
||||
|
||||
if step is None:
|
||||
if isinstance(range, float):
|
||||
@@ -197,7 +199,9 @@ init -1500 python:
|
||||
range=self.range,
|
||||
value=value,
|
||||
changed=self.changed,
|
||||
step=self.step)
|
||||
step=self.step,
|
||||
force_step=self.force_step,
|
||||
)
|
||||
|
||||
def get_style(self):
|
||||
return self.style, "v" + self.style
|
||||
@@ -236,17 +240,19 @@ init -1500 python:
|
||||
|
||||
offset = 0
|
||||
action = None
|
||||
force_step = False
|
||||
|
||||
identity_fields = [ 'object', ]
|
||||
equality_fields = [ 'range', 'max_is_zero', 'style', 'offset', 'step', 'action']
|
||||
equality_fields = [ 'range', 'max_is_zero', 'style', 'offset', 'step', 'action', 'force_step' ]
|
||||
|
||||
def __init__(self, object, field, range, max_is_zero=False, style="bar", offset=0, step=None, action=None):
|
||||
def __init__(self, object, field, range, max_is_zero=False, style="bar", offset=0, step=None, action=None, force_step=False):
|
||||
self.object = object
|
||||
self.field = field
|
||||
self.range = range
|
||||
self.max_is_zero = max_is_zero
|
||||
self.style = style
|
||||
self.offset = offset
|
||||
self.force_step = force_step
|
||||
|
||||
if step is None:
|
||||
if isinstance(range, float):
|
||||
@@ -288,13 +294,15 @@ init -1500 python:
|
||||
range=self.range,
|
||||
value=value,
|
||||
changed=self.changed,
|
||||
step=self.step)
|
||||
step=self.step,
|
||||
force_step=self.force_step,
|
||||
)
|
||||
|
||||
def get_style(self):
|
||||
return self.style, "v" + self.style
|
||||
|
||||
@renpy.pure
|
||||
def VariableValue(variable, range, max_is_zero=False, style="bar", offset=0, step=None, action=None):
|
||||
def VariableValue(variable, range, max_is_zero=False, style="bar", offset=0, step=None, action=None, force_step=False):
|
||||
"""
|
||||
:doc: value
|
||||
|
||||
@@ -323,7 +331,7 @@ init -1500 python:
|
||||
If not None, an action to call when the field has changed.
|
||||
"""
|
||||
|
||||
return FieldValue(store, variable, range, max_is_zero=max_is_zero, style=style, offset=offset, step=step, action=action)
|
||||
return FieldValue(store, variable, range, max_is_zero=max_is_zero, style=style, offset=offset, step=step, action=action, force_step=force_step)
|
||||
|
||||
@renpy.pure
|
||||
class ScreenVariableValue(BarValue, FieldEquality):
|
||||
@@ -356,16 +364,18 @@ init -1500 python:
|
||||
|
||||
action = None
|
||||
offset = 0
|
||||
force_step = False
|
||||
|
||||
identity_fields = [ ]
|
||||
equality_fields = [ 'variable', 'max_is_zero', 'style', 'offset', 'step', 'action']
|
||||
equality_fields = [ 'variable', 'max_is_zero', 'style', 'offset', 'step', 'action', 'force_step' ]
|
||||
|
||||
def __init__(self, variable, range, max_is_zero=False, style="bar", offset=0, step=None, action=None):
|
||||
def __init__(self, variable, range, max_is_zero=False, style="bar", offset=0, step=None, action=None, force_step=False):
|
||||
self.variable = variable
|
||||
self.range = range
|
||||
self.max_is_zero = max_is_zero
|
||||
self.style = style
|
||||
self.offset = offset
|
||||
self.force_step = force_step
|
||||
|
||||
if step is None:
|
||||
if isinstance(range, float):
|
||||
@@ -414,7 +424,9 @@ init -1500 python:
|
||||
range=self.range,
|
||||
value=value,
|
||||
changed=self.changed,
|
||||
step=self.step)
|
||||
step=self.step,
|
||||
force_step=self.force_step,
|
||||
)
|
||||
|
||||
def get_style(self):
|
||||
return self.style, "v" + self.style
|
||||
|
||||
@@ -389,13 +389,13 @@ init -1500 python in build:
|
||||
mac_identity = None
|
||||
|
||||
# The command used for mac codesigning.
|
||||
mac_codesign_command = [ "/usr/bin/codesign", "-s", "{identity}", "-f", "--deep", "--no-strict", "{app}" ]
|
||||
mac_codesign_command = [ "/usr/bin/codesign", "--entitlements={entitlements}", "--options=runtime", "--timestamp", "-s", "{identity}", "-f", "--deep", "--no-strict", "{app}" ]
|
||||
|
||||
# The command used to build a dmg.
|
||||
mac_create_dmg_command = [ "/usr/bin/hdiutil", "create", "-format", "UDBZ", "-volname", "{volname}", "-srcfolder", "{sourcedir}", "-ov", "{dmg}" ]
|
||||
|
||||
# The command used to sign a dmg.
|
||||
mac_codesign_dmg_command = [ "/usr/bin/codesign", "-s", "{identity}", "-f", "{dmg}" ]
|
||||
mac_codesign_dmg_command = [ "/usr/bin/codesign", "--timestamp", "-s", "{identity}", "-f", "{dmg}" ]
|
||||
|
||||
# Do we want to add the script_version file?
|
||||
script_version = True
|
||||
|
||||
@@ -190,6 +190,10 @@ init -1900 python:
|
||||
if version <= (7, 3, 0):
|
||||
config.force_sound = False
|
||||
|
||||
if version <= (7, 3, 2):
|
||||
config.audio_directory = None
|
||||
config.early_start_store = True
|
||||
|
||||
# The version of Ren'Py this script is intended for, or
|
||||
# None if it's intended for the current version.
|
||||
config.script_version = None
|
||||
|
||||
@@ -388,8 +388,11 @@ init -1500 python:
|
||||
|
||||
renderer_info = renpy.get_renderer_info()
|
||||
|
||||
if config.gl2 and not renderer_info.get("models", False):
|
||||
problem = "fixed"
|
||||
|
||||
# Software renderer check.
|
||||
if config.renderer != "sw" and renderer_info["renderer"] == "sw":
|
||||
elif config.renderer != "sw" and renderer_info["renderer"] == "sw":
|
||||
problem = "sw"
|
||||
|
||||
# Speed check.
|
||||
|
||||
@@ -39,6 +39,9 @@ init -1100 python in gui:
|
||||
The height of the default window.
|
||||
"""
|
||||
|
||||
if (not renpy.is_init_phase()) and config.developer:
|
||||
raise Exception("gui.init may only be called during the init phase.")
|
||||
|
||||
config.screen_width = width
|
||||
config.screen_height = height
|
||||
|
||||
|
||||
@@ -456,6 +456,7 @@ init -1500 python:
|
||||
|
||||
|
||||
renpy.mode('nvl_menu')
|
||||
renpy.shown_window()
|
||||
|
||||
if nvl_list is None:
|
||||
store.nvl_list = [ ]
|
||||
|
||||
@@ -200,7 +200,7 @@ init -1500 python:
|
||||
* Preference("gl tearing", False) - Skips frames rather than tearing.
|
||||
|
||||
* Preference("font transform", "opendyslexic") - Sets the accessibility font transform to opendyslexic.
|
||||
* Preference("font transform", "dejavusans") - Sets the accessibility font trandform to deja vu sans.
|
||||
* Preference("font transform", "dejavusans") - Sets the accessibility font transform to deja vu sans.
|
||||
* Preference("font transform", None) - Disables the accessibility font transform.
|
||||
|
||||
* Preference("font size", 1.0) - Sets the accessibility font size scaling factor.
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
init python:
|
||||
|
||||
renpy.register_shader("renpy.geometry", variables="""
|
||||
uniform mat4 uTransform;
|
||||
attribute vec4 aPosition;
|
||||
""", vertex_100="""
|
||||
gl_Position = uTransform * aPosition;
|
||||
""")
|
||||
|
||||
renpy.register_shader("renpy.texture", variables="""
|
||||
uniform sampler2D uTex0;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
""", vertex_110="""
|
||||
vTexCoord = aTexCoord;
|
||||
""", fragment_110="""
|
||||
gl_FragColor = texture2D(uTex0, vTexCoord.xy);
|
||||
""")
|
||||
|
||||
renpy.register_shader("renpy.solid", variables="""
|
||||
uniform vec4 uSolidColor;
|
||||
""", fragment_110="""
|
||||
gl_FragColor = uSolidColor;
|
||||
""")
|
||||
|
||||
renpy.register_shader("renpy.dissolve", variables="""
|
||||
uniform sampler2D uTex0;
|
||||
uniform sampler2D uTex1;
|
||||
uniform float uDissolve;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
""", vertex_110="""
|
||||
vTexCoord = aTexCoord;
|
||||
""", fragment_110="""
|
||||
vec4 color0 = texture2D(uTex0, vTexCoord.st);
|
||||
vec4 color1 = texture2D(uTex1, vTexCoord.st);
|
||||
|
||||
gl_FragColor = mix(color0, color1, uDissolve);
|
||||
""")
|
||||
|
||||
renpy.register_shader("renpy.imagedissolve", variables="""
|
||||
uniform sampler2D uTex0;
|
||||
uniform sampler2D uTex1;
|
||||
uniform sampler2D uTex2;
|
||||
uniform float uDissolveOffset;
|
||||
uniform float uDissolveMultiplier;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
""", vertex_110="""
|
||||
vTexCoord = aTexCoord;
|
||||
""", fragment_110="""
|
||||
vec4 color0 = texture2D(uTex0, vTexCoord.st);
|
||||
vec4 color1 = texture2D(uTex1, vTexCoord.st);
|
||||
vec4 color2 = texture2D(uTex2, vTexCoord.st);
|
||||
|
||||
float a = clamp((color0.a + uDissolveOffset) * uDissolveMultiplier, 0.0, 1.0);
|
||||
gl_FragColor = mix(color1, color2, a);
|
||||
""")
|
||||
|
||||
|
||||
renpy.register_shader("renpy.colormatrix", variables="""
|
||||
uniform mat4 uColorMatrix;
|
||||
""", fragment_120="""
|
||||
gl_FragColor = gl_FragColor * uColorMatrix;
|
||||
""")
|
||||
|
||||
renpy.register_shader("renpy.alpha", variables="""
|
||||
uniform float uAlpha;
|
||||
uniform float uOver;
|
||||
""", fragment_130="""
|
||||
gl_FragColor = gl_FragColor * vec4(uAlpha, uAlpha, uAlpha, uAlpha * uOver);
|
||||
""")
|
||||
|
||||
renpy.register_shader("renpy.ftl", variables="""
|
||||
attribute vec4 aPosition;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
uniform sampler2D uTex0;
|
||||
""", vertex_100="""
|
||||
vTexCoord = aTexCoord;
|
||||
gl_Position = aPosition;
|
||||
""", fragment_100="""
|
||||
gl_FragColor = texture2D(uTex0, vTexCoord.xy);
|
||||
""")
|
||||
@@ -59,6 +59,9 @@ init -1600 python hide:
|
||||
# Should we profile reloading?
|
||||
config.profile_reload = False
|
||||
|
||||
# When should start_store happen?
|
||||
config.early_start_store = False
|
||||
|
||||
init -1600 python:
|
||||
|
||||
def _init_language():
|
||||
@@ -180,11 +183,17 @@ label _splashscreen:
|
||||
# tell anyone.
|
||||
label _start:
|
||||
|
||||
call _start_store
|
||||
if config.early_start_store:
|
||||
call _start_store
|
||||
|
||||
python:
|
||||
renpy.execute_default_statement(True)
|
||||
|
||||
if not config.early_start_store:
|
||||
call _start_store
|
||||
|
||||
python:
|
||||
|
||||
# Predict the main menu. When a load occurs, the loaded data will
|
||||
# overwrite the prediction requests.
|
||||
if renpy.has_screen("main_menu"):
|
||||
@@ -192,7 +201,6 @@ label _start:
|
||||
|
||||
renpy.block_rollback()
|
||||
|
||||
|
||||
scene black
|
||||
|
||||
if not _restart:
|
||||
|
||||
@@ -170,8 +170,8 @@ init -1500 python:
|
||||
:doc: voice_action
|
||||
|
||||
This allows the volume of each characters to be adjusted.
|
||||
If `volume` is None, this returns the value of volume of `voice_tag`.
|
||||
Otherwise, this set it to `volume`.
|
||||
If `volume` is None, this returns a BarValue that
|
||||
controls the value of `voice_tag`. Otherwise, this set it to `volume`.
|
||||
|
||||
`volume` is a number between 0.0 and 1.0, and is interpreted as a
|
||||
fraction of the mixer volume for `voice` channel.
|
||||
@@ -185,6 +185,17 @@ init -1500 python:
|
||||
else:
|
||||
return SetDict(persistent._character_volume, voice_tag, volume)
|
||||
|
||||
def GetCharacterVolume(voice_tag):
|
||||
"""
|
||||
:doc: preference_functions
|
||||
|
||||
This returns the volume associated with voice tag, a number
|
||||
between 0.0 and 1.0, which is interpreted as a fraction of the
|
||||
mixer volume for the `voice` channel.
|
||||
"""
|
||||
|
||||
return persistent._character_volume.get(voice_tag, 1.0)
|
||||
|
||||
@renpy.pure
|
||||
class PlayCharacterVoice(Action, FieldEquality):
|
||||
"""
|
||||
@@ -309,6 +320,7 @@ init -1500 python:
|
||||
for tlid in [
|
||||
renpy.game.context().translate_identifier,
|
||||
renpy.game.context().alternate_translate_identifier,
|
||||
renpy.game.context().deferred_translate_identifier,
|
||||
]:
|
||||
|
||||
if tlid is None:
|
||||
@@ -330,7 +342,7 @@ init -1500 python:
|
||||
|
||||
break
|
||||
|
||||
self.tlid = renpy.game.context().translate_identifier
|
||||
self.tlid = renpy.game.context().translate_identifier or renpy.game.context().deferred_translate_identifier
|
||||
|
||||
if self.filename:
|
||||
self.sustain = False
|
||||
@@ -432,6 +444,8 @@ init -1500 python hide:
|
||||
else:
|
||||
_voice.play = None
|
||||
|
||||
renpy.game.context().deferred_translate_identifier = None
|
||||
|
||||
_voice.auto_file = vi.auto_filename
|
||||
_voice.sustain = vi.sustain
|
||||
_voice.tlid = vi.tlid
|
||||
@@ -517,7 +531,7 @@ python early hide:
|
||||
return fn
|
||||
|
||||
def execute_voice(fn):
|
||||
fn = eval(fn)
|
||||
fn = _audio_eval(fn)
|
||||
voice(fn)
|
||||
|
||||
def lint_voice(fn):
|
||||
|
||||
@@ -954,6 +954,9 @@ ftfont_scale = { }
|
||||
# This is used to scale the ascent and descent of a font.
|
||||
ftfont_vertical_extent_scale = { }
|
||||
|
||||
# The default shader.
|
||||
default_shader = "renpy.geometry"
|
||||
|
||||
|
||||
def say_attribute_transition_callback(*args):
|
||||
"""
|
||||
@@ -993,6 +996,16 @@ disable_input = False
|
||||
# also determine the order of their render.
|
||||
keep_side_render_order = True
|
||||
|
||||
# Should this game enable and require gl2?
|
||||
gl2 = False
|
||||
|
||||
# Does this game use the depth buffer? If so, how many bits of depth should
|
||||
# it use?
|
||||
depth_size = None
|
||||
|
||||
# A list of screens to remove when the context is copied.
|
||||
context_copy_remove_screens = [ "notify" ]
|
||||
|
||||
del os
|
||||
del collections
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ from renpy.minstore import *
|
||||
# But please note that this will not be available in the body
|
||||
# of user code, unless we re-import it.
|
||||
import renpy.display
|
||||
import renpy.audio
|
||||
import renpy.text
|
||||
|
||||
import renpy.display.im as im
|
||||
@@ -208,6 +209,7 @@ MultipleTransition = renpy.curry.curry(renpy.display.transition.MultipleTransiti
|
||||
ComposeTransition = renpy.curry.curry(renpy.display.transition.ComposeTransition)
|
||||
Pause = renpy.curry.curry(renpy.display.transition.NoTransition)
|
||||
SubTransition = renpy.curry.curry(renpy.display.transition.SubTransition)
|
||||
|
||||
# Misc.
|
||||
ADVSpeaker = ADVCharacter = renpy.character.ADVCharacter
|
||||
Speaker = Character = renpy.character.Character
|
||||
@@ -217,6 +219,8 @@ MultiPersistent = renpy.persistent.MultiPersistent
|
||||
Action = renpy.ui.Action
|
||||
BarValue = renpy.ui.BarValue
|
||||
|
||||
AudioData = renpy.audio.audio.AudioData
|
||||
|
||||
# NOTE: When exporting something from here, decide if we need to add it to
|
||||
# renpy.pyanalysis.pure_functions.
|
||||
|
||||
|
||||
+109
-43
@@ -667,7 +667,7 @@ class SayBehavior(renpy.display.layout.Null):
|
||||
elif renpy.game.context().seen_current(True):
|
||||
return True
|
||||
else:
|
||||
renpy.config.skipping = False
|
||||
renpy.config.skipping = None
|
||||
renpy.exports.restart_interaction()
|
||||
|
||||
else:
|
||||
@@ -702,6 +702,9 @@ class Button(renpy.display.layout.Window):
|
||||
keysym = None
|
||||
alternate_keysym = None
|
||||
|
||||
# This locks the displayable against further change.
|
||||
locked = False
|
||||
|
||||
def __init__(self, child=None, style='button', clicked=None,
|
||||
hovered=None, unhovered=None, action=None, role=None,
|
||||
time_policy=None, keymap={}, alternate=None,
|
||||
@@ -745,6 +748,14 @@ class Button(renpy.display.layout.Window):
|
||||
|
||||
return get_tooltip(self.action)
|
||||
|
||||
def _in_current_store(self):
|
||||
rv = self._copy()
|
||||
rv.style = self.style.copy()
|
||||
rv.set_style_prefix(self.style.prefix, True)
|
||||
rv.focusable = False
|
||||
rv.locked = True
|
||||
return rv
|
||||
|
||||
def predict_one_action(self):
|
||||
predict_action(self.clicked)
|
||||
predict_action(self.hovered)
|
||||
@@ -840,41 +851,46 @@ class Button(renpy.display.layout.Window):
|
||||
|
||||
def per_interact(self):
|
||||
|
||||
if self.action is not None:
|
||||
if self.is_selected():
|
||||
role = 'selected_'
|
||||
if not self.locked:
|
||||
|
||||
if self.action is not None:
|
||||
if self.is_selected():
|
||||
role = 'selected_'
|
||||
else:
|
||||
role = ''
|
||||
|
||||
if self.is_sensitive():
|
||||
clicked = self.action
|
||||
else:
|
||||
clicked = None
|
||||
role = ''
|
||||
|
||||
else:
|
||||
role = ''
|
||||
clicked = self.clicked
|
||||
|
||||
if self.is_sensitive():
|
||||
clicked = self.action
|
||||
if self.role_parameter is not None:
|
||||
role = self.role_parameter
|
||||
|
||||
if (role != self.role) or (clicked is not self.clicked):
|
||||
renpy.display.render.invalidate(self)
|
||||
self.role = role
|
||||
self.clicked = clicked
|
||||
|
||||
if self.clicked is not None:
|
||||
self.set_style_prefix(self.role + "idle_", True)
|
||||
self.focusable = True
|
||||
else:
|
||||
clicked = None
|
||||
role = ''
|
||||
|
||||
else:
|
||||
role = ''
|
||||
clicked = self.clicked
|
||||
|
||||
if self.role_parameter is not None:
|
||||
role = self.role_parameter
|
||||
|
||||
if (role != self.role) or (clicked is not self.clicked):
|
||||
renpy.display.render.invalidate(self)
|
||||
self.role = role
|
||||
self.clicked = clicked
|
||||
|
||||
if self.clicked is not None:
|
||||
self.set_style_prefix(self.role + "idle_", True)
|
||||
self.focusable = True
|
||||
else:
|
||||
self.set_style_prefix(self.role + "insensitive_", True)
|
||||
self.focusable = False
|
||||
self.set_style_prefix(self.role + "insensitive_", True)
|
||||
self.focusable = False
|
||||
|
||||
super(Button, self).per_interact()
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
if self.locked:
|
||||
return None
|
||||
|
||||
def handle_click(action):
|
||||
renpy.exports.play(self.style.activate_sound)
|
||||
|
||||
@@ -938,7 +954,7 @@ class Button(renpy.display.layout.Window):
|
||||
if (self.clicked is not None) and map_event(ev, "button_ignore"):
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
|
||||
if (self.clicked is not None) and map_event(ev, "button_alternate_ignore"):
|
||||
if (self.alternate is not None) and map_event(ev, "button_alternate_ignore"):
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
|
||||
# If clicked,
|
||||
@@ -1111,6 +1127,7 @@ class Input(renpy.text.text.Text): # @UndefinedVariable
|
||||
default = u""
|
||||
edit_text = u""
|
||||
value = None
|
||||
shown = False
|
||||
|
||||
def __init__(self,
|
||||
default="",
|
||||
@@ -1171,15 +1188,10 @@ class Input(renpy.text.text.Text): # @UndefinedVariable
|
||||
self.content = replaces.content
|
||||
self.editable = replaces.editable
|
||||
self.caret_pos = replaces.caret_pos
|
||||
self.shown = replaces.shown
|
||||
|
||||
self.update_text(self.content, self.editable)
|
||||
|
||||
def _show(self):
|
||||
if self.default != self.content:
|
||||
self.content = self.default
|
||||
self.caret_pos = len(self.content)
|
||||
self.update_text(self.content, self.editable)
|
||||
|
||||
def update_text(self, new_content, editable, check_size=False):
|
||||
|
||||
edit = renpy.display.interface.text_editing
|
||||
@@ -1272,6 +1284,18 @@ class Input(renpy.text.text.Text): # @UndefinedVariable
|
||||
if self.value.default and (default_input_value is None):
|
||||
default_input_value = self.value
|
||||
|
||||
if not self.shown:
|
||||
|
||||
if self.value is not None:
|
||||
default = self.value.get_text()
|
||||
self.default = unicode(default)
|
||||
|
||||
self.content = self.default
|
||||
self.caret_pos = len(self.content)
|
||||
self.update_text(self.content, self.editable)
|
||||
|
||||
self.shown = True
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
self.old_caret_pos = self.caret_pos
|
||||
@@ -1370,7 +1394,10 @@ class Input(renpy.text.text.Text): # @UndefinedVariable
|
||||
if ev.unicode and ord(ev.unicode[0]) >= 32:
|
||||
raw_text = ev.unicode
|
||||
elif renpy.display.interface.text_event_in_queue():
|
||||
raw_text = ''
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
elif (32 <= ev.key < 127) and not (ev.mod & (pygame.KMOD_ALT | pygame.KMOD_META)):
|
||||
# Ignore printable keycodes without unicode.
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
|
||||
if raw_text is not None:
|
||||
|
||||
@@ -1428,7 +1455,9 @@ class Adjustment(renpy.object.Object):
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, range=1, value=0, step=None, page=None, changed=None, adjustable=None, ranged=None): # @ReservedAssignment
|
||||
force_step = False
|
||||
|
||||
def __init__(self, range=1, value=0, step=None, page=None, changed=None, adjustable=None, ranged=None, force_step=False): # @ReservedAssignment
|
||||
"""
|
||||
The following parameters correspond to fields or properties on
|
||||
the adjustment object:
|
||||
@@ -1456,12 +1485,12 @@ class Adjustment(renpy.object.Object):
|
||||
The following parameters control the behavior of the adjustment.
|
||||
|
||||
`adjustable`
|
||||
If True, this adjustment can be changed by a bar. If False,
|
||||
it can't.
|
||||
If True, this adjustment can be changed by a bar. If False,
|
||||
it can't.
|
||||
|
||||
It defaults to being adjustable if a `changed` function
|
||||
is given or if the adjustment is associated with a viewport,
|
||||
and not adjustable otherwise.
|
||||
It defaults to being adjustable if a `changed` function
|
||||
is given or if the adjustment is associated with a viewport,
|
||||
and not adjustable otherwise.
|
||||
|
||||
`changed`
|
||||
This function is called with the new value when the value of
|
||||
@@ -1471,6 +1500,16 @@ class Adjustment(renpy.object.Object):
|
||||
This function is called with the adjustment object when
|
||||
the range of the adjustment is set by a viewport.
|
||||
|
||||
`force_step`
|
||||
If True and this adjustment changes by dragging associated
|
||||
viewport or a bar, value will be changed only if the drag
|
||||
reached next step.
|
||||
If "release" and this adjustment changes by dragging associated
|
||||
viewport or a bar, after the release, value will be
|
||||
rounded to the nearest step.
|
||||
If False, this adjustment will changes by dragging, ignoring
|
||||
the step value.
|
||||
|
||||
.. method:: change(value)
|
||||
|
||||
Changes the value of the adjustment to `value`, updating
|
||||
@@ -1490,9 +1529,27 @@ class Adjustment(renpy.object.Object):
|
||||
self.changed = changed
|
||||
self.adjustable = adjustable
|
||||
self.ranged = ranged
|
||||
self.force_step = force_step
|
||||
|
||||
def round_value(self, value, release):
|
||||
# Prevent deadlock border points
|
||||
if value <= 0:
|
||||
return 0
|
||||
elif value >= self._range:
|
||||
return self._range
|
||||
|
||||
if self.force_step is False:
|
||||
return value
|
||||
|
||||
if (not release) and self.force_step == "release":
|
||||
return value
|
||||
|
||||
return type(self.value)(self.step * round(float(value) / self.step))
|
||||
|
||||
def get_value(self):
|
||||
if self._value > self._range:
|
||||
if self._value <= 0:
|
||||
return 0
|
||||
if self._value >= self._range:
|
||||
return self._range
|
||||
|
||||
return self._value
|
||||
@@ -1907,9 +1964,18 @@ class Bar(renpy.display.core.Displayable):
|
||||
renpy.display.tts.speak(renpy.minstore.__("deactivate"))
|
||||
self.set_style_prefix("hover_", True)
|
||||
renpy.display.focus.set_grab(None)
|
||||
ignore_event = True
|
||||
|
||||
# Invoke rounding adjustment on bar release
|
||||
value = self.adjustment.round_value(value, release=True)
|
||||
if value != old_value:
|
||||
rv = self.adjustment.change(value)
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
|
||||
if value != old_value:
|
||||
value = self.adjustment.round_value(value, release=False)
|
||||
rv = self.adjustment.change(value)
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
+18
-10
@@ -1921,6 +1921,10 @@ class Interface(object):
|
||||
renderers = [ "gl", "angle", "sw" ]
|
||||
else:
|
||||
renderers = [ "gl", "sw" ]
|
||||
|
||||
if renpy.config.gl2:
|
||||
renderers = [ "gl2", "egl2" ] + renderers
|
||||
|
||||
else:
|
||||
renderers = [ renderer, "sw" ]
|
||||
|
||||
@@ -1968,6 +1972,9 @@ class Interface(object):
|
||||
return rv
|
||||
|
||||
def kill_textures(self):
|
||||
if renpy.display.draw is not None:
|
||||
renpy.display.draw.kill_textures()
|
||||
|
||||
renpy.display.render.free_memory()
|
||||
renpy.text.text.layout_cache_clear()
|
||||
|
||||
@@ -1977,7 +1984,6 @@ class Interface(object):
|
||||
"""
|
||||
|
||||
self.kill_textures()
|
||||
|
||||
renpy.display.im.cache.clear()
|
||||
renpy.display.module.bo_cache = None
|
||||
|
||||
@@ -1990,14 +1996,16 @@ class Interface(object):
|
||||
if renpy.display.draw and renpy.display.draw.info["renderer"] == "sw":
|
||||
renpy.display.video.movie_stop(clear=False)
|
||||
|
||||
renpy.display.render.free_memory()
|
||||
renpy.text.text.layout_cache_clear()
|
||||
renpy.display.module.bo_cache = None
|
||||
|
||||
if self.display_reset:
|
||||
|
||||
pygame.key.stop_text_input() # @UndefinedVariable
|
||||
pygame.key.set_text_input_rect(None) # @UndefinedVariable
|
||||
self.text_rect = None
|
||||
|
||||
renpy.display.draw.deinit()
|
||||
|
||||
if renpy.display.draw.info["renderer"] == "angle":
|
||||
renpy.display.draw.quit()
|
||||
|
||||
@@ -2005,13 +2013,7 @@ class Interface(object):
|
||||
# minimized state on windows.
|
||||
pygame.display.quit()
|
||||
|
||||
renpy.display.render.free_memory()
|
||||
renpy.display.im.cache.clear()
|
||||
renpy.text.text.layout_cache_clear()
|
||||
|
||||
renpy.display.module.bo_cache = None
|
||||
|
||||
self.kill_textures_and_surfaces()
|
||||
self.kill_textures_and_surfaces()
|
||||
|
||||
self.old_text_rect = None
|
||||
self.display_reset = False
|
||||
@@ -2042,6 +2044,7 @@ class Interface(object):
|
||||
for draw in draws:
|
||||
if draw.set_mode(virtual_size, physical_size, fullscreen):
|
||||
renpy.display.draw = draw
|
||||
renpy.display.render.models = draw.info.get("models", False)
|
||||
break
|
||||
else:
|
||||
# pygame.display.quit()
|
||||
@@ -3419,6 +3422,11 @@ class Interface(object):
|
||||
|
||||
size = (ev.w // self.dpi_scale, ev.h // self.dpi_scale)
|
||||
|
||||
# Refresh fullscreen status (e.g. user pressed Esc. in browser)
|
||||
main_window = pygame.display.get_window()
|
||||
self.fullscreen = main_window is not None and bool(main_window.get_window_flags() & (pygame.WINDOW_FULLSCREEN_DESKTOP|pygame.WINDOW_FULLSCREEN))
|
||||
renpy.game.preferences.fullscreen = self.fullscreen
|
||||
|
||||
if pygame.display.get_surface().get_size() != ev.size:
|
||||
self.set_mode(size)
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
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
|
||||
|
||||
has been computed, the layout properties are ignored in favor of the
|
||||
position stored inside the Drag.
|
||||
|
||||
`d`
|
||||
If present, the child of this Drag. Drags use the child style
|
||||
@@ -601,10 +602,12 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
|
||||
if ((self.alternate is not None) and
|
||||
if (
|
||||
(self.alternate is not None) and
|
||||
renpy.display.touch and
|
||||
(self.click_time is not None) and
|
||||
((st - self.click_time) > renpy.config.longpress_duration)):
|
||||
((st - self.click_time) > renpy.config.longpress_duration)
|
||||
):
|
||||
|
||||
self.click_time = None
|
||||
|
||||
@@ -612,6 +615,8 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
renpy.exports.vibrate(renpy.config.longpress_vibrate)
|
||||
|
||||
# Handle clicking on droppables.
|
||||
if not grabbed:
|
||||
if self.clicked is not None and map_event(ev, "drag_deactivate"):
|
||||
@@ -684,11 +689,11 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
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 drop is not None:
|
||||
drop.set_style_prefix("selected_idle_", True)
|
||||
|
||||
if map_event(ev, 'drag_deactivate'):
|
||||
|
||||
self.click_time = None
|
||||
|
||||
@@ -532,7 +532,6 @@ def free_memory():
|
||||
Frees some memory.
|
||||
"""
|
||||
|
||||
renpy.display.draw.free_memory()
|
||||
cache.clear()
|
||||
|
||||
|
||||
|
||||
+72
-18
@@ -152,8 +152,8 @@ class Frame(renpy.display.core.Displayable):
|
||||
An image manipulator that will be resized by this frame.
|
||||
|
||||
`left`
|
||||
The size of the border on the left side. This can also be an
|
||||
:func:`Borders` object, in which case that object is use in place
|
||||
The size of the border on the left side. This can also be a
|
||||
:func:`Borders` object, in which case that object is used in place
|
||||
of the other parameters.
|
||||
|
||||
`top`
|
||||
@@ -167,8 +167,10 @@ class Frame(renpy.display.core.Displayable):
|
||||
The side of the border on the bottom. If None, defaults to `top`.
|
||||
|
||||
`tile`
|
||||
If true, tiling is used to resize sections of the image,
|
||||
rather than scaling.
|
||||
If set to True, tiling is used to resize sections of the image,
|
||||
rather than scaling. If set to the string "integer", the nearest
|
||||
integer number of tiles will be used in each direction. That set of
|
||||
full tiles will then be scaled up or down to fit the required area.
|
||||
|
||||
::
|
||||
|
||||
@@ -180,6 +182,7 @@ class Frame(renpy.display.core.Displayable):
|
||||
__version__ = 1
|
||||
|
||||
properties = { }
|
||||
tile_ratio = 0.5
|
||||
|
||||
def after_upgrade(self, version):
|
||||
if version < 2:
|
||||
@@ -188,7 +191,9 @@ class Frame(renpy.display.core.Displayable):
|
||||
self.top = self.yborder
|
||||
self.bottom = self.yborder
|
||||
|
||||
def __init__(self, image, left=None, top=None, right=None, bottom=None, xborder=0, yborder=0, bilinear=True, tile=False, **properties):
|
||||
def __init__(self, image, left=None, top=None, right=None, bottom=None,
|
||||
xborder=0, yborder=0, bilinear=True, tile=False,
|
||||
tile_ratio=0.5, **properties):
|
||||
super(Frame, self).__init__(**properties)
|
||||
|
||||
self.image = renpy.easy.displayable(image)
|
||||
@@ -203,6 +208,9 @@ class Frame(renpy.display.core.Displayable):
|
||||
bottom = insets.bottom
|
||||
|
||||
self.tile = tile
|
||||
# When tile="integer" the proportion of an edge tile that determines
|
||||
# whether to use less tiles and stretch or more tiles and shrink
|
||||
self.tile_ratio = float(tile_ratio)
|
||||
|
||||
# Compat for old argument names.
|
||||
if left is None:
|
||||
@@ -227,7 +235,9 @@ class Frame(renpy.display.core.Displayable):
|
||||
self.top,
|
||||
self.right,
|
||||
self.bottom,
|
||||
" tile" if self.tile else "")
|
||||
(" tile ({})".format(self.tile_ratio) if self.tile == "integer"
|
||||
else " tile" if self.tile
|
||||
else ""))
|
||||
|
||||
def __eq__(self, o):
|
||||
if not self._equals(o):
|
||||
@@ -248,6 +258,9 @@ class Frame(renpy.display.core.Displayable):
|
||||
if self.tile != o.tile:
|
||||
return False
|
||||
|
||||
if self.tile_ratio != o.tile_ratio:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
@@ -345,18 +358,36 @@ class Frame(renpy.display.core.Displayable):
|
||||
if csw != cdw or csh != cdh:
|
||||
|
||||
if self.tile:
|
||||
newcr = Render(cdw, cdh)
|
||||
ctw, cth = cdw, cdh
|
||||
|
||||
xtiles = max(1, cdw // csw + (1 if cdw % csw else 0))
|
||||
ytiles = max(1, cdh // csh + (1 if cdh % csh else 0))
|
||||
|
||||
if cdw % csw or cdh % csh:
|
||||
# Area is not an exact integer number of tiles
|
||||
|
||||
if self.tile == "integer":
|
||||
if cdw % csw / float(csw) < self.tile_ratio:
|
||||
xtiles = max(1, xtiles-1)
|
||||
if cdh % csh / float(csh) < self.tile_ratio:
|
||||
ytiles = max(1, ytiles-1)
|
||||
|
||||
# Set size of the used tiles (ready to scale)
|
||||
ctw, cth = csw * xtiles, csh * ytiles
|
||||
|
||||
newcr = Render(ctw, cth)
|
||||
newcr.xclipping = True
|
||||
newcr.yclipping = True
|
||||
|
||||
for x in xrange(0, cdw, csw):
|
||||
for y in xrange(0, cdh, csh):
|
||||
newcr.blit(cr, (x, y))
|
||||
for x in xrange(0, xtiles):
|
||||
for y in xrange(0, ytiles):
|
||||
newcr.blit(cr, (x * csw, y * csh))
|
||||
|
||||
csw, csh = ctw, cth
|
||||
cr = newcr
|
||||
|
||||
else:
|
||||
|
||||
if csw != cdw or csh != cdh:
|
||||
# Subsurface needs scaling
|
||||
newcr = Render(cdw, cdh)
|
||||
newcr.forward = Matrix2D(1.0 * csw / cdw, 0, 0, 1.0 * csh / cdh)
|
||||
newcr.reverse = Matrix2D(1.0 * cdw / csw, 0, 0, 1.0 * cdh / csh)
|
||||
@@ -465,19 +496,42 @@ class Frame(renpy.display.core.Displayable):
|
||||
|
||||
# Scale or tile if we have to.
|
||||
if dstsize != srcsize:
|
||||
|
||||
if self.tile:
|
||||
tilew, tileh = srcsize
|
||||
dstw, dsth = dstsize
|
||||
|
||||
surf2 = renpy.display.pgrender.surface_unscaled(dstsize, surf)
|
||||
xtiles = max(
|
||||
1, dstw // tilew + (1 if dstw % tilew else 0))
|
||||
ytiles = max(
|
||||
1, dsth // tileh + (1 if dsth % tileh else 0))
|
||||
|
||||
for y in range(0, dsth, tileh):
|
||||
for x in range(0, dstw, tilew):
|
||||
surf2.blit(surf, (x, y))
|
||||
if dstw % tilew or dsth % tileh:
|
||||
# Area is not an exact integer number of tiles
|
||||
|
||||
surf = surf2
|
||||
if self.tile == "integer":
|
||||
if dstw % tilew / float(tilew) < self.tile_ratio:
|
||||
xtiles = max(1, xtiles-1)
|
||||
if dsth % tileh / float(tileh) < self.tile_ratio:
|
||||
ytiles = max(1, ytiles-1)
|
||||
|
||||
else:
|
||||
# Tile at least one tile in each direction
|
||||
surf2 = renpy.display.pgrender.surface_unscaled(
|
||||
(tilew * xtiles, tileh * ytiles), surf)
|
||||
|
||||
for y in range(0, ytiles):
|
||||
for x in range(0, xtiles):
|
||||
surf2.blit(surf, (x*tilew, y*tileh))
|
||||
|
||||
if self.tile is True:
|
||||
# Trim the tiled surface to required size
|
||||
surf = surf2.subsurface((0, 0, dstw, dsth))
|
||||
else:
|
||||
# Using integer full 'tiles' per side
|
||||
srcsize = (tilew * xtiles, tileh * ytiles)
|
||||
surf = surf2
|
||||
|
||||
if dstsize != srcsize:
|
||||
surf2 = renpy.display.scale.real_transform_scale(surf, dstsize)
|
||||
surf = surf2
|
||||
|
||||
|
||||
+21
-6
@@ -1230,6 +1230,8 @@ class DynamicDisplayable(renpy.display.core.Displayable):
|
||||
|
||||
nosave = [ 'child' ]
|
||||
|
||||
_duplicatable = True
|
||||
|
||||
def after_setstate(self):
|
||||
self.child = None
|
||||
|
||||
@@ -1248,12 +1250,25 @@ class DynamicDisplayable(renpy.display.core.Displayable):
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def _duplicate(self, args):
|
||||
rv = self._copy(args)
|
||||
|
||||
if rv.child is not None and rv.child._duplicateable:
|
||||
rv.child = rv.child._duplicate(args)
|
||||
|
||||
return rv
|
||||
|
||||
def visit(self):
|
||||
return [ ]
|
||||
|
||||
def update(self, st, at):
|
||||
child, redraw = self.function(st, at, *self.args, **self.kwargs)
|
||||
child = renpy.easy.displayable(child)
|
||||
|
||||
if child._duplicatable:
|
||||
child = child._duplicate(self._args)
|
||||
child._unique()
|
||||
|
||||
child.visit_all(lambda c : c.per_interact())
|
||||
|
||||
self.child = child
|
||||
@@ -1856,14 +1871,13 @@ class Flatten(Container):
|
||||
cr = renpy.display.render.render(self.child, width, height, st, at)
|
||||
cw, ch = cr.get_size()
|
||||
|
||||
tex = cr.render_to_texture(True)
|
||||
|
||||
rv = renpy.display.render.Render(cw, ch)
|
||||
rv.blit(tex, (0, 0))
|
||||
rv.depends_on(cr, focus=True)
|
||||
rv.blit(cr, (0, 0))
|
||||
|
||||
rv.reverse = renpy.display.draw.draw_to_virt
|
||||
rv.forward = renpy.display.render.IDENTITY
|
||||
rv.operation = renpy.display.render.FLATTEN
|
||||
|
||||
rv.mesh = True
|
||||
rv.shaders = ( "renpy.texture", )
|
||||
|
||||
self.offsets = [ (0, 0) ]
|
||||
|
||||
@@ -1872,6 +1886,7 @@ class Flatten(Container):
|
||||
def get_placement(self):
|
||||
return self.child.get_placement()
|
||||
|
||||
|
||||
class AlphaMask(Container):
|
||||
"""
|
||||
:doc: disp_imagelike
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
cdef class Matrix:
|
||||
|
||||
cdef float m[0]
|
||||
|
||||
cdef public float xdx
|
||||
cdef public float xdy
|
||||
cdef public float xdz
|
||||
cdef public float xdw
|
||||
|
||||
cdef public float ydx
|
||||
cdef public float ydy
|
||||
cdef public float ydz
|
||||
cdef public float ydw
|
||||
|
||||
cdef public float zdx
|
||||
cdef public float zdy
|
||||
cdef public float zdz
|
||||
cdef public float zdw
|
||||
|
||||
cdef public float wdx
|
||||
cdef public float wdy
|
||||
cdef public float wdz
|
||||
cdef public float wdw
|
||||
|
||||
|
||||
cdef inline void transform4(Matrix self, float *ox, float *oy, float *oz, float *ow, float x, float y, float z, float w):
|
||||
ox[0] = x * self.xdx + y * self.xdy + z * self.xdz + w * self.xdw
|
||||
oy[0] = x * self.ydx + y * self.ydy + z * self.ydz + w * self.ydw
|
||||
oz[0] = x * self.zdx + y * self.zdy + z * self.zdz + w * self.zdw
|
||||
ow[0] = x * self.wdx + y * self.wdy + z * self.wdz + w * self.wdw
|
||||
|
||||
cdef inline void transform3(Matrix self, float *ox, float *oy, float *oz, float x, float y, float z, float w):
|
||||
ox[0] = x * self.xdx + y * self.xdy + z * self.xdz + w * self.xdw
|
||||
oy[0] = x * self.ydx + y * self.ydy + z * self.ydz + w * self.ydw
|
||||
oz[0] = x * self.zdx + y * self.zdy + z * self.zdz + w * self.zdw
|
||||
|
||||
cdef inline void transform2(Matrix self, float *ox, float *oy, float x, float y, float z, float w):
|
||||
ox[0] = x * self.xdx + y * self.xdy + z * self.xdz + w * self.xdw
|
||||
oy[0] = x * self.ydx + y * self.ydy + z * self.ydz + w * self.ydw
|
||||
|
||||
cpdef bint is_unit_aligned(Matrix self)
|
||||
|
||||
cdef class Matrix2D(Matrix):
|
||||
pass
|
||||
@@ -0,0 +1,191 @@
|
||||
from __future__ import print_function
|
||||
|
||||
from libc.string cimport memset
|
||||
from libc.math cimport sin, cos, M_PI as pi
|
||||
|
||||
cdef float *aligned_1 = [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
|
||||
cdef float *aligned_2 = [ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
|
||||
|
||||
fields = [
|
||||
"xdx", "xdy", "xdz", "xdw",
|
||||
"ydx", "ydy", "ydz", "ydw",
|
||||
"zdx", "zdy", "zdz", "zdw",
|
||||
"wdx", "wdy", "wdz", "wdw",
|
||||
]
|
||||
|
||||
|
||||
cdef class Matrix:
|
||||
"""
|
||||
Represents a 4x4 matrix.
|
||||
"""
|
||||
|
||||
def __init__(Matrix self, l):
|
||||
|
||||
memset(self.m, 0, sizeof(float) * 16)
|
||||
|
||||
if l is None:
|
||||
return
|
||||
|
||||
cdef int lenl = len(l)
|
||||
|
||||
if lenl == 4:
|
||||
(self.xdx, self.xdy,
|
||||
self.ydx, self.ydy) = l
|
||||
self.ydy = 1.0
|
||||
self.wdw = 1.0
|
||||
|
||||
elif lenl == 9:
|
||||
(self.xdx, self.xdy, self.xdz,
|
||||
self.ydx, self.ydy, self.ydz,
|
||||
self.zdx, self.zdy, self.zdz) = l
|
||||
self.wdw = 1.0
|
||||
|
||||
elif lenl == 16:
|
||||
(self.xdx, self.xdy, self.xdz, self.xdw,
|
||||
self.ydx, self.ydy, self.ydz, self.ydw,
|
||||
self.zdx, self.zdy, self.zdz, self.zdw,
|
||||
self.wdx, self.wdy, self.wdz, self.wdw) = l
|
||||
|
||||
else:
|
||||
raise Exception("Unsupported matrix length {} (must be 4, 9, or 16).".format(len(l)))
|
||||
|
||||
|
||||
def __getstate__(self):
|
||||
rv = { }
|
||||
|
||||
for i in range(16):
|
||||
rv[fields[i]] = self.m[i]
|
||||
|
||||
return rv
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
memset(self.m, 0, sizeof(float) * 16)
|
||||
|
||||
self.zdz = 1.0
|
||||
self.wdw = 1.0
|
||||
|
||||
for i in range(16):
|
||||
if fields[i] in state:
|
||||
self.m[i] = state[fields[i]]
|
||||
|
||||
def __mul__(Matrix self, Matrix other):
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = other.wdx*self.xdw + other.xdx*self.xdx + other.ydx*self.xdy + other.zdx*self.xdz
|
||||
rv.xdy = other.wdy*self.xdw + other.xdy*self.xdx + other.ydy*self.xdy + other.zdy*self.xdz
|
||||
rv.xdz = other.wdz*self.xdw + other.xdz*self.xdx + other.ydz*self.xdy + other.zdz*self.xdz
|
||||
rv.xdw = other.wdw*self.xdw + other.xdw*self.xdx + other.ydw*self.xdy + other.zdw*self.xdz
|
||||
|
||||
rv.ydx = other.wdx*self.ydw + other.xdx*self.ydx + other.ydx*self.ydy + other.zdx*self.ydz
|
||||
rv.ydy = other.wdy*self.ydw + other.xdy*self.ydx + other.ydy*self.ydy + other.zdy*self.ydz
|
||||
rv.ydz = other.wdz*self.ydw + other.xdz*self.ydx + other.ydz*self.ydy + other.zdz*self.ydz
|
||||
rv.ydw = other.wdw*self.ydw + other.xdw*self.ydx + other.ydw*self.ydy + other.zdw*self.ydz
|
||||
|
||||
rv.zdx = other.wdx*self.zdw + other.xdx*self.zdx + other.ydx*self.zdy + other.zdx*self.zdz
|
||||
rv.zdy = other.wdy*self.zdw + other.xdy*self.zdx + other.ydy*self.zdy + other.zdy*self.zdz
|
||||
rv.zdz = other.wdz*self.zdw + other.xdz*self.zdx + other.ydz*self.zdy + other.zdz*self.zdz
|
||||
rv.zdw = other.wdw*self.zdw + other.xdw*self.zdx + other.ydw*self.zdy + other.zdw*self.zdz
|
||||
|
||||
rv.wdx = other.wdx*self.wdw + other.xdx*self.wdx + other.ydx*self.wdy + other.zdx*self.wdz
|
||||
rv.wdy = other.wdy*self.wdw + other.xdy*self.wdx + other.ydy*self.wdy + other.zdy*self.wdz
|
||||
rv.wdz = other.wdz*self.wdw + other.xdz*self.wdx + other.ydz*self.wdy + other.zdz*self.wdz
|
||||
rv.wdw = other.wdw*self.wdw + other.xdw*self.wdx + other.ydw*self.wdy + other.zdw*self.wdz
|
||||
|
||||
return rv
|
||||
|
||||
def __getitem__(Matrix self, int index):
|
||||
if 0 <= index < 16:
|
||||
return self.m[index]
|
||||
|
||||
raise IndexError("Matrix index out of range.")
|
||||
|
||||
def __setitem__(Matrix self, int index, float value):
|
||||
if 0 <= index < 16:
|
||||
self.m[index] = value
|
||||
return
|
||||
|
||||
raise IndexError("Matrix index out of range.")
|
||||
|
||||
def __repr__(Matrix self):
|
||||
cdef int x, y
|
||||
|
||||
rv = "Matrix(["
|
||||
|
||||
for 0 <= y < 4:
|
||||
if y:
|
||||
rv += "\n "
|
||||
for 0 <= x < 4:
|
||||
rv += "{:8.5f}, ".format(self.m[x + y * 4])
|
||||
|
||||
return rv + "])"
|
||||
|
||||
def transform(Matrix self, float x, float y, float z=0.0, float w=1.0, int components=2):
|
||||
cdef float ox, oy, oz, ow
|
||||
|
||||
self.transform4(&ox, &oy, &oz, &ow, x, y, z, w)
|
||||
|
||||
if components == 2:
|
||||
return (ox, oy)
|
||||
elif components == 3:
|
||||
return (ox, oy, oz)
|
||||
elif components == 4:
|
||||
return (ox, oy, oz, ow)
|
||||
|
||||
|
||||
def __richcmp__(Matrix self, Matrix other, op):
|
||||
|
||||
if op != 2:
|
||||
return NotImplemented
|
||||
|
||||
if self is other:
|
||||
return True
|
||||
|
||||
cdef int i
|
||||
cdef double total
|
||||
|
||||
total = 0
|
||||
|
||||
for 0 < i < 16:
|
||||
total += abs(self.m[i] - other.m[i])
|
||||
|
||||
return total < .0001
|
||||
|
||||
cpdef bint is_unit_aligned(Matrix self):
|
||||
"""
|
||||
Returns true if exactly one of abs(xdx) or abs(xdy) is 1.0, and
|
||||
the same for xdy and ydy. This is intended to report if a matrix
|
||||
is aligned to the axes.
|
||||
"""
|
||||
|
||||
cdef int i
|
||||
cdef float v
|
||||
cdef float total_1
|
||||
cdef float total_2
|
||||
|
||||
total_1 = 0
|
||||
total_2 = 0
|
||||
|
||||
for 0 < i < 16:
|
||||
v = abs(self.m[i])
|
||||
total_1 += abs(i - aligned_1[i])
|
||||
total_2 += abs(i - aligned_2[i])
|
||||
|
||||
return (total_1 < .0001) or (total_2 < .0001)
|
||||
|
||||
cdef class Matrix2D(Matrix):
|
||||
|
||||
def __init__(Matrix2D self, double xdx, double xdy, double ydx, double ydy):
|
||||
memset(self.m, 0, sizeof(float) * 16)
|
||||
|
||||
self.xdx = xdx
|
||||
self.xdy = xdy
|
||||
self.ydx = ydx
|
||||
self.ydy = ydy
|
||||
|
||||
self.zdz = 1.0
|
||||
self.wdw = 1.0
|
||||
|
||||
|
||||
include "matrix_functions.pxi"
|
||||
@@ -0,0 +1,141 @@
|
||||
|
||||
|
||||
def identity():
|
||||
"""
|
||||
Returns an identity matrix.
|
||||
"""
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = 1.00000000000000
|
||||
rv.ydy = 1.00000000000000
|
||||
rv.zdz = 1.00000000000000
|
||||
rv.wdw = 1.00000000000000
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def offset(float x, float y, float z):
|
||||
"""
|
||||
Returns a matrix that offsets the vertex by a fixed amount.
|
||||
"""
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = 1.00000000000000
|
||||
rv.xdw = x
|
||||
rv.ydy = 1.00000000000000
|
||||
rv.ydw = y
|
||||
rv.zdz = 1.00000000000000
|
||||
rv.zdw = z
|
||||
rv.wdw = 1.00000000000000
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def rotate(float x, float y, float z):
|
||||
"""
|
||||
Returns a matrix that rotates the displayable around the
|
||||
origin.
|
||||
|
||||
`x`, `y`, `x`
|
||||
The amount to rotate around the origin, in degrees.
|
||||
"""
|
||||
|
||||
cdef float sinx = sin(pi*x/180)
|
||||
cdef float cosx = cos(pi*x/180)
|
||||
cdef float siny = sin(pi*y/180)
|
||||
cdef float cosy = cos(pi*y/180)
|
||||
cdef float sinz = sin(pi*z/180)
|
||||
cdef float cosz = cos(pi*z/180)
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = cosy*cosz
|
||||
rv.xdy = -cosx*sinz + cosz*sinx*siny
|
||||
rv.xdz = cosx*cosz*siny + sinx*sinz
|
||||
rv.ydx = cosy*sinz
|
||||
rv.ydy = cosx*cosz + sinx*siny*sinz
|
||||
rv.ydz = cosx*siny*sinz - cosz*sinx
|
||||
rv.zdx = -siny
|
||||
rv.zdy = cosy*sinx
|
||||
rv.zdz = cosx*cosy
|
||||
rv.wdw = 1
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def perspective(float w, float h, float n, float p, float f):
|
||||
"""
|
||||
Returns the Ren'Py projection matrix. This is a view into a 3d space
|
||||
where (0, 0) is the top left corner (`w`/2, `h`/2) is the center, and
|
||||
(`w`,`h`) is the bottom right, when the z coordinate is 0.
|
||||
|
||||
`w`, `h`
|
||||
The width and height of the input plane, in pixels.
|
||||
|
||||
`n`
|
||||
The distance of the near plane from the camera.
|
||||
|
||||
`p`
|
||||
The distance of the 1:1 plane from the camera. This is where 1 pixel
|
||||
is one coordinate unit.
|
||||
|
||||
`f`
|
||||
The distance of the far plane from the camera.
|
||||
"""
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = p
|
||||
rv.xdz = -w/2
|
||||
rv.ydy = p
|
||||
rv.ydz = -h/2
|
||||
rv.zdz = -(f + n)/(f - n)
|
||||
rv.zdw = (-2*f*n + p*(f + n))/(f - n)
|
||||
rv.wdz = -1.00000000000000
|
||||
rv.wdw = p
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def screen_projection(float w, float h):
|
||||
"""
|
||||
This generates a matrix that projects the Ren'Py space, where (0, 0) is the
|
||||
top left and (`w`, `h`) is the bottom right, into the OpenGL viewport, where
|
||||
(-1.0, 1.0) is the top left and (1.0, -1.0) is the bottom.
|
||||
|
||||
Generates the matrix that projects the Ren'Py screen to the OpenGL screen.
|
||||
"""
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = 2/w
|
||||
rv.xdw = -1.00000000000000
|
||||
rv.ydy = -2/h
|
||||
rv.ydw = 1.00000000000000
|
||||
rv.zdz = 1.00000000000000
|
||||
rv.wdw = 1.00000000000000
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def texture_projection(float w, float h):
|
||||
"""
|
||||
This generates a matrix that project the Ren'Py space, where (0, 0) is the
|
||||
top left and (`w`, `h`) is the bottom right, into the OpenGL render-to-texture
|
||||
space, where (-1.0, -1.0) is the top left and (1.0, 1.0) is the bottom.
|
||||
|
||||
Generates the matrix that projects the Ren'Py screen to the OpenGL screen.
|
||||
"""
|
||||
|
||||
cdef Matrix rv = Matrix(None)
|
||||
|
||||
rv.xdx = 2/w
|
||||
rv.xdw = -1.00000000000000
|
||||
rv.ydy = 2/h
|
||||
rv.ydw = -1.00000000000000
|
||||
rv.zdz = 1.00000000000000
|
||||
rv.wdw = 1.00000000000000
|
||||
|
||||
return rv
|
||||
@@ -171,8 +171,7 @@ class SpriteManager(renpy.display.core.Displayable):
|
||||
SpriteManagers have the following fields:
|
||||
|
||||
`width`, `height`
|
||||
|
||||
The width and height of this SpriteManager, in pixels.
|
||||
The width and height of this SpriteManager, in pixels.
|
||||
|
||||
|
||||
SpriteManagers have the following methods:
|
||||
|
||||
@@ -19,14 +19,8 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
cdef class Matrix2D:
|
||||
cdef public double xdx
|
||||
cdef public double xdy
|
||||
cdef public double ydx
|
||||
cdef public double ydy
|
||||
|
||||
cpdef tuple transform(Matrix2D self, double x, double y)
|
||||
cpdef bint is_unit_aligned(Matrix2D self)
|
||||
from renpy.display.matrix cimport Matrix, Matrix2D
|
||||
|
||||
cdef class Render:
|
||||
|
||||
@@ -39,14 +33,27 @@ cdef class Render:
|
||||
cdef public set parents
|
||||
cdef public list depends_on_list
|
||||
|
||||
# gl, sw: The drawing operation and its parameters.
|
||||
cdef public int operation
|
||||
cdef public double operation_complete
|
||||
cdef public bint operation_alpha
|
||||
cdef public object operation_parameter
|
||||
|
||||
cdef public Matrix2D forward, reverse
|
||||
# The transform toward texture space
|
||||
cdef public Matrix forward
|
||||
|
||||
# The transform toward screen space.
|
||||
cdef public Matrix reverse
|
||||
|
||||
# Alpha multiplication - this is multipled with r, g, b, and a, to reduce
|
||||
# the alpha of this Render and its children.
|
||||
cdef public double alpha
|
||||
|
||||
# Over multiplication - this is multiplied with a. This is really (1-additive),
|
||||
# such that if this is 0.0, additive blending occurs.
|
||||
cdef public double over
|
||||
|
||||
# True if child textures should be rendered in nearest-neighbor mode.
|
||||
cdef public object nearest
|
||||
|
||||
cdef public list focuses
|
||||
@@ -62,12 +69,41 @@ cdef class Render:
|
||||
cdef public bint xclipping
|
||||
cdef public bint yclipping
|
||||
|
||||
# gl, sw: Caching of render-to-texture.
|
||||
cdef public object surface, alpha_surface, half_cache
|
||||
|
||||
cdef public bint modal
|
||||
|
||||
cdef public bint text_input
|
||||
|
||||
# gl2 ######################################################################
|
||||
|
||||
# The mesh. If this is not None, the children are all rendered to Textures,
|
||||
# and used to form a model. If this is True, the Mesh is taken from the first
|
||||
# child's Texture, otherwise this must be a Mesh.
|
||||
cdef public object mesh
|
||||
|
||||
# A tuple of shaders that will be used when rendering, or None.
|
||||
cdef public tuple shaders
|
||||
|
||||
# A dictionary containing uniforms that will be used when rendering, or
|
||||
# None.
|
||||
cdef public dict uniforms
|
||||
|
||||
# Properties that control rendering.
|
||||
cdef public dict properties
|
||||
|
||||
# Used to cache the result of rendering this Render to a texture.
|
||||
cdef public object cached_texture
|
||||
|
||||
# Used to cache the model.
|
||||
cdef public object cached_model
|
||||
|
||||
# True if the texture has been loaded.
|
||||
cdef public bint loaded
|
||||
|
||||
|
||||
# operations ###############################################################
|
||||
|
||||
cpdef int blit(Render self, source, tuple pos, object focus=*, object main=*, object index=*)
|
||||
cpdef int subpixel_blit(Render self, source, tuple pos, object focus=*, object main=*, object index=*)
|
||||
cpdef int absolute_blit(Render self, source, tuple pos, object focus=*, object main=*, object index=*)
|
||||
|
||||
+65
-93
@@ -22,6 +22,14 @@
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from renpy.display.matrix import Matrix, Matrix2D
|
||||
from renpy.display.matrix cimport Matrix, Matrix2D
|
||||
|
||||
# This is required to get these to re-export despite having been defined
|
||||
# in cython.
|
||||
globals()["Matrix"] = Matrix
|
||||
globals()["Matrix2D"] = Matrix2D
|
||||
|
||||
import collections
|
||||
import pygame_sdl2 as pygame
|
||||
import threading
|
||||
@@ -59,6 +67,10 @@ per_frame = False
|
||||
# Are we rendering for the purpose of sizing something.
|
||||
sizing = False
|
||||
|
||||
# This is true if we're using a renderer that supports models,
|
||||
# false otherwise.
|
||||
models = False
|
||||
|
||||
def adjust_render_cache_times(old_time, new_time):
|
||||
"""
|
||||
This adjusts the render cache such that if a render starts at
|
||||
@@ -410,74 +422,6 @@ def redraw(d, when):
|
||||
redraw_queue.append((when + renpy.game.interface.frame_time, d))
|
||||
|
||||
|
||||
cdef class Matrix2D:
|
||||
"""
|
||||
This represents a 2d matrix that can be used to transform
|
||||
points and things like that.
|
||||
"""
|
||||
|
||||
def __getstate__(self):
|
||||
return dict(
|
||||
xdx = self.xdx,
|
||||
xdy = self.xdy,
|
||||
ydx = self.ydx,
|
||||
ydy = self.ydy)
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.xdx = state['xdx']
|
||||
self.xdy = state['xdy']
|
||||
self.ydx = state['ydx']
|
||||
self.ydy = state['ydy']
|
||||
|
||||
def __init__(Matrix2D self, double xdx, double xdy, double ydx, double ydy):
|
||||
self.xdx = xdx
|
||||
self.xdy = xdy
|
||||
self.ydx = ydx
|
||||
self.ydy = ydy
|
||||
|
||||
cpdef tuple transform(Matrix2D self, double x, double y):
|
||||
return (x * self.xdx + y * self.xdy), (x * self.ydx + y * self.ydy)
|
||||
|
||||
def __mul__(Matrix2D self, Matrix2D other):
|
||||
return Matrix2D(
|
||||
other.xdx * self.xdx + other.xdy * self.ydx,
|
||||
other.xdx * self.xdy + other.xdy * self.ydy,
|
||||
other.ydx * self.xdx + other.ydy * self.ydx,
|
||||
other.ydx * self.xdy + other.ydy * self.ydy)
|
||||
|
||||
def __repr__(self):
|
||||
return "Matrix2D(xdx=%f, xdy=%f, ydx=%f, ydy=%f)" % (self.xdx, self.xdy, self.ydx, self.ydy)
|
||||
|
||||
def __richcmp__(self, other, op):
|
||||
|
||||
if op != 2:
|
||||
return NotImplemented
|
||||
|
||||
if self is other:
|
||||
return True
|
||||
|
||||
return (
|
||||
abs(self.xdx - other.xdx) +
|
||||
abs(self.xdy - other.xdy) +
|
||||
abs(self.ydx - other.ydx) +
|
||||
abs(self.ydy - other.ydy)) < .00001
|
||||
|
||||
cpdef bint is_unit_aligned(Matrix2D self):
|
||||
"""
|
||||
Returns true if exactly one of abs(xdx) or abs(xdy) is 1.0, and
|
||||
the same for xdy and ydy. This is intended to report if a matrix
|
||||
is aligned to the axes.
|
||||
|
||||
(It will also return true for something like xdx=1, xdy=0, ydx=1, xdy=1,
|
||||
but that should never happen.)
|
||||
"""
|
||||
|
||||
cdef bint unit_xdx = .99999 < abs(self.xdx) < 1.00001
|
||||
cdef bint unit_xdy = .99999 < abs(self.xdy) < 1.00001
|
||||
cdef bint unit_ydx = .99999 < abs(self.ydx) < 1.00001
|
||||
cdef bint unit_ydy = .99999 < abs(self.ydy) < 1.00001
|
||||
|
||||
return (unit_xdx ^ unit_xdy) and (unit_ydx ^ unit_ydy)
|
||||
|
||||
|
||||
IDENTITY = Matrix2D(1, 0, 0, 1)
|
||||
@@ -630,6 +574,7 @@ BLIT = 0
|
||||
DISSOLVE = 1
|
||||
IMAGEDISSOLVE = 2
|
||||
PIXELLATE = 3
|
||||
FLATTEN = 4
|
||||
|
||||
cdef class Render:
|
||||
|
||||
@@ -649,7 +594,6 @@ cdef class Render:
|
||||
# Is has this render been removed from the cache?
|
||||
self.cache_killed = False
|
||||
|
||||
|
||||
self.width = width
|
||||
self.height = height
|
||||
|
||||
@@ -659,25 +603,6 @@ cdef class Render:
|
||||
# back to front.
|
||||
self.children = [ ]
|
||||
|
||||
# The set of renders that either have us as children, or depend on
|
||||
# us.
|
||||
self.parents = set()
|
||||
|
||||
# The renders we depend on, including our children.
|
||||
self.depends_on_list = [ ]
|
||||
|
||||
# The operation we're performing. (BLIT, DISSOLVE, OR IMAGE_DISSOLVE)
|
||||
self.operation = BLIT
|
||||
|
||||
# The fraction of the operation that is complete.
|
||||
self.operation_complete = 0.0
|
||||
|
||||
# Should the dissolve operations preserve alpha?
|
||||
self.operation_alpha = False
|
||||
|
||||
# The parameter to the operation.
|
||||
self.operation_parameter = 0
|
||||
|
||||
# Forward is used to transform from screen coordinates to child
|
||||
# coordinates.
|
||||
# Reverse is used to transform from child coordinates to screen
|
||||
@@ -730,6 +655,33 @@ cdef class Render:
|
||||
self.xclipping = False
|
||||
self.yclipping = False
|
||||
|
||||
# Are we modal?
|
||||
self.modal = False
|
||||
|
||||
# Are we a text input?
|
||||
self.text_input = False
|
||||
|
||||
# gl, sw
|
||||
|
||||
# The set of renders that either have us as children, or depend on
|
||||
# us.
|
||||
self.parents = set()
|
||||
|
||||
# The renders we depend on, including our children.
|
||||
self.depends_on_list = [ ]
|
||||
|
||||
# The operation we're performing. (BLIT, DISSOLVE, OR IMAGE_DISSOLVE)
|
||||
self.operation = BLIT
|
||||
|
||||
# The fraction of the operation that is complete.
|
||||
self.operation_complete = 0.0
|
||||
|
||||
# Should the dissolve operations preserve alpha?
|
||||
self.operation_alpha = False
|
||||
|
||||
# The parameter to the operation.
|
||||
self.operation_parameter = 0
|
||||
|
||||
# Caches of the texture created by rendering this surface.
|
||||
self.surface = None
|
||||
self.alpha_surface = None
|
||||
@@ -738,11 +690,31 @@ cdef class Render:
|
||||
# (This is set in gldraw.)
|
||||
self.half_cache = None
|
||||
|
||||
# Are we modal?
|
||||
self.modal = False
|
||||
# gl2
|
||||
|
||||
# Are we a text input?
|
||||
self.text_input = False
|
||||
# The mesh. If this is not None, the children are all rendered to Textures,
|
||||
# and used to form a model. If this is True, the Mesh is taken from the first
|
||||
# child's Texture, otherwise this must be a Mesh.
|
||||
self.mesh = None
|
||||
|
||||
# A tuple of shaders that will be used when rendering, or None.
|
||||
self.shaders = None
|
||||
|
||||
# A dictionary containing uniforms that will be used when rendering, or
|
||||
# None.
|
||||
self.uniforms = None
|
||||
|
||||
# Properties that are used for rendering.
|
||||
self.properties = None
|
||||
|
||||
# Used to cache the result of rendering this Render to a texture.
|
||||
self.cached_texture = None
|
||||
|
||||
# Used to cache the model.
|
||||
self.cached_model = None
|
||||
|
||||
# Have the textures been loaded?
|
||||
self.loaded = False
|
||||
|
||||
live_renders.append(self)
|
||||
|
||||
@@ -1410,7 +1382,7 @@ cdef class Render:
|
||||
|
||||
return Canvas(surf)
|
||||
|
||||
def screen_rect(self, double sx, double sy, Matrix2D transform):
|
||||
def screen_rect(self, double sx, double sy, Matrix transform):
|
||||
"""
|
||||
Returns the rectangle, in screen-space coordinates, that will be covered
|
||||
by this render when it's drawn to the screen at sx, sy, with the transform
|
||||
|
||||
+26
-11
@@ -680,7 +680,11 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
rv.focus_screen = self
|
||||
|
||||
hiding = (self.phase == OLD) or (self.phase == HIDE)
|
||||
sensitive = renpy.python.py_eval(self.screen.sensitive, locals=self.scope)
|
||||
|
||||
if self.screen is None:
|
||||
sensitive = False
|
||||
else:
|
||||
sensitive = renpy.python.py_eval(self.screen.sensitive, locals=self.scope)
|
||||
|
||||
rv.blit(child, (0, 0), focus=sensitive and not hiding, main=not hiding)
|
||||
rv.modal = self.modal and not hiding
|
||||
@@ -698,6 +702,9 @@ class ScreenDisplayable(renpy.display.layout.Container):
|
||||
if (self.phase == OLD) or (self.phase == HIDE):
|
||||
return
|
||||
|
||||
if not self.screen:
|
||||
return None
|
||||
|
||||
if not renpy.python.py_eval(self.screen.sensitive, locals=self.scope):
|
||||
ev = renpy.display.interface.time_event
|
||||
|
||||
@@ -908,17 +915,25 @@ def prepare_screens():
|
||||
|
||||
predict_cache.clear()
|
||||
|
||||
if not analyzed:
|
||||
analyze_screens()
|
||||
old_predicting = renpy.display.predict.predicting
|
||||
renpy.display.predict.predicting = True
|
||||
|
||||
for s in sorted_variants():
|
||||
if s.ast is None:
|
||||
continue
|
||||
try:
|
||||
|
||||
s.ast.unprepare_screen()
|
||||
s.ast.prepare_screen()
|
||||
if not analyzed:
|
||||
analyze_screens()
|
||||
|
||||
prepared = True
|
||||
for s in sorted_variants():
|
||||
if s.ast is None:
|
||||
continue
|
||||
|
||||
s.ast.unprepare_screen()
|
||||
s.ast.prepare_screen()
|
||||
|
||||
prepared = True
|
||||
|
||||
finally:
|
||||
renpy.display.predict.predicting = old_predicting
|
||||
|
||||
if renpy.config.developer and use_cycle:
|
||||
raise Exception("The following screens use each other in a loop: " + ", ".join(use_cycle) +". This is not allowed.")
|
||||
@@ -1071,8 +1086,8 @@ def show_screen(_screen_name, *_args, **kwargs):
|
||||
If true, the screen will be automatically hidden at the end of
|
||||
the current interaction.
|
||||
|
||||
Keyword arguments not beginning with underscore (_) are used to
|
||||
initialize the screen's scope.
|
||||
Non-keyword arguments, and keyword arguments that do not begin with
|
||||
an underscore, are passed to the screen.
|
||||
"""
|
||||
|
||||
_layer = kwargs.pop("_layer", None)
|
||||
|
||||
+9
-14
@@ -28,7 +28,7 @@ import weakref
|
||||
import time
|
||||
import os
|
||||
|
||||
from renpy.display.render import blit_lock, IDENTITY, BLIT, DISSOLVE, IMAGEDISSOLVE, PIXELLATE
|
||||
from renpy.display.render import blit_lock, IDENTITY, BLIT, DISSOLVE, IMAGEDISSOLVE, PIXELLATE, FLATTEN
|
||||
|
||||
# A map from cached surface to rle version of cached surface.
|
||||
rle_cache = weakref.WeakKeyDictionary()
|
||||
@@ -338,6 +338,10 @@ def draw_special(what, dest, x, y):
|
||||
dest.subsurface((0, 0, w, h)),
|
||||
px, px, px, px)
|
||||
|
||||
elif what.operation == FLATTEN:
|
||||
surf = what.children[0][0].render_to_texture(dest.get_masks()[3])
|
||||
dest.subsurface((0, 0, w, h)).blit(surf, (0, 0))
|
||||
|
||||
else:
|
||||
raise Exception("Unknown operation: %d" % what.operation)
|
||||
|
||||
@@ -635,8 +639,8 @@ def draw_transformed(dest, clip, what, xo, yo, alpha, forward, reverse):
|
||||
cxo, cyo = reverse.transform(cxo, cyo)
|
||||
|
||||
if what.forward:
|
||||
child_forward = forward * what.forward
|
||||
child_reverse = what.reverse * reverse
|
||||
child_forward = what.forward * forward
|
||||
child_reverse = reverse * what.reverse
|
||||
else:
|
||||
child_forward = forward
|
||||
child_reverse = reverse
|
||||
@@ -1108,22 +1112,13 @@ class SWDraw(object):
|
||||
self.mutated_surface(surf)
|
||||
return surf
|
||||
|
||||
def free_memory(self):
|
||||
def kill_textures(self):
|
||||
"""
|
||||
Frees up memory.
|
||||
Kills all textures and caches of textures.
|
||||
"""
|
||||
|
||||
rle_cache.clear()
|
||||
|
||||
def deinit(self):
|
||||
"""
|
||||
Called when we're restarted.
|
||||
"""
|
||||
|
||||
renpy.display.render.free_memory()
|
||||
|
||||
return
|
||||
|
||||
def quit(self): # @ReservedAssignment
|
||||
"""
|
||||
Shuts down the drawing system.
|
||||
|
||||
@@ -369,6 +369,19 @@ class Dissolve(Transition):
|
||||
rv.operation_alpha = self.alpha or renpy.config.dissolve_force_alpha
|
||||
rv.operation_complete = complete
|
||||
|
||||
if renpy.display.render.models:
|
||||
|
||||
target = rv.get_size()
|
||||
|
||||
if top.get_size() != target:
|
||||
top = top.subsurface((0, 0, width, height))
|
||||
if bottom.get_size() != target:
|
||||
bottom = bottom.subsurface((0, 0, width, height))
|
||||
|
||||
rv.mesh = True
|
||||
rv.shaders = ( "renpy.dissolve", )
|
||||
rv.uniforms = { "uDissolve" : complete }
|
||||
|
||||
rv.blit(bottom, (0, 0), focus=False, main=False)
|
||||
rv.blit(top, (0, 0), focus=True, main=True)
|
||||
|
||||
@@ -509,6 +522,32 @@ class ImageDissolve(Transition):
|
||||
rv.operation_complete = complete
|
||||
rv.operation_parameter = self.ramplen
|
||||
|
||||
if renpy.display.render.models:
|
||||
|
||||
target = rv.get_size()
|
||||
|
||||
if image.get_size() != target:
|
||||
image = image.subsurface((0, 0, width, height))
|
||||
if top.get_size() != target:
|
||||
top = top.subsurface((0, 0, width, height))
|
||||
if bottom.get_size() != target:
|
||||
bottom = bottom.subsurface((0, 0, width, height))
|
||||
|
||||
ramp = self.ramplen
|
||||
|
||||
# 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) * complete
|
||||
|
||||
rv.mesh = True
|
||||
rv.shaders = ( "renpy.imagedissolve", )
|
||||
rv.uniforms = { "uDissolveOffset" : offset, "uDissolveMultiplier" : 256.0 / ramp }
|
||||
|
||||
rv.blit(image, (0, 0), focus=False, main=False)
|
||||
rv.blit(bottom, (0, 0), focus=False, main=False)
|
||||
rv.blit(top, (0, 0), focus=True, main=True)
|
||||
|
||||
@@ -278,7 +278,7 @@ class Viewport(renpy.display.layout.Container):
|
||||
|
||||
return rv
|
||||
|
||||
def check_edge_redraw(self, st):
|
||||
def check_edge_redraw(self, st, reset_st=True):
|
||||
redraw = False
|
||||
|
||||
if (self.edge_xspeed > 0) and (self.xadjustment.value < self.xadjustment.range):
|
||||
@@ -293,7 +293,8 @@ class Viewport(renpy.display.layout.Container):
|
||||
|
||||
if redraw:
|
||||
renpy.display.render.redraw(self, 0)
|
||||
self.edge_last_st = st
|
||||
if reset_st or self.edge_last_st is None:
|
||||
self.edge_last_st = st
|
||||
else:
|
||||
self.edge_last_st = None
|
||||
|
||||
@@ -309,18 +310,38 @@ class Viewport(renpy.display.layout.Container):
|
||||
|
||||
if self.draggable and renpy.display.focus.get_grab() == self:
|
||||
|
||||
old_xvalue = self.xadjustment.value
|
||||
old_yvalue = self.yadjustment.value
|
||||
|
||||
if renpy.display.behavior.map_event(ev, 'viewport_drag_end'):
|
||||
renpy.display.focus.set_grab(None)
|
||||
|
||||
# Invoke rounding adjustment on viewport release
|
||||
xvalue = self.xadjustment.round_value(old_xvalue, release=True)
|
||||
self.xadjustment.change(xvalue)
|
||||
yvalue = self.yadjustment.round_value(old_yvalue, release=True)
|
||||
self.yadjustment.change(yvalue)
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
|
||||
oldx, oldy = self.drag_position
|
||||
dx = x - oldx
|
||||
dy = y - oldy
|
||||
|
||||
self.xadjustment.change(self.xadjustment.value - dx)
|
||||
self.yadjustment.change(self.yadjustment.value - dy)
|
||||
new_xvalue = self.xadjustment.round_value(old_xvalue - dx, release=False)
|
||||
if old_xvalue == new_xvalue:
|
||||
newx = oldx
|
||||
else:
|
||||
self.xadjustment.change(new_xvalue)
|
||||
newx = x
|
||||
|
||||
self.drag_position = (x, y) # W0201
|
||||
new_yvalue = self.yadjustment.round_value(old_yvalue - dy, release=False)
|
||||
if old_yvalue == new_yvalue:
|
||||
newy = oldy
|
||||
else:
|
||||
self.yadjustment.change(new_yvalue)
|
||||
newy = y
|
||||
|
||||
if renpy.display.behavior.map_event(ev, 'viewport_drag_end'):
|
||||
renpy.display.focus.set_grab(None)
|
||||
raise renpy.display.core.IgnoreEvent()
|
||||
self.drag_position = (newx, newy) # W0201
|
||||
|
||||
if not ((0 <= x < self.width) and (0 <= y <= self.height)):
|
||||
self.edge_xspeed = 0
|
||||
@@ -474,7 +495,7 @@ class Viewport(renpy.display.layout.Container):
|
||||
self.edge_yspeed = self.edge_speed * self.edge_function(yspeed)
|
||||
|
||||
if xspeed or yspeed:
|
||||
self.check_edge_redraw(st)
|
||||
self.check_edge_redraw(st, reset_st=False)
|
||||
else:
|
||||
self.edge_last_st = None
|
||||
|
||||
|
||||
+12
-3
@@ -147,6 +147,8 @@ class Context(renpy.object.Object):
|
||||
|
||||
temporary_attributes = None
|
||||
|
||||
deferred_translate_identifier = None
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
if not self.current:
|
||||
@@ -277,7 +279,7 @@ class Context(renpy.object.Object):
|
||||
# executed?
|
||||
self.force_checkpoint = False
|
||||
|
||||
# A mapt from a channel to the Movie playing on that channel.
|
||||
# A map from a channel to the Movie playing on that channel.
|
||||
self.movie = { }
|
||||
|
||||
if context:
|
||||
@@ -299,6 +301,9 @@ class Context(renpy.object.Object):
|
||||
|
||||
self.scene_lists = renpy.display.core.SceneLists(oldsl, self.images)
|
||||
|
||||
for i in renpy.config.context_copy_remove_screens:
|
||||
self.scene_lists.remove("screens", i, None)
|
||||
|
||||
self.make_dynamic([ "_return", "_args", "_kwargs", "mouse_visible", "suppress_overlay", "_side_image_attributes" ])
|
||||
self.dynamic_stack.append({ })
|
||||
|
||||
@@ -319,6 +324,10 @@ class Context(renpy.object.Object):
|
||||
# The alternate identifier of the current translate block.
|
||||
self.alternate_translate_identifier = None
|
||||
|
||||
# The translate identifier of the last say statement with
|
||||
# interact = False.
|
||||
self.deferred_translate_identifier = None
|
||||
|
||||
def replace_node(self, old, new):
|
||||
|
||||
def replace_one(name):
|
||||
@@ -369,7 +378,7 @@ class Context(renpy.object.Object):
|
||||
|
||||
for k, v in dynamic.iteritems():
|
||||
if isinstance(v, Delete):
|
||||
del store[k]
|
||||
store.pop(k, None)
|
||||
else:
|
||||
store[k] = v
|
||||
|
||||
@@ -592,7 +601,7 @@ class Context(renpy.object.Object):
|
||||
except renpy.game.CallException as e:
|
||||
|
||||
if e.from_current:
|
||||
return_site = node.name
|
||||
return_site = getattr(node, "statement_start", node).name
|
||||
else:
|
||||
if self.next_node is None:
|
||||
raise Exception("renpy.call can't be used when the next node is undefined.")
|
||||
|
||||
+30
-11
@@ -91,7 +91,6 @@ from renpy.parser import unelide_filename, get_parse_errors
|
||||
from renpy.translation import change_language, known_languages
|
||||
from renpy.translation.generation import generic_filter as transform_text
|
||||
|
||||
|
||||
from renpy.persistent import register_persistent
|
||||
|
||||
from renpy.character import show_display_say, predict_show_display_say, display_say
|
||||
@@ -116,6 +115,8 @@ from renpy.loader import add_python_directory
|
||||
|
||||
from renpy.lint import try_compile, try_eval
|
||||
|
||||
from renpy.gl2.gl2shadercache import register_shader
|
||||
|
||||
renpy_pure("ParameterizedText")
|
||||
renpy_pure("Keymap")
|
||||
renpy_pure("has_screen")
|
||||
@@ -469,7 +470,7 @@ def can_show(name, layer=None, tag=None):
|
||||
return None
|
||||
|
||||
|
||||
def showing(name, layer='master'):
|
||||
def showing(name, layer=None):
|
||||
"""
|
||||
:doc: image_func
|
||||
|
||||
@@ -481,7 +482,6 @@ def showing(name, layer='master'):
|
||||
component of the image name. It may also be a string giving
|
||||
only the image tag.
|
||||
|
||||
|
||||
`layer`
|
||||
The layer to check. If None, uses the default layer for `tag`.
|
||||
"""
|
||||
@@ -780,7 +780,7 @@ def scene(layer='master'):
|
||||
renpy.config.missing_scene(layer)
|
||||
|
||||
|
||||
def input(prompt, default='', allow=None, exclude='{}', length=None, with_none=None, pixel_width=None): # @ReservedAssignment
|
||||
def input(prompt, default='', allow=None, exclude='{}', length=None, with_none=None, pixel_width=None, screen="input"): # @ReservedAssignment
|
||||
"""
|
||||
:doc: input
|
||||
|
||||
@@ -809,6 +809,10 @@ def input(prompt, default='', allow=None, exclude='{}', length=None, with_none=N
|
||||
If not None, the input is limited to being this many pixels wide,
|
||||
in the font used by the input to display text.
|
||||
|
||||
`screen`
|
||||
The name of the screen that takes input. If not given, the ``input``
|
||||
screen is used.
|
||||
|
||||
If :var:`config.disable_input` is True, this function only returns
|
||||
`default`.
|
||||
"""
|
||||
@@ -828,14 +832,17 @@ def input(prompt, default='', allow=None, exclude='{}', length=None, with_none=N
|
||||
|
||||
fixed = in_fixed_rollback()
|
||||
|
||||
if has_screen("input"):
|
||||
if has_screen(screen):
|
||||
widget_properties = { }
|
||||
widget_properties["input"] = dict(default=default, length=length, allow=allow, exclude=exclude, editable=not fixed, pixel_width=pixel_width)
|
||||
|
||||
show_screen("input", _transient=True, _widget_properties=widget_properties, prompt=prompt)
|
||||
show_screen(screen, _transient=True, _widget_properties=widget_properties, prompt=prompt)
|
||||
|
||||
else:
|
||||
|
||||
if screen != "input":
|
||||
raise Exception("The '{}' screen does not exist.".format(screen))
|
||||
|
||||
renpy.ui.window(style='input_window')
|
||||
renpy.ui.vbox()
|
||||
|
||||
@@ -1188,6 +1195,8 @@ def display_menu(items,
|
||||
**scope)
|
||||
|
||||
else:
|
||||
renpy.exports.shown_window()
|
||||
|
||||
renpy.ui.window(style=window_style, focus="menu")
|
||||
renpy.ui.menu(items,
|
||||
location=renpy.game.context().current,
|
||||
@@ -2670,7 +2679,7 @@ def get_placement(d):
|
||||
return placement(p)
|
||||
|
||||
|
||||
def get_image_bounds(tag, width=None, height=None, layer='master'):
|
||||
def get_image_bounds(tag, width=None, height=None, layer=None):
|
||||
"""
|
||||
:doc: image_func
|
||||
|
||||
@@ -2868,8 +2877,8 @@ def call_screen(_screen_name, *args, **kwargs):
|
||||
to occur. The screen is hidden at the end of the interaction, and
|
||||
the result of the interaction is returned.
|
||||
|
||||
Keyword arguments not beginning with _ are passed to the scope of
|
||||
the screen.
|
||||
Positional arguments, and keyword arguments that do not begin with
|
||||
_ are passed to the screen.
|
||||
|
||||
If the keyword argument `_with_none` is false, "with None" is not
|
||||
run at the end of end of the interaction.
|
||||
@@ -3715,8 +3724,8 @@ def get_skipping():
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
Returns true if the Ren'Py is skipping, "fast" if Ren'Py is fast skipping,
|
||||
and false if it is not skipping.
|
||||
Returns "slow" if the Ren'Py is skipping, "fast" if Ren'Py is fast skipping,
|
||||
and None if it is not skipping.
|
||||
"""
|
||||
|
||||
return renpy.config.skipping
|
||||
@@ -3783,3 +3792,13 @@ def is_skipping():
|
||||
"""
|
||||
|
||||
return not not renpy.config.skipping
|
||||
|
||||
|
||||
def is_init_phase():
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
Returns True if Ren'Py is currently executing init code, or False otherwise.
|
||||
"""
|
||||
|
||||
return renpy.game.context().init_phase
|
||||
|
||||
@@ -1526,16 +1526,19 @@ cdef extern from "glcompat.h" nogil:
|
||||
cdef int glActiveTextureARB(GLenum) except? 0
|
||||
cdef int glAttachObjectARB(GLhandleARB, GLhandleARB) except? 0
|
||||
cdef int glBindFramebufferEXT(GLenum, GLuint) except? 0
|
||||
cdef int glBindRenderbufferEXT(GLenum, GLuint) except? 0
|
||||
cdef int glBindTexture(GLenum, GLuint) except? 0
|
||||
cdef int glBlendFunc(GLenum, GLenum) except? 0
|
||||
cdef int glClear(GLbitfield) except? 0
|
||||
cdef int glClearColor(GLclampf, GLclampf, GLclampf, GLclampf) except? 0
|
||||
cdef int glCompileShaderARB(GLhandleARB) except? 0
|
||||
cdef int glCopyTexImage2D(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint) except? 0
|
||||
cdef int glCopyTexSubImage2D(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei) except? 0
|
||||
cdef GLhandleARB glCreateProgramObjectARB() except? 0
|
||||
cdef GLhandleARB glCreateShaderObjectARB(GLenum) except? 0
|
||||
cdef int glDeleteFramebuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glDeleteProgram(GLuint) except? 0
|
||||
cdef int glDeleteRenderbuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glDeleteShader(GLuint) except? 0
|
||||
cdef int glDeleteTextures(GLsizei, GLuint *) except? 0
|
||||
cdef int glDisable(GLenum) except? 0
|
||||
@@ -1544,8 +1547,10 @@ cdef int glDrawArrays(GLenum, GLint, GLsizei) except? 0
|
||||
cdef int glEnable(GLenum) except? 0
|
||||
cdef int glEnableVertexAttribArrayARB(GLuint) except? 0
|
||||
cdef int glFinish() except? 0
|
||||
cdef int glFramebufferRenderbufferEXT(GLenum, GLenum, GLenum, GLuint) except? 0
|
||||
cdef int glFramebufferTexture2DEXT(GLenum, GLenum, GLenum, GLuint, GLint) except? 0
|
||||
cdef int glGenFramebuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glGenRenderbuffersEXT(GLsizei, GLuint *) except? 0
|
||||
cdef int glGenTextures(GLsizei, GLuint *) except? 0
|
||||
cdef GLint glGetAttribLocationARB(GLhandleARB, GLchar *) except? 0
|
||||
cdef int glGetIntegerv(GLenum, GLint *) except? 0
|
||||
@@ -1557,6 +1562,7 @@ cdef GLchar * glGetString(GLenum) except? NULL
|
||||
cdef GLint glGetUniformLocationARB(GLhandleARB, GLchar *) except? 0
|
||||
cdef int glLinkProgramARB(GLhandleARB) except? 0
|
||||
cdef int glReadPixels(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLubyte *) except? 0
|
||||
cdef int glRenderbufferStorageEXT(GLenum, GLenum, GLsizei, GLsizei) except? 0
|
||||
cdef int glScissor(GLint, GLint, GLsizei, GLsizei) except? 0
|
||||
cdef int glShaderSourceARB(GLhandleARB, GLsizei, GLchar * *, GLint *) except? 0
|
||||
cdef int glTexImage2D(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, GLubyte *) except? 0
|
||||
|
||||
+90
-2
@@ -1,5 +1,3 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import renpy
|
||||
|
||||
@@ -52,6 +50,21 @@ cdef int glBindFramebufferEXT(GLenum a0, GLuint a1) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glBindRenderbufferEXT(GLenum a0, GLuint a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glBindRenderbufferEXT')
|
||||
cdef GLenum error
|
||||
realGlBindRenderbufferEXT(a0, a1)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glBindRenderbufferEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glBindTexture(GLenum a0, GLuint a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glBindTexture')
|
||||
@@ -128,6 +141,21 @@ cdef int glCompileShaderARB(GLhandleARB a0) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glCopyTexImage2D(GLenum a0, GLint a1, GLenum a2, GLint a3, GLint a4, GLsizei a5, GLsizei a6, GLint a7) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glCopyTexImage2D')
|
||||
cdef GLenum error
|
||||
realGlCopyTexImage2D(a0, a1, a2, a3, a4, a5, a6, a7)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glCopyTexImage2D' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glCopyTexSubImage2D(GLenum a0, GLint a1, GLint a2, GLint a3, GLint a4, GLint a5, GLsizei a6, GLsizei a7) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glCopyTexSubImage2D')
|
||||
@@ -203,6 +231,21 @@ cdef int glDeleteProgram(GLuint a0) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glDeleteRenderbuffersEXT(GLsizei a0, GLuint * a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glDeleteRenderbuffersEXT')
|
||||
cdef GLenum error
|
||||
realGlDeleteRenderbuffersEXT(a0, a1)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glDeleteRenderbuffersEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glDeleteShader(GLuint a0) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glDeleteShader')
|
||||
@@ -323,6 +366,21 @@ cdef int glFinish() except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glFramebufferRenderbufferEXT(GLenum a0, GLenum a1, GLenum a2, GLuint a3) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glFramebufferRenderbufferEXT')
|
||||
cdef GLenum error
|
||||
realGlFramebufferRenderbufferEXT(a0, a1, a2, a3)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glFramebufferRenderbufferEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glFramebufferTexture2DEXT(GLenum a0, GLenum a1, GLenum a2, GLuint a3, GLint a4) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glFramebufferTexture2DEXT')
|
||||
@@ -353,6 +411,21 @@ cdef int glGenFramebuffersEXT(GLsizei a0, GLuint * a1) except? 0:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glGenRenderbuffersEXT(GLsizei a0, GLuint * a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glGenRenderbuffersEXT')
|
||||
cdef GLenum error
|
||||
realGlGenRenderbuffersEXT(a0, a1)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glGenRenderbuffersEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glGenTextures(GLsizei a0, GLuint * a1) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glGenTextures')
|
||||
@@ -518,6 +591,21 @@ cdef int glReadPixels(GLint a0, GLint a1, GLsizei a2, GLsizei a3, GLenum a4, GLe
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glRenderbufferStorageEXT(GLenum a0, GLenum a1, GLsizei a2, GLsizei a3) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glRenderbufferStorageEXT')
|
||||
cdef GLenum error
|
||||
realGlRenderbufferStorageEXT(a0, a1, a2, a3)
|
||||
if check_errors:
|
||||
error = realGlGetError()
|
||||
if error:
|
||||
message = 'GL error %x in glRenderbufferStorageEXT' % error
|
||||
if check_errors & 1:
|
||||
renpy.display.log.write('%s', message)
|
||||
if check_errors & 2:
|
||||
raise Exception(message)
|
||||
return 1
|
||||
|
||||
cdef int glScissor(GLint a0, GLint a1, GLsizei a2, GLsizei a3) except? 0:
|
||||
if check_errors & 4:
|
||||
renpy.display.log.write('glScissor')
|
||||
|
||||
+4
-3
@@ -19,6 +19,7 @@
|
||||
# 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 renpy.display.matrix cimport Matrix, Matrix2D
|
||||
cimport renpy.display.render as render
|
||||
|
||||
cdef class Environ
|
||||
@@ -58,8 +59,8 @@ cdef class GLDraw:
|
||||
cdef public object draw_per_virt
|
||||
|
||||
# Matrices that transform drawable to virtual, and vice versa.
|
||||
cdef public render.Matrix2D virt_to_draw
|
||||
cdef public render.Matrix2D draw_to_virt
|
||||
cdef public Matrix virt_to_draw
|
||||
cdef public Matrix draw_to_virt
|
||||
|
||||
cdef public int fast_redraw_frames
|
||||
|
||||
@@ -78,7 +79,7 @@ cdef class GLDraw:
|
||||
double yo,
|
||||
double alpha,
|
||||
double over,
|
||||
render.Matrix2D reverse,
|
||||
Matrix reverse,
|
||||
bint nearest,
|
||||
bint subpixel) except 1
|
||||
|
||||
|
||||
+34
-21
@@ -65,10 +65,11 @@ cdef bint EGL
|
||||
EGL = egl_available()
|
||||
|
||||
# Cache various externals, so we can use them more efficiently.
|
||||
cdef int DISSOLVE, IMAGEDISSOLVE, PIXELLATE
|
||||
cdef int DISSOLVE, IMAGEDISSOLVE, PIXELLATE, FLATTEN
|
||||
DISSOLVE = renpy.display.render.DISSOLVE
|
||||
IMAGEDISSOLVE = renpy.display.render.IMAGEDISSOLVE
|
||||
PIXELLATE = renpy.display.render.PIXELLATE
|
||||
FLATTEN = renpy.display.render.FLATTEN
|
||||
|
||||
cdef object IDENTITY
|
||||
IDENTITY = renpy.display.render.IDENTITY
|
||||
@@ -181,11 +182,15 @@ cdef class GLDraw:
|
||||
return False
|
||||
|
||||
if self.did_init:
|
||||
self.deinit()
|
||||
self.kill_textures()
|
||||
|
||||
if renpy.android:
|
||||
fullscreen = False
|
||||
|
||||
# Refresh fullscreen status (e.g. user pressed Esc. in browser)
|
||||
main_window = pygame.display.get_window()
|
||||
self.old_fullscreen = main_window is not None and bool(main_window.get_window_flags() & (pygame.WINDOW_FULLSCREEN_DESKTOP|pygame.WINDOW_FULLSCREEN))
|
||||
|
||||
if fullscreen != self.old_fullscreen:
|
||||
|
||||
self.did_init = False
|
||||
@@ -414,8 +419,8 @@ cdef class GLDraw:
|
||||
else:
|
||||
self.draw_per_virt = 1.0
|
||||
|
||||
self.virt_to_draw = render.Matrix2D(self.draw_per_virt, 0, 0, self.draw_per_virt)
|
||||
self.draw_to_virt = render.Matrix2D(1.0 / self.draw_per_virt, 0, 0, 1.0 / self.draw_per_virt)
|
||||
self.virt_to_draw = Matrix2D(self.draw_per_virt, 0, 0, self.draw_per_virt)
|
||||
self.draw_to_virt = Matrix2D(1.0 / self.draw_per_virt, 0, 0, 1.0 / self.draw_per_virt)
|
||||
|
||||
if not self.did_init:
|
||||
if not self.init():
|
||||
@@ -446,17 +451,12 @@ cdef class GLDraw:
|
||||
|
||||
return True
|
||||
|
||||
def deinit(self):
|
||||
def quit(self):
|
||||
"""
|
||||
De-initializes the system in preparation for a restart, or
|
||||
quit. Flushes out all the textures while it's at it.
|
||||
This shuts down the module and all use of the GL context.
|
||||
"""
|
||||
|
||||
renpy.display.interface.kill_textures()
|
||||
|
||||
self.texture_cache.clear()
|
||||
|
||||
gltexture.dealloc_textures()
|
||||
self.kill_textures()
|
||||
|
||||
if self.rtt:
|
||||
self.rtt.deinit()
|
||||
@@ -464,8 +464,6 @@ cdef class GLDraw:
|
||||
if self.environ:
|
||||
self.environ.deinit()
|
||||
|
||||
def quit(self):
|
||||
|
||||
if not self.old_fullscreen:
|
||||
renpy.display.gl_size = self.physical_size
|
||||
|
||||
@@ -943,13 +941,13 @@ cdef class GLDraw:
|
||||
double yo,
|
||||
double alpha,
|
||||
double over,
|
||||
render.Matrix2D reverse,
|
||||
Matrix reverse,
|
||||
bint nearest,
|
||||
bint subpixel) except 1:
|
||||
|
||||
cdef render.Render rend
|
||||
cdef double cxo, cyo, tcxo, tcyo
|
||||
cdef render.Matrix2D child_reverse
|
||||
cdef Matrix child_reverse
|
||||
|
||||
if not isinstance(what, render.Render):
|
||||
|
||||
@@ -1039,7 +1037,7 @@ cdef class GLDraw:
|
||||
return 0
|
||||
|
||||
|
||||
if rend.operation == PIXELLATE:
|
||||
elif rend.operation == PIXELLATE:
|
||||
self.set_clip(clip)
|
||||
|
||||
p = rend.operation_parameter
|
||||
@@ -1049,7 +1047,7 @@ cdef class GLDraw:
|
||||
p /= 2
|
||||
pc = self.get_half(pc)
|
||||
|
||||
reverse *= renpy.display.render.Matrix2D(1.0 * what.width / pc.width, 0, 0, 1.0 * what.height / pc.height)
|
||||
reverse *= Matrix2D(1.0 * what.width / pc.width, 0, 0, 1.0 * what.height / pc.height)
|
||||
|
||||
gltexture.blit(
|
||||
pc,
|
||||
@@ -1063,6 +1061,21 @@ cdef class GLDraw:
|
||||
|
||||
return 0
|
||||
|
||||
elif rend.operation == FLATTEN:
|
||||
self.set_clip(clip)
|
||||
|
||||
gltexture.blit(
|
||||
rend.children[0][0].render_to_texture(True),
|
||||
xo,
|
||||
yo,
|
||||
reverse * self.draw_to_virt,
|
||||
alpha,
|
||||
over,
|
||||
self.environ,
|
||||
nearest)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
# Compute clipping.
|
||||
if rend.xclipping or rend.yclipping:
|
||||
@@ -1100,7 +1113,7 @@ cdef class GLDraw:
|
||||
return 0
|
||||
|
||||
if rend.reverse is not None and rend.reverse is not IDENTITY:
|
||||
child_reverse = rend.reverse * reverse
|
||||
child_reverse = reverse * rend.reverse
|
||||
else:
|
||||
child_reverse = reverse
|
||||
|
||||
@@ -1209,7 +1222,7 @@ cdef class GLDraw:
|
||||
if what.half_cache:
|
||||
return what.half_cache
|
||||
|
||||
reverse = renpy.display.render.Matrix2D(0.5, 0, 0, .5)
|
||||
reverse = Matrix2D(0.5, 0, 0, .5)
|
||||
|
||||
width = max(what.width / 2, 1)
|
||||
height = max(what.height / 2, 1)
|
||||
@@ -1399,7 +1412,7 @@ cdef class GLDraw:
|
||||
|
||||
return rv
|
||||
|
||||
def free_memory(self):
|
||||
def kill_textures(self):
|
||||
self.texture_cache.clear()
|
||||
gltexture.dealloc_textures()
|
||||
|
||||
|
||||
@@ -31,11 +31,17 @@ cdef int round(double d):
|
||||
return <int> (d + .5)
|
||||
|
||||
|
||||
VERTEX_SHADER1 = """\
|
||||
GLES_PORTABILITY = """\
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
# else
|
||||
precision mediump float;
|
||||
# endif
|
||||
#endif
|
||||
"""
|
||||
|
||||
VERTEX_SHADER1 = GLES_PORTABILITY + """\
|
||||
uniform mat4 Projection;
|
||||
|
||||
attribute vec4 Vertex;
|
||||
@@ -53,11 +59,7 @@ void main() {
|
||||
}
|
||||
"""
|
||||
|
||||
VERTEX_SHADER2 = """\
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
VERTEX_SHADER2 = GLES_PORTABILITY + """\
|
||||
uniform mat4 Projection;
|
||||
|
||||
attribute vec4 Vertex;
|
||||
@@ -78,11 +80,7 @@ void main() {
|
||||
}
|
||||
"""
|
||||
|
||||
VERTEX_SHADER3 = """\
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
VERTEX_SHADER3 = GLES_PORTABILITY + """\
|
||||
uniform mat4 Projection;
|
||||
|
||||
attribute vec4 Vertex;
|
||||
@@ -109,11 +107,7 @@ void main() {
|
||||
|
||||
|
||||
|
||||
BLIT_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
BLIT_SHADER = GLES_PORTABILITY + """\
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
|
||||
@@ -130,11 +124,7 @@ void main()
|
||||
}
|
||||
"""
|
||||
|
||||
BLIT_CLIP_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
BLIT_CLIP_SHADER = GLES_PORTABILITY + """\
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
|
||||
@@ -155,11 +145,7 @@ void main()
|
||||
}
|
||||
"""
|
||||
|
||||
BLEND_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
BLEND_SHADER = GLES_PORTABILITY + """\
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
@@ -182,11 +168,7 @@ void main()
|
||||
"""
|
||||
|
||||
|
||||
BLEND_CLIP_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
BLEND_CLIP_SHADER = GLES_PORTABILITY + """\
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
@@ -212,11 +194,7 @@ void main()
|
||||
}
|
||||
"""
|
||||
|
||||
IMAGEBLEND_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
IMAGEBLEND_SHADER = GLES_PORTABILITY + """\
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
@@ -244,11 +222,7 @@ void main()
|
||||
}
|
||||
"""
|
||||
|
||||
IMAGEBLEND_CLIP_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
IMAGEBLEND_CLIP_SHADER = GLES_PORTABILITY + """\
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
|
||||
+27
-11
@@ -35,22 +35,41 @@ cdef GLuint fbo
|
||||
# The root framebuffer.
|
||||
cdef GLint root_fbo
|
||||
|
||||
# The renderbuffer object we use.
|
||||
cdef GLuint texture
|
||||
|
||||
class FboRtt(Rtt):
|
||||
"""
|
||||
This class uses texture copying to implement Render-to-texture.
|
||||
"""
|
||||
|
||||
def init(self):
|
||||
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &root_fbo);
|
||||
renpy.display.log.write("Root FBO is: %d", root_fbo)
|
||||
|
||||
glGenFramebuffersEXT(1, &fbo)
|
||||
glGenTextures(1, &texture)
|
||||
|
||||
cdef int i
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &i)
|
||||
self.size_limit = i
|
||||
renpy.display.log.write("FBO Maximum Texture Size: %d", i)
|
||||
self.size_limit = min(i, 2048)
|
||||
renpy.display.log.write("FBO Maximum Texture Size: %d", self.size_limit)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.size_limit, self.size_limit, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL)
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)
|
||||
glFramebufferTexture2DEXT(
|
||||
GL_FRAMEBUFFER_EXT,
|
||||
GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_TEXTURE_2D,
|
||||
texture,
|
||||
0)
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, root_fbo)
|
||||
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &root_fbo);
|
||||
renpy.display.log.write("Root FBO is: %d", root_fbo)
|
||||
|
||||
def deinit(self):
|
||||
"""
|
||||
@@ -59,6 +78,7 @@ class FboRtt(Rtt):
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, root_fbo)
|
||||
glDeleteFramebuffersEXT(1, &fbo)
|
||||
glDeleteTextures(1, &texture)
|
||||
|
||||
def begin(self):
|
||||
"""
|
||||
@@ -77,18 +97,14 @@ class FboRtt(Rtt):
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)
|
||||
|
||||
glFramebufferTexture2DEXT(
|
||||
GL_FRAMEBUFFER_EXT,
|
||||
GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_TEXTURE_2D,
|
||||
texture,
|
||||
0)
|
||||
|
||||
environ.viewport(0, 0, w, h)
|
||||
environ.ortho(x, x + w, y, y + h, -1, 1)
|
||||
|
||||
draw_func(x, y, w, h)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture)
|
||||
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0)
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, root_fbo)
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
# 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 renpy.display.matrix cimport Matrix
|
||||
cimport renpy.display.render as render
|
||||
from gldraw cimport Environ
|
||||
|
||||
@@ -70,7 +71,7 @@ cpdef blit(
|
||||
TextureGrid tg,
|
||||
double sx,
|
||||
double sy,
|
||||
render.Matrix2D transform,
|
||||
Matrix transform,
|
||||
double alpha,
|
||||
double over,
|
||||
Environ environ,
|
||||
@@ -81,7 +82,7 @@ cpdef blend(
|
||||
TextureGrid tg1,
|
||||
double sx,
|
||||
double sy,
|
||||
render.Matrix2D transform,
|
||||
Matrix transform,
|
||||
double alpha,
|
||||
double over,
|
||||
double fraction,
|
||||
@@ -94,7 +95,7 @@ cpdef imageblend(
|
||||
TextureGrid tg2,
|
||||
double sx,
|
||||
double sy,
|
||||
render.Matrix2D transform,
|
||||
Matrix transform,
|
||||
double alpha,
|
||||
double over,
|
||||
double fraction,
|
||||
|
||||
+4
-17
@@ -269,25 +269,12 @@ cdef class TextureCore:
|
||||
self.generation = 0
|
||||
self.number = 0
|
||||
|
||||
# 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
|
||||
self.xadd = 0
|
||||
self.ymul = 0
|
||||
self.yadd = 0
|
||||
|
||||
# These contained the premultiplied (but not GPU-loaded)
|
||||
# surface. They allow us to defer loading until the surface is
|
||||
# needed.
|
||||
|
||||
self.premult = None
|
||||
self.premult_size = 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
|
||||
@@ -992,7 +979,7 @@ def align_axes(*args):
|
||||
return rv
|
||||
|
||||
|
||||
cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, double alpha, double over, Environ environ, bint nearest):
|
||||
cpdef blit(TextureGrid tg, double sx, double sy, Matrix transform, double alpha, double over, Environ environ, bint nearest):
|
||||
"""
|
||||
This draws texgrid `tg` to the screen. `sx` and `sy` are offsets from
|
||||
the upper-left corner of the screen.
|
||||
@@ -1037,7 +1024,7 @@ cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, doub
|
||||
|
||||
y += texh
|
||||
|
||||
cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matrix2D transform, double alpha, double over, double fraction, Environ environ, bint nearest):
|
||||
cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, Matrix transform, double alpha, double over, double fraction, Environ environ, bint nearest):
|
||||
"""
|
||||
Blends two textures to the screen.
|
||||
|
||||
@@ -1094,7 +1081,7 @@ cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matri
|
||||
y += t0h
|
||||
|
||||
|
||||
cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, double sy, render.Matrix2D transform, double alpha, double over, double fraction, int ramp, Environ environ, bint nearest):
|
||||
cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, double sy, Matrix transform, double alpha, double over, double fraction, int ramp, Environ environ, bint nearest):
|
||||
"""
|
||||
This uses texture 0 to control the blending of tetures 1 and 2 to
|
||||
the screen.
|
||||
@@ -1384,7 +1371,7 @@ cdef void draw_rectangle(
|
||||
double y,
|
||||
double w,
|
||||
double h,
|
||||
render.Matrix2D transform,
|
||||
Matrix transform,
|
||||
TextureCore tex0, float tex0x, float tex0y,
|
||||
TextureCore tex1, float tex1x, float tex1y,
|
||||
TextureCore tex2, float tex2x, float tex2y,
|
||||
|
||||
+24
-41
@@ -19,16 +19,14 @@
|
||||
# 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 renpy.display.matrix cimport Matrix, Matrix2D
|
||||
cimport renpy.display.render as render
|
||||
|
||||
cdef class Environ
|
||||
from renpy.gl2.gl2texture cimport TextureLoader
|
||||
from uguugl cimport *
|
||||
|
||||
cdef class GL2Draw:
|
||||
|
||||
cdef bint did_init
|
||||
cdef bint did_texture_test
|
||||
cdef Environ environ
|
||||
cdef public object rtt
|
||||
cdef object window
|
||||
cdef tuple virtual_size
|
||||
cdef public tuple physical_size
|
||||
@@ -45,53 +43,38 @@ cdef class GL2Draw:
|
||||
cdef public object fullscreen_surface
|
||||
cdef object display_info
|
||||
cdef tuple clip_cache
|
||||
cdef bint fast_dissolve
|
||||
cdef tuple default_clip
|
||||
cdef bint did_render_to_texture
|
||||
cdef float dpi_scale
|
||||
cdef object ready_texture_queue
|
||||
cdef object shader_cache
|
||||
|
||||
cdef public tuple clip_rtt_box
|
||||
|
||||
# The number of drawable pixels per virtual pixel.
|
||||
cdef public object draw_per_virt
|
||||
cdef public float draw_per_phys
|
||||
cdef public tuple drawable_viewport
|
||||
|
||||
# Matrices that transform drawable to virtual, and vice versa.
|
||||
cdef public render.Matrix2D virt_to_draw
|
||||
cdef public render.Matrix2D draw_to_virt
|
||||
cdef public object draw_per_virt
|
||||
cdef public Matrix virt_to_draw
|
||||
cdef public Matrix draw_to_virt
|
||||
|
||||
cdef public int fast_redraw_frames
|
||||
|
||||
cdef public bint gles
|
||||
|
||||
cpdef set_clip(GL2Draw self, tuple clip)
|
||||
# The color texture object used for offscreen rendering.
|
||||
cdef GLuint color_texture
|
||||
|
||||
cpdef int draw_render_textures(
|
||||
GL2Draw self,
|
||||
object what,
|
||||
bint non_aligned) except 1
|
||||
# The depth renderbuffer object used for offscreen rendering.
|
||||
cdef GLuint depth_renderbuffer
|
||||
|
||||
cpdef int draw_transformed(
|
||||
GL2Draw self,
|
||||
object what,
|
||||
tuple clip,
|
||||
double xo,
|
||||
double yo,
|
||||
double alpha,
|
||||
double over,
|
||||
render.Matrix2D reverse,
|
||||
bint nearest,
|
||||
bint subpixel) except 1
|
||||
# The framebuffer object used for offscreen rendering.
|
||||
cdef GLuint fbo
|
||||
|
||||
cdef class Environ:
|
||||
cdef void blit(self)
|
||||
cdef void blend(self, double fraction)
|
||||
cdef void imageblend(self, double fraction, int ramp)
|
||||
cdef void set_vertex(self, float *vertices)
|
||||
cdef void set_texture(self, int unit, float *coords)
|
||||
cdef void set_color(self, double r, double g, double b, double a)
|
||||
cdef void set_clip(self, tuple clip_box, GL2Draw draw)
|
||||
cdef void unset_clip(self, GL2Draw draw)
|
||||
cdef void ortho(self, double left, double right, double bottom, double top, double near, double far)
|
||||
cdef void viewport(self, int x, int y, int width, int height)
|
||||
# The texture_loader singleton.
|
||||
cdef public TextureLoader texture_loader
|
||||
|
||||
# The default FBO.
|
||||
cdef public GLuint default_fbo
|
||||
|
||||
# The current FBO.
|
||||
cdef public GLuint current_fbo
|
||||
|
||||
cdef void change_fbo(self, GLuint fbo)
|
||||
|
||||
+556
-700
File diff suppressed because it is too large
Load Diff
@@ -1,696 +0,0 @@
|
||||
#cython: profile=False
|
||||
# Copyright 2004-2019 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 __future__ import print_function
|
||||
|
||||
DEF ANGLE = False
|
||||
|
||||
from uguugl cimport *
|
||||
from gl2draw cimport *
|
||||
|
||||
cdef int round(double d):
|
||||
return <int> (d + .5)
|
||||
|
||||
|
||||
VERTEX_SHADER1 = """\
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform mat4 Projection;
|
||||
|
||||
attribute vec4 Vertex;
|
||||
attribute vec2 VertexTexCoord0;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
|
||||
varying vec2 pos;
|
||||
|
||||
void main() {
|
||||
TexCoord0 = VertexTexCoord0;
|
||||
|
||||
pos = Vertex.xy;
|
||||
gl_Position = Projection * Vertex;
|
||||
}
|
||||
"""
|
||||
|
||||
VERTEX_SHADER2 = """\
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform mat4 Projection;
|
||||
|
||||
attribute vec4 Vertex;
|
||||
attribute vec2 VertexTexCoord0;
|
||||
attribute vec2 VertexTexCoord1;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
varying vec2 TexCoord1;
|
||||
|
||||
varying vec2 pos;
|
||||
|
||||
void main() {
|
||||
TexCoord0 = VertexTexCoord0;
|
||||
TexCoord1 = VertexTexCoord1;
|
||||
|
||||
pos = Vertex.xy;
|
||||
gl_Position = Projection * Vertex;
|
||||
}
|
||||
"""
|
||||
|
||||
VERTEX_SHADER3 = """\
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform mat4 Projection;
|
||||
|
||||
attribute vec4 Vertex;
|
||||
attribute vec2 VertexTexCoord0;
|
||||
attribute vec2 VertexTexCoord1;
|
||||
attribute vec2 VertexTexCoord2;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
varying vec2 TexCoord1;
|
||||
varying vec2 TexCoord2;
|
||||
|
||||
varying vec2 pos;
|
||||
|
||||
void main() {
|
||||
TexCoord0 = VertexTexCoord0;
|
||||
TexCoord1 = VertexTexCoord1;
|
||||
TexCoord2 = VertexTexCoord2;
|
||||
|
||||
pos = Vertex.xy;
|
||||
gl_Position = Projection * Vertex;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
BLIT_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
|
||||
varying vec2 pos;
|
||||
uniform vec2 clip0;
|
||||
uniform vec2 clip1;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color0 = texture2D(tex0, TexCoord0.st);
|
||||
gl_FragColor = color0 * Color;
|
||||
}
|
||||
"""
|
||||
|
||||
BLIT_CLIP_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
|
||||
varying vec2 pos;
|
||||
uniform vec2 clip0;
|
||||
uniform vec2 clip1;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 color0 = texture2D(tex0, TexCoord0.st);
|
||||
gl_FragColor = color0 * Color;
|
||||
}
|
||||
"""
|
||||
|
||||
BLEND_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
uniform float done;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
varying vec2 TexCoord1;
|
||||
|
||||
varying vec2 pos;
|
||||
uniform vec2 clip0;
|
||||
uniform vec2 clip1;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color0 = texture2D(tex0, TexCoord0.st);
|
||||
vec4 color1 = texture2D(tex1, TexCoord1.st);
|
||||
|
||||
gl_FragColor = mix(color0, color1, done) * Color;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
BLEND_CLIP_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
uniform float done;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
varying vec2 TexCoord1;
|
||||
|
||||
varying vec2 pos;
|
||||
uniform vec2 clip0;
|
||||
uniform vec2 clip1;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 color0 = texture2D(tex0, TexCoord0.st);
|
||||
vec4 color1 = texture2D(tex1, TexCoord1.st);
|
||||
|
||||
gl_FragColor = mix(color0, color1, done) * Color;
|
||||
}
|
||||
"""
|
||||
|
||||
IMAGEBLEND_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
uniform float offset;
|
||||
uniform float multiplier;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
varying vec2 TexCoord1;
|
||||
varying vec2 TexCoord2;
|
||||
|
||||
varying vec2 pos;
|
||||
uniform vec2 clip0;
|
||||
uniform vec2 clip1;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 color0 = texture2D(tex0, TexCoord0.st);
|
||||
vec4 color1 = texture2D(tex1, TexCoord1.st);
|
||||
vec4 color2 = texture2D(tex2, TexCoord2.st);
|
||||
|
||||
float a = clamp((color0.a + offset) * multiplier, 0.0, 1.0);
|
||||
|
||||
gl_FragColor = mix(color1, color2, a) * Color;
|
||||
}
|
||||
"""
|
||||
|
||||
IMAGEBLEND_CLIP_SHADER = """
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
uniform vec4 Color;
|
||||
uniform sampler2D tex0;
|
||||
uniform sampler2D tex1;
|
||||
uniform sampler2D tex2;
|
||||
uniform float offset;
|
||||
uniform float multiplier;
|
||||
|
||||
varying vec2 TexCoord0;
|
||||
varying vec2 TexCoord1;
|
||||
varying vec2 TexCoord2;
|
||||
|
||||
varying vec2 pos;
|
||||
uniform vec2 clip0;
|
||||
uniform vec2 clip1;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 color0 = texture2D(tex0, TexCoord0.st);
|
||||
vec4 color1 = texture2D(tex1, TexCoord1.st);
|
||||
vec4 color2 = texture2D(tex2, TexCoord2.st);
|
||||
|
||||
float a = clamp((color0.a + offset) * multiplier, 0.0, 1.0);
|
||||
|
||||
gl_FragColor = mix(color1, color2, a) * Color;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
def check_status(shader, 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
|
||||
|
||||
if shader:
|
||||
glGetShaderiv(handle, type, &status)
|
||||
else:
|
||||
glGetProgramiv(handle, type, &status)
|
||||
|
||||
if status == 1: # 0 for problems.
|
||||
return
|
||||
|
||||
if shader:
|
||||
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length)
|
||||
else:
|
||||
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length)
|
||||
|
||||
log = ' ' * log_length
|
||||
|
||||
if shader:
|
||||
glGetShaderInfoLog(handle, log_length, &log_length, <char *> log)
|
||||
else:
|
||||
glGetProgramInfoLog(handle, log_length, &log_length, <char *> log)
|
||||
|
||||
raise Exception("Shader error: %s" % log)
|
||||
|
||||
|
||||
def compile_shader(kind, source):
|
||||
"""
|
||||
Allocates and compiles a shader.
|
||||
"""
|
||||
|
||||
cdef const char *sourceptr = <const char *> source
|
||||
cdef int lensource = len(source)
|
||||
|
||||
handle = glCreateShader(kind)
|
||||
glShaderSource(handle, 1, <const GLchar * const*> &sourceptr, &lensource)
|
||||
glCompileShader(handle)
|
||||
|
||||
check_status(True, handle, GL_COMPILE_STATUS)
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
def compile_program(vertex, fragment):
|
||||
"""
|
||||
Compiles a pair of shaders into a program.
|
||||
"""
|
||||
|
||||
vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex)
|
||||
fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment)
|
||||
|
||||
program = glCreateProgram()
|
||||
|
||||
glAttachShader(program, vertex_shader)
|
||||
glAttachShader(program, fragment_shader)
|
||||
|
||||
glLinkProgram(program)
|
||||
|
||||
check_status(False, program, GL_LINK_STATUS)
|
||||
|
||||
glUseProgram(program)
|
||||
|
||||
glDeleteShader(vertex_shader)
|
||||
glDeleteShader(fragment_shader)
|
||||
|
||||
return program
|
||||
|
||||
cdef class Program(object):
|
||||
"""
|
||||
Encapsulates a program.
|
||||
"""
|
||||
|
||||
cdef GLuint program
|
||||
|
||||
# Attributes.
|
||||
cdef GLint Vertex
|
||||
cdef GLint VertexTexCoord0
|
||||
cdef GLint VertexTexCoord1
|
||||
cdef GLint VertexTexCoord2
|
||||
|
||||
# Uniforms.
|
||||
cdef GLint Projection
|
||||
cdef GLint Color
|
||||
|
||||
cdef GLint tex0
|
||||
cdef GLint tex1
|
||||
cdef GLint tex2
|
||||
|
||||
cdef GLint clip0
|
||||
cdef GLint clip1
|
||||
|
||||
cdef GLint offset
|
||||
cdef GLint multiplier
|
||||
cdef GLint done
|
||||
|
||||
def __init__(self, vertex, fragment):
|
||||
self.program = compile_program(vertex, fragment)
|
||||
|
||||
self.Vertex = glGetAttribLocation(self.program, "Vertex")
|
||||
self.VertexTexCoord0 = glGetAttribLocation(self.program, "VertexTexCoord0")
|
||||
self.VertexTexCoord1 = glGetAttribLocation(self.program, "VertexTexCoord1")
|
||||
self.VertexTexCoord2 = glGetAttribLocation(self.program, "VertexTexCoord2")
|
||||
|
||||
self.Projection = glGetUniformLocation(self.program, "Projection")
|
||||
self.tex0 = glGetUniformLocation(self.program, "tex0")
|
||||
self.tex1 = glGetUniformLocation(self.program, "tex1")
|
||||
self.tex2 = glGetUniformLocation(self.program, "tex2")
|
||||
self.offset = glGetUniformLocation(self.program, "offset")
|
||||
self.multiplier = glGetUniformLocation(self.program, "multiplier")
|
||||
self.done = glGetUniformLocation(self.program, "done")
|
||||
self.Color = glGetUniformLocation(self.program, "Color")
|
||||
self.clip0 = glGetUniformLocation(self.program, "clip0")
|
||||
self.clip1 = glGetUniformLocation(self.program, "clip1")
|
||||
|
||||
def disable_attribs(self):
|
||||
# Disable the vertex attributes used by this program.
|
||||
|
||||
if self.Vertex != -1:
|
||||
glDisableVertexAttribArray(self.Vertex)
|
||||
|
||||
if self.VertexTexCoord0 != -1:
|
||||
glDisableVertexAttribArray(self.VertexTexCoord0)
|
||||
|
||||
if self.VertexTexCoord1 != -1:
|
||||
glDisableVertexAttribArray(self.VertexTexCoord1)
|
||||
|
||||
if self.VertexTexCoord2 != -1:
|
||||
glDisableVertexAttribArray(self.VertexTexCoord2)
|
||||
|
||||
def delete(self):
|
||||
glDeleteProgram(self.program)
|
||||
|
||||
|
||||
cdef class ShaderEnviron(Environ):
|
||||
"""
|
||||
This is an environment that uses shaders.
|
||||
"""
|
||||
|
||||
cdef Program program
|
||||
cdef float projection[16]
|
||||
|
||||
cdef Program blit_program
|
||||
cdef Program blend_program
|
||||
cdef Program imageblend_program
|
||||
|
||||
cdef Program blit_clip_program
|
||||
cdef Program blend_clip_program
|
||||
cdef Program imageblend_clip_program
|
||||
|
||||
cdef bint clipping
|
||||
cdef double clip_x0
|
||||
cdef double clip_y0
|
||||
cdef double clip_x1
|
||||
cdef double clip_y1
|
||||
|
||||
cdef int viewport_x
|
||||
cdef int viewport_y
|
||||
cdef int viewport_w
|
||||
cdef int viewport_h
|
||||
|
||||
|
||||
def init(self):
|
||||
|
||||
self.blit_program = Program(VERTEX_SHADER1, BLIT_SHADER)
|
||||
self.blit_clip_program = Program(VERTEX_SHADER1, BLIT_CLIP_SHADER)
|
||||
|
||||
self.blend_program = Program(VERTEX_SHADER2, BLEND_SHADER)
|
||||
self.blend_clip_program = Program(VERTEX_SHADER2, BLEND_CLIP_SHADER)
|
||||
|
||||
self.imageblend_program = Program(VERTEX_SHADER3, IMAGEBLEND_SHADER)
|
||||
self.imageblend_clip_program = Program(VERTEX_SHADER3, IMAGEBLEND_CLIP_SHADER)
|
||||
|
||||
# The current program.
|
||||
self.program = None
|
||||
|
||||
def deinit(self):
|
||||
"""
|
||||
Called before changing the GL context.
|
||||
"""
|
||||
|
||||
if self.program is not None:
|
||||
self.program.disable_attribs()
|
||||
self.program = None
|
||||
|
||||
self.blit_program.delete()
|
||||
self.blend_program.delete()
|
||||
self.imageblend_program.delete()
|
||||
|
||||
def activate(self, Program program):
|
||||
|
||||
if self.program is not None:
|
||||
self.program.disable_attribs()
|
||||
|
||||
self.program = program
|
||||
|
||||
glUseProgram(program.program)
|
||||
glUniformMatrix4fv(program.Projection, 1, GL_FALSE, self.projection)
|
||||
|
||||
if self.clipping:
|
||||
glUniform2f(program.clip0, self.clip_x0 - .01, self.clip_y0 - .01)
|
||||
glUniform2f(program.clip1, self.clip_x1 + .01, self.clip_y1 + .01)
|
||||
|
||||
cdef void blit(self):
|
||||
|
||||
if self.clipping:
|
||||
program = self.blit_clip_program
|
||||
else:
|
||||
program = self.blit_program
|
||||
|
||||
if self.program is not program:
|
||||
self.activate(program)
|
||||
glUniform1i(program.tex0, 0)
|
||||
|
||||
cdef void blend(self, double fraction):
|
||||
if self.clipping:
|
||||
program = self.blend_clip_program
|
||||
else:
|
||||
program = self.blend_program
|
||||
|
||||
if self.program is not program:
|
||||
self.activate(program)
|
||||
glUniform1i(program.tex0, 0)
|
||||
glUniform1i(program.tex1, 1)
|
||||
|
||||
glUniform1f(program.done, fraction)
|
||||
|
||||
cdef void imageblend(self, double fraction, int ramp):
|
||||
|
||||
if self.clipping:
|
||||
program = self.imageblend_clip_program
|
||||
else:
|
||||
program = self.imageblend_program
|
||||
|
||||
if self.program is not program:
|
||||
self.activate(program)
|
||||
glUniform1i(program.tex0, 0)
|
||||
glUniform1i(program.tex1, 1)
|
||||
glUniform1i(program.tex2, 2)
|
||||
|
||||
# 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.
|
||||
glUniform1f(program.multiplier, 256.0 / ramp)
|
||||
glUniform1f(program.offset, offset)
|
||||
|
||||
cdef void set_vertex(self, float *vertices):
|
||||
glEnableVertexAttribArray(self.program.Vertex)
|
||||
glVertexAttribPointer(self.program.Vertex, 2, GL_FLOAT, GL_FALSE, 0, <GLubyte *> vertices)
|
||||
|
||||
cdef void set_texture(self, int unit, float *coords):
|
||||
cdef tex
|
||||
|
||||
if unit == 0:
|
||||
tex = self.program.VertexTexCoord0
|
||||
elif unit == 1:
|
||||
tex = self.program.VertexTexCoord1
|
||||
elif unit == 2:
|
||||
tex = self.program.VertexTexCoord2
|
||||
else:
|
||||
return
|
||||
|
||||
if tex < 0:
|
||||
return
|
||||
|
||||
if coords != NULL:
|
||||
glVertexAttribPointer(tex, 2, GL_FLOAT, GL_FALSE, 0, <GLubyte *> coords)
|
||||
glEnableVertexAttribArray(tex)
|
||||
else:
|
||||
glDisableVertexAttribArray(tex)
|
||||
|
||||
cdef void set_color(self, double r, double g, double b, double a):
|
||||
glUniform4f(self.program.Color, r, g, b, a)
|
||||
|
||||
cdef void ortho(self, double left, double right, double bottom, double top, double near, double far):
|
||||
|
||||
self.projection[ 0] = 2 / (right - left)
|
||||
self.projection[ 4] = 0
|
||||
self.projection[ 8] = 0
|
||||
self.projection[12] = -(right + left) / (right - left)
|
||||
|
||||
self.projection[ 1] = 0
|
||||
self.projection[ 5] = 2 / (top - bottom)
|
||||
self.projection[ 9] = 0
|
||||
self.projection[13] = -(top + bottom) / (top - bottom)
|
||||
|
||||
self.projection[ 2] = 0
|
||||
self.projection[ 6] = 0
|
||||
self.projection[10] = -2 / (far - near)
|
||||
self.projection[14] = -(far + near) / (far - near)
|
||||
|
||||
self.projection[ 3] = 0
|
||||
self.projection[ 7] = 0
|
||||
self.projection[11] = 0
|
||||
self.projection[15] = 1
|
||||
|
||||
if self.program is not None:
|
||||
self.program.disable_attribs()
|
||||
|
||||
self.program = None
|
||||
|
||||
cdef void project(self, x, y, z, double *rv_x, double *rv_y, double *rv_z):
|
||||
"""
|
||||
Given a point, projects it using the projection.
|
||||
"""
|
||||
|
||||
rv_x[0] = x * self.projection[0] + y * self.projection[4] + z * self.projection[8] + self.projection[12]
|
||||
rv_y[0] = x * self.projection[1] + y * self.projection[5] + z * self.projection[9] + self.projection[13]
|
||||
rv_z[0] = x * self.projection[2] + y * self.projection[6] + z * self.projection[10] + self.projection[14]
|
||||
|
||||
cdef void set_clip(self, tuple clip_box, GL2Draw draw):
|
||||
|
||||
cdef double minx, miny, maxx, maxy, z
|
||||
cdef double vwidth, vheight
|
||||
cdef double px, py, pw, ph
|
||||
cdef int cx, cy, cw, ch
|
||||
cdef int psw, psh
|
||||
|
||||
if clip_box == draw.default_clip:
|
||||
self.unset_clip(draw)
|
||||
return
|
||||
|
||||
minx, miny, maxx, maxy = clip_box
|
||||
psw, psh = draw.physical_size
|
||||
|
||||
# The clipping box.
|
||||
self.clipping = True
|
||||
self.clip_x0 = minx
|
||||
self.clip_y0 = miny
|
||||
self.clip_x1 = maxx
|
||||
self.clip_y1 = maxy
|
||||
|
||||
# Set the scissor rectangle to be slightly larger than the
|
||||
# clipping box. This ensures everything that needs to be drawn
|
||||
# is drawn, and we don't spend a lot of time shading clipped
|
||||
# fragments.
|
||||
|
||||
if draw.clip_rtt_box is None:
|
||||
|
||||
z = 0
|
||||
|
||||
# Project to normalized coordinates.
|
||||
self.project(minx, miny, z, &minx, &miny, &z)
|
||||
self.project(maxx, maxy, z, &maxx, &maxy, &z)
|
||||
|
||||
# Convert to window coordinates.
|
||||
minx = (minx + 1) * self.viewport_w / 2 + self.viewport_x
|
||||
maxx = (maxx + 1) * self.viewport_w / 2 + self.viewport_x
|
||||
miny = (miny + 1) * self.viewport_h / 2 + self.viewport_y
|
||||
maxy = (maxy + 1) * self.viewport_h / 2 + self.viewport_y
|
||||
|
||||
# Increase the bounding box, to ensure every relevant pixel is
|
||||
# in it. The shader will take care of enforcing the actual box.
|
||||
minx -= 1
|
||||
maxx += 1
|
||||
miny += 1
|
||||
maxy -= 1
|
||||
|
||||
if minx < 0:
|
||||
minx = 0
|
||||
if miny < 0:
|
||||
miny = 0
|
||||
|
||||
glEnable(GL_SCISSOR_TEST)
|
||||
glScissor(<GLint> round(minx), <GLint> round(maxy), <GLint> round(maxx - minx), <GLsizei> round(miny - maxy))
|
||||
|
||||
else:
|
||||
|
||||
cx, cy, cw, ch = draw.clip_rtt_box
|
||||
|
||||
glEnable(GL_SCISSOR_TEST)
|
||||
glScissor(<GLint> round(minx - cx), <GLint> round(miny - cy), <GLint> round(maxx - minx), <GLint> round(maxy - miny))
|
||||
|
||||
if self.program is not None:
|
||||
self.program.disable_attribs()
|
||||
|
||||
self.program = None
|
||||
|
||||
cdef void unset_clip(self, GL2Draw draw):
|
||||
|
||||
glDisable(GL_SCISSOR_TEST)
|
||||
|
||||
self.clipping = False
|
||||
self.clip_x0 = 0
|
||||
self.clip_y0 = 0
|
||||
self.clip_x1 = 65535
|
||||
self.clip_y1 = 65535
|
||||
|
||||
if self.program is not None:
|
||||
self.program.disable_attribs()
|
||||
|
||||
self.program = None
|
||||
|
||||
cdef void viewport(self, int x, int y, int width, int height):
|
||||
glViewport(x, y, width, height)
|
||||
self.viewport_x = x
|
||||
self.viewport_y = y
|
||||
self.viewport_w = width
|
||||
self.viewport_h = height
|
||||
@@ -0,0 +1,73 @@
|
||||
from renpy.display.matrix cimport Matrix
|
||||
|
||||
cdef class Polygon:
|
||||
|
||||
# The number of points in the polygon.
|
||||
cdef int points
|
||||
|
||||
# The stride of the polygon - the number of floats comprising a data
|
||||
# point.
|
||||
cdef int stride
|
||||
|
||||
# The data in a polygon.
|
||||
cdef float *data
|
||||
|
||||
cpdef Polygon copy(Polygon self)
|
||||
|
||||
cpdef void offset_inplace(Polygon self, double x, double y, double z)
|
||||
cpdef Polygon offset(Polygon self, double x, double y, double z)
|
||||
|
||||
cpdef void multiply_matrix_inplace(Polygon self, Matrix matrix)
|
||||
cpdef Polygon multiply_matrix(Polygon self, Matrix matrix)
|
||||
|
||||
cpdef void perspective_divide_inplace(Polygon self)
|
||||
cpdef Polygon perspective_divide(Polygon self)
|
||||
|
||||
cpdef Polygon intersect(Polygon self, Polygon other)
|
||||
|
||||
# Constructors for particularly useful polygons.
|
||||
cpdef Polygon rectangle(double l, double t, double r, double b)
|
||||
cpdef Polygon texture_rectangle(double pl, double pt, double pr, double pb, double tl, double tt, double tr, double tb)
|
||||
|
||||
cdef class Mesh:
|
||||
|
||||
# The total number of points.
|
||||
cdef public int points
|
||||
|
||||
# The stride - the amount of data per point, in floats.
|
||||
cdef public int stride
|
||||
|
||||
# A map from an attribute to the offset of that attribute.
|
||||
cdef public dict attributes
|
||||
|
||||
# A list of polygons that comprise the mesh.
|
||||
cdef public list polygons
|
||||
|
||||
# An array that contains all the data from the points. This is NULL
|
||||
# until it's created.
|
||||
cdef float *data
|
||||
|
||||
cdef float *get_data(self, int offset)
|
||||
|
||||
# The count of polygons that comprise the mesh. This is only valid after
|
||||
# get_data is called.
|
||||
cdef public int polygon_count
|
||||
|
||||
# If all the polygons in the mesh have the same number of points, this is
|
||||
# that number of points. Else, it's 0.
|
||||
cdef public int polygon_points
|
||||
|
||||
cpdef Mesh copy(Mesh self)
|
||||
|
||||
cpdef void offset_inplace(Mesh self, double x, double y, double z)
|
||||
cpdef Mesh offset(Mesh self, double x, double y, double z)
|
||||
|
||||
cpdef void multiply_matrix_inplace(Mesh self, Matrix matrix)
|
||||
cpdef Mesh multiply_matrix(Mesh self, Matrix matrix)
|
||||
|
||||
cpdef void perspective_divide_inplace(Mesh self)
|
||||
cpdef Mesh perspective_divide(Mesh self)
|
||||
|
||||
cpdef Mesh intersect(Mesh self, Mesh other)
|
||||
cpdef Mesh crop(Mesh self, Polygon other)
|
||||
|
||||
@@ -0,0 +1,835 @@
|
||||
from __future__ import print_function
|
||||
|
||||
from renpy.display.matrix cimport Matrix
|
||||
from libc.stdlib cimport malloc, free
|
||||
from libc.string cimport memcpy
|
||||
from libc.math cimport copysign
|
||||
|
||||
DEF MAX_POINTS = 128
|
||||
|
||||
DEF X = 0
|
||||
DEF Y = 1
|
||||
DEF Z = 2
|
||||
DEF W = 3
|
||||
|
||||
DEF TX = 4
|
||||
DEF TY = 5
|
||||
|
||||
|
||||
cdef class Polygon:
|
||||
|
||||
def __init__(Polygon self, int stride, int points, data):
|
||||
"""
|
||||
Allocates a new Polygon.
|
||||
|
||||
`stride`
|
||||
The number of floats per vertex. This should be at least 3, for the
|
||||
default aPosition vec3.
|
||||
|
||||
`points`
|
||||
The number of vertices in the polygon that space is allocated for.
|
||||
If `data` is given, this is also the number of points in the polygon.
|
||||
|
||||
`data`
|
||||
If not None, an iterable of length stride * points, that gives the
|
||||
vertex data for each of the points.
|
||||
"""
|
||||
|
||||
cdef int i
|
||||
|
||||
self.stride = stride
|
||||
|
||||
self.data = <float *> malloc(sizeof(float) * points * stride)
|
||||
|
||||
if data is None:
|
||||
self.points = 0
|
||||
else:
|
||||
self.points = points
|
||||
|
||||
for 0 <= i < stride * points:
|
||||
self.data[i] = data[i]
|
||||
|
||||
def __dealloc__(Polygon self):
|
||||
free(self.data)
|
||||
|
||||
cpdef Polygon copy(Polygon self):
|
||||
"""
|
||||
Returns a copy of this polygon.
|
||||
"""
|
||||
|
||||
cdef Polygon rv = Polygon(self.stride, self.points, None)
|
||||
rv.points = self.points
|
||||
memcpy(rv.data, self.data, sizeof(float) * self.stride * self.points)
|
||||
return rv
|
||||
|
||||
cpdef void offset_inplace(Polygon self, double x, double y, double z):
|
||||
cdef float *p = self.data
|
||||
cdef int i
|
||||
|
||||
for 0 <= i < self.points:
|
||||
p[X] += x
|
||||
p[Y] += y
|
||||
p[Z] += z
|
||||
|
||||
p += self.stride
|
||||
|
||||
cpdef Polygon offset(Polygon self, double x, double y, double z):
|
||||
cdef Polygon rv = self.copy()
|
||||
rv.offset_inplace(x, y, z)
|
||||
return rv
|
||||
|
||||
cpdef void perspective_divide_inplace(Polygon self):
|
||||
"""
|
||||
Performs a perspective divide on each point in this polygon, in place.
|
||||
"""
|
||||
|
||||
cdef float *p = self.data
|
||||
cdef int i
|
||||
|
||||
for 0 <= i < self.points:
|
||||
if p[W]:
|
||||
p[X] /= p[W]
|
||||
p[Y] /= p[W]
|
||||
p[Z] /= p[W]
|
||||
|
||||
p += self.stride
|
||||
|
||||
cpdef Polygon perspective_divide(Polygon self):
|
||||
"""
|
||||
Returns a perspective divided copy of this polygon.
|
||||
"""
|
||||
|
||||
cdef Polygon rv = self.copy()
|
||||
rv.perspective_divide_inplace()
|
||||
return rv
|
||||
|
||||
cpdef void multiply_matrix_inplace(Polygon self, Matrix m):
|
||||
"""
|
||||
Multiplies each point's position with the matrix `m`, in place.
|
||||
"""
|
||||
|
||||
cdef int i
|
||||
cdef float *p = self.data
|
||||
|
||||
for 0 <= i < self.points:
|
||||
m.transform4(p, p+1, p+2, p+3, p[0], p[1], p[2], p[3])
|
||||
p += self.stride
|
||||
|
||||
cpdef Polygon multiply_matrix(Polygon self, Matrix m):
|
||||
"""
|
||||
Multiplies each point's position with the matrix `m`, in place,
|
||||
and returns a copy.
|
||||
"""
|
||||
|
||||
cdef Polygon rv = self.copy()
|
||||
rv.multiply_matrix_inplace(m)
|
||||
return rv
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, Matrix):
|
||||
return self.multiply_matrix(other)
|
||||
|
||||
return NotImplemented
|
||||
|
||||
def __rmul__(self, other):
|
||||
if isinstance(other, Matrix):
|
||||
return self.multiply_matrix(other)
|
||||
|
||||
return NotImplemented
|
||||
|
||||
cpdef Polygon intersect(Polygon self, Polygon other):
|
||||
"""
|
||||
Returns a new polygon that is the intersection of the current polygon
|
||||
and the other polygon.
|
||||
"""
|
||||
|
||||
rv = intersect(other, self, self.stride + other.stride - 4, True)
|
||||
|
||||
if rv is None:
|
||||
return None
|
||||
|
||||
# We only need to interpolate OP if it has something other than
|
||||
# position data.
|
||||
if other.stride > 4:
|
||||
barycentric(other, rv, self.stride - 4)
|
||||
|
||||
barycentric(self, rv, 0)
|
||||
|
||||
return rv
|
||||
|
||||
def __repr__(self):
|
||||
rv = "<Polygon"
|
||||
|
||||
for 0 <= p < self.points:
|
||||
rv += "\n ["
|
||||
for 0 <= i < self.stride:
|
||||
rv += "{:g}, ".format(self.data[p * self.stride + i])
|
||||
rv += "]"
|
||||
|
||||
rv += ">"
|
||||
return rv
|
||||
|
||||
|
||||
cpdef Polygon rectangle(double l, double t, double r, double b):
|
||||
"""
|
||||
Generates a rectangle with one corner at (l, t, 0, 1) and the other at (r, b, 0, 1).
|
||||
"""
|
||||
|
||||
cdef Polygon rv = Polygon(4, 4, None)
|
||||
|
||||
rv.points = 4
|
||||
|
||||
cdef float *p = rv.data
|
||||
|
||||
p[X] = l
|
||||
p[Y] = t
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
|
||||
p += 4
|
||||
|
||||
p[X] = r
|
||||
p[Y] = t
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
|
||||
p += 4
|
||||
|
||||
p[X] = r
|
||||
p[Y] = b
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
|
||||
p += 4
|
||||
|
||||
p[X] = l
|
||||
p[Y] = b
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
cpdef Polygon texture_rectangle(double pl, double pt, double pr, double pb, double tl, double tt, double tr, double tb):
|
||||
"""
|
||||
This generates a rectangle with teture coordinates. One corner is at (pl, pt, 0, 1) with
|
||||
texture coordinates (tl, tt), while the other is at (pr, pb, 0, 1) / (tr, tb).
|
||||
"""
|
||||
|
||||
cdef Polygon rv = Polygon(6, 4, None)
|
||||
|
||||
rv.points = 4
|
||||
|
||||
cdef float *p = rv.data
|
||||
|
||||
p[X] = pl
|
||||
p[Y] = pt
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
p[TX] = tl
|
||||
p[TY] = tt
|
||||
|
||||
p += 6
|
||||
|
||||
p[X] = pr
|
||||
p[Y] = pt
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
p[TX] = tr
|
||||
p[TY] = tt
|
||||
|
||||
p += 6
|
||||
|
||||
p[X] = pr
|
||||
p[Y] = pb
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
p[TX] = tr
|
||||
p[TY] = tb
|
||||
|
||||
p += 6
|
||||
|
||||
p[X] = pl
|
||||
p[Y] = pb
|
||||
p[Z] = 0
|
||||
p[W] = 1
|
||||
p[TX] = tl
|
||||
p[TY] = tb
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
# Accssor functions for the contents of polygons.
|
||||
cdef inline float get(Polygon p, int index, int offset):
|
||||
return p.data[index * p.stride + offset]
|
||||
|
||||
cdef inline float *ref(Polygon p, int index, int offset):
|
||||
return &p.data[index * p.stride + offset]
|
||||
|
||||
cdef inline float set(Polygon p, int index, int offset, float value):
|
||||
p.data[index * p.stride + offset] = value
|
||||
return value
|
||||
|
||||
|
||||
cdef void intersectLines(
|
||||
float x1, float y1,
|
||||
float x2, float y2,
|
||||
float x3, float y3,
|
||||
float x4, float y4,
|
||||
float *px, float *py,
|
||||
):
|
||||
|
||||
"""
|
||||
Given a line that goes through (x1, y1) to (x2, y2), and a second line
|
||||
that goes through (x3, y3) and (x4, y4), find the point where the two
|
||||
lines intersect.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
cdef float denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
|
||||
px[0] = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom
|
||||
py[0] = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom
|
||||
|
||||
cdef Polygon intersectOnce(float winding, float a0x, float a0y, float a1x, float a1y, Polygon p, int rvstride):
|
||||
|
||||
# The vector from a0 to a1.
|
||||
cdef float vecax = a1x - a0x
|
||||
cdef float vecay = a1y - a0y
|
||||
|
||||
# The vector from a0 to each point.
|
||||
cdef float vecpx
|
||||
cdef float vexpx
|
||||
|
||||
# For each point, are we inside or outside?
|
||||
cdef bint inside[MAX_POINTS]
|
||||
|
||||
cdef int i
|
||||
cdef int j
|
||||
cdef bint allin = True
|
||||
|
||||
# Figure out which points are 'inside' the wound line.
|
||||
for 0 <= i < p.points:
|
||||
vecpx = get(p, i, X) - a0x
|
||||
vecpy = get(p, i, Y) - a0y
|
||||
|
||||
inside[i] = winding * (vecax * vecpy - vecay * vecpx) <= 0.00001
|
||||
allin = allin and inside[i]
|
||||
|
||||
# If all the points are inside, just return the polygon intact.
|
||||
if allin:
|
||||
return p
|
||||
|
||||
rv = Polygon(rvstride, p.points * 2, None)
|
||||
|
||||
j = p.points - 1
|
||||
|
||||
for 0 <= i < p.points:
|
||||
if inside[i]:
|
||||
if not inside[j]:
|
||||
intersectLines(
|
||||
a0x, a0y, a1x, a1y,
|
||||
get(p, j, X), get(p, j, Y), get(p, i, X), get(p, i, Y),
|
||||
ref(rv, rv.points, X), ref(rv, rv.points, Y))
|
||||
|
||||
rv.points += 1
|
||||
|
||||
set(rv, rv.points, X, get(p, i, X))
|
||||
set(rv, rv.points, Y, get(p, i, Y))
|
||||
rv.points += 1
|
||||
|
||||
else:
|
||||
if inside[j]:
|
||||
intersectLines(
|
||||
a0x, a0y, a1x, a1y,
|
||||
get(p, j, X), get(p, j, Y), get(p, i, X), get(p, i, Y),
|
||||
ref(rv, rv.points, X), ref(rv, rv.points, Y))
|
||||
|
||||
rv.points += 1
|
||||
|
||||
j = i
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
cdef Polygon restride_polygon(Polygon src, int new_stride):
|
||||
"""
|
||||
Returns a copy of the polygon with the stride changed to
|
||||
be `new_stride`.
|
||||
"""
|
||||
|
||||
cdef Polygon rv = Polygon(new_stride, src.points, None)
|
||||
|
||||
cdef float *ap = src.data
|
||||
cdef float *bp = rv.data
|
||||
|
||||
cdef int i
|
||||
|
||||
for 0 <= i < src.points:
|
||||
bp[X] = ap[X]
|
||||
bp[Y] = ap[Y]
|
||||
bp[Z] = ap[Z]
|
||||
|
||||
ap += src.stride
|
||||
bp += rv.stride
|
||||
|
||||
rv.points = src.points
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
cpdef intersect(Polygon a, Polygon b, int new_stride, bint copy):
|
||||
"""
|
||||
Given two Polygons, returns a new Polygon that is the intersecti of
|
||||
the two. This assumes that both polygons are convex, and wound in the
|
||||
same direction (clockwise or counterclockwise).
|
||||
|
||||
`new_stride` is the stride of the new Polygon.
|
||||
"""
|
||||
|
||||
cdef int i
|
||||
cdef float a0x, a0y, a1x, a1y
|
||||
cdef float winding
|
||||
|
||||
a0x = get(a, a.points-2, X)
|
||||
a0y = get(a, a.points-2, Y)
|
||||
|
||||
a1x = get(a, a.points-1, X)
|
||||
a1y = get(a, a.points-1, Y)
|
||||
|
||||
cdef Polygon rv = b
|
||||
|
||||
for 0 <= i < a.points:
|
||||
a2x = get(a, i, X)
|
||||
a2y = get(a, i, Y)
|
||||
|
||||
winding = (a2x - a0x) * (a1y - a0y) - (a2y - a0y) * (a1x - a0x)
|
||||
winding = copysign(1.0, winding)
|
||||
|
||||
if winding:
|
||||
rv = intersectOnce(winding, a1x, a1y, a2x, a2y, rv, new_stride)
|
||||
|
||||
if rv.points < 3:
|
||||
return None
|
||||
|
||||
a0x = a1x
|
||||
a0y = a1y
|
||||
|
||||
a1x = a2x
|
||||
a1y = a2y
|
||||
|
||||
if rv is b:
|
||||
if (not copy) and (new_stride == rv.stride):
|
||||
return rv
|
||||
|
||||
rv = restride_polygon(rv, new_stride)
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
cpdef barycentric(Polygon a, Polygon b, int offset):
|
||||
"""
|
||||
This uses barycentric interpolation to transfer the attributes from
|
||||
Polygon `a` to Polygon `b`, starting at `offset`.
|
||||
"""
|
||||
|
||||
cdef int i
|
||||
cdef int j
|
||||
cdef int k
|
||||
|
||||
cdef float ax0 = get(a, 0, X)
|
||||
cdef float ay0 = get(a, 0, Y)
|
||||
cdef float az0 = get(a, 0, Z)
|
||||
|
||||
cdef float v0x = get(a, 1, X) - ax0
|
||||
cdef float v0y = get(a, 1, Y) - ay0
|
||||
cdef float v0z = get(a, 1, Z) - az0
|
||||
|
||||
cdef float v1x, v1y, v1z, v2x, v2y, v2z
|
||||
cdef float d00, d01, d11, d20, d21
|
||||
cdef float d003, d013, d113, d203, d213
|
||||
cdef float denom
|
||||
cdef float u, v, w
|
||||
|
||||
for 2 <= i < a.points:
|
||||
|
||||
v1x = get(a, i, X) - ax0
|
||||
v1y = get(a, i, Y) - ay0
|
||||
v1z = get(a, i, Z) - az0
|
||||
|
||||
d00 = v0x * v0x + v0y * v0y
|
||||
d01 = v0x * v1x + v0y * v1y
|
||||
d11 = v1x * v1x + v1y * v1y
|
||||
|
||||
d003 = d00 + v0z * v0z
|
||||
d013 = d01 + v0z * v1z
|
||||
d113 = d11 + v1z * v1z
|
||||
|
||||
denom = d00 * d11 - d01 * d01
|
||||
denom3 = d003 * d113 - d013 * d013
|
||||
|
||||
if denom and denom3:
|
||||
|
||||
for 0 <= j < b.points:
|
||||
|
||||
v2x = get(b, j, X) - ax0
|
||||
v2y = get(b, j, Y) - ay0
|
||||
|
||||
d20 = v2x * v0x + v2y * v0y
|
||||
d21 = v2x * v1x + v2y * v1y
|
||||
|
||||
v = (d11 * d20 - d01 * d21) / denom
|
||||
w = (d00 * d21 - d01 * d20) / denom
|
||||
|
||||
if not ((-0.00001 <= v <= 1.00001) and (-0.00001 <= w <= 1.00001)):
|
||||
continue
|
||||
|
||||
u = 1.0 - v - w
|
||||
|
||||
z = u * az0 + v * get(a, i-1, Z) + w * get(a, i, Z)
|
||||
set(b, j, Z, z)
|
||||
set(b, j, W, 1.0)
|
||||
|
||||
v2z = z - az0
|
||||
|
||||
d203 = d20 + v2z * v0z
|
||||
d213 = d21 + v2z * v1z
|
||||
|
||||
v = (d113 * d203 - d013 * d213) / denom3
|
||||
w = (d003 * d213 - d013 * d203) / denom3
|
||||
u = 1.0 - v - w
|
||||
|
||||
for 3 <= k < a.stride:
|
||||
set(b, j, k + offset,
|
||||
u * get(a, 0, k) +
|
||||
v * get(a, i-1, k) +
|
||||
w * get(a, i, k))
|
||||
|
||||
v0x = v1x
|
||||
v0y = v1y
|
||||
|
||||
|
||||
def barycentric_point(Polygon a, float x, float y):
|
||||
"""
|
||||
This expects Polygon a to be a polygon with a stride of 6, with a
|
||||
position (x, y, z, 1) and a pair of attributes (tx, ty) at each
|
||||
point.
|
||||
|
||||
Given `x` and `y`, this barycentricly interpolates the `x` and `y`
|
||||
at the point, if it's inside the Polygon. It returns None, None
|
||||
if the point is inside the polygon.
|
||||
|
||||
This is mostly intended to be used to interpolate screen-space
|
||||
coordinates onto a Render's internal coordinate space.
|
||||
"""
|
||||
|
||||
cdef Polygon b = Polygon(6, 1, None)
|
||||
b.points = 1
|
||||
|
||||
cdef float *p = b.data
|
||||
p[X] = x
|
||||
p[Y] = y
|
||||
p[Z] = 0.0
|
||||
p[W] = 0.0
|
||||
|
||||
barycentric(a, b, 0)
|
||||
|
||||
if p[W] == 0:
|
||||
return None, None
|
||||
|
||||
return (p[TX], p[TY])
|
||||
|
||||
|
||||
cdef class Mesh:
|
||||
|
||||
def __init__(Mesh self):
|
||||
"""
|
||||
Represents a mesh consisting of one or more polygons. A mesh needs
|
||||
to be created either by:
|
||||
|
||||
* First, create the mesh object.
|
||||
* Next, add any additional attributes to it.
|
||||
* Finally, add polygons to the mesh.
|
||||
|
||||
Or by copying the mesh or calling a method that returns a new mesh.
|
||||
|
||||
After that, the inplace methods can be called to further change
|
||||
the mesh.
|
||||
|
||||
Lastly, get_data can be called to access the mesh data. Once get_data
|
||||
is called, the mesh becomes immutable. (This is usally called by
|
||||
Shader.draw.)
|
||||
"""
|
||||
|
||||
self.points = 0
|
||||
self.stride = 4
|
||||
self.polygons = [ ]
|
||||
self.attributes = { "aPosition" : 0 }
|
||||
self.data = NULL
|
||||
|
||||
def __dealloc__(Mesh self):
|
||||
if self.data:
|
||||
free(self.data)
|
||||
|
||||
def add_attribute(Mesh self, name, size):
|
||||
"""
|
||||
Adds an attribute to this mesh.
|
||||
|
||||
`name`
|
||||
The name of the attribute.
|
||||
|
||||
`size`
|
||||
The number of floats per vertex that make up the attribute.
|
||||
"""
|
||||
|
||||
self.attributes[name] = self.stride
|
||||
self.stride += size
|
||||
|
||||
def add_polygon(Mesh self, data):
|
||||
"""
|
||||
Adds a polygon.
|
||||
|
||||
`data`
|
||||
This is an iterable. It should have self.stride data for each
|
||||
vertex, and the number of vertices is derived from the length
|
||||
of the data.
|
||||
"""
|
||||
|
||||
cdef Polygon p = Polygon(self.stride, len(data) // self.stride, data)
|
||||
self.points += p.points
|
||||
|
||||
self.polygons.append(p)
|
||||
|
||||
|
||||
def add_rectangle(Mesh self, double x, double y, double w, double h):
|
||||
"""
|
||||
Adds a polygon.
|
||||
"""
|
||||
|
||||
self.points += 4
|
||||
self.polygons.append(rectangle(x, y, w, h))
|
||||
|
||||
|
||||
def add_texture_rectangle(Mesh self, double pl, double pt, double pr, double pb, double tl, double tt, double tr, double tb):
|
||||
"""
|
||||
Returns a polygon corresponding to a texture rectangle.
|
||||
"""
|
||||
|
||||
self.points += 4
|
||||
self.polygons.append(texture_rectangle(pl, pt, pr, pb, tl, tt, tr, tb))
|
||||
|
||||
|
||||
cdef float *get_data(Mesh self, int offset):
|
||||
"""
|
||||
When called, this freezes the data of this mesh. It then returns
|
||||
a pointer to the data for the attribute at ``offset``. This is a
|
||||
pointer to the first piece of data, with others following at
|
||||
self.stride intervals.
|
||||
"""
|
||||
|
||||
cdef Polygon p
|
||||
cdef int i
|
||||
cdef int count
|
||||
cdef int points
|
||||
|
||||
self.polygon_count = count = len(self.polygons)
|
||||
|
||||
if not count:
|
||||
self.polygon_points = 0
|
||||
return NULL
|
||||
|
||||
p = self.polygons[0]
|
||||
points = p.points
|
||||
|
||||
if count == 1:
|
||||
self.polygon_points = points
|
||||
return p.data + offset
|
||||
|
||||
if not self.data:
|
||||
self.data = <float *> malloc(self.points * self.stride * sizeof(float))
|
||||
|
||||
i = 0
|
||||
|
||||
for p in self.polygons:
|
||||
memcpy(&self.data[i], p.data, p.points * self.stride * sizeof(float))
|
||||
i += p.points * self.stride
|
||||
|
||||
if p.points != points:
|
||||
points = 0
|
||||
|
||||
self.polygon_points = points
|
||||
|
||||
return self.data + offset
|
||||
|
||||
cpdef Mesh copy(Mesh self):
|
||||
"""
|
||||
Returns a copy of this Mesh.
|
||||
"""
|
||||
|
||||
rv = Mesh()
|
||||
rv.stride = self.stride
|
||||
rv.points = self.points
|
||||
rv.polygons = [ i.copy() for i in self.polygons ]
|
||||
rv.attributes = self.attributes
|
||||
|
||||
return rv
|
||||
|
||||
cpdef void offset_inplace(Mesh self, double x, double y, double z):
|
||||
"""
|
||||
Offsets each polygon in the mesh, in place.
|
||||
"""
|
||||
|
||||
cdef Polygon p
|
||||
|
||||
for p in self.polygons:
|
||||
p.offset_inplace(x, y, z)
|
||||
|
||||
cpdef Mesh offset(self, double x, double y, double z):
|
||||
"""
|
||||
Returns a copy of the mesh with each polygon offset.
|
||||
"""
|
||||
|
||||
cdef Mesh rv = self.copy()
|
||||
rv.offset_inplace(x, y, z)
|
||||
return rv
|
||||
|
||||
|
||||
cpdef void perspective_divide_inplace(Mesh self):
|
||||
"""
|
||||
Performs a perspective divide on this mesh, inplace.
|
||||
"""
|
||||
|
||||
cdef Polygon p
|
||||
|
||||
for p in self.polygons:
|
||||
p.perspective_divide_inplace()
|
||||
|
||||
cpdef Mesh perspective_divide(Mesh self):
|
||||
"""
|
||||
Returns a copy of this mesh that has been perspective divided.
|
||||
"""
|
||||
|
||||
cdef Mesh rv = self.copy()
|
||||
rv.perspective_divide_inplace()
|
||||
return rv
|
||||
|
||||
cpdef void multiply_matrix_inplace(Mesh self, Matrix matrix):
|
||||
"""
|
||||
Multiplies the position data in this Mesh by the matrix, in place.
|
||||
"""
|
||||
|
||||
cdef Polygon p
|
||||
|
||||
for p in self.polygons:
|
||||
p.multiply_matrix_inplace(matrix)
|
||||
|
||||
cpdef Mesh multiply_matrix(Mesh self, Matrix matrix):
|
||||
"""
|
||||
Returns a copy of this Mesh with the position data multipled by Matrix.
|
||||
"""
|
||||
|
||||
cdef Mesh rv = self.copy()
|
||||
rv.multiply_matrix_inplace(matrix)
|
||||
return rv
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, Matrix):
|
||||
return self.multiply_matrix(other)
|
||||
|
||||
return NotImplemented
|
||||
|
||||
def __rmul__(self, other):
|
||||
if isinstance(other, Matrix):
|
||||
return self.multiply_matrix(other)
|
||||
|
||||
return NotImplemented
|
||||
|
||||
cpdef Mesh intersect(Mesh self, Mesh other):
|
||||
"""
|
||||
Intersects this mesh with another mesh, and returns a new mesh that
|
||||
is the result. The resulting mesh has z- and w-coordinates from this
|
||||
mesh. Attributes that are present in this mesh are taken from
|
||||
this mesh, otherwise the attributes from the other mesh are used.
|
||||
"""
|
||||
|
||||
rv = Mesh()
|
||||
rv.stride = self.stride + other.stride - 4
|
||||
rv.attributes = { k : v + self.stride - 4 for k, v in other.attributes.iteritems() }
|
||||
rv.attributes.update(self.attributes)
|
||||
|
||||
cdef Polygon op
|
||||
cdef Polygon sp
|
||||
cdef Polygon p
|
||||
|
||||
for op in other.polygons:
|
||||
for sp in self.polygons:
|
||||
p = intersect(op, sp, rv.stride, True)
|
||||
|
||||
if p is None:
|
||||
continue
|
||||
|
||||
# We only need to interpolate OP if it has something other than
|
||||
# position data.
|
||||
if op.stride > 4:
|
||||
barycentric(op, p, self.stride - 4)
|
||||
|
||||
barycentric(sp, p, 0)
|
||||
|
||||
rv.polygons.append(p)
|
||||
rv.points += p.points
|
||||
|
||||
return rv
|
||||
|
||||
cpdef Mesh crop(Mesh self, Polygon op):
|
||||
"""
|
||||
This uses the polygon `op` to crop this mesh.
|
||||
|
||||
This may or may not return a new Mesh. (If op contains all of self, it
|
||||
will return self.)
|
||||
"""
|
||||
|
||||
same = True
|
||||
|
||||
cdef Polygon sp
|
||||
cdef Polygon p
|
||||
|
||||
cdef list polygons = [ ]
|
||||
cdef int points = 0
|
||||
|
||||
for sp in self.polygons:
|
||||
p = intersect(op, sp, self.stride, False)
|
||||
|
||||
if p is None:
|
||||
same = False
|
||||
continue
|
||||
|
||||
if p is not sp:
|
||||
same = False
|
||||
barycentric(sp, p, 0)
|
||||
|
||||
polygons.append(p)
|
||||
points += p.points
|
||||
|
||||
if same:
|
||||
return self
|
||||
|
||||
rv = Mesh()
|
||||
rv.stride = self.stride
|
||||
rv.attributes = self.attributes
|
||||
rv.polygons = polygons
|
||||
rv.points = points
|
||||
|
||||
return rv
|
||||
|
||||
def __repr__(self):
|
||||
rv = "<Mesh "
|
||||
|
||||
for p in self.polygons:
|
||||
rv += repr(p)
|
||||
rv += ", "
|
||||
|
||||
rv += ">"
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#@PydevCodeAnalysisIgnore
|
||||
#cython: profile=False
|
||||
# Copyright 2004-2019 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 __future__ import print_function
|
||||
|
||||
from uguugl cimport *
|
||||
from gl2draw cimport *
|
||||
from gl2draw import Rtt
|
||||
|
||||
import renpy
|
||||
|
||||
# The framebuffer object we use.
|
||||
cdef GLuint fbo
|
||||
|
||||
# The root framebuffer.
|
||||
cdef GLint root_fbo
|
||||
|
||||
class FboRtt(Rtt):
|
||||
"""
|
||||
This class uses texture copying to implement Render-to-texture.
|
||||
"""
|
||||
|
||||
def init(self):
|
||||
glGenFramebuffers(1, &fbo)
|
||||
|
||||
cdef int i
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &i)
|
||||
self.size_limit = i
|
||||
renpy.display.log.write("FBO Maximum Texture Size: %d", i)
|
||||
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &root_fbo);
|
||||
renpy.display.log.write("Root FBO is: %d", root_fbo)
|
||||
|
||||
def deinit(self):
|
||||
"""
|
||||
Called before changing the GL context.
|
||||
"""
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, root_fbo)
|
||||
glDeleteFramebuffers(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, Environ environ, 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.
|
||||
"""
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
|
||||
|
||||
glFramebufferTexture2D(
|
||||
GL_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D,
|
||||
texture,
|
||||
0)
|
||||
|
||||
environ.viewport(0, 0, w, h)
|
||||
environ.ortho(x, x + w, y, y + h, -1, 1)
|
||||
|
||||
draw_func(x, y, w, h)
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, root_fbo)
|
||||
|
||||
|
||||
def get_size_limit(self, dimension):
|
||||
return self.size_limit
|
||||
@@ -0,0 +1,21 @@
|
||||
from uguugl cimport *
|
||||
|
||||
cdef class Program:
|
||||
|
||||
# The name of this program.
|
||||
cdef public object name
|
||||
|
||||
# The number of the OpenGL program created.
|
||||
cdef GLuint program
|
||||
|
||||
# The text of the vertex and fragment shaders.
|
||||
cdef object vertex
|
||||
cdef object fragment
|
||||
|
||||
cdef public dict uniforms
|
||||
|
||||
cdef public list attributes
|
||||
|
||||
cdef public int sampler
|
||||
|
||||
cdef GLuint load_shader(self, GLenum shader_type, source) except? 0
|
||||
@@ -0,0 +1,302 @@
|
||||
from uguugl cimport *
|
||||
from libc.stdlib cimport malloc, free
|
||||
|
||||
from renpy.gl2.gl2geometry cimport Polygon, Mesh
|
||||
from renpy.gl2.gl2texture cimport GLTexture
|
||||
from renpy.display.matrix cimport Matrix
|
||||
|
||||
class ShaderError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
GLSL_PRECISIONS = {
|
||||
"highp",
|
||||
"mediump",
|
||||
"lowp",
|
||||
}
|
||||
|
||||
|
||||
cdef class Uniform:
|
||||
cdef Program program
|
||||
cdef GLint location
|
||||
cdef bint ready
|
||||
|
||||
def __init__(self, program, location):
|
||||
self.program = program
|
||||
self.location = location
|
||||
self.ready = False
|
||||
|
||||
cdef void assign(self, data):
|
||||
return
|
||||
|
||||
cdef void finish(self):
|
||||
return
|
||||
|
||||
cdef class UniformFloat(Uniform):
|
||||
cdef void assign(self, data):
|
||||
glUniform1f(self.location, data)
|
||||
|
||||
cdef class UniformVec2(Uniform):
|
||||
cdef void assign(self, data):
|
||||
glUniform2f(self.location, data[0], data[1])
|
||||
|
||||
cdef class UniformVec3(Uniform):
|
||||
cdef void assign(self, data):
|
||||
glUniform3f(self.location, data[0], data[1], data[2])
|
||||
|
||||
cdef class UniformVec4(Uniform):
|
||||
cdef void assign(self, data):
|
||||
glUniform4f(self.location, data[0], data[1], data[2], data[3])
|
||||
|
||||
cdef class UniformMat4(Uniform):
|
||||
cdef void assign(self, data):
|
||||
glUniformMatrix4fv(self.location, 1, GL_TRUE, (<Matrix> data).m)
|
||||
|
||||
cdef class UniformSampler2D(Uniform):
|
||||
cdef int sampler
|
||||
|
||||
def __init__(self, program, location):
|
||||
Uniform.__init__(self, program, location)
|
||||
self.sampler = program.sampler
|
||||
program.sampler += 1
|
||||
|
||||
cdef void assign(self, data):
|
||||
glActiveTexture(GL_TEXTURE0 + self.sampler)
|
||||
glUniform1i(self.location, self.sampler)
|
||||
|
||||
if isinstance(data, GLTexture):
|
||||
glBindTexture(GL_TEXTURE_2D, data.number)
|
||||
else:
|
||||
glBindTexture(GL_TEXTURE_2D, data)
|
||||
|
||||
cdef void finish(self):
|
||||
glActiveTexture(GL_TEXTURE0 + self.sampler)
|
||||
return
|
||||
|
||||
|
||||
UNIFORM_TYPES = {
|
||||
"float" : UniformFloat,
|
||||
"vec2" : UniformVec2,
|
||||
"vec3" : UniformVec3,
|
||||
"vec4" : UniformVec4,
|
||||
"mat4" : UniformMat4,
|
||||
"sampler2D" : UniformSampler2D,
|
||||
}
|
||||
|
||||
cdef class Attribute:
|
||||
cdef object name
|
||||
cdef GLint location
|
||||
cdef GLint size
|
||||
|
||||
def __init__(self, name, GLint location, GLint size):
|
||||
self.name = name
|
||||
self.location = location
|
||||
self.size = size
|
||||
|
||||
ATTRIBUTE_TYPES = {
|
||||
"float" : 1,
|
||||
"vec2" : 2,
|
||||
"vec3" : 3,
|
||||
"vec4" : 4,
|
||||
}
|
||||
|
||||
|
||||
cdef class Program:
|
||||
"""
|
||||
Represents an OpenGL program.
|
||||
"""
|
||||
|
||||
def __init__(self, name, vertex, fragment):
|
||||
self.name = name
|
||||
self.vertex = vertex
|
||||
self.fragment = fragment
|
||||
|
||||
# A map from uniform name to a Uniform object.
|
||||
self.uniforms = { }
|
||||
|
||||
# A list of Attribute objects
|
||||
self.attributes = [ ]
|
||||
|
||||
# The index of the next sampler to be added.
|
||||
self.sampler = 0
|
||||
|
||||
def find_variables(self, source):
|
||||
|
||||
for l in source.split("\n"):
|
||||
|
||||
l = l.strip()
|
||||
l = l.rstrip("; ")
|
||||
tokens = l.split()
|
||||
|
||||
def advance():
|
||||
if not tokens:
|
||||
return None
|
||||
else:
|
||||
return tokens.pop(0)
|
||||
|
||||
token = advance()
|
||||
|
||||
if token == "invariant":
|
||||
token = advance()
|
||||
|
||||
if token == "uniform":
|
||||
storage = "uniform"
|
||||
types = UNIFORM_TYPES
|
||||
elif token == "attribute":
|
||||
storage = "attribute"
|
||||
types = ATTRIBUTE_TYPES
|
||||
else:
|
||||
continue
|
||||
|
||||
token = advance()
|
||||
|
||||
if token in ( "highp", "mediump", "lowp"):
|
||||
token = advance()
|
||||
continue
|
||||
|
||||
if token not in types:
|
||||
raise ShaderError("Unsupported type {} in '{}'. Only float, vec<2-4>, mat<2-4>, and sampler2D are supported.".format(token, l))
|
||||
|
||||
type = token
|
||||
|
||||
name = advance()
|
||||
if name is None:
|
||||
raise ShaderError("Couldn't finds name in {}".format(l))
|
||||
|
||||
if tokens:
|
||||
raise ShaderError("Spurious tokens after the name in '{}'. Arrays are not supported in Ren'Py.".format(l))
|
||||
|
||||
if storage == "uniform":
|
||||
location = glGetUniformLocation(self.program, name)
|
||||
|
||||
if location >= 0:
|
||||
self.uniforms[name] = types[type](self, location)
|
||||
|
||||
else:
|
||||
location = glGetAttribLocation(self.program, name)
|
||||
|
||||
if location >= 0:
|
||||
self.attributes.append(Attribute(name, location, types[type]))
|
||||
|
||||
cdef GLuint load_shader(self, GLenum shader_type, source) except? 0:
|
||||
"""
|
||||
This loads a shader into the GPU, and returns the number.
|
||||
"""
|
||||
|
||||
cdef GLuint shader
|
||||
cdef GLchar *source_ptr = <char *> source
|
||||
cdef GLint length
|
||||
cdef GLint status
|
||||
|
||||
cdef char error[1024]
|
||||
|
||||
shader = glCreateShader(shader_type)
|
||||
length = len(source)
|
||||
|
||||
glShaderSource(shader, 1, <const GLchar * const *> &source_ptr, &length)
|
||||
glCompileShader(shader)
|
||||
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status)
|
||||
|
||||
if status == GL_FALSE:
|
||||
glGetShaderInfoLog(shader, 1024, NULL, error)
|
||||
raise ShaderError((<object> error).decode("utf-8"))
|
||||
|
||||
return shader
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
This loads the program into the GPU.
|
||||
"""
|
||||
|
||||
cdef GLuint fragment
|
||||
cdef GLuint vertex
|
||||
cdef GLuint program
|
||||
cdef GLint status
|
||||
|
||||
cdef char error[1024]
|
||||
|
||||
vertex = self.load_shader(GL_VERTEX_SHADER, self.vertex)
|
||||
fragment = self.load_shader(GL_FRAGMENT_SHADER, self.fragment)
|
||||
|
||||
program = glCreateProgram()
|
||||
glAttachShader(program, vertex)
|
||||
glAttachShader(program, fragment)
|
||||
glLinkProgram(program)
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status)
|
||||
|
||||
if status == GL_FALSE:
|
||||
glGetProgramInfoLog(program, 1024, NULL, error)
|
||||
raise ShaderError((<object> error).decode("utf-8"))
|
||||
|
||||
glDeleteShader(vertex)
|
||||
glDeleteShader(fragment)
|
||||
|
||||
self.program = program
|
||||
|
||||
self.find_variables(self.vertex)
|
||||
self.find_variables(self.fragment)
|
||||
|
||||
def missing(self, kind, name):
|
||||
raise Exception("Shader {} has not been given {} {}.".format(self.name, kind, name))
|
||||
|
||||
def start(self):
|
||||
glUseProgram(self.program)
|
||||
|
||||
def set_uniform(self, name, value):
|
||||
cdef Uniform u
|
||||
u = self.uniforms.get(name, None)
|
||||
if u is None:
|
||||
return
|
||||
|
||||
u.assign(value)
|
||||
u.ready = True
|
||||
|
||||
def set_uniforms(self, dict uniforms):
|
||||
cdef Uniform u
|
||||
|
||||
for name, value in uniforms.iteritems():
|
||||
u = self.uniforms.get(name, None)
|
||||
if u is None:
|
||||
continue
|
||||
|
||||
u.assign(value)
|
||||
u.ready = True
|
||||
|
||||
def draw(self, Mesh mesh):
|
||||
|
||||
cdef Attribute a
|
||||
|
||||
# Set up the attributes.
|
||||
for a in self.attributes:
|
||||
offset = mesh.attributes.get(a.name, None)
|
||||
if offset is None:
|
||||
self.missing("mesh attribute", a.ame)
|
||||
|
||||
glVertexAttribPointer(a.location, a.size, GL_FLOAT, GL_FALSE, mesh.stride * sizeof(float), mesh.get_data(offset))
|
||||
glEnableVertexAttribArray(a.location)
|
||||
|
||||
if mesh.polygon_points == 3:
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3 * mesh.polygon_count)
|
||||
return
|
||||
|
||||
cdef int i = 0
|
||||
cdef Polygon p
|
||||
|
||||
for p in mesh.polygons:
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_FAN, i, p.points)
|
||||
i += p.points
|
||||
|
||||
def finish(self):
|
||||
cdef Attribute a
|
||||
cdef Uniform u
|
||||
|
||||
for a in self.attributes:
|
||||
glDisableVertexAttribArray(a.location)
|
||||
|
||||
for u in self.uniforms.itervalues():
|
||||
u.finish()
|
||||
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
import re
|
||||
import io
|
||||
import os
|
||||
|
||||
import renpy.display
|
||||
|
||||
# A map from shader part name to ShaderPart
|
||||
shader_part = { }
|
||||
|
||||
|
||||
def register_shader(name, **kwargs):
|
||||
"""
|
||||
This registers a part of a shader. Shader parts have a name, and then
|
||||
|
||||
`name`
|
||||
A string giving the name of the shader part. Names starting with an
|
||||
underscore or "renpy." are reserved for Ren'Py.
|
||||
|
||||
`variables`
|
||||
The variables used by the shader part. These should be listed one per
|
||||
line, a storage (uniform, attribute, or varing) followed by a type,
|
||||
name, and semicolon. For example::
|
||||
|
||||
variables='''
|
||||
uniform sampler2D uTex0;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
'''
|
||||
|
||||
`vertex_functions`
|
||||
If given, a string containing functions that will be included in the
|
||||
vertex shader.
|
||||
|
||||
`fragment_functions`
|
||||
If given, a string containing functions that will be included in the
|
||||
fragment shader.
|
||||
|
||||
Other keyword arguments should start with ``vertex_`` or ``fragment_``,
|
||||
and end with an integer priority. So "fragment_120" or "vertex_30". These
|
||||
give text that's placed in the appropriate shader at the given priority,
|
||||
with lower priority numbers inserted before higher priority numbers.
|
||||
"""
|
||||
|
||||
ShaderPart(name, **kwargs)
|
||||
|
||||
|
||||
class ShaderPart(object):
|
||||
"""
|
||||
Arguments are as for register_shader.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, name, variables="", vertex_functions="", fragment_functions="", **kwargs):
|
||||
|
||||
if not re.match(r'^[\w\.]+$', name):
|
||||
raise Exception("The shader name {!r} contains an invalid character. Shader names are limited to ASCII alphanumeric characters, _, and .".format(name))
|
||||
|
||||
self.name = name
|
||||
shader_part[name] = self
|
||||
|
||||
self.vertex_functions = vertex_functions
|
||||
self.fragment_functions = fragment_functions
|
||||
|
||||
# A list of priority, text pairs for each section of the vertex and fragment shaders.
|
||||
self.vertex_parts = [ ]
|
||||
self.fragment_parts = [ ]
|
||||
|
||||
# Sets of (storage, type, name) tuples, where storage is one of 'uniform', 'attribute', or 'varying',
|
||||
self.vertex_variables = set()
|
||||
self.fragment_variables = set()
|
||||
|
||||
# A sets of variable names used in the vertex and fragments shader.
|
||||
vertex_used = set()
|
||||
fragment_used = set()
|
||||
|
||||
for k, v in kwargs.iteritems():
|
||||
|
||||
shader, _, priority = k.partition('_')
|
||||
|
||||
if not priority:
|
||||
# Trigger error handling.
|
||||
shader = None
|
||||
|
||||
try:
|
||||
priority = int(priority)
|
||||
except:
|
||||
shader = None
|
||||
|
||||
if shader == "vertex":
|
||||
parts = self.vertex_parts
|
||||
used = vertex_used
|
||||
elif shader == "fragment":
|
||||
parts = self.fragment_parts
|
||||
used = fragment_used
|
||||
else:
|
||||
raise Exception("Keyword arguments to ShaderPart must be of the form {vertex,fragment}_{priority}.")
|
||||
|
||||
parts.append((priority, v))
|
||||
|
||||
for m in re.finditer(r'\b\w+\b', v):
|
||||
used.add(m.group(0))
|
||||
|
||||
for l in variables.split("\n"):
|
||||
l = l.strip(' ;')
|
||||
|
||||
a = l.split()
|
||||
if not a:
|
||||
continue
|
||||
|
||||
if len(a) != 3:
|
||||
print("Unknown shader variable line {!r}. Only the form '{{uniform,attribute,vertex}} {{type}} {{name}} is allowed.".format(l))
|
||||
|
||||
a = tuple(a)
|
||||
name = a[2]
|
||||
|
||||
if name in vertex_used:
|
||||
self.vertex_variables.add(a)
|
||||
|
||||
if name in fragment_used:
|
||||
self.fragment_variables.add(a)
|
||||
|
||||
|
||||
# A map from a tuple giving the parts that comprise a shader, to the Shader
|
||||
# object. The same shader might appear multiple times, to optimize performance.
|
||||
cache = { }
|
||||
|
||||
|
||||
def source(variables, parts, functions, fragment, gles):
|
||||
"""
|
||||
Given lists of variables and parts, converts them into textual source
|
||||
code for a shader.
|
||||
|
||||
`fragment`
|
||||
Should be set to true to generate the code for a fragment shader.
|
||||
"""
|
||||
|
||||
rv = [ ]
|
||||
|
||||
if gles:
|
||||
rv.append("""
|
||||
#version 100 es
|
||||
""")
|
||||
|
||||
if fragment:
|
||||
rv.append("""
|
||||
precision mediump float;
|
||||
""")
|
||||
|
||||
else:
|
||||
rv.append("""
|
||||
#version 120
|
||||
""")
|
||||
|
||||
rv.extend(functions)
|
||||
|
||||
for storage, type_, name in sorted(variables):
|
||||
rv.append("{} {} {};\n".format(storage, type_, name))
|
||||
|
||||
rv.append("\nvoid main() {\n")
|
||||
|
||||
parts.sort()
|
||||
|
||||
for _, part in parts:
|
||||
rv.append(part)
|
||||
|
||||
rv.append("}\n")
|
||||
|
||||
return "".join(rv)
|
||||
|
||||
|
||||
class ShaderCache(object):
|
||||
"""
|
||||
This class caches shaders that were compiled. It's also responsible for
|
||||
recording shaders that have been used, persisting them to disk, and then
|
||||
loading the shaders back into the cache.
|
||||
"""
|
||||
|
||||
def __init__(self, filename, gles):
|
||||
|
||||
# The filename that we'll load the list of shaders from, and
|
||||
# persist it to.
|
||||
self.filename = filename
|
||||
|
||||
# Are we gles?
|
||||
self.gles = gles
|
||||
|
||||
# A map from tuples of partnames to the shaders that have been
|
||||
# created.
|
||||
self.cache = { }
|
||||
|
||||
# A set of tuples of partnames corresponding to shaders that existed
|
||||
# in the past, but do not exist now.
|
||||
self.missing = set()
|
||||
|
||||
def get(self, partnames):
|
||||
"""
|
||||
Gets a shader, creating it if necessary.
|
||||
|
||||
`partnames`
|
||||
A tuple of strings, giving the names of the shader parts to include in
|
||||
the cache.
|
||||
"""
|
||||
|
||||
rv = self.cache.get(partnames, None)
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
partnameset = set(partnames)
|
||||
partnameset.add(renpy.config.default_shader)
|
||||
sortedpartnames = tuple(sorted(partnameset))
|
||||
|
||||
rv = self.cache.get(sortedpartnames, None)
|
||||
if rv is not None:
|
||||
self.cache[partnames] = rv
|
||||
return rv
|
||||
|
||||
# If the cache missed entirely, we have to generate the source code for the
|
||||
# shaders.
|
||||
|
||||
vertex_variables = set()
|
||||
vertex_parts = [ ]
|
||||
vertex_functions = [ ]
|
||||
|
||||
fragment_variables = set()
|
||||
fragment_parts = [ ]
|
||||
fragment_functions = [ ]
|
||||
|
||||
for i in sortedpartnames:
|
||||
|
||||
p = shader_part.get(i, None)
|
||||
|
||||
if p is None:
|
||||
raise Exception("{!r} is not a known shader part.".format(i))
|
||||
|
||||
vertex_variables |= p.vertex_variables
|
||||
vertex_parts.extend(p.vertex_parts)
|
||||
vertex_functions.append(p.vertex_functions)
|
||||
|
||||
fragment_variables |= p.fragment_variables
|
||||
fragment_parts.extend(p.fragment_parts)
|
||||
fragment_functions.append(p.fragment_functions)
|
||||
|
||||
vertex = source(vertex_variables, vertex_parts, vertex_functions, False, self.gles)
|
||||
fragment = source(fragment_variables, fragment_parts, fragment_functions, True, self.gles)
|
||||
|
||||
from renpy.gl2.gl2shader import Program
|
||||
|
||||
rv = Program(sortedpartnames, vertex, fragment)
|
||||
rv.load()
|
||||
|
||||
self.cache[partnames] = rv
|
||||
self.cache[sortedpartnames] = rv
|
||||
return rv
|
||||
|
||||
def check(self, partnames):
|
||||
"""
|
||||
Returns true if every part in partnames is a known part, or False
|
||||
otherwise.
|
||||
"""
|
||||
|
||||
for i in partnames:
|
||||
if i not in shader_part:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Saves the list of shaders to the file.
|
||||
"""
|
||||
|
||||
fn = "<unknown>"
|
||||
|
||||
try:
|
||||
fn = renpy.loader.get_path(self.filename)
|
||||
|
||||
tmp = fn + ".tmp"
|
||||
|
||||
with io.open(tmp, "w", encoding="utf-8") as f:
|
||||
shaders = set(self.cache.keys()) | self.missing
|
||||
|
||||
for i in shaders:
|
||||
f.write(u" ".join(i) + "\r\n")
|
||||
|
||||
try:
|
||||
os.unlink(fn)
|
||||
except:
|
||||
pass
|
||||
|
||||
os.rename(tmp, fn)
|
||||
|
||||
except:
|
||||
renpy.display.log.write("Saving shaders to {!r}:".format(fn))
|
||||
renpy.display.log.exception()
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
Loads the list of shaders from the file, and compiles all shaders
|
||||
for which the parts exist, and for which compilation can succeed.
|
||||
"""
|
||||
|
||||
try:
|
||||
f = renpy.loader.load(self.filename)
|
||||
except:
|
||||
renpy.display.log.write("Could not open {!r}:".format(self.filename))
|
||||
return
|
||||
|
||||
for l in f:
|
||||
l = l.strip()
|
||||
partnames = tuple(l.strip().split())
|
||||
|
||||
if not partnames:
|
||||
continue
|
||||
|
||||
if not self.check(partnames):
|
||||
self.missing.add(partnames)
|
||||
continue
|
||||
|
||||
try:
|
||||
self.get(partnames)
|
||||
except:
|
||||
renpy.display.log.write("Precompiling shader {!r}:".format(partnames))
|
||||
renpy.display.log.exception()
|
||||
self.missing.add(partnames)
|
||||
|
||||
f.close()
|
||||
+45
-74
@@ -19,85 +19,56 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
cimport renpy.display.render as render
|
||||
from gl2draw cimport Environ
|
||||
from uguugl cimport *
|
||||
from renpy.gl2.gl2shader cimport Program
|
||||
from renpy.gl2.gl2geometry cimport Mesh
|
||||
from renpy.gl2.gl2draw cimport GL2Draw
|
||||
|
||||
cdef class TextureCore:
|
||||
cdef class TextureLoader:
|
||||
|
||||
# The draw object associated with this TextureLoader
|
||||
cdef GL2Draw draw
|
||||
|
||||
# All the texture number currently allocated by this loader.
|
||||
cdef set allocated
|
||||
|
||||
# A list of (number, generation) pairs for textures that need to be freed.
|
||||
cdef list free_list
|
||||
|
||||
# The total size (in bytes) of all the textures that have been allocated
|
||||
# but not deallocated.
|
||||
cdef int total_texture_size
|
||||
|
||||
# The program used for fast texture loading
|
||||
cdef Program ftl_program
|
||||
|
||||
# The queue of textures that need to be loaded.
|
||||
cdef object texture_load_queue
|
||||
|
||||
# The maximum size of a texture.
|
||||
cdef GLint max_texture_width
|
||||
cdef GLint max_texture_height
|
||||
|
||||
|
||||
cdef class GLTexture:
|
||||
|
||||
# The size of the texture, in pixels.
|
||||
cdef public int width
|
||||
cdef public int height
|
||||
cdef public int generation
|
||||
|
||||
# The number of the texture in OpenGL.
|
||||
cdef public unsigned int number
|
||||
cdef bint loaded
|
||||
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)
|
||||
# Has this texture been loaded yet?
|
||||
cdef public bint loaded
|
||||
|
||||
cdef public object debug
|
||||
# If we are doing in-place loading, this is the data that's used for
|
||||
# that.
|
||||
cdef object surface
|
||||
|
||||
cdef class TextureGrid:
|
||||
# If we're not doing in-place loading, this is the data that's used for
|
||||
# that.
|
||||
cdef unsigned char *data
|
||||
|
||||
|
||||
cdef object __weakref__
|
||||
|
||||
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
|
||||
|
||||
cpdef void make_ready(self, bint nearest)
|
||||
|
||||
cdef public object debug
|
||||
cdef public bint ready
|
||||
|
||||
|
||||
cpdef blit(
|
||||
TextureGrid tg,
|
||||
double sx,
|
||||
double sy,
|
||||
render.Matrix2D transform,
|
||||
double alpha,
|
||||
double over,
|
||||
Environ environ,
|
||||
bint nearest)
|
||||
|
||||
cpdef blend(
|
||||
TextureGrid tg0,
|
||||
TextureGrid tg1,
|
||||
double sx,
|
||||
double sy,
|
||||
render.Matrix2D transform,
|
||||
double alpha,
|
||||
double over,
|
||||
double fraction,
|
||||
Environ environ,
|
||||
bint nearest)
|
||||
|
||||
cpdef imageblend(
|
||||
TextureGrid tg0,
|
||||
TextureGrid tg1,
|
||||
TextureGrid tg2,
|
||||
double sx,
|
||||
double sy,
|
||||
render.Matrix2D transform,
|
||||
double alpha,
|
||||
double over,
|
||||
double fraction,
|
||||
int ramp,
|
||||
Environ environ,
|
||||
bint nearest)
|
||||
# The texture loader associated with this texture.
|
||||
cdef TextureLoader loader
|
||||
|
||||
+464
-1305
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -38,7 +38,7 @@ from libc.stdlib cimport calloc, free
|
||||
from cpython.buffer cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_CONTIG, PyBUF_CONTIG_RO
|
||||
|
||||
cimport uguugl
|
||||
from uguugl import reset_error, get_error, enable_check_error, load
|
||||
from uguugl import load
|
||||
|
||||
cdef object proxy_return_string(const GLubyte *s):
|
||||
"""
|
||||
|
||||
+273
-1300
File diff suppressed because it is too large
Load Diff
+15
-6
@@ -734,14 +734,23 @@ class RenpyImporter(object):
|
||||
if filename.endswith("__init__.py"):
|
||||
mod.__path__ = [ filename[:-len("__init__.py")] ]
|
||||
|
||||
source = load(filename).read().decode("utf8")
|
||||
if source and source[0] == u'\ufeff':
|
||||
source = source[1:]
|
||||
source = source.encode("raw_unicode_escape")
|
||||
for encoding in [ "utf-8", "latin-1" ]:
|
||||
|
||||
source = source.replace("\r", "")
|
||||
try:
|
||||
|
||||
source = load(filename).read().decode(encoding)
|
||||
if source and source[0] == u'\ufeff':
|
||||
source = source[1:]
|
||||
source = source.encode("raw_unicode_escape")
|
||||
|
||||
source = source.replace("\r", "")
|
||||
|
||||
code = compile(source, filename, 'exec', renpy.python.old_compile_flags, 1)
|
||||
break
|
||||
except:
|
||||
if encoding == "latin-1":
|
||||
raise
|
||||
|
||||
code = compile(source, filename, 'exec', renpy.python.old_compile_flags, 1)
|
||||
exec code in mod.__dict__
|
||||
|
||||
return sys.modules[fullname]
|
||||
|
||||
+14
-5
@@ -439,6 +439,8 @@ def save(slotname, extra_info='', mutate_flag=False):
|
||||
location.scan()
|
||||
clear_slot(slotname)
|
||||
|
||||
# The thread used for autosave.
|
||||
autosave_thread = None
|
||||
|
||||
# Flag that lets us know if an autosave is in progress.
|
||||
autosave_not_running = threading.Event()
|
||||
@@ -448,7 +450,7 @@ autosave_not_running.set()
|
||||
autosave_counter = 0
|
||||
|
||||
|
||||
def autosave_thread(take_screenshot):
|
||||
def autosave_thread_function(take_screenshot):
|
||||
|
||||
global autosave_counter
|
||||
|
||||
@@ -521,6 +523,8 @@ def force_autosave(take_screenshot=False, block=False):
|
||||
If True, blocks until the autosave completes.
|
||||
"""
|
||||
|
||||
global autosave_thread
|
||||
|
||||
if renpy.game.after_rollback or renpy.exports.in_rollback():
|
||||
return
|
||||
|
||||
@@ -528,6 +532,11 @@ def force_autosave(take_screenshot=False, block=False):
|
||||
if not autosave_not_running.isSet():
|
||||
return
|
||||
|
||||
# Join the autosave thread to clear resources.
|
||||
if autosave_thread is not None:
|
||||
autosave_thread.join()
|
||||
autosave_thread = None
|
||||
|
||||
# Do not save if we're in the main menu.
|
||||
if renpy.store.main_menu:
|
||||
return
|
||||
@@ -555,12 +564,12 @@ def force_autosave(take_screenshot=False, block=False):
|
||||
autosave_not_running.clear()
|
||||
|
||||
if not renpy.emscripten:
|
||||
t = threading.Thread(target=autosave_thread, args=(take_screenshot,))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
autosave_thread = threading.Thread(target=autosave_thread_function, args=(take_screenshot,))
|
||||
autosave_thread.daemon = True
|
||||
autosave_thread.start()
|
||||
else:
|
||||
import emscripten
|
||||
emscripten.async_call(autosave_thread, take_screenshot, -1)
|
||||
emscripten.async_call(autosave_thread_function, take_screenshot, -1)
|
||||
|
||||
|
||||
################################################################################
|
||||
|
||||
+49
-4
@@ -228,11 +228,56 @@ def choose_variants():
|
||||
renpy.config.variants.insert(0, 'phone')
|
||||
renpy.config.variants.insert(0, 'small')
|
||||
|
||||
else:
|
||||
if renpy.emscripten:
|
||||
renpy.config.variants.insert(0, 'web')
|
||||
elif renpy.emscripten:
|
||||
import emscripten, re
|
||||
|
||||
# web
|
||||
renpy.config.variants.insert(0, 'web')
|
||||
|
||||
# mobile
|
||||
userAgent = emscripten.run_script_string(r'''navigator.userAgent''')
|
||||
mobile = re.search('Mobile|Android|iPad|iPhone', userAgent)
|
||||
if mobile:
|
||||
renpy.config.variants.insert(0, 'mobile')
|
||||
# Reserve android/ios for when the OS API is exposed
|
||||
#if re.search('Android', userAgent):
|
||||
# renpy.config.variants.insert(0, 'android')
|
||||
#if re.search('iPad|iPhone', userAgent):
|
||||
# renpy.config.variants.insert(0, 'ios')
|
||||
|
||||
# touch
|
||||
touch = emscripten.run_script_int(r'''
|
||||
('ontouchstart' in window) ||
|
||||
(navigator.maxTouchPoints > 0) ||
|
||||
(navigator.msMaxTouchPoints > 0)''')
|
||||
if touch == 1:
|
||||
# mitigate hybrids (e.g. ms surface) by restricting touch to mobile
|
||||
if mobile:
|
||||
renpy.config.variants.insert(0, 'touch')
|
||||
|
||||
# large/medium/small
|
||||
# tablet/phone
|
||||
# screen.width/height is auto-adjusted by browser,
|
||||
# so it can be used as a physical sizereference
|
||||
# (see also window.devicePixelRatio)
|
||||
# e.g. Galaxy S5:
|
||||
# - physical / OpenGL: 1080x1920
|
||||
# - web screen: 360x640 w/ devicePixelRatio=3
|
||||
ref_width = emscripten.run_script_int(r'''screen.width''')
|
||||
ref_height = emscripten.run_script_int(r'''screen.height''')
|
||||
# medium reference point: ipad 1024x768, ipad pro 1336x1024 (browser "pixels")
|
||||
if mobile:
|
||||
if (ref_width < 768 or ref_height < 768):
|
||||
renpy.config.variants.insert(0, 'small')
|
||||
renpy.config.variants.insert(0, 'phone')
|
||||
else:
|
||||
renpy.config.variants.insert(0, 'medium')
|
||||
renpy.config.variants.insert(0, 'tablet')
|
||||
else:
|
||||
renpy.config.variants.insert(0, 'pc')
|
||||
renpy.config.variants.insert(0, 'large')
|
||||
|
||||
else:
|
||||
renpy.config.variants.insert(0, 'pc')
|
||||
|
||||
renpy.config.variants.insert(0, 'large')
|
||||
|
||||
|
||||
@@ -1970,6 +1970,9 @@ def menu_statement(l, loc):
|
||||
|
||||
rv.extend(menu)
|
||||
|
||||
for i in rv:
|
||||
i.statement_start = rv[0]
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ pure_functions = {
|
||||
"_",
|
||||
"_p",
|
||||
"absolute",
|
||||
"__renpy__list__",
|
||||
"__renpy__dict__",
|
||||
"__renpy__set__",
|
||||
|
||||
# defaultstore.py
|
||||
"ImageReference", "Image", "Frame", "Solid", "LiveComposite", "LiveCrop",
|
||||
|
||||
+9
-5
@@ -1646,9 +1646,9 @@ class RollbackLog(renpy.object.Object):
|
||||
fwd_name, fwd_data = self.forward[0]
|
||||
|
||||
if (self.current.context.current == fwd_name
|
||||
and data == fwd_data
|
||||
and (keep_rollback or self.rolled_forward)
|
||||
):
|
||||
and data == fwd_data
|
||||
and (keep_rollback or self.rolled_forward)
|
||||
):
|
||||
self.forward.pop(0)
|
||||
else:
|
||||
del self.forward[:]
|
||||
@@ -1705,7 +1705,11 @@ class RollbackLog(renpy.object.Object):
|
||||
This is called to try to recover when rollback fails.
|
||||
"""
|
||||
|
||||
if not renpy.config.load_failed_label:
|
||||
lfl = renpy.config.load_failed_label
|
||||
if callable(lfl):
|
||||
lfl = lfl()
|
||||
|
||||
if not lfl:
|
||||
raise Exception("Couldn't find a place to stop rolling back. Perhaps the script changed in an incompatible way?")
|
||||
|
||||
rb = self.log.pop()
|
||||
@@ -1715,7 +1719,7 @@ class RollbackLog(renpy.object.Object):
|
||||
renpy.exports.pop_call()
|
||||
|
||||
renpy.game.contexts[0].force_checkpoint = True
|
||||
renpy.game.contexts[0].goto_label(renpy.config.load_failed_label)
|
||||
renpy.game.contexts[0].goto_label(lfl)
|
||||
|
||||
raise renpy.game.RestartTopContext()
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ many = renpy.object.Sentinel("many")
|
||||
def register_sl_displayable(*args, **kwargs):
|
||||
"""
|
||||
:doc: custom_sl class
|
||||
:args: (name, displayable, style, nchildren=0, scope=False, replaces=False, default_keywords={})
|
||||
:args: (name, displayable, style, nchildren=0, scope=False, replaces=False, default_keywords={}, default_properties=True)
|
||||
|
||||
Registers a screen language statement that creates a displayable.
|
||||
|
||||
@@ -464,6 +464,9 @@ def register_sl_displayable(*args, **kwargs):
|
||||
`default_keywords`
|
||||
The default set of keyword arguments to supply to the displayable.
|
||||
|
||||
`default_properties`
|
||||
If true, the ui and position properties are added by default.
|
||||
|
||||
Returns an object that can have positional arguments and properties
|
||||
added to it by calling the following methods. Each of these methods
|
||||
returns the object it is called on, allowing methods to be chained
|
||||
|
||||
@@ -39,6 +39,9 @@ position_property_names = [
|
||||
"maximum",
|
||||
"xmaximum",
|
||||
"ymaximum",
|
||||
"minimum",
|
||||
"xminimum",
|
||||
"yminimum",
|
||||
"area",
|
||||
"clipping",
|
||||
"xfill",
|
||||
@@ -93,9 +96,6 @@ text_property_names = [
|
||||
"text_align",
|
||||
"text_y_fudge",
|
||||
"underline",
|
||||
"minimum",
|
||||
"xminimum",
|
||||
"yminimum",
|
||||
"hinting",
|
||||
"adjust_spacing",
|
||||
]
|
||||
@@ -121,9 +121,6 @@ window_properties = [ Style(i) for i in [
|
||||
"ypadding",
|
||||
"padding",
|
||||
"size_group",
|
||||
"minimum",
|
||||
"xminimum",
|
||||
"yminimum",
|
||||
] ]
|
||||
|
||||
button_properties = [ Style(i) for i in [
|
||||
@@ -182,9 +179,6 @@ box_property_names = [
|
||||
"fit_first",
|
||||
"xfit",
|
||||
"yfit",
|
||||
"minimum",
|
||||
"xminimum",
|
||||
"yminimum",
|
||||
]
|
||||
|
||||
box_properties = [ Style(i) for i in box_property_names ]
|
||||
|
||||
@@ -250,6 +250,10 @@ def substitute(s, scope=None, force=False, translate=True):
|
||||
else:
|
||||
kwargs = renpy.store.__dict__ # @UndefinedVariable
|
||||
|
||||
s = formatter.vformat(s, (), kwargs)
|
||||
try:
|
||||
s = formatter.vformat(s, (), kwargs)
|
||||
except:
|
||||
if renpy.display.predict.predicting: # @UndefinedVariable
|
||||
return " ", True
|
||||
|
||||
return s, (s != old_s)
|
||||
|
||||
+8
-1
@@ -302,7 +302,14 @@ class TextSegment(object):
|
||||
tf = font_func(tf)
|
||||
|
||||
if not isinstance(tf, font.FontGroup):
|
||||
yield (self, s)
|
||||
|
||||
if self.font is tf:
|
||||
yield (self , s)
|
||||
else:
|
||||
seg = TextSegment(self)
|
||||
seg.font = tf
|
||||
yield (seg, s)
|
||||
|
||||
return
|
||||
|
||||
segs = { }
|
||||
|
||||
+6
-3
@@ -75,6 +75,8 @@ class BarValue(renpy.object.Object):
|
||||
# Alt text.
|
||||
alt = "Bar"
|
||||
|
||||
force_step = False
|
||||
|
||||
def replaces(self, other):
|
||||
return
|
||||
|
||||
@@ -817,8 +819,6 @@ def menu(menuitems,
|
||||
default=False,
|
||||
**properties):
|
||||
|
||||
# menu is now a conglomeration of other widgets. And bully for it.
|
||||
|
||||
renpy.ui.vbox(style=style, **properties)
|
||||
|
||||
for label, val in menuitems:
|
||||
@@ -829,7 +829,10 @@ def menu(menuitems,
|
||||
text = choice_style
|
||||
button = choice_button_style
|
||||
|
||||
clicked = ChoiceReturn(label, val, location)
|
||||
if isinstance(val, ChoiceReturn):
|
||||
clicked = val
|
||||
else:
|
||||
clicked = ChoiceReturn(label, val, location)
|
||||
|
||||
if clicked.get_chosen():
|
||||
text = choice_chosen_style
|
||||
|
||||
-1499
File diff suppressed because it is too large
Load Diff
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname $0)/.."
|
||||
|
||||
pushd notarized/in
|
||||
rm -Rf /tmp/notarize
|
||||
mkdir -p /tmp/notarize
|
||||
tar xjf renpy.tar.bz2 -C /tmp/notarize
|
||||
popd
|
||||
|
||||
pushd /tmp/notarize
|
||||
mv renpy-*-sdk/renpy.app .
|
||||
rm -Rf renpy-*-sdk
|
||||
|
||||
codesign --verify --verbose renpy.app
|
||||
|
||||
zip -r renpy.app.zip renpy.app
|
||||
|
||||
xcrun altool --asc-provider XHTE5H7Z79 -u tom@rothamel.us -p "@keychain:altool" \
|
||||
--notarize-app \
|
||||
--primary-bundle-id org.renpy.renpy \
|
||||
-f renpy.app.zip
|
||||
|
||||
popd
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname $0)/.."
|
||||
|
||||
pushd /tmp/notarize
|
||||
|
||||
result="$(xcrun altool --notarization-history 0 --asc-provider XHTE5H7Z79 -u tom@rothamel.us -p '@keychain:altool' | head -6 | tail -1)"
|
||||
echo $result
|
||||
status="$(echo $result | cut -d ' ' -f 5)"
|
||||
|
||||
if [ $status = "success" ]; then
|
||||
echo "Success... now stapling."
|
||||
else
|
||||
exit
|
||||
fi
|
||||
|
||||
xcrun stapler staple -v renpy.app
|
||||
|
||||
popd
|
||||
|
||||
rm -Rf notarized/out/renpy.app || true
|
||||
cp -a /tmp/notarize/renpy.app notarized/out/
|
||||
|
||||
echo "Done."
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
dmg="/Users/tom/magnetic/ab/website/renpy/dl/$1/renpy-$1-sdk.dmg"
|
||||
|
||||
if [ ! -e "$dmg" ]; then
|
||||
echo "$dmg" not found.
|
||||
exit 1
|
||||
else
|
||||
echo "$dmg" found.
|
||||
fi
|
||||
|
||||
xcrun altool --asc-provider XHTE5H7Z79 -u tom@rothamel.us -p "@keychain:altool" \
|
||||
--notarize-app \
|
||||
--primary-bundle-id org.renpy.renpy.dmg \
|
||||
-f "$dmg"
|
||||
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
dmg="/Users/tom/magnetic/ab/website/renpy/dl/$1/renpy-$1-sdk.dmg"
|
||||
|
||||
if [ ! -e "$dmg" ]; then
|
||||
echo "$dmg" not found.
|
||||
exit 1
|
||||
else
|
||||
echo "$dmg" found.
|
||||
fi
|
||||
|
||||
xcrun stapler staple --verbose "$dmg"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user