Compare commits

...

254 Commits

Author SHA1 Message Date
Tom Rothamel 3d4ef2df96 Increase skip speed. 2015-03-08 12:46:48 -04:00
Tom Rothamel 2b20ef7834 Work on call stack corruption.
- Pop return blindly pops things - which prevents problems if the return
  label doesn't exist.
- When config.developer is true, we monitor for and try to fix call stack
  corruption.
- When config.developer is false, we try to survive call stack corruption,
  although this may lead to other errors.
2015-03-08 12:14:03 -04:00
Tom Rothamel e4fe7f3586 Limit the size of the textures we render to.
When using the FBO, we'd use the largest textures available,
even when the data was only large enough to fill a small portion
of those textures.
2015-03-07 16:17:09 -05:00
Tom Rothamel 7cfc6ad1ba Wrap dictionary and set comprehensions to support rollback.
Thanks to rivvil for noticing the problem and contributing the
fix.
2015-03-07 10:24:49 -05:00
Tom Rothamel 57c27cfde4 Do not block lint. 2015-03-07 10:24:41 -05:00
Tom Rothamel 3ceec0b62d Properly analyze nested imagemaps.
If an imagemap statement is non-constant, neither are its hotspot
children. We need to re-evaluate the hotspot children whenever
the non-constant imagemap changes.

Fixes #567.
2015-03-06 23:56:48 -05:00
Tom Rothamel fe1d1e5499 Respect xysize/xminimum/yminimum on Solid and Frame. 2015-03-06 22:59:39 -05:00
Tom Rothamel ca944b5089 Ignore ignored TIMEEVENTS.
Ignoring a TIMEEVENT is probably a mistake, but doing so previously
caused a TIMEEVENT to be posted, which would stop redraws from
happening entirely.
2015-03-05 23:15:08 -05:00
Tom Rothamel 92163cd704 Drag should only ignore relevant events.
Notably, it shouldn't ignore TIMEEVENT.
2015-03-05 23:12:19 -05:00
Tom Rothamel edfd705a52 alt+shift+I inspects all layers. 2015-03-05 21:55:01 -05:00
Tom Rothamel 4a1557edf3 Include rectangle in imagemap hash.
Fixes #566, and probably many of our ongoing problems.
2015-03-04 21:06:06 -05:00
Tom Rothamel 4c55cab9fc Detect and report potential infinite loop.
We define an IL as 10 seconds of no interactions. (60s during the
init phase.)

Fixes #565.
2015-03-04 17:12:33 -05:00
Tom Rothamel 8a9eb86bac Use file data, rather than modification time, in imagemap cache.
This should fix a longstanding problem where changes to files
might not be reflected in the imagemap cache.
2015-03-03 22:20:48 -05:00
Tom Rothamel 077c7818ec Use the copy RTT on PC platforms.
Until we switch to one FBO-per-size, the FBO RTT doesn't improve
performance much, and it causes problems with older Nvidia drivers
on windows.
2015-03-03 21:02:11 -05:00
Tom Rothamel 136db345c9 Add support for manually failing GL or ANGLE.
For testing purposes.
2015-03-02 21:54:14 -05:00
Tom Rothamel 31b711b672 Re-enable HW video.
Accidentally shipped with it defaulting to off.
2015-03-01 22:13:32 -05:00
Tom Rothamel 7aeed18720 Tell RAPT we're Ren'Py. 2015-03-01 17:31:05 -05:00
Tom Rothamel 7da86f27e9 Fix missing argument. 2015-02-28 12:46:45 -05:00
Tom Rothamel e851096b77 Only skip during a TIMEEVENT.
This prevents a sufficiently fast skip time from consuming the KEYDOWN
events that might be used to end skipping.
2015-02-27 22:30:35 -05:00
Tom Rothamel 91cdebd401 Take execution state even if the ATL has finished. 2015-02-27 21:27:37 -05:00
Tom Rothamel 939034a481 RawChild takes ATL, not a displayable.x 2015-02-27 09:29:24 -05:00
Tom Rothamel 4ae3092877 Fix an issue with constant transforms. 2015-02-26 23:59:08 -05:00
Tom Rothamel db23bd0f91 Make ALL_EVENTS a dense set.
This saves the memory required to store the list version of ALL_EVENTS,
and the time required to search through it.
2015-02-26 23:30:07 -05:00
Tom Rothamel 5e0de94e9a Implement LiveCrop and LiveComposite in terms of Transforms.
Transforms are the preferred path for many things.
2015-02-26 23:23:12 -05:00
Tom Rothamel cdfbfcd481 Recompile non-constant ATL at execution.
This fixes a problem reported where ATL was being compiled at screen
prediction time - which might be before variables used by the ATL block
have finished updating.

The fix was to compile non-constant ATL twice - first, during ATL
prediction, and then again once the ATL is ready to execute for
real.

PM: http://lemmasoft.renai.us/forums/ucp.php?i=pm&mode=view&f=0&p=163661
2015-02-26 23:17:49 -05:00
Tom Rothamel 5d49b6b75b Better reprs for Image, ImageReference, and ATLTransform.
This helps tell them apart while debugging.
2015-02-26 23:17:03 -05:00
Tom Rothamel f9a7b7dc21 Remove texture from texture cache when it leaves the image cache. 2015-02-25 09:32:30 -05:00
Tom Rothamel 61b7550157 Memory profiling improvements.
* Do not double count surfaces.
* Display a banner while performing profiling operations.
2015-02-25 09:32:30 -05:00
kyouryuukunn fc7fcc8db9 Merge pull request #562 from kyouryuukunn/update_japanese
update japanese
2015-02-25 16:15:38 +09:00
kyouryuukunn 2cdb8adb64 update japanese 2015-02-25 16:13:38 +09:00
Tom Rothamel a22b406f46 Check timestamps for correctness. 2015-02-24 19:30:19 -05:00
Tom Rothamel cff0b43f96 Add renpy.copy_save.
A function that copies saves around.
2015-02-23 21:57:12 -05:00
Tom Rothamel 0a2bee8a78 Add a memory profiling key. 2015-02-23 21:57:12 -05:00
Tom Rothamel 0e53af427f Merge pull request #560 from javimat/master
Update Spanish Translations
2015-02-23 18:14:14 -05:00
Tom Rothamel 3120b5e438 Use FBOs on any platform where an FBO is available.
Hopefully, this will prevent the "flopping" problem people have been
seeing on Android.
2015-02-22 11:24:15 -05:00
Tom Rothamel 01689fc02a Input should only ignore keys that generate text input.
This means that when escape is pressed while editing, we'll be taken
to the game menu. (Ditto for pageup and rollback, etc.)
2015-02-22 11:09:12 -05:00
Tom Rothamel afc9a2d97c If the user closes the onscreen keyboard, reopen it. 2015-02-21 22:28:09 -05:00
Tom Rothamel df5d891ee7 Add config.missing_label_callback.
This is a function that can replace missing labels with other labels.

Fixes #561.
2015-02-21 21:57:44 -05:00
Tom Rothamel d7ba76f44f atl: Parameterize (reset) children when showing them.
Fixes #557.
2015-02-20 22:38:34 -05:00
Tom Rothamel 10cda2103f Copy Fixeds when they're parameterized.
Parameterization (a terrible name) is used to reset transforms. In
cases where a single transform should be reset, a Fixed full of
tranforms should be replaced with a Fixed full of reset transforms.

(This is especially true for Fixeds created as part of a multiple
contains block in an ATL transform.)
2015-02-20 22:35:51 -05:00
Tom Rothamel 616cdbd218 atl: Contains block should only create a fixed if 2 or more.
This mirrors the behavior of the rest of Ren'Py, and makes the
contains block statement mirror the contains expression statement.
2015-02-20 22:06:06 -05:00
Tom Rothamel 2199a4db1c Focus_mask should be true by default for drags.
This restores compatibility with the behavior of 6.18.3.
2015-02-19 23:15:02 -05:00
Tom Rothamel c4b673099f Allow drags to go partially offscreen. 2015-02-19 22:53:11 -05:00
Tom Rothamel c61b01ee0c Simplify/fix PNG writing. 2015-02-18 23:31:23 -05:00
Tom Rothamel 24f26acea4 Work around a problem with the NSUrl.path property on iOS.
On 7.0, it's a method. On 8.0, it's a property. I don't get why,
 but this defensively codes around it.
2015-02-17 19:42:45 -05:00
Tom Rothamel f4e5e0f297 Allow use of the integrated GPU on macs.
Controlled by build.allow_integrated_gpu variable.
2015-02-17 19:14:20 -05:00
javimat a78d9bbccf Update common.rpy 2015-02-17 11:59:46 +01:00
javimat 89ec94a72b Update common.rpy in Spanish tl of Launcher 2015-02-17 11:56:38 +01:00
javimat cf495ac494 Update Spanish Template 2015-02-17 11:51:13 +01:00
Tom Rothamel 0eb54ef113 Fix missing word in LGPL name. 2015-02-16 22:42:54 -05:00
Tom Rothamel 3043543901 Fix tagging. 2015-02-16 21:16:36 -05:00
Tom Rothamel 6f56cbb12e Adjust tagging. 2015-02-16 21:14:19 -05:00
Tom Rothamel a7542015ab Remove translaton TODOs. 2015-02-16 21:07:07 -05:00
Tom Rothamel 3e20a92c80 More reliable read of sums. 2015-02-15 23:23:59 -05:00
Tom Rothamel 93812b4a1b Deal with potentially corrupt sums file.
For some reason, on my mac, the sums file is getting corrupted.
2015-02-15 22:47:59 -05:00
Tom Rothamel 4f3a0c546f Remove debug print. 2015-02-15 21:19:08 -05:00
Tom Rothamel 097978b044 This code is obsolete with pygame_sdl2. 2015-02-15 20:57:35 -05:00
Tom Rothamel da041e5170 Properly classify renios. 2015-02-15 20:57:18 -05:00
Tom Rothamel 9b626fe039 On windows, use the Ren'Py executable to relaunch if it exists. 2015-02-15 16:35:36 -05:00
Tom Rothamel c51db4ce64 Fix tagging, tag all projects. 2015-02-15 16:32:50 -05:00
Tom Rothamel 01b66c6197 Remove quit and maximize keybindings.
These are redundant on SDL2, which will synthesize more appropriate
system events from the platform-specific keypresses. This redundancy
can cause problems - when we first synthesize a quit event from
alt-F4, and then get the real QUIT, we behave incorrectly.

Fixes #554.
2015-02-14 22:55:02 -05:00
Tom Rothamel 2a31925ef7 Change the icon of lib/windows-i686/<game>.exe
This is the icon that's used when the game is pinned to the
windows taskbar.
2015-02-14 20:25:41 -05:00
Tom Rothamel 9480b544fb Predict main_menu while in the splashscreen.
Fixes #503.
2015-02-13 22:35:14 -05:00
Tom Rothamel 8c989bb684 Prevent renpy.stop_predict_screen from throwing exceptions.
We now ignore the case where we stop predicting a screen that
wasn't being predicted. Previously, we threw an exception.
2015-02-13 22:33:28 -05:00
Tom Rothamel d9dd895775 Remove leftover call. 2015-02-12 23:40:57 -05:00
Tom Rothamel a149858701 Add iOS documentation. 2015-02-12 23:39:41 -05:00
Tom Rothamel 3a1105935c Include gesture function docs. 2015-02-12 23:38:33 -05:00
Tom Rothamel c5fa5ca98b Ignore unknown KEYDOWN events in input.
This prevents them from triggering Keymap events when an input
is present.
2015-02-12 21:19:37 -05:00
Tom Rothamel e40e780834 Document gestures. 2015-02-11 17:27:26 -05:00
Tom Rothamel 5f23501413 Remove default gestures (except for progress).
At least until we can think about what sort of gestures we want in an
iOS game.
2015-02-11 17:25:44 -05:00
Tom Rothamel 0631221d98 Allow config.dispatch_gesture to end an interaction. 2015-02-11 17:25:25 -05:00
Tom Rothamel 87fc8b0468 Merge achievements when persistent data is changed. 2015-02-10 18:39:28 -05:00
Tom Rothamel b6d16ef601 Document the achievement system. 2015-02-10 18:25:11 -05:00
Tom Rothamel 72704eb945 Fixes to steam support; do not distribute by default. 2015-02-09 22:41:27 -05:00
Tom Rothamel 23c202e25f Write changelog. 2015-02-09 22:18:22 -05:00
Tom Rothamel 253cf2a5c7 Bump version to 6.99, add name. 2015-02-08 21:16:12 -05:00
Tom Rothamel dfce28b881 Merge pull request #549 from evilantishad0w/editfunctoggle
add toggle to show/hide "Edit File" section
2015-02-08 21:06:21 -05:00
Tom Rothamel 013cfdadea Build fribidi on Android. 2015-02-08 20:52:01 -05:00
evilantishad0w 71545e6d3a cleaned toggle code up a bit 2015-02-08 17:26:21 -07:00
Tom Rothamel 8282084f48 Allow resize on ANGLE. 2015-02-08 15:16:08 -05:00
Tom Rothamel 5d53028f62 Revise license and help.
This includes a better compliance notice and a revised list of
software licenses and repositories.
2015-02-08 12:34:57 -05:00
Tom Rothamel c43f364eab Ignore spurious resize events.
Windows seems to generate a spurious 1x1 resize event after leaving
fullscreen, and the occasional spurious (though correct) resize when
entering and leaving fullscreen mode.

We use the size of the window to debounce these events.

Fixes #382.
2015-02-07 23:53:28 -05:00
Tom Rothamel 93b25e9627 Use the desktop resolution when going fullscreen.
This works a lot better.
2015-02-07 21:42:27 -05:00
Tom Rothamel 3051687b4c Enable ZIP64 - allows packaging of large games. 2015-02-07 13:58:10 -05:00
Tom Rothamel 94cca9458b Use renpy.exe as gamename.exe.
Now that they differ, we want to use the Ren'Py-specific name.

Fixes #547.
2015-02-07 13:52:23 -05:00
Tom Rothamel c63e58f170 Fix analysis of ATL.
Analyzing ATL would crash old pre-ATL games. Also, we weren't
analyzing some atl clauses.
2015-02-07 00:07:02 -05:00
Tom Rothamel 3aa40537e9 Cleanups for #498.
The l_checkbox_box style change allows checkboxes to take up multiple
lines, but may need to be localized for different translations.
2015-02-06 19:45:52 -05:00
Tom Rothamel 495fa5512c Merge pull request #498 from Neurone/master
Let choose to developer if strings need to be empty while generating translations
2015-02-06 19:39:12 -05:00
Tom Rothamel f561b1ce04 Merge pull request #502 from tlm-2501/master
Added a Russian translation for the tutorial game
2015-02-06 19:37:13 -05:00
Tom Rothamel 7def90322f Translate last error message in updater.
Adds to #534. Languages that use a different word order can use a
translaton like "Unknown type {1} while unpacking {0}."
2015-02-06 19:33:00 -05:00
Tom Rothamel 75c8861de9 Merge pull request #534 from javimat/master
Add translation function _() in Update 00updater.rpy error messages
2015-02-06 19:31:57 -05:00
Tom Rothamel 9b5de49aae Viewport takes xminimum, xmaximum.
Fixes #458.
2015-02-06 19:00:05 -05:00
Tom Rothamel 3e5197f909 doc: Document _return as part of input.
Fixes #506.
2015-02-05 21:18:57 -05:00
Tom Rothamel 152ba2d7e5 doc: Document nvl show and nvl hide.
fixes #510.
2015-02-05 21:14:36 -05:00
Tom Rothamel 1d4d093a88 lint: Allow side-only image attributes.
This prevents spurious lint warnings. Fixes #545.
2015-02-05 21:02:17 -05:00
Tom Rothamel 955e02ce26 add_from: Integrate with launcher.
Enabled by default, this should mitigate or fix the "could not find
return label" problem.

Fixes #530.
2015-02-04 21:01:03 -05:00
evilantishad0w b499d95390 add toggle to show/hide "Edit File" section
Many power users have no need for the edit shortcuts in the launcher,
and in projects with a large number of script files hitting "edit all
script files" by accident can be annoying
2015-02-04 12:35:27 -07:00
Tom Rothamel df36d206d3 add_from: Implement the add_from command.
This should help long-term games manage changes to calls and return
sites.
2015-02-03 23:25:50 -05:00
Tom Rothamel 9af5e19054 add_from: Store the start and end of each logical line.
This makes editing the files possible, since we now know where we can
insert new clauses at the end of a statement.

As part of this commit, we change how we remove CR from the file,
so we can get unicode-byte accurate locations within the file.
2015-02-03 23:17:02 -05:00
Tom Rothamel 8492045273 Keep the Pass when introducing a From statement. 2015-02-03 19:08:48 -05:00
Tom Rothamel 49a3b15816 Never play voice during a with statement. 2015-02-02 21:32:11 -05:00
Tom Rothamel f015bb7b81 Mouseareas should not activate during a focus grab. 2015-02-02 19:00:33 -05:00
Tom Rothamel 44aa9c6fc8 replay: True/False locked was inverted.
Fixes #356.
2015-02-01 23:11:59 -05:00
Tom Rothamel d4eebdff49 Only load textures that are predicted or used.
Fixes #532.
2015-02-01 09:48:37 -05:00
Tom Rothamel f42572c1f8 Avoid double-copy of surfaces in sw renderer.
This also makes the load_texture semantics the same as those on the
GL side.
2015-02-01 09:47:53 -05:00
Tom Rothamel 356c6e346a Insert a Return at the end of each file.
Fixes #490.
2015-02-01 08:59:01 -05:00
Tom Rothamel 22eb62afff Add a precheck pass to lint.
This lets us try to resolve forward references. For now, this is
limited to tags used in image statemets that are used in hide
blocks.

Fixes #505.
2015-01-31 23:17:01 -05:00
Tom Rothamel 7d17c87ed0 Use shutil.copyfile with saves.
Fixes #543.
2015-01-31 21:46:51 -05:00
Tom Rothamel 7c8e93a046 Add set manipulation actions.
AddToSet, RemoveFromSet, and ToggleSetMembership allow one to
manipulate sets and lists-as-sets.
2015-01-30 20:21:51 -05:00
Tom Rothamel 86d250079b data: Fix equality for the names of screen variables. 2015-01-30 17:14:33 -05:00
Tom Rothamel b2cb51a61b transform: Function is called at the start of each interaction.
Fixes #523.
2015-01-29 21:27:54 -05:00
Tom Rothamel 4cfe681d00 transform: Properly proxy transform_anchor
Fixes #522.
2015-01-29 21:24:46 -05:00
Tom Rothamel c670a25f8b android: Fsencode strings passed to popen.
Fixes #526.
2015-01-29 20:06:40 -05:00
Tom Rothamel db5ee1e91f Merge pull request #539 from Nolanlemahn/master
Update copyright notices and scripts for 2015
2015-01-28 17:40:40 -05:00
Nolanlemahn ca1f1f1032 Update the copyright notices in the file headers for 2015. 2015-01-28 11:22:22 -08:00
Nolanlemahn 32800f1c48 Update copyright scripts for 2015 2015-01-28 11:21:31 -08:00
Tom Rothamel 66544cd4b2 text: Document custom text tags
Fixes #513.
2015-01-26 23:51:05 -05:00
Tom Rothamel 94df2f93b7 text: Add custom text tags to lint. 2015-01-26 22:30:20 -05:00
Tom Rothamel 4c1269c62e text: Add improved custom text tags.
These new text tags process the token list, which makes it possible
to change tags and text to other things. (For example, we are now
able to make a rot13 text tag.)
2015-01-26 22:15:18 -05:00
Tom Rothamel a94989eb06 Add high-level achievements API. 2015-01-25 22:36:24 -05:00
Tom Rothamel 0cc2df8800 steam: User account functions. 2015-01-25 18:27:40 -05:00
kyouryuukunn d62f28d849 Merge pull request #536 from kyouryuukunn/update_japanese_template
Update japanese template
2015-01-25 10:56:17 +09:00
kyouryuukunn 31de055d6f update japanese translation 2015-01-25 10:53:11 +09:00
Tom Rothamel a3daed1409 steam: Add indicate_achievement_progress. 2015-01-24 20:47:24 -05:00
Tom Rothamel d7ccd581ae steam: add INT stats. 2015-01-24 20:38:28 -05:00
kyouryuukunn f559367d6a update japanese 2015-01-25 10:21:12 +09:00
Tom Rothamel 064d24e838 steam: Default the notification popup to the top-right. 2015-01-24 20:17:31 -05:00
Tom Rothamel ec894fc458 steam: Bind more overlay functions. 2015-01-24 20:06:55 -05:00
Tom Rothamel 845f802a59 steam: Bind apps and overlay. 2015-01-24 19:41:54 -05:00
Tom Rothamel 6680a16db6 Fix typo in field name. 2015-01-24 15:38:08 -05:00
Tom Rothamel d838a3d07a steam: Support floating-point stats. 2015-01-23 22:22:27 -05:00
Tom Rothamel 1e35f405fb steam: Production quality init/achievements. 2015-01-23 21:52:35 -05:00
Tom Rothamel 9900bf6ecc steam: Generic approach to Steam callbacks.
And when we say generic, we mean it. This uses a C++ template that
can bind C functions to Steam callbacks.
2015-01-23 21:51:50 -05:00
Tom Rothamel ab36e3d59a Add support for registering a list of periodic callbacks.
For example, steam uses this to run its callbacks.
2015-01-23 21:50:26 -05:00
Tom Rothamel d370760071 Code to demonstrate binding a Steam callback. 2015-01-22 21:12:35 -05:00
Tom Rothamel 0310e60b1c Add _renpysteam module.
For now, this just initializes steam, to prove the linking is correct.
2015-01-21 22:23:28 -05:00
Tom Rothamel 54614e2b83 steam: Add support for building c++ extensions. 2015-01-21 22:20:01 -05:00
Tom Rothamel 92032f123b iap: Update Android support. 2015-01-21 22:15:25 -05:00
Tom Rothamel f799dfcb31 Doc fix. 2015-01-18 23:20:07 -05:00
Tom Rothamel 99698fdd06 iap: Add the ability to query the price from the server. 2015-01-18 23:19:48 -05:00
Tom Rothamel 4bf0b7ca67 iap: iOS: Purchase, restore purchases, and defer purchases. 2015-01-18 20:51:56 -05:00
javimat 685fd09a75 Update 00updater.rpy
Add the translation function _() to `raise UpdateError` strings because they are showed to the end user.

Don't know how this can be done in line 1030: `raise UpdateError("While unpacking {}, unknown type {}.".format(info.name, info.type))`
2015-01-17 12:02:28 +01:00
Tom Rothamel 75825e7c2c iap: Set and validate product identifiers. 2015-01-17 05:05:25 -05:00
Tom Rothamel 052ec96f54 iap: Start work on iOS. 2015-01-16 23:17:37 -05:00
Tom Rothamel a4ab8fa083 Control log-to-stdout via a config variable. 2015-01-16 23:17:11 -05:00
Tom Rothamel 75e5a29470 Do not error out if a slot doesn't exist.
Fixes #493.
2015-01-14 17:32:00 -05:00
Tom Rothamel 04db67cad7 Do not pass parent's style prefix to Bar or Drag.
Fixes #500.
2015-01-14 17:27:15 -05:00
Tom Rothamel 0550a85716 When an error occurs while loading an image, report the image. 2015-01-13 08:56:19 -05:00
Tom Rothamel 91d5f6cc21 Add context manager that changes exception_info. 2015-01-13 08:55:59 -05:00
Tom Rothamel 82433d3dc0 Add ios presplash to build, allow Android to use .png. 2015-01-12 21:44:04 -05:00
Tom Rothamel 663cac933f Deal with audio with an initial PTS.
We were ignoring an initial PTS on the video track, but not the
audio. This could cause the two tracks to go out of sync.
2015-01-12 21:43:28 -05:00
Tom Rothamel 520ff08595 Prevent segfault when audio stream is unknown.
More accurately, prevent a segfault from occuring when we know
that an audio stream exists, but we are unable to create the
codec for it.
2015-01-11 10:54:53 -05:00
Tom Rothamel 95e12cab07 tts: Add clipboard voicing. 2015-01-10 21:29:21 -05:00
Tom Rothamel 52093520fd Do not pop open the text editor on Android configuration fail. 2015-01-10 11:59:47 -05:00
Tom Rothamel f92e459801 Remove debug print. 2015-01-10 00:22:14 -05:00
Tom Rothamel b8d08dda5a gesture: Implement support for gestures on touchscreen devices. 2015-01-09 23:05:58 -05:00
Tom Rothamel f8453fc4fd Optionally, log gl function names before each call.
This makes it possible to debug crashes in GL code.
2015-01-08 22:37:53 -05:00
Tom Rothamel c5c3a57f9d Log to stdout on mobile platforms.
The various mobile platfors redirect stdout to places that are more
visible than the filesystem.
2015-01-08 22:37:21 -05:00
Tom Rothamel 83245c7432 Parameterize children of Sprites.
This ensures that Transforms used as children of Sprites maintain
their own state (or more precisely, all Transforms added in a
single frame will have a state different than Transforms from
other frames).

Fixes #529.
2015-01-07 21:45:07 -05:00
Tom Rothamel 5715bdec00 Return False when checking if unknown items have been purchased. 2015-01-07 18:09:06 -05:00
Tom Rothamel c57253cfce Fix divide-by-zero.
Fixes #521.
2015-01-07 18:07:59 -05:00
Tom Rothamel 85fa790711 Add _progress screen.
Accessed by shift+alt+P, this easter egg of a screen show how much
of the game has been played through.
2015-01-05 21:41:46 -05:00
Tom Rothamel c379dd6bc3 Drags now support focus_mask. 2015-01-05 21:41:18 -05:00
Tom Rothamel e42d04ad9e Always use a max-size window on iOS and Android.
Letting the system choose means we can't be caught by unfortunate
rotations.
2015-01-05 20:40:00 -05:00
Tom Rothamel f361f7d0ef Do not force a big window on the desktop.
Some mobile code was leaking over to the desktop side.
2015-01-04 11:52:44 -05:00
Tom Rothamel 69bd85f98f Update docs. 2015-01-03 18:18:31 -05:00
Tom Rothamel b4cee2db25 Automatically maintain the text input state and text rectangle. 2015-01-03 18:07:14 -05:00
Tom Rothamel b16e7ebf8e Compat for renpy.styleclass.
Fixes #518.
2015-01-02 21:59:41 -05:00
Tom Rothamel 4f9dcd4fdc Stroke both font borders when creating outlines.
Previously we only stroked the outside border. This caused problems
when a portion of the character had an interior border on the
outside.

For example, we encountered a ? character where the top
part was outside and the bottom part was inside - it seems to
have something to do with the clockwise/counterclockwise order
of the font's control points.
2015-01-02 21:38:11 -05:00
Tom Rothamel 3dc33d4238 Add support for IME-based text editing to Input. 2015-01-02 21:06:29 -05:00
Tom Rothamel aa16b64225 Add support for n-thickness underlines to {u}. 2015-01-02 20:27:34 -05:00
Tom Rothamel f93d3b9fc9 Fix parsing of word-like operators in simple_expressions. 2015-01-02 20:12:38 -05:00
Tom Rothamel 250103bf4e Deal with empty unicode events. 2015-01-01 14:01:30 -05:00
Tom Rothamel bc6767bdf4 Ignore key events when an IME is in use. 2015-01-01 14:00:56 -05:00
Tom Rothamel 15a6b39a40 Add support for double-underline.
This isn't user-exposed, it's just for IME use.
2015-01-01 14:00:08 -05:00
Tom Rothamel 83352e3e29 Input uses TEXTINPUT events, if possible. 2015-01-01 00:20:00 -05:00
Tom Rothamel c8c52477c9 When on mac, allow the user to try to launch Xcode. 2014-12-31 20:41:47 -05:00
Tom Rothamel 042ae30b62 Sanitize Xcode identifiers. 2014-12-31 20:29:28 -05:00
Tom Rothamel b9f3bbe950 Distribute Ren'Py files into ios apps. 2014-12-31 00:40:51 -05:00
Tom Rothamel 2fd1416ce4 Interface for Xcode project creation. 2014-12-30 23:43:54 -05:00
Tom Rothamel 722c99ed04 Select/Open Xcode projects directory. 2014-12-29 23:16:33 -05:00
Tom Rothamel b59c94ad7f Factor the directory chooser into its own function. 2014-12-29 22:51:43 -05:00
Tom Rothamel 547a504f7b Add iOS launcher UI. 2014-12-28 22:35:04 -05:00
Tom Rothamel 51a168c12f Add the ability to emulate iOS devices. 2014-12-28 22:34:43 -05:00
Tom Rothamel 3573a42ef7 Factor mobile build stuff common to android/ios into own file. 2014-12-28 18:33:24 -05:00
Tom Rothamel 23d69c7c8e android: Add the ability to launch after the build. 2014-12-27 21:15:31 -05:00
Tom Rothamel 77e44a5ab5 Use pysdlsound on all platforms, including Android. 2014-12-26 23:37:45 -05:00
Tom Rothamel b892ca4791 Merge pull request #517 from evilantishad0w/master
added "suspend_rollback()" functionality
2014-12-26 18:13:16 -05:00
evilantishad0w 4775d4f082 removed extraneous line
^^;;
2014-12-26 14:11:49 -07:00
Tom Rothamel 2148a68df8 Remove legacy SDL_VIDEODRIVER setting.
Fixes a problem when upgrading Ren'Py from 6.18.
2014-12-26 16:06:28 -05:00
evilantishad0w 52a8fd1b63 changed to suspend_rollback(), fixes 2014-12-26 13:20:47 -07:00
evilantishad0w 422db61d71 add renpy.rollback_skip()
Add functionality to skip a block of code in rollback, used to prevent
rollback during a minigame or other similar event
2014-12-26 12:46:31 -07:00
Tom Rothamel 749462beec Make hardware video optional. 2014-12-25 16:29:59 -05:00
Tom Rothamel 8726c6d50b Select device variants on iOS. 2014-12-24 15:10:36 -05:00
Tom Rothamel 6ae531e893 Protect against crashes due to no player existing. 2014-12-24 15:06:10 -05:00
Tom Rothamel dc117ffbe1 Remove a debug print. 2014-12-23 23:24:55 -05:00
Tom Rothamel 40e3eaaf64 Add an iOS video player. 2014-12-23 23:09:37 -05:00
Tom Rothamel 72e4607e82 Factor the android video player out into its own class. 2014-12-23 23:09:15 -05:00
Tom Rothamel cfdaa95bea Pause native and android audio and video on suspend. 2014-12-22 21:52:56 -05:00
Tom Rothamel 2be0638602 Fix build on iOS. 2014-12-22 21:52:47 -05:00
Tom Rothamel 6ec5a0c122 Support resize on mobile platforms. 2014-12-18 21:28:26 -05:00
Tom Rothamel fd1902ecd2 Package renios. 2014-12-17 23:03:09 -05:00
Tom Rothamel ec77844b1a Bump version. 2014-12-17 23:02:57 -05:00
Tom Rothamel 8c238ae4ff Optionally accept the path to pygame_sdl2 to use for the build. 2014-12-16 23:13:42 -05:00
Tom Rothamel 4c909922d4 Properly make prefixed_all_properties public. 2014-12-16 22:21:46 -05:00
Tom Rothamel 8358539667 Make new modules findable by modulefinder. 2014-12-15 23:37:07 -05:00
Tom Rothamel 5c87617652 Replace some android tests with mobile device tests. 2014-12-14 22:16:17 -05:00
Tom Rothamel a102a7dca9 Use fbo to render-to-texture on iOS.
This also includes changing rtt_fbo to retrieve the default
framebuffer, rather than using fbo 0 (as documented by GL).
2014-12-14 22:02:13 -05:00
Tom Rothamel a2e8758965 On iOS, log to stdout.
So xcode gets it, rather than it becoming unaccessable.
2014-12-14 21:57:22 -05:00
Tom Rothamel 5914e9317c Find the iOS save directory. 2014-12-14 18:29:17 -05:00
Tom Rothamel 094dbe7386 Fixes to support GL on iOS. 2014-12-13 23:50:11 -05:00
Tom Rothamel 84debf31c7 Remove recursive imports in the style code. 2014-12-13 23:49:41 -05:00
Tom Rothamel 5afacd4dec The enum is not defined in GLES2. 2014-12-13 23:48:45 -05:00
Tom Rothamel 4221eb049f Move android detect to renpy module, add renpy.mobile.
The latter is a flag that determines if we're on android or ios,
inclusive. (These platforms tend to behave similarly, and different
from the desktop platforms.)
2014-12-13 23:45:14 -05:00
Tom Rothamel 4971ff139f Fix renpy.style.StyleCore.__setattr__.
It was using the wrong variable name.
2014-12-12 00:18:10 -05:00
Tom Rothamel e5a50b4b4d Remove renpy.styleclass entirely.
Its functionality has been split over the many renpy.styledata modules.
2014-12-12 00:17:31 -05:00
Tom Rothamel 5222a47b9d Break stylepropertyfunctions.pxi up into ten pyx files.
The hope is this will allow faster independent compilation.
2014-12-11 23:51:25 -05:00
Tom Rothamel 98afd6402c Only generate python properties for unprefixed style properties.
To reduce the size of the compiled library, we replace the use of
python properties for prefixed style properties with the __setattr__
and __delattr__ methods.

This shouldn't have much performance impact, as sets of style
properties should only occur in init code.
2014-12-10 23:13:21 -05:00
Tom Rothamel 24fdc18a47 Start breaking styleclass.pyx up into renpy.styledata.
This should eventually make compilation faster.
2014-12-10 21:46:58 -05:00
Tom Rothamel e5632b27b2 Changes to make build on iOS. 2014-12-09 19:24:40 -05:00
Tom Rothamel 14db5d588f Add support for android on pygame_sdl2. 2014-12-09 19:24:18 -05:00
Tom Rothamel dbb990c0f7 Merge pull request #504 from tlm-2501/patch-1
Merge "Update language_basics.rst" from tlm-2501/patch-1
2014-12-01 21:07:18 -05:00
Tom Rothamel a34bed7e11 Implement android/iOS lifecycle. 2014-11-30 22:22:54 -05:00
Tom Rothamel 7c61befcb0 import pygame_sdl2 as pygame, instead of import pygame.
This is intended to make autocomplete use pygame_sdl2 when
legacy names exist.
2014-11-30 19:29:57 -05:00
Tom Rothamel 9381c7399b Do not run desktop-only code when playing android video. 2014-11-30 17:15:13 -05:00
tlm-2501 439365977f Update language_basics.rst
Fixed escape sequences -- backslashes weren't escaped, as a result they were not visible.
2014-11-30 01:38:41 +03:00
Tom Rothamel 5b3a7bf02e Import _android_sound. 2014-11-29 11:41:43 -05:00
Tom Rothamel 1be45fb2d4 Android keybindings. 2014-11-29 11:40:28 -05:00
Tom Rothamel a327517cf8 Link against png16. 2014-11-29 11:38:47 -05:00
Tom Rothamel f9204ad5a0 Set GL_ALPHA_SIZE to 8 on all GL platforms (incl. Android). 2014-11-29 01:48:23 -05:00
Tom Rothamel 5b5a7ab907 Fix a a problem where we free an unallocated object. 2014-11-28 23:18:44 -05:00
Tom Rothamel 634bb3ad64 Use the new approach to get the activity. 2014-11-28 22:18:26 -05:00
Tom Rothamel 329d8d3ee1 Move gl1 functions into their own file.
Now that we're wrapping the GL functions, all the functions in gl.pyx
have to exist. The gl1 functions are missing on GLES2 systems, which
means they can't exist in a file we use there. Hence breaking things
up into two files.
2014-11-28 21:59:04 -05:00
tlm 24c7e845c3 Added a Russian translation for the tutorial game 2014-11-26 20:39:04 +03:00
Tom Rothamel 3f01f49da3 Link android against SDL2. 2014-11-23 22:28:37 -05:00
Tom Rothamel 6d7c28560c gl: Error checks controlled by RENPY_GL_CHECK_ERRORS. 2014-11-19 22:38:13 -05:00
Lapalissiano 23931a5676 Ignored virtualenv 'env' folder 2014-11-20 04:07:54 +01:00
Giuseppe Bertone b4dd9f6878 Fixed tab; 2014-11-20 03:20:10 +01:00
Giuseppe Bertone 2903b81360 Empty strings are now optional while exporting strings for translation, and you can use a specific option in the preference panel to activate this behavior (default is false); 2014-11-20 03:17:52 +01:00
Tom Rothamel 942cf82354 gl: Add function name to gl error messages. 2014-11-18 22:21:54 -05:00
Tom Rothamel 4dcdd1ad65 gl: Check for errors after every call. 2014-11-17 23:31:04 -05:00
Tom Rothamel a2a3c284a3 Initialize angle under pygame_sdl2. 2014-11-16 00:25:10 -05:00
Tom Rothamel 4497d5e30f Use the single-file pygame_sdl2 C api. 2014-11-16 00:24:46 -05:00
Tom Rothamel 9c5e037db6 Merge branch 'master' into sdl2 2014-11-15 23:10:15 -05:00
Tom Rothamel 2b6c7941d6 Do not predict labels that do not exist.
Fixes #491.
2014-11-14 19:52:13 -05:00
Tom Rothamel 4e11d77258 We no longer need to force windib. (Which no longer exists.) 2014-11-12 21:48:31 -05:00
Tom Rothamel 9791e379e3 Build w/ SDL2 on Windows.
For now, ANGLE is disabled. At some point, we'll try to use SDL to
initialize it.
2014-11-11 09:59:01 -05:00
Tom Rothamel b59dc7906c Only copy ANGLE files if they're out of date. 2014-11-11 00:08:00 -05:00
Tom Rothamel 253726c433 Merge branch 'master' into sdl2 2014-11-07 22:22:34 -05:00
Tom Rothamel 06e3a75515 Add \[ as a way of escaping [.
This just replaces \[ with [[, which continues to work.

Fixes #489.
2014-11-07 22:21:21 -05:00
Tom Rothamel 2925e1e64f nogil_copy should copy without using the alpha channel. 2014-11-07 22:15:02 -05:00
Tom Rothamel ead574ae6b Report a traceback when pysdlsound fails to import. 2014-11-06 23:02:37 -05:00
Tom Rothamel 1f4d4cd974 Zero out the audio buffer before mixing samples into it.
This is necessary for SDL 2.
2014-11-06 20:49:05 -05:00
Tom Rothamel 2deaf3689a RWOpsFromPythonThreaded -> RWOpsFromPython
In pygame_sdl2, rwops is always threadsafe.
2014-11-05 23:59:39 -05:00
292 changed files with 16289 additions and 3067 deletions
+1
View File
@@ -10,6 +10,7 @@
saves
tmp
cache
env
log.txt
/errors.txt
+24 -18
View File
@@ -34,22 +34,34 @@ else:
tag = False
def check_dirty():
if args.no_tag:
return
SOURCE = [
"/home/tom/ab/renpy",
"/home/tom/ab/android/",
"/home/tom/ab/android/python-for-android",
"/home/tom/ab/ripe/renios",
"/home/tom/ab/renpy-deps",
"/home/tom/ab/pygame_sdl2",
]
if subprocess.check_call([ "git", "diff", "--quiet", "HEAD" ]):
print "Directory not checked in: {}".format(os.getcwd())
sys.exit(1)
if tag:
for i in SOURCE:
os.chdir(i)
os.chdir("/home/tom/ab/renpy")
check_dirty()
if subprocess.call([ "git", "diff", "--quiet", "HEAD" ]):
print "Directory not checked in: {}".format(os.getcwd())
sys.exit(1)
os.chdir("/home/tom/ab/renpy/android")
check_dirty()
for i in SOURCE:
os.chdir(i)
if i == SOURCE[0]:
tag = version
else:
tag = "renpy-" + version
subprocess.check_call([ "git", "tag", "-a", tag, "-m", "Tagging Ren'Py + " + version + " release." ])
if not args.no_tag:
subprocess.check_call([ "git", "tag", "-a", "rapt-" + version, "-m", "Tagging RAPT release." ])
os.chdir("/home/tom/ab/renpy/dl")
@@ -58,11 +70,5 @@ for i in links:
os.unlink(i)
os.symlink(short_version, i)
os.chdir("/home/tom/ab/renpy")
if tag and not args.no_tag:
cmd = [ "git", "tag", "-a", version, "-m", "Ren'Py " + version ]
subprocess.check_call(cmd)
os.chdir("/home/tom/ab/website")
subprocess.check_call("./upload.sh")
+1 -1
View File
@@ -1,2 +1,2 @@
lib\windows-i686\python.exe -OO renpy.py
lib\windows-i686\python.exe -OO renpy.py tutorial
pause
+9 -2
View File
@@ -45,6 +45,7 @@ def main():
ap = argparse.ArgumentParser()
ap.add_argument("version")
ap.add_argument("--fast", action="store_true")
ap.add_argument("--pygame", action="store", default=None)
args = ap.parse_args()
@@ -123,11 +124,17 @@ def main():
android = os.path.abspath("android")
rapt_build = subprocess.Popen([
rapt_cmd = [
os.path.join(android, "build_renpy.sh"),
"renpy",
ROOT,
],
]
if args.pygame:
rapt_cmd.append(args.pygame)
rapt_build = subprocess.Popen(
rapt_cmd,
cwd = android,
stdout=out,
stderr=out)
+134 -105
View File
@@ -2,131 +2,160 @@
<head>
<title>README</title>
<style>
BODY {
background: #fff;
color: #444;
padding-left: 20%;
padding-top: 1em;
padding-bottom: 1em;
padding-right: 20%;
font-family: sans-serif;
line-height: 1.6em;
background: #fff;
color: #444;
padding-left: 20%;
padding-top: 1em;
padding-bottom: 1em;
padding-right: 20%;
font-family: sans-serif;
line-height: 1.6em;
}
DT {
font-weight: bold;
margin-top: .33em;
font-weight: bold;
margin-top: .33em;
}
H2 {
color: #000;
margin-left: -2.5em;
color: #000;
margin-left: -2.5em;
}
H3 {
color: #000;
margin-left: -1.5em;
color: #000;
margin-left: -1.5em;
}
.editsection {
display: none;
display: none;
}
</style>
</head>
<body>
<div id="renpy_help"></div>
<h2>Basic Help</h2>
<p>
To advance through the game, <tt>left-click</tt> or press the <tt>space</tt>
or <tt>enter</tt> keys. When at a menu, <tt>left-click</tt> to make
a choice, or use the arrow keys to select a choice and <tt>enter</tt>
to activate it.
</p>
<h3>Game Menu</h3>
<p>
When playing a game, <tt>right-click</tt> or press the <tt>escape</tt>
key to enter the game menu. The game menu gives the following
choices:
</p>
<dl>
<dt>Return</dt>
<dd>Returns to the game.</dd>
<dt>Save Game</dt>
<dd>Allows you to save a game by clicking on a save slot.</dd>
<dt>Load Game</dt>
<dd>Allows you to load a game by clicking on a save slot.
Clicking on "Auto" accesses the automatic save slots.</dd>
<dt>Preferences</dt>
<dd>
Changes the game preferences (options/configuration):
<dl>
<dt>Display</dt>
<dd>Switches between fullscreen and windowed mode.</dd>
<dt>Transitions</dt>
<dd>Controls the display of transitions between game
screens.</dd>
<dt>Text Speed</dt>
<dd>Controls the rate at which text displays. The further
to the right this slider is, the faster the text will display.
All the way to the right causes text to be shown instantly.</dd>
<dt>Joystick</dt>
<dd>Lets you control the game using a joystick.</dd>
<dt>Skip</dt>
<dd>Chooses between skipping messages that have been
already seen (in any play through the game), and skipping all
messages.</dd>
<dt>Begin Skipping</dt>
<dd>Returns to the game, while skipping.</dd>
<dt>After Choices</dt>
<dd>Controls if skipping stops upon reaching a menu.</dd>
<dt>Auto-Forward Time</dt>
<dd>Controls automatic advance. The further to the left
this slider is, the shorter the amount of time before the game
advances. All the way to the right means text will never
auto-forward.</dd>
<dt>Music, Sound, and Voice Volume</dt>
<dd>Controls the volume of the Music, Sound effect, and
Voice channels, respectively. The further to the right these
are, the louder the volume.</dd>
</dl>
</dd>
</dl>
<dl>
<dt>Main Menu</dt>
<dd>Returns to the main menu, ending the current game.</dd>
<dt>Help</dt>
<dd>Shows this help screen.</dd>
<dt>Quit</dt>
<dd>Exits the game; the game will be closed and ended.</dd>
</dl>
<h3>Key and Mouse Bindings</h3>
<dl>
<dt>Left-click, Enter</dt>
<dd>Advances through the game, activates menu choices, buttons,
and sliders.</dd>
<dt>Space</dt>
<dd>Advances through the game, but does not activate choices.</dd>
<dt>Arrow Keys</dt>
<dd>Selects menu choices, buttons, and sliders.</dd>
<dt>Ctrl</dt>
<dd>Causes skipping to occur while the ctrl key is held down.</dd>
<dt>Tab</dt>
<dd>Toggles skipping, causing it to occur until tab is pressed
again.</dd>
<dt>Mousewheel-Up, PageUp</dt>
<dd>Causes rollback to occur. Rollback reverses the game back
in time, showing prior text and even allowing menu choices to be
changed.</dd>
<dt>Mousewheel-Down, PageDown</dt>
<dd>Causes rollforward to occur, canceling out a previous
rollback.</dd>
<dt>Right-click, Escape</dt>
<dd>Enters the game menu. When in the game menu, returns to the
game.</dd>
<dt>Middle-click, H</dt>
<dd>Hides the text window and other transient displays.</dd>
<dt>F</dt>
<dd>Toggles fullscreen mode</dd>
<dt>S</dt>
<dd>Takes a screenshot, saving it in a file named
screenshotxxxx.png, where xxxx is a serial number.</dd>
<dt>Alt-M, Command-H</dt>
<dd>Hides (iconifies) the window.</dd>
<dt>Alt-F4, Command-Q</dt>
<dd>Quits the game.</dd>
<dt>Delete</dt>
<dd>When a save slot is selected, deletes that save slot.</dd>
<dt>v</dt>
<dd>
Toggles self-voicing mode, which reads text to the user using an
os-supplied speech synthesizer. For more information, please read
the <a href="http://www.renpy.org/doc/html/self_voicing.html">self-voicing</a>
documentation.
</dd>
<dt>Shift+C</dt>
<dd>Toggles clipboard-voicing mode, which copies text to the
clipboard so it can be read by a screen reader.</dd>
</dl>
<p><a name="Basic_Help" id="Basic_Help"></a></p>
<h2><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=1" title="Edit section: Basic Help">edit</a>]</span> <span class="mw-headline">Basic Help</span></h2>
<p>To advance through the game, <tt>left-click</tt> or press the <tt>space</tt> or <tt>enter</tt> keys. When at a menu, <tt>left-click</tt> to make a choice, or use the arrow keys to select a choice and <tt>enter</tt> to activate it.</p>
<p><a name="Game_Menu" id="Game_Menu"></a></p>
<h3><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=2" title="Edit section: Game Menu">edit</a>]</span> <span class="mw-headline">Game Menu</span></h3>
<p>When playing a game, <tt>right-click</tt> or press the <tt>escape</tt> key to enter the game menu. The game menu gives the following choices:</p>
<dl>
<dt>Return</dt>
<dd>Returns to the game.</dd>
<dt>Save Game</dt>
<dd>Allows you to save a game by clicking on a save slot.</dd>
<dt>Load Game</dt>
<dd>Allows you to load a game by clicking on a save slot. Clicking on "Auto" accesses the automatic save slots.</dd>
<dt>Preferences</dt>
<dd>Changes the game preferences (options/configuration):
<dl>
<dt>Display</dt>
<dd>Switches between fullscreen and windowed mode.</dd>
<dt>Transitions</dt>
<dd>Controls the display of transitions between game screens.</dd>
<dt>Text Speed</dt>
<dd>Controls the rate at which text displays. The further to the right this slider is, the faster the text will display. All the way to the right causes text to be shown instantly.</dd>
<dt>Joystick</dt>
<dd>Lets you control the game using a joystick.</dd>
<dt>Skip</dt>
<dd>Chooses between skipping messages that have been already seen (in any play through the game), and skipping all messages.</dd>
<dt>Begin Skipping</dt>
<dd>Returns to the game, while skipping.</dd>
<dt>After Choices</dt>
<dd>Controls if skipping stops upon reaching a menu.</dd>
<dt>Auto-Forward Time</dt>
<dd>Controls automatic advance. The further to the left this slider is, the shorter the amount of time before the game advances. All the way to the right means text will never auto-forward.</dd>
<dt>Music, Sound, and Voice Volume</dt>
<dd>Controls the volume of the Music, Sound effect, and Voice channels, respectively. The further to the right these are, the louder the volume.</dd>
</dl>
</dd>
</dl>
<dl>
<dt>Main Menu</dt>
<dd>Returns to the main menu, ending the current game.</dd>
<dt>Help</dt>
<dd>Shows this help screen.</dd>
<dt>Quit</dt>
<dd>Exits the game; the game will be closed and ended.</dd>
</dl>
<p><a name="Key_and_Mouse_Bindings" id="Key_and_Mouse_Bindings"></a></p>
<h3><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=3" title="Edit section: Key and Mouse Bindings">edit</a>]</span> <span class="mw-headline">Key and Mouse Bindings</span></h3>
<dl>
<dt>Left-click, Enter</dt>
<dd>Advances through the game, activates menu choices, buttons, and sliders.</dd>
<dt>Space</dt>
<dd>Advances through the game, but does not activate choices.</dd>
<dt>Arrow Keys</dt>
<dd>Selects menu choices, buttons, and sliders.</dd>
<dt>Ctrl</dt>
<dd>Causes skipping to occur while the ctrl key is held down.</dd>
<dt>Tab</dt>
<dd>Toggles skipping, causing it to occur until tab is pressed again.</dd>
<dt>Mousewheel-Up, PageUp</dt>
<dd>Causes rollback to occur. Rollback reverses the game back in time, showing prior text and even allowing menu choices to be changed.</dd>
<dt>Mousewheel-Down, PageDown</dt>
<dd>Causes rollforward to occur, cancelling out a previous rollback.</dd>
<dt>Right-click, Escape</dt>
<dd>Enters the game menu. When in the game menu, returns to the game.</dd>
<dt>Middle-click, H</dt>
<dd>Hides the text window and other transient displays.</dd>
<dt>F</dt>
<dd>Toggles fullscreen mode</dd>
<dt>S</dt>
<dd>Takes a screenshot, saving it in a file named screenshotxxxx.png, where xxxx is a serial number.</dd>
<dt>Alt-M, Command-H</dt>
<dd>Hides (iconifies) the window.</dd>
<dt>Alt-F4, Command-Q</dt>
<dd>Quits the game.</dd>
<dt>Delete</dt>
<dd>When a save slot is selected, deletes that save slot.</dd>
<dt>v</dt>
<dd>Toggles self-voicing mode, which reads text to the user using an os-supplied
speech synthesizer. For more information, please read the <a href="http://www.renpy.org/dev-doc/html/self_voicing.html">self-voicing</a>
documentation.</dd>
</dl>
<p><a name="Legal_Notice" id="Legal_Notice"></a></p>
<h2><span class="editsection">[<a href="/w/index.php?title=renpy/Help&amp;action=edit&amp;section=4" title="Edit section: Legal Notice">edit</a>]</span> <span class="mw-headline">Legal Notice</span></h2>
<p>This game uses source code from a number of open source projects. For a list, and a location where the source code can be downloaded from, please view the LICENSE.txt file in the renpy directory, or visit <a href="http://www.renpy.org/wiki/renpy/License" class="external free" title="http://www.renpy.org/wiki/renpy/License" rel="nofollow">http://www.renpy.org/wiki/renpy/License</a> .</p>
<h2>Legal Notice</h2>
<p>
This program contains free software licensed under a number of
licenses, including the GNU Lesser Public License. A complete list
of software is available at <a
href="http://www.renpy.org/doc/html/license.html"
>http://www.renpy.org/doc/html/license.html</a>.
</body>
</html>
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+27 -206
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -43,6 +43,7 @@ init python:
PLAY_KEYS_TEXT = _("Opens the file containing the Google Play keys in the editor.\n\nThis is only needed if the application is using an expansion APK. Read the documentation for more details.")
BUILD_TEXT = _("Builds the Android package.")
BUILD_AND_INSTALL_TEXT = _("Builds the Android package, and installs it on an Android device connected to your computer.")
BUILD_INSTALL_AND_LAUNCH_TEXT = _("Builds the Android package, installs it on an Android device connected to your computer, then launches the app on your device.")
CONNECT_TEXT = _("Connects to an Android device running ADB in TCP/IP mode.")
DISCONNECT_TEXT = _("Disconnects from an Android device running ADB in TCP/IP mode.")
@@ -66,7 +67,6 @@ init python:
sys.path.insert(0, os.path.join(RAPT_PATH, "buildlib"))
else:
RAPT_PATH = None
RAPT_PATH is None
find_rapt()
@@ -79,6 +79,8 @@ init python:
import rapt.install_sdk
import rapt.plat
import rapt.interface
rapt.plat.renpy = True
else:
rapt = None
@@ -131,184 +133,6 @@ init python:
else:
return None
class AndroidInterface(object):
def __init__(self):
self.process = None
self.filename = project.current.temp_filename("android.txt")
self.info_msg = ""
with open(self.filename, "w"):
pass
def log(self, msg):
with open(self.filename, "a") as f:
f.write("\n")
f.write(msg)
f.write("\n")
def info(self, prompt):
self.info_msg = prompt
interface.processing(prompt, pause=False)
self.log(prompt)
def yesno(self, prompt, submessage=None):
return interface.yesno(prompt, submessage=submessage)
def yesno_choice(self, prompt, default=None):
choices = [ (True, "Yes"), (False, "No") ]
return interface.choice(prompt, choices, default)
def terms(self, url, prompt):
submessage = _("{a=%s}%s{/a}") % (url, url)
if not interface.yesno(prompt, submessage=submessage):
self.fail("You must accept the terms and conditions to proceed.", edit=False)
def input(self, prompt, empty=None):
if empty is None:
empty = ''
while True:
rv = interface.input(_("QUESTION"), prompt, default=empty, cancel=Jump("android"))
rv = rv.strip()
if rv:
return rv
def choice(self, prompt, choices, default):
return interface.choice(prompt, choices, default, cancel=Jump("android"))
def fail(self, prompt, edit=True):
self.log(prompt)
prompt = re.sub(r'(http://\S+)', r'{a=\1}\1{/a}', prompt)
# Open android.txt in the editor.
if edit:
editor.EditAbsolute(self.filename)()
interface.error(prompt, label="android")
def success(self, prompt):
self.log(prompt)
interface.info(prompt, pause=False)
def final_success(self, prompt):
self.log(prompt)
interface.info(prompt, label="android")
def run_yes_thread(self):
import time
try:
while self.run_yes:
self.process.stdin.write('y\n')
self.process.stdin.flush()
time.sleep(.2)
except:
import traceback
traceback.print_exc()
def call(self, cmd, cancel=False, use_path=False, yes=False):
print
print " ".join(cmd)
self.cmd = cmd
f = open(self.filename, "a")
f.write("\n\n\n")
if cancel:
cancel_action = self.cancel
else:
cancel_action = None
startupinfo = None
if renpy.windows:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
self.yes_thread = None
try:
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action)
kwargs = { }
if yes:
kwargs["stdin"] = subprocess.PIPE
try:
self.process = subprocess.Popen(cmd, cwd=RAPT_PATH, stdout=f, stderr=f, startupinfo=startupinfo, **kwargs)
except:
import traceback
traceback.print_exc(file=f)
raise
if yes:
import threading
self.run_yes = True
self.yes_thread = threading.Thread(target=self.run_yes_thread)
self.yes_thread.daemon = True
self.yes_thread.start()
renpy.call_screen("android_process", interface=self)
finally:
f.close()
interface.hide_screen()
if yes and self.yes_thread:
self.run_yes = False
self.yes_thread.join()
self.process = None
self.yes_thread = None
def check_process(self):
rv = self.process.poll()
if rv is not None:
if rv:
raise subprocess.CalledProcessError(rv, self.cmd)
else:
return True
def download(self, url, dest):
try:
d = Downloader(url, dest)
cancel_action = [ d.cancel, Jump("android") ]
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action, bar_value=DownloaderValue(d))
ui.timer(.1, action=d.check, repeat=True)
ui.interact()
finally:
interface.hide_screen()
def background(self, f):
try:
t = threading.Thread(target=f)
t.start()
interface.processing(self.info_msg, show_screen=True)
while t.is_alive():
renpy.pause(0)
t.join(0.25)
finally:
interface.hide_screen()
def cancel(self):
if self.process:
self.process.terminate()
renpy.jump("android")
class AndroidBuild(Action):
"""
@@ -321,22 +145,6 @@ init python:
def __call__(self):
renpy.jump(self.label)
class LaunchEmulator(Action):
def __init__(self, emulator, variants):
self.emulator = emulator
self.variants = variants
def __call__(self):
env = {
"RENPY_EMULATOR" : self.emulator,
"RENPY_VARIANT" : self.variants,
}
p = project.current
p.launch(env=env)
def update_android_json(p, gui):
"""
Updates .android.json to include the google play information.
@@ -372,7 +180,7 @@ init python:
with open(filename, "w") as f:
json.dump(android_json, f)
def android_build(command, p=None, gui=True):
def android_build(command, p=None, gui=True, launch=False):
"""
This actually builds the package.
"""
@@ -389,7 +197,7 @@ init python:
if gui:
reporter = distribute.GuiReporter()
rapt_interface = AndroidInterface()
rapt_interface = MobileInterface("android")
else:
reporter = distribute.TextReporter()
rapt_interface = rapt.interface.Interface()
@@ -404,7 +212,7 @@ init python:
)
with interface.nolinks():
rapt.build.build(rapt_interface, dist, command)
rapt.build.build(rapt_interface, dist, command, launch=launch)
# The android support can stick unicode into os.environ. Fix that.
init 100 python:
@@ -468,7 +276,8 @@ screen android:
frame style "l_indent":
has vbox
has hbox:
spacing 15
textbutton _("Phone"):
action LaunchEmulator("touch", "small phone touch android")
@@ -478,7 +287,7 @@ screen android:
action LaunchEmulator("touch", "medium tablet touch android")
hovered tt.Action(TABLET_TEXT)
textbutton _("Television / OUYA"):
textbutton _("Television"):
action LaunchEmulator("tv", "small tv ouya android")
hovered tt.Action(OUYA_TEXT)
@@ -514,6 +323,10 @@ screen android:
action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build_and_install"))
hovered tt.Action(BUILD_AND_INSTALL_TEXT)
textbutton _("Build, Install & Launch"):
action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build_install_and_launch"))
hovered tt.Action(BUILD_INSTALL_AND_LAUNCH_TEXT)
add SPACER
add SEPARATOR2
@@ -576,7 +389,7 @@ label android_installsdk:
python:
with interface.nolinks():
rapt.install_sdk.install_sdk(AndroidInterface())
rapt.install_sdk.install_sdk(MobileInterface("android"))
jump android
@@ -584,7 +397,7 @@ label android_installsdk:
label android_configure:
python:
rapt.configure.configure(AndroidInterface(), project.current.path)
rapt.configure.configure(MobileInterface("android", edit=False), project.current.path)
jump android
@@ -602,6 +415,13 @@ label android_build_and_install:
jump android
label android_build_install_and_launch:
$ android_build([ 'release', 'install' ], launch=True)
jump android
label android_connect:
python hide:
@@ -641,7 +461,7 @@ label android_connect:
persistent.connect_address = address
rapt_interface = AndroidInterface()
rapt_interface = MobileInterface("android")
rapt.build.connect(rapt_interface, address)
jump android
@@ -650,7 +470,7 @@ label android_disconnect:
python hide:
rapt_interface = AndroidInterface()
rapt_interface = MobileInterface("android")
rapt.build.disconnect(rapt_interface)
jump android
@@ -661,12 +481,13 @@ init python:
ap = renpy.arguments.ArgumentParser()
ap.add_argument("project", help="The path to the project directory.")
ap.add_argument("command", help="Commands to pass to ant. (Try 'release' 'install'.)", nargs='+')
ap.add_argument("--launch", action="store_true", help="Launches the app after build and install compete.")
args = ap.parse_args()
p = project.Project(args.project)
android_build(args.command, p=p, gui=False)
android_build(args.command, p=p, gui=False, launch=args.launch)
return False
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+93
View File
@@ -0,0 +1,93 @@
# Copyright 2004-2015 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.
init python:
def choose_directory(path):
"""
Pops up a directory chooser.
`path`
The directory that is selected by default. If None, config.renpy_base
is selected.
Returns a (path, is_default) tuple, where path is the chosen directory,
and is_default is true if and only if it was chosen by default mechanism
rather than user choice.
"""
if path:
default_path = path
else:
try:
default_path = os.path.dirname(os.path.abspath(config.renpy_base))
except:
default_path = os.path.abspath(config.renpy_base)
if EasyDialogs:
choice = EasyDialogs.AskFolder(defaultLocation=default_path, wanted=unicode)
if choice is not None:
path = choice
else:
path = None
else:
try:
cmd = [ "/usr/bin/python", os.path.join(config.gamedir, "tkaskdir.py"), renpy.fsencode(default_path) ]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
choice = p.stdout.read()
code = p.wait()
except:
import traceback
traceback.print_exc()
code = 0
choice = ""
path = None
interface.error(_("Ren'Py was unable to run python with tkinter to choose the directory. Please install the python-tk or tkinter package."), label=None)
if code:
interface.error(_("Ren'Py was unable to run python with tkinter to choose the directory. Please install the python-tk or tkinter package."), label=None)
elif choice:
path = choice.decode("utf-8")
is_default = False
if path is None:
path = default_path
is_default = True
path = renpy.fsdecode(path)
if not os.path.isdir(path):
path = os.path.abspath(config.renpy_base)
is_default = True
return path, is_default
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+28 -12
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -399,13 +399,13 @@ init python in distribute:
# Add Python (with the same name as our executables)
self.add_python()
# Build the mac app.
# Build the mac app and windows exes.
self.add_mac_files()
self.add_windows_files()
# Add generated/special files.
if not build['renpy']:
self.add_renpy_files()
self.add_windows_files()
# Assign the x-bit as necessary.
self.mark_executable()
@@ -630,6 +630,9 @@ init python in distribute:
],
)
if self.build.get('allow_integrated_gpu', False):
plist["NSSupportsAutomaticGraphicsSwitching"] = True
rv = self.temp_filename("Info.plist")
plistlib.writePlist(plist, rv)
return rv
@@ -663,10 +666,10 @@ init python in distribute:
os.path.join(config.renpy_base, "lib/darwin-x86_64/pythonw"),
True)
self.add_file(
windows,
"lib/windows-i686/" + self.executable_name + ".exe",
os.path.join(config.renpy_base, "lib/windows-i686/pythonw.exe"))
# self.add_file(
# windows,
# "lib/windows-i686/" + self.executable_name + ".exe",
# os.path.join(config.renpy_base, "lib/windows-i686/renpy.exe"))
def add_mac_files(self):
"""
@@ -700,19 +703,31 @@ init python in distribute:
Adds windows-specific files.
"""
if self.build['renpy']:
windows = 'binary'
else:
windows = 'windows'
icon_fn = os.path.join(self.project.path, "icon.ico")
old_exe_fn = os.path.join(config.renpy_base, "renpy.exe")
old_main_fn = os.path.join(config.renpy_base, "lib/windows-i686/renpy.exe")
if os.path.exists(icon_fn):
exe_fn = self.temp_filename("renpy.exe")
main_fn = self.temp_filename("main.exe")
with open(exe_fn, "wb") as f:
f.write(change_icons(old_exe_fn, icon_fn))
with open(main_fn, "wb") as f:
f.write(change_icons(old_main_fn, icon_fn))
else:
exe_fn = old_exe_fn
main_fn = old_main_fn
self.add_file("windows", "renpy.exe", exe_fn)
self.add_file(windows, self.exe, exe_fn)
self.add_file(windows, "lib/windows-i686/" + self.exe, main_fn)
def mark_executable(self):
"""
@@ -737,9 +752,7 @@ init python in distribute:
parts = fn.split('/')
p = parts[0]
if p == "renpy.exe":
p = self.exe
elif p == "renpy.sh":
if p == "renpy.sh":
p = self.sh
elif p == "renpy.py":
p = self.py
@@ -866,7 +879,7 @@ init python in distribute:
if not data:
break
sums.write(struct.pack("I", zlib.adler32(data) & 0xffffffff))
sums.write(struct.pack("<I", zlib.adler32(data) & 0xffffffff))
if self.include_update and not self.build_update and not dlc:
os.unlink(update_fn)
@@ -888,12 +901,15 @@ init python in distribute:
with open(fn, "rb") as f:
digest = hashlib.sha256(f.read()).hexdigest()
sums_size = os.path.getsize(self.destination + "/" + self.base_name + "-" + variant + ".sums")
index[variant] = {
"version" : self.update_version,
"pretty_version" : self.pretty_version,
"digest" : digest,
"zsync_url" : self.base_name + "-" + variant + ".zsync",
"sums_url" : self.base_name + "-" + variant + ".sums",
"sums_size" : sums_size,
"json_url" : self.base_name + "-" + variant + ".update.json",
}
+34 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -191,6 +191,7 @@ screen build_distributions:
has vbox
textbutton _("Edit options.rpy") action editor.Edit("game/options.rpy", check=True)
textbutton _("Add from clauses to calls, once") action Jump("add_from")
textbutton _("Refresh") action Jump("build_distributions")
@@ -219,14 +220,44 @@ screen build_distributions:
$ description = pkg["description"]
textbutton "[description!q]" action PackageToggle(pkg["name"]) style "l_checkbox"
add SPACER
add SPACER
add HALF_SPACER
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Options:")
add HALF_SPACER
if project.current.dump["build"]["include_update"]:
textbutton _("Build Updates") action DataToggle("build_update") style "l_checkbox"
textbutton _("Add from clauses to calls") action DataToggle("add_from") style "l_checkbox"
textbutton _("Back") action Jump("front_page") style "l_left_button"
textbutton _("Build") action Jump("distribute") style "l_right_button"
textbutton _("Build") action Jump("start_distribute") style "l_right_button"
label add_from_common:
python:
interface.processing(_("Adding from clauses to call statements that do not have them."))
project.current.launch([ "add_from" ], wait=True)
return
label add_from:
call add_from_common
jump build_distributions
label start_distribute:
if project.current.data["add_from"]:
call add_from_common
jump distribute
label build_update_dump:
python:
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+11 -9
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -197,18 +197,19 @@ screen front_page_project:
textbutton _("base") action OpenDirectory(".")
# textbutton _("images") action OpenDirectory("game/images") style "l_list"
# textbutton _("save") action None style "l_list"
vbox:
if persistent.show_edit_funcs:
label _("Edit File") style "l_label_small"
label _("Edit File") style "l_label_small"
frame style "l_indent":
has vbox
frame style "l_indent":
has vbox
textbutton "script.rpy" action editor.Edit("game/script.rpy", check=True)
textbutton "options.rpy" action editor.Edit("game/options.rpy", check=True)
textbutton "screens.rpy" action editor.Edit("game/screens.rpy", check=True)
textbutton _("All script files") action editor.EditAll()
textbutton "script.rpy" action editor.Edit("game/script.rpy", check=True)
textbutton "options.rpy" action editor.Edit("game/options.rpy", check=True)
textbutton "screens.rpy" action editor.Edit("game/screens.rpy", check=True)
textbutton _("All script files") action editor.EditAll()
add SPACER
add SEPARATOR
@@ -242,6 +243,7 @@ screen front_page_project:
textbutton _("Build Distributions") action Jump("build_distributions")
textbutton _("Android") action Jump("android")
textbutton _("iOS") action Jump("ios")
textbutton _("Generate Translations") action Jump("translate")
textbutton _("Extract Dialogue") action Jump("extract_dialogue")
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+363
View File
@@ -0,0 +1,363 @@
# Copyright 2004-2015 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.
init python:
IOS_NO_RENIOS = 0
IOS_NO_DIRECTORY = 1
IOS_NO_PROJECT = 2
IOS_OK = 3
IOS_NO_RENIOS_TEXT = _("To build iOS packages, please download renios, unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher.")
IOS_NO_DIRECTORY_TEXT = _("The directory in where Xcode projects will be placed has not been selected. Choose 'Select Directory' to select it.")
IOS_NO_PROJECT_TEXT = _("There is no Xcode project corresponding to the current Ren'Py project. Choose 'Create Xcode Project' to create one.")
IOS_OK_TEXT = _("An Xcode project exists. Choose 'Update Xcode Project' to update it with the latest game files, or use Xcode to build and install it.")
IPHONE_TEXT = _("Attempts to emulate an iPhone.\n\nTouch input is emulated through the mouse, but only when the button is held down.")
IPAD_TEXT = _("Attempts to emulate an iPad.\n\nTouch input is emulated through the mouse, but only when the button is held down.")
IOS_SELECT_DIRECTORY_TEXT = _("Selects the directory where Xcode projects will be placed.")
IOS_CREATE_PROJECT_TEXT = _("Creates an Xcode project corresponding to the current Ren'Py project.")
IOS_UPDATE_PROJECT_TEXT = _("Updates the Xcode project with the latest game files. This must be done each time the Ren'Py project changes.")
IOS_XCODE_TEXT = _("Opens the Xcode project in Xcode.")
IOS_OPEN_DIRECTORY_TEXT = _("Opens the directory containing Xcode projects.")
def find_renios():
global RENIOS_PATH
candidates = [ ]
RENIOS_PATH = os.path.join(config.renpy_base, "renios")
if os.path.isdir(RENIOS_PATH):
import sys
sys.path.insert(0, os.path.join(RENIOS_PATH, "buildlib"))
else:
RENIOS_PATH = None
find_renios()
if RENIOS_PATH:
import renios.create
def IOSState():
if not RENIOS_PATH:
return IOS_NO_RENIOS
elif not persistent.xcode_projects_directory:
return IOS_NO_DIRECTORY
elif not os.path.exists(xcode_project()):
return IOS_NO_PROJECT
else:
return IOS_OK
def IOSStateText(state):
if state == IOS_NO_RENIOS:
return IOS_NO_RENIOS_TEXT
elif state == IOS_NO_DIRECTORY:
return IOS_NO_DIRECTORY_TEXT
elif state == IOS_NO_PROJECT:
return IOS_NO_PROJECT_TEXT
else:
return IOS_OK_TEXT
def IOSIfState(state, needed, action):
"""
If `state` is `needed` or better, `action` is returned. Otherwise,
returns None, disabling the button.
"""
if state >= needed:
return action
else:
return None
xcode_name_cache = { }
def xcode_name(s):
"""
Returns a version of `s` that's safe to use in Xcode.
"""
if s in xcode_name_cache:
return xcode_name_cache[s]
s = re.sub(r'[^\w\-\.]', '', s)
xcode_name_cache[s] = s
return s
def xcode_project(p=None):
"""
Return the path to the Xcode project corresponding to `p`, or the current
project if `p` is None
"""
if p is None:
p = project.current
if persistent.xcode_projects_directory is None:
raise Exception("The Xcode projects directory has not been set.")
return os.path.join(persistent.xcode_projects_directory, xcode_name(p.name))
def ios_create(p=None, gui=True):
dest = xcode_project(p)
if os.path.exists(dest):
interface.yesno(_("The Xcode project already exists. Would you like to rename the old project, and replace it with a new one?"), no=Jump("ios"))
i = 0
while True:
i += 1
backup = dest + "." + str(i)
if not os.path.exists(backup):
break
os.rename(dest, backup)
iface = MobileInterface("ios")
renios.create.create_project(iface, dest)
ios_populate(p, gui=gui)
def ios_populate(p=None, gui=True):
"""
This actually builds the package.
"""
import shutil
if p is None:
p = project.current
dist = os.path.join(xcode_project(p), "base")
if os.path.exists(dist):
shutil.rmtree(dist)
if gui:
reporter = distribute.GuiReporter()
else:
reporter = distribute.TextReporter()
distribute.Distributor(p,
reporter=reporter,
packages=[ 'ios' ],
build_update=False,
noarchive=True,
packagedest=dist,
report_success=False,
)
for fn in os.listdir(dist):
if fn.endswith(".py"):
os.rename(
os.path.join(dist, fn),
os.path.join(dist, "main.py"),
)
break
def launch_xcode():
dist = xcode_project(None)
base = os.path.basename(dist)
xcodeproj = "{}/{}.xcodeproj".format(dist, base)
subprocess.call([ 'open', renpy.fsencode(xcodeproj) ])
screen ios:
default tt = Tooltip(None)
$ state = IOSState()
frame:
style_group "l"
style "l_root"
window:
has vbox
label _("iOS: [project.current.name!q]")
add HALF_SPACER
hbox:
# Left side.
frame:
style "l_indent"
xmaximum ONEHALF
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Emulation:")
add HALF_SPACER
frame style "l_indent":
has hbox:
spacing 15
textbutton _("iPhone"):
action LaunchEmulator("ios-touch", "small phone touch ios")
hovered tt.Action(IPHONE_TEXT)
textbutton _("iPad"):
action LaunchEmulator("ios-touch", "medium tablet touch ios")
hovered tt.Action(IPAD_TEXT)
add SPACER
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Build:")
add HALF_SPACER
frame style "l_indent":
has vbox
textbutton _("Select Xcode Projects Directory"):
action IOSIfState(state, IOS_NO_DIRECTORY, Jump("select_xcode_projects_directory"))
hovered tt.Action(IOS_SELECT_DIRECTORY_TEXT)
textbutton _("Create Xcode Project"):
action IOSIfState(state, IOS_NO_PROJECT, Jump("create_xcode_project"))
hovered tt.Action(IOS_CREATE_PROJECT_TEXT)
textbutton _("Update Xcode Project"):
action IOSIfState(state, IOS_NO_PROJECT, Jump("update_xcode_project"))
hovered tt.Action(IOS_UPDATE_PROJECT_TEXT)
if renpy.macintosh:
textbutton _("Launch Xcode"):
action IOSIfState(state, IOS_OK, launch_xcode)
hovered tt.Action(IOS_XCODE_TEXT)
# textbutton _("Configure"):
# action AndroidIfState(state, ANDROID_NO_CONFIG, Jump("android_configure"))
# hovered tt.Action(CONFIGURE_TEXT)
#
# textbutton _("Build Package"):
# action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build"))
# hovered tt.Action(BUILD_TEXT)
#
# textbutton _("Build & Install"):
# action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build_and_install"))
# hovered tt.Action(BUILD_AND_INSTALL_TEXT)
#
# textbutton _("Build, Install & Launch"):
# action AndroidIfState(state, ANDROID_OK, AndroidBuild("android_build_install_and_launch"))
# hovered tt.Action(BUILD_INSTALL_AND_LAUNCH_TEXT)
add SPACER
add SEPARATOR2
frame:
style "l_indent"
has vbox
text _("Other:")
add HALF_SPACER
frame style "l_indent":
has vbox
textbutton _("Open Xcode Projects Directory"):
action IOSIfState(state, IOS_NO_PROJECT, OpenDirectory(persistent.xcode_projects_directory, absolute=True))
hovered tt.Action(IOS_OPEN_DIRECTORY_TEXT)
# Right side.
frame:
style "l_indent"
xmaximum ONEHALF
xfill True
has vbox
add SEPARATOR2
frame:
style "l_indent"
has vbox
add SPACER
if tt.value:
text tt.value
else:
text IOSStateText(state)
textbutton _("Back") action Jump("front_page") style "l_left_button"
label ios:
if RENIOS_PATH is None:
$ interface.yesno(_("Before packaging iOS apps, you'll need to download renios, Ren'Py's iOS support. Would you like to download renios now?"), no=Jump("front_page"))
$ add_dlc("renios", restart=True)
call screen ios
label select_xcode_projects_directory:
python hide:
interface.interaction(_("XCODE PROJECTS DIRECTORY"), _("Please choose the Xcode Projects Directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"))
path, is_default = choose_directory(persistent.xcode_projects_directory)
if is_default:
interface.info(_("Ren'Py has set the Xcode Projects Directory to:"), "[path!q]", path=path)
persistent.xcode_projects_directory = path
jump ios
label create_xcode_project:
$ ios_create(None, True)
jump ios
label update_xcode_project:
$ ios_populate(None, True)
jump ios
+234
View File
@@ -0,0 +1,234 @@
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# This file contains mobile build things that are shared by the android
# and iOS builds.
init python:
class LaunchEmulator(Action):
def __init__(self, emulator, variants):
self.emulator = emulator
self.variants = variants
def __call__(self):
env = {
"RENPY_EMULATOR" : self.emulator,
"RENPY_VARIANT" : self.variants,
}
p = project.current
p.launch(env=env)
class MobileInterface(object):
"""
This is used to interface between the launcher and RAPT/RENIOS.
"""
def __init__(self, platform, edit=True):
"""
`platform`
The name of the platform we're using for. Used for libraries,
cancel labels, and logfiles.
`edit`
If true, we launch the log file in the editor on failure.
"""
self.platform = platform
self.edit = edit
self.process = None
self.filename = project.current.temp_filename(platform + ".txt")
self.info_msg = ""
with open(self.filename, "w"):
pass
def log(self, msg):
with open(self.filename, "a") as f:
f.write("\n")
f.write(msg)
f.write("\n")
def info(self, prompt):
self.info_msg = prompt
interface.processing(prompt, pause=False)
self.log(prompt)
def yesno(self, prompt, submessage=None):
return interface.yesno(prompt, submessage=submessage)
def yesno_choice(self, prompt, default=None):
choices = [ (True, "Yes"), (False, "No") ]
return interface.choice(prompt, choices, default)
def terms(self, url, prompt):
submessage = _("{a=%s}%s{/a}") % (url, url)
if not interface.yesno(prompt, submessage=submessage):
self.fail("You must accept the terms and conditions to proceed.", edit=False)
def input(self, prompt, empty=None):
if empty is None:
empty = ''
while True:
rv = interface.input(_("QUESTION"), prompt, default=empty, cancel=Jump("android"))
rv = rv.strip()
if rv:
return rv
def choice(self, prompt, choices, default):
return interface.choice(prompt, choices, default, cancel=Jump("android"))
def fail(self, prompt, edit=True):
self.log(prompt)
prompt = re.sub(r'(http://\S+)', r'{a=\1}\1{/a}', prompt)
# Open android.txt in the editor.
if edit and self.edit:
editor.EditAbsolute(self.filename)()
interface.error(prompt, label="android")
def success(self, prompt):
self.log(prompt)
interface.info(prompt, pause=False)
def final_success(self, prompt):
self.log(prompt)
interface.info(prompt, label="android")
def run_yes_thread(self):
import time
try:
while self.run_yes:
self.process.stdin.write('y\n')
self.process.stdin.flush()
time.sleep(.2)
except:
import traceback
traceback.print_exc()
def call(self, cmd, cancel=False, use_path=False, yes=False):
cmd = [ renpy.fsencode(i) for i in cmd ]
self.cmd = cmd
f = open(self.filename, "a")
f.write("\n\n\n")
if cancel:
cancel_action = self.cancel
else:
cancel_action = None
startupinfo = None
if renpy.windows:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
self.yes_thread = None
try:
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action)
kwargs = { }
if yes:
kwargs["stdin"] = subprocess.PIPE
try:
self.process = subprocess.Popen(cmd, cwd=renpy.fsencode(RAPT_PATH), stdout=f, stderr=f, startupinfo=startupinfo, **kwargs)
except:
import traceback
traceback.print_exc(file=f)
raise
if yes:
import threading
self.run_yes = True
self.yes_thread = threading.Thread(target=self.run_yes_thread)
self.yes_thread.daemon = True
self.yes_thread.start()
renpy.call_screen("android_process", interface=self)
finally:
f.close()
interface.hide_screen()
if yes and self.yes_thread:
self.run_yes = False
self.yes_thread.join()
self.process = None
self.yes_thread = None
def check_process(self):
rv = self.process.poll()
if rv is not None:
if rv:
raise subprocess.CalledProcessError(rv, self.cmd)
else:
return True
def download(self, url, dest):
try:
d = Downloader(url, dest)
cancel_action = [ d.cancel, Jump(self.platform) ]
interface.processing(self.info_msg, show_screen=True, cancel=cancel_action, bar_value=DownloaderValue(d))
ui.timer(.1, action=d.check, repeat=True)
ui.interact()
finally:
interface.hide_screen()
def background(self, f):
try:
t = threading.Thread(target=f)
t.start()
interface.processing(self.info_msg, show_screen=True)
while t.is_alive():
renpy.pause(0)
t.join(0.25)
finally:
interface.hide_screen()
def cancel(self):
if self.process:
self.process.terminate()
renpy.jump(self.platform)
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+14 -4
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -245,13 +245,22 @@ init python:
## Now, add the Ren'Py distribution in using classify_renpy.
build.classify_renpy("rapt/**", "rapt")
build.classify_renpy("**~", None)
build.classify_renpy("**/#*", None)
build.classify_renpy("**/thumbs.db", None)
build.classify_renpy("**/.*", None)
build.classify_renpy("rapt/**", "rapt")
build.classify_renpy("renios/prototype/base/", None)
build.classify_renpy("renios/prototype/prototype.xcodeproj/*.xcworkspace/", None)
build.classify_renpy("renios/prototype/prototype.xcodeproj/xcuserdata/", None)
build.classify_renpy("renios/prototype/**", "renios")
build.classify_renpy("renios/buildlib/**", "renios")
build.classify_renpy("renios/ios.py", "renios")
build.classify_renpy("renios/", "renios")
build.classify_renpy("**.old", None)
build.classify_renpy("**.new", None)
build.classify_renpy("**.bak", None)
@@ -310,11 +319,12 @@ init python:
build.classify_renpy("module/pysdlsound/*.pyx", "source")
# all-platforms binary.
build.classify_renpy("lib/**/_renpysteam*", None)
build.classify_renpy("lib/**/*steam_api*", None)
build.classify_renpy("lib/*/renpy", None)
build.classify_renpy("lib/*/renpy.exe", None)
build.classify_renpy("lib/**", "binary")
build.classify_renpy("renpy.sh", "binary")
build.classify_renpy("renpy.exe", "binary")
# renpy.app is now built from scratch from distribute.rpy.
# jedit rules.
@@ -343,4 +353,4 @@ init python:
build.package("editra-mac", "zip", "editra-all editra-mac", dlc=True)
build.package("editra-windows", "zip", "editra-all editra-windows", dlc=True)
build.package("rapt", "zip", "rapt", dlc=True)
build.package("renios", "zip", "renios", dlc=True)
+25 -12
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -107,7 +107,28 @@ init python in distribute:
"""
def __init__(self, filename):
self.zipfile = ZipFile(filename, "w", zipfile.ZIP_DEFLATED)
self.zipfile = ZipFile(filename, "w", zipfile.ZIP_DEFLATED, True)
def get_date_time(self, path):
"""
Gets the datetime for a file. If the time doesn't exist or is
weird, use the current time instead.
"""
try:
s = os.stat(path)
rv = time.gmtime(s.st_mtime)[:6]
# Check that the time is sensible.
if rv[0] < 2000:
rv = None
except:
rv = None
if rv is None:
rv = time.gmtime()[:6]
return rv
def add_file(self, name, path, xbit):
@@ -115,13 +136,7 @@ init python in distribute:
raise Exception("path for " + name + " must not be None.")
zi = zipfile.ZipInfo(name)
try:
s = os.stat(path)
zi.date_time = time.gmtime(s.st_mtime)[:6]
except:
zi.date_time = time.gmtime()[:6]
zi.date_time = self.get_date_time(path)
zi.compress_type = zipfile.ZIP_DEFLATED
zi.create_system = 3
@@ -137,9 +152,7 @@ init python in distribute:
return
zi = zipfile.ZipInfo(name + "/")
s = os.stat(path)
zi.date_time = time.gmtime(s.st_mtime)[:6]
zi.date_time = self.get_date_time(path)
zi.compress_type = zipfile.ZIP_STORED
zi.create_system = 3
zi.external_attr = (long(0040755) << 16) | 0x10
+6 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -25,6 +25,9 @@ init python:
config.gl_enable = persistent.gl_enable
if persistent.show_edit_funcs is None:
persistent.show_edit_funcs = True
if persistent.windows_console is None:
persistent.windows_console = False
@@ -168,7 +171,9 @@ screen preferences:
textbutton _("Hardware rendering") style "l_checkbox" action ToggleField(persistent, "gl_enable")
textbutton _("Show templates") style "l_checkbox" action ToggleField(persistent, "show_templates")
textbutton _("Show edit buttons") style "l_checkbox" action ToggleField(persistent, "show_edit_funcs")
textbutton _("Large fonts") style "l_checkbox" action [ ToggleField(persistent, "large_print"), renpy.utter_restart ]
textbutton _("Generate empty strings for translations") style "l_checkbox" action ToggleField(persistent, "generate_empty_strings")
if renpy.windows:
textbutton _("Console output") style "l_checkbox" action ToggleField(persistent, "windows_console")
+5 -54
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -121,6 +121,7 @@ init python in project:
data.setdefault("build_update", False)
data.setdefault("packages", [ "all" ])
data.setdefault("add_from", True)
def make_tmp(self):
"""
@@ -553,62 +554,12 @@ label choose_projects_directory:
interface.interaction(_("PROJECTS DIRECTORY"), _("Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"), _("This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."),)
path = persistent.projects_directory
path, is_default = choose_directory(persistent.projects_directory)
if path:
default_path = path
else:
try:
default_path = os.path.dirname(os.path.abspath(config.renpy_base))
except:
default_path = os.path.abspath(config.renpy_base)
if EasyDialogs:
choice = EasyDialogs.AskFolder(defaultLocation=default_path, wanted=unicode)
if choice is not None:
path = choice
else:
path = None
else:
try:
cmd = [ "/usr/bin/python", os.path.join(config.gamedir, "tkaskdir.py"), renpy.fsencode(default_path) ]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
choice = p.stdout.read()
code = p.wait()
except:
import traceback
traceback.print_exc()
code = 0
choice = ""
path = None
interface.error(_("Ren'Py was unable to run python with tkinter to choose the projects directory. Please install the python-tk or tkinter package."), label=None)
if code:
interface.error(_("Ren'Py was unable to run python with tkinter to choose the projects directory. Please install the python-tk or tkinter package."), label=None)
elif choice:
path = choice.decode("utf-8")
if path is None:
path = default_path
if is_default:
interface.info(_("Ren'Py has set the projects directory to:"), "[path!q]", path=path)
path = renpy.fsdecode(path)
if os.path.isdir(path):
persistent.projects_directory = path
else:
path = os.path.abspath(config.renpy_base)
persistent.projects_directory = path
project.manager.scan()
+7 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -104,9 +104,9 @@ init 1 python:
def checkbox(full, color):
if full:
return im.Twocolor("images/checkbox_full.png", color, color, yalign=0.5)
return im.Twocolor("images/checkbox_full.png", color, color, style="l_checkbox_box")
else:
return im.Twocolor("images/checkbox_empty.png", color, color, yalign=0.5)
return im.Twocolor("images/checkbox_empty.png", color, color, style="l_checkbox_box")
init 1:
@@ -322,6 +322,10 @@ init 1:
selected_hover_background checkbox(True, HOVER)
insensitive_background checkbox(False, DISABLED)
style l_checkbox_box:
yanchor 0.5
ypos 11
style l_checkbox_text is l_button_text:
selected_font LIGHT
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+21 -9
View File
@@ -3,11 +3,11 @@ translate japanese strings:
# game/android.rpy:12
old "To build Android packages, please download RAPT (from {a=http://www.renpy.org/dl/android}here{/a}), unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher."
new "Androidパッケージをビルドするためには{a=http://www.renpy.org/dl/android}RAPT{/a}をダウンロードして解凍し、Ren'Py ディレクトリーに配置してからランチャーを再起動してください。"
new "Androidパッケージをビルドするためには{a=http://www.renpy.org/dl/android}RAPT{/a}をダウンロードして解凍し、Ren'Py ディレクトリーに配置してランチャーを再起動してください。"
# game/android.rpy:13
old "RAPT has been installed, but you'll need to install the Android SDK before you can build Android packages. Choose Install SDK to do this."
new "RAPT はインストールされましたが、Androidパッケージをビルドする前に Android SDK もインストールする必要があります。このためにSDKをインストールしてください。"
new "RAPT はインストールされましたが、Androidパッケージをビルドする前に Android SDK もインストールする必要があります。SDKをインストールしてください。"
# game/android.rpy:14
old "RAPT has been installed, but a key hasn't been configured. Please create a new key, or restore android.keystore."
@@ -15,7 +15,7 @@ translate japanese strings:
# game/android.rpy:15
old "The current project has not been configured. Use \"Configure\" to configure it before building."
new "現在のプロジェクトは設定されていません。「設定」を用してビルド前に設定してください。"
new "現在のプロジェクトは設定されていません。「設定」を使用してビルド前に設定してください。"
# game/android.rpy:16
old "Choose \"Build\" to build the current project, or attach an Android device and choose \"Build & Install\" to build and install it on the device."
@@ -23,23 +23,23 @@ translate japanese strings:
# game/android.rpy:18
old "Attempts to emulate an Android phone.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Android Phoneをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみす。Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
new "Android Phoneをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみ反応します。Escapeはメニューボタン、PageUpはバックボタンに割り当てられています。"
# game/android.rpy:19
old "Attempts to emulate an Android tablet.\n\nTouch input is emulated through the mouse, but only when the button is held down. Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Android tabletをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみす。Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
new "Android tabletをエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみ反応します。Escapeはメニューボタン、PageUpはバックボタンに割り当てられています。"
# game/android.rpy:20
old "Attempts to emulate an OUYA console.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "Android OUYAをエミュレートします。\n\nコントローラーの入力は矢印キー、Enterはセレクトボタン、Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
new "Android OUYAをエミュレートします。\n\nコントローラーの入力は矢印キー、Enterはセレクトボタン、Escapeはメニューボタン、PageUpはバックボタンに割り当てられています。"
# game/android.rpy:22
old "Downloads and installs the Android SDK and supporting packages. Optionally, generates the keys required to sign the package."
new "Android SDKをダウンロード後インストールします。任意でサインに必要なキーを生成します。"
new "Android SDKをダウンロード後インストールします。サインに必要なキーを任意で生成します。"
# game/android.rpy:23
old "Configures the package name, version, and other information about this project."
new "このプロジェクトについてパッケージ名バージョン、その他の情報を設定してください。"
new "このプロジェクトについてパッケージ名バージョン、その他の情報を設定してください。"
# game/android.rpy:24
old "Opens the file containing the Google Play keys in the editor.\n\nThis is only needed if the application is using an expansion APK. Read the documentation for more details."
@@ -115,7 +115,7 @@ translate japanese strings:
# game/android.rpy:39
old "Attempts to emulate a televison-based Android console, like the OUYA or Fire TV.\n\nController input is mapped to the arrow keys, Enter is mapped to the select button, Escape is mapped to the menu button, and PageUp is mapped to the back button."
new "OUYAやFire TVのようなテレビで動作する Android デバイスをエミュレートします。\n\nコントローラーの入力は矢印キー、Enterはセレクトボタン、Escapeはメニューボタン、PageUpはバックボタンにマップされています。"
new "OUYAやFire TVのようなテレビで動作する Android デバイスをエミュレートします。\n\nコントローラーの入力は矢印キー、Enterはセレクトボタン、Escapeはメニューボタン、PageUpはバックボタンに割り当てられています。"
# game/android.rpy:47
old "Connects to an Android device running ADB in TCP/IP mode."
@@ -161,3 +161,15 @@ translate japanese strings:
old "The port must be a number."
new "ポートは数字でなければなりません。"
# game/android.rpy:46
old "Builds the Android package, installs it on an Android device connected to your computer, then launches the app on your device."
new "Android パッケージをビルドして、接続された Android にインストール、 そのデバイスでアプリを起動します。"
# game/android.rpy:288
old "Television"
new "Television"
# game/android.rpy:324
old "Build, Install & Launch"
new "ビルドとインストール、起動"
+7
View File
@@ -0,0 +1,7 @@
translate japanese strings:
# game/choose_directory.rpy:73
old "Ren'Py was unable to run python with tkinter to choose the directory. Please install the python-tk or tkinter package."
new "Ren'Py は tkinter でディレクトリーを選択出来ません。 python-tk か tkinter をインストールしてください。"
+493 -499
View File
@@ -1,499 +1,493 @@
translate japanese strings:
# renpy/common/00action_file.rpy:124
old "%b %d, %H:%M"
new "%m月%d日, %H:%M"
# renpy/common/00action_file.rpy:587
old "Quick save complete."
new "クイックセーブ完了。"
translate japanese strings:
# renpy/common/00gallery.rpy:521
old "Image [index] of [count] locked."
new "画像 [index] / [count] はロックされています。"
# renpy/common/00gallery.rpy:539
old "prev"
new "前へ"
# renpy/common/00gallery.rpy:540
old "next"
new "次へ"
# renpy/common/00gallery.rpy:541
old "slideshow"
new "スライドショー"
# renpy/common/00gallery.rpy:542
old "return"
new "戻る"
translate japanese strings:
# renpy/common/00gltest.rpy:50
old "Graphics Acceleration"
new "グラフィック・アクセラレーション"
# renpy/common/00gltest.rpy:54
old "Automatically Choose"
new "自動選択"
# renpy/common/00gltest.rpy:59
old "Force Angle/DirectX Renderer"
new "Angle/DirectX による描画を強制"
# renpy/common/00gltest.rpy:63
old "Force OpenGL Renderer"
new "OpenGL による描画を強制"
# renpy/common/00gltest.rpy:67
old "Force Software Renderer"
new "ソフトウェアによる描画を強制"
# renpy/common/00gltest.rpy:73
old "Changes will take effect the next time this program is run."
new "変更は、次にプログラムを起動した時に反映されます。"
# renpy/common/00gltest.rpy:77
old "Quit"
new "終了"
# renpy/common/00gltest.rpy:82
old "Return"
new "戻る"
# renpy/common/00gltest.rpy:112
old "Performance Warning"
new "パフォーマンスに関する注意"
# renpy/common/00gltest.rpy:117
old "This computer is using software rendering."
new "このコンピュータはソフトウェアレンダリングを使用しています。"
# renpy/common/00gltest.rpy:119
old "This computer is not using shaders."
new "このコンピューターはシェーダーを使用していません。"
# renpy/common/00gltest.rpy:121
old "This computer is displaying graphics slowly."
new "このコンピューターは描画速度が遅いです。"
# renpy/common/00gltest.rpy:123
old "This computer has a problem displaying graphics: [problem]."
new "このコンピューターはグラフィックスの表示に問題があります: [problem]。"
# renpy/common/00gltest.rpy:128
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
new "グラフィックドライバーは古いか、あるいは正常に動作していません。これはグラフィックスの表示が遅くなったり、正常に表示されない原因となります。DirectXをアップデートするとこの問題を解決できます。"
# renpy/common/00gltest.rpy:130
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
new "グラフィックドライバーは古いか、あるいは正常に動作していません。これはグラフィックスの表示が遅くなったり、正常に表示されない原因となります。"
# renpy/common/00gltest.rpy:135
old "Update DirectX"
new "DirectXのアップデート"
# renpy/common/00gltest.rpy:141
old "Continue, Show this warning again"
new "今後も、この注意を表示する"
# renpy/common/00gltest.rpy:145
old "Continue, Don't show warning again"
new "今後は、この注意を表示しない"
# renpy/common/00gltest.rpy:171
old "Updating DirectX."
new "DirectXのアップデート中"
# renpy/common/00gltest.rpy:175
old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
new "DirectXウェブセットアップが開始されました。タスクバーに最小化された状態で開始したので、画面に従ってDirectXをインストールして下さい。"
# renpy/common/00gltest.rpy:179
old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
new "{b}メモ:{/b} MicrosoftのDirectXウェブセットアッププログラムは、デフォルトでBingツールバーをインストールします。このツールバーが不要な場合は、対応したチェックボックスを解除して下さい。"
# renpy/common/00gltest.rpy:183
old "When setup finishes, please click below to restart this program."
new "セットアップが完了したら、以下をクリックしてプログラムを再起動して下さい。"
# renpy/common/00gltest.rpy:185
old "Restart"
new "再起動"
translate japanese strings:
# renpy/common/00keymap.rpy:168
old "Saved screenshot as %s."
new "スクリーンショットを %s に保存しました。"
translate japanese strings:
# renpy/common/00layout.rpy:421
old "Are you sure?"
new "本当にいいですか?"
# renpy/common/00layout.rpy:422
old "Are you sure you want to delete this save?"
new "この保存データを本当に削除しますか?"
# renpy/common/00layout.rpy:423
old "Are you sure you want to overwrite your save?"
new "本当に保存データを上書きしますか?"
# renpy/common/00layout.rpy:424
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
new "読み込みによって未保存のゲームが失われます。\n本当に読み込みますか?"
# renpy/common/00layout.rpy:425
old "Are you sure you want to quit?"
new "本当にゲームを終了しますか?"
# renpy/common/00layout.rpy:426
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
new "本当にメインメニューに戻りますか?\nこれによって未保存のゲームが失われます。"
# renpy/common/00layout.rpy:427
old "Are you sure you want to begin skipping?"
new "本当にスキップモードを開始しますか?"
# renpy/common/00layout.rpy:428
old "Are you sure you want to skip to the next choice?"
new "本当に次の選択肢までスキップしますか?"
# renpy/common/00layout.rpy:429
old "Are you sure you want to skip to unseen dialogue or the next choice?"
new "本当に未読の会話、もしくは次の選択肢までスキップしますか?"
translate japanese strings:
# renpy/common/00library.rpy:77
old "Skip Mode"
new "スキップモード"
# renpy/common/00library.rpy:80
old "Fast Skip Mode"
new "高速スキップモード"
translate japanese strings:
# renpy/common/00updater.rpy:1258
old "Updater"
new "アップデーター"
# renpy/common/00updater.rpy:1267
old "This program is up to date."
new "このプログラムは最新版です。"
# renpy/common/00updater.rpy:1269
old "[u.version] is available. Do you want to install it?"
new "[u.version] が利用可能です。インストールしますか?"
# renpy/common/00updater.rpy:1271
old "Preparing to download the updates."
new "アップデートをダウンロードする準備をしています。"
# renpy/common/00updater.rpy:1273
old "Downloading the updates."
new "アップデートをダウンロードしています。"
# renpy/common/00updater.rpy:1275
old "Unpacking the updates."
new "アップデートを展開しています。"
# renpy/common/00updater.rpy:1279
old "The updates have been installed. The program will restart."
new "アップデートがインストールされました。プログラムを再起動します。"
# renpy/common/00updater.rpy:1281
old "The updates have been installed."
new "アップデートがインストールされました。"
# renpy/common/00updater.rpy:1283
old "The updates were cancelled."
new "アップデートがキャンセルされました。"
translate japanese strings:
# renpy/common/_compat/gamemenu.rpym:180
old "Empty Slot."
new "空のスロット"
# renpy/common/_compat/gamemenu.rpym:337
old "Previous"
new "前へ"
# renpy/common/_compat/gamemenu.rpym:344
old "Next"
new "次"
translate japanese strings:
# renpy/common/_compat/preferences.rpym:411
old "Joystick Mapping"
new "ジョイスティックのマッピング"
translate japanese strings:
# renpy/common/_errorhandling.rpym:408
old "An exception has occurred."
new "例外が発生しました。"
# renpy/common/_errorhandling.rpym:434
old "Rollback"
new "ロールバック"
# renpy/common/_errorhandling.rpym:436
old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
new "一つ前へのロールバックを試み、セーブまたは他の選択肢を選ぶことを許可します。"
# renpy/common/_errorhandling.rpym:439
old "Ignore"
new "無視"
# renpy/common/_errorhandling.rpym:441
old "Ignores the exception, allowing you to continue. This often leads to additional errors."
new "例外を無視し、ゲームの継続を許可します。この場合、付加的なエラーが発生する原因となることがあります。"
# renpy/common/_errorhandling.rpym:444
old "Reload"
new "再読み込み"
# renpy/common/_errorhandling.rpym:446
old "Reloads the game from disk, saving and restoring game state if possible."
new "ディスクからゲームを再読み込みし、可能であればゲームの保存と復元をします。"
# renpy/common/_errorhandling.rpym:448
old "Open Traceback"
new "トレースバックを開く"
# renpy/common/_errorhandling.rpym:450
old "Opens the traceback.txt file in a text editor."
new "テキストエディターで traceback.txt を開きます。"
# renpy/common/_errorhandling.rpym:456
old "Quits the game."
new "ゲームを終了します。"
# renpy/common/_errorhandling.rpym:483
old "Parsing the script failed."
new "スクリプトの変換に失敗しました。"
# renpy/common/_errorhandling.rpym:510
old "Open Parse Errors"
new "変換エラーを開く"
# renpy/common/_errorhandling.rpym:512
old "Opens the errors.txt file in a text editor."
new "テキストエディターで errors.txt を開きます。"
translate japanese strings:
# renpy/common/_layout/classic_load_save.rpym:152
old "a"
new "a"
# renpy/common/_layout/classic_load_save.rpym:161
old "q"
new "q"
translate japanese strings:
# renpy/common/00console.rpy:179
old "%(version)s console, originally by Shiz, C, and delta.\n"
new "%(version)s コンソール, 作成者: Shiz, C, delta\n"
# renpy/common/00console.rpy:180
old "Press <esc> to exit console. Type help for help.\n"
new "<esc> を押して終了。help と入力してヘルプを表示。\n"
# renpy/common/00console.rpy:184
old "Ren'Py script enabled."
new "Ren'Py スクリプト有効。"
# renpy/common/00console.rpy:186
old "Ren'Py script disabled."
new "Ren'Py スクリプト無効。"
# renpy/common/00console.rpy:392
old "help: show this help"
new "help: このヘルプを表示"
# renpy/common/00console.rpy:397
old "commands:\n"
new "コマンド:\n"
# renpy/common/00console.rpy:407
old " <renpy script statement>: run the statement\n"
new " <Ren'Py スクリプトステートメント>: ステートメントを実行\n"
# renpy/common/00console.rpy:409
old " <python expression or statement>: run the expression or statement"
new " <Python 式またはステートメント>: 式またはステートメントを実行"
# renpy/common/00console.rpy:417
old "clear: clear the console history"
new "clear: コンソール履歴を消去"
# renpy/common/00console.rpy:421
old "exit: exit the console"
new "exit: コンソールを終了"
# renpy/common/00console.rpy:429
old "load <slot>: loads the game from slot"
new "load <スロット>: スロットからゲームをロード"
# renpy/common/00console.rpy:442
old "save <slot>: saves the game in slot"
new "save <スロット>: スロットにゲームを保存"
# renpy/common/00console.rpy:453
old "reload: reloads the game, refreshing the scripts"
new "reload: ゲームをリロードしてスクリプトを再読み込み"
# renpy/common/00console.rpy:461
old "watch <expression>: watch a python expression"
new "watch <式>: Python 式をウォッチ"
# renpy/common/00console.rpy:470
old "unwatch <expression>: stop watching an expression"
new "unwatch <式>: Python 式のウォッチを解除"
# renpy/common/00console.rpy:478
old "unwatchall: stop watching all expressions"
new "unwatchall: すべての式のウォッチを解除"
# renpy/common/00console.rpy:484
old "jump <label>: jumps to label"
new "jump <ラベル>: ラベルにジャンプ"
# renpy/common/00keymap.rpy:332
old "Autoreload"
new "オートリロード"
translate japanese strings:
# renpy/common/_developer/developer.rpym:65
old "Developer Menu"
new "開発者メニュー"
# renpy/common/_developer/developer.rpym:67
old "Reload Game (Shift+R)"
new "ゲームのリロード (Shift+R)"
# renpy/common/_developer/developer.rpym:69
old "Console (Shift+O)"
new "コンソール (Shift+D)"
# renpy/common/_developer/developer.rpym:71
old "Variable Viewer"
new "変数ビューアー"
# renpy/common/_developer/developer.rpym:73
old "Theme Test"
new "テーマのテスト"
# renpy/common/_developer/developer.rpym:75
old "Image Location Picker"
new "画像位置ピッカー"
# renpy/common/_developer/developer.rpym:77
old "Filename List"
new "ファイル名のリスト"
# renpy/common/_developer/developer.rpym:81
old "Show Image Load Log"
new "画像ロード履歴の表示"
# renpy/common/_developer/developer.rpym:84
old "Hide Image Load Log"
new "画像ロード履歴の非表示"
# renpy/common/_developer/developer.rpym:149
old "No variables have changed since the game started."
new "ゲーム起動時から変更された変数はありません。"
# renpy/common/_developer/developer.rpym:152
old "Return to the developer menu"
new "開発者メニューに戻ります"
# renpy/common/_developer/developer.rpym:309
old "Undefined Images"
new "未定義の画像"
# renpy/common/_developer/developer.rpym:409
old "Rectangle: %r"
new "矩形: %r"
# renpy/common/_developer/developer.rpym:414
old "Mouse position: %r"
new "マウス位置: %r"
# renpy/common/_developer/developer.rpym:416
old "Right-click or escape to quit."
new "右クリックまたはEscで終了。"
# renpy/common/_developer/developer.rpym:467
old "Done"
new "完了"
translate japanese strings:
# renpy/common/_developer/inspector.rpym:43
old "Displayable Inspector"
new "Displayable インスペクター"
# renpy/common/_developer/inspector.rpym:49
old "Nothing to inspect."
new "インスペクトするものがありません"
# renpy/common/_developer/inspector.rpym:58
old "Size"
new "サイズ"
# renpy/common/_developer/inspector.rpym:63
old "Style"
new "スタイル"
# renpy/common/_developer/inspector.rpym:123
old "Inspecting Styles of [displayable_name!q]"
new "[displayable_name!q] のスタイルをインスペクト中"
# renpy/common/_developer/inspector.rpym:135
old "displayable:"
new "Displayable:"
# renpy/common/_developer/inspector.rpym:142
old " (no properties affect the displayable)"
new " (Displayable に影響しているプロパティーはありません)"
# renpy/common/_developer/inspector.rpym:144
old " (default properties omitted)"
new " (デフォルトのプロパティーは省略します)"
# renpy/common/_developer/inspector.rpym:174
old "<repr() failed>"
new "<repr() 失敗>"
# renpy/common/_developer/developer.rpym:273
old "{b}Missing Images{/b}"
new "{b}M画像が見付かりません{/b}"
# renpy/common/_developer/inspector.rpym:80
old "Location"
new "ファイル"
# Translation updated at 2013-02-18 11:40
translate japanese strings:
# renpy/common/00library.rpy:77
old "Skip Mode"
new "スキップモード"
# renpy/common/00library.rpy:80
old "Fast Skip Mode"
new "高速スキップモード"
# renpy/common/00updater.rpy:1255
old "Updater"
new "アップデーター"
# renpy/common/00updater.rpy:1264
old "This program is up to date."
new "このプログラムは最新の状態です。"
# renpy/common/00updater.rpy:1266
old "[u.version] is available. Do you want to install it?"
new "[u.version] が利用可能です。インストールしますか?"
# renpy/common/00updater.rpy:1268
old "Preparing to download the updates."
new "ダウンロードする準備をしています。"
# renpy/common/00updater.rpy:1270
old "Downloading the updates."
new "アップデートをダウンロードしています。"
# renpy/common/00updater.rpy:1272
old "Unpacking the updates."
new "アップデートを展開しています。"
# renpy/common/00updater.rpy:1276
old "The updates have been installed. The program will restart."
new "アップデートがインストールされました。プログラムを再起動します。"
# renpy/common/00updater.rpy:1278
old "The updates have been installed."
new "アップデートが完了しました。"
# renpy/common/00updater.rpy:1280
old "The updates were cancelled."
new "アップデートがキャンセルされました。"
# renpy/common/_compat/preferences.rpym:411
old "Joystick Mapping"
new "ジョイスティックの割り当て"
# renpy/common/00layout.rpy:421
old "Are you sure?"
new "続けますか?"
# renpy/common/00layout.rpy:422
old "Are you sure you want to delete this save?"
new "このセーブデータを消去しますか?"
# renpy/common/00layout.rpy:423
old "Are you sure you want to overwrite your save?"
new "このセーブデータに上書きしますか?"
# renpy/common/00layout.rpy:424
old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
new "セーブされていないデータは失われます\n続けますか?"
# renpy/common/00layout.rpy:425
old "Are you sure you want to quit?"
new "終了しますか?"
# renpy/common/00layout.rpy:426
old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
new "メインメニューに戻りますか?\nセーブされていないデータは破棄されます"
# renpy/common/_errorhandling.rpym:408
old "An exception has occurred."
new "例外が発生しました。"
# renpy/common/_errorhandling.rpym:434
old "Rollback"
new "ロールバック"
# renpy/common/_errorhandling.rpym:436
old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
new "セーブまたは他の選択肢が選べるように、ロールバックを使って直前に戻ります。"
# renpy/common/_errorhandling.rpym:439
old "Ignore"
new "無視"
# renpy/common/_errorhandling.rpym:441
old "Ignores the exception, allowing you to continue. This often leads to additional errors."
new "例外を無視してゲームを続行します。連鎖的にエラーが発生する可能性があります。"
# renpy/common/_errorhandling.rpym:444
old "Reload"
new "リロード"
# renpy/common/_errorhandling.rpym:446
old "Reloads the game from disk, saving and restoring game state if possible."
new "ディスクからゲームをリロードして、現在の状況を保存、可能であれば復元します。"
# renpy/common/_errorhandling.rpym:448
old "Open Traceback"
new "トレースバックを開く"
# renpy/common/_errorhandling.rpym:450
old "Opens the traceback.txt file in a text editor."
new "テキストエディターで traceback.txt を開きます。"
# renpy/common/_errorhandling.rpym:456
old "Quits the game."
new "ゲームを終了します。"
# renpy/common/_errorhandling.rpym:483
old "Parsing the script failed."
new "スクリプトの変換に失敗しました。"
# renpy/common/_errorhandling.rpym:510
old "Open Parse Errors"
new "変換エラーを開く"
# renpy/common/_errorhandling.rpym:512
old "Opens the errors.txt file in a text editor."
new "テキストエディターで errors.txt を開きます。"
# renpy/common/00keymap.rpy:167
old "Saved screenshot as %s."
new "スクリーンショットを %s に保存しました。"
# renpy/common/00gltest.rpy:50
old "Graphics Acceleration"
new "グラフィック・アクセラレーション"
# renpy/common/00gltest.rpy:54
old "Automatically Choose"
new "自動で選択する"
# renpy/common/00gltest.rpy:59
old "Force Angle/DirectX Renderer"
new "Angle/DirectX レンダラーを使う"
# renpy/common/00gltest.rpy:63
old "Force OpenGL Renderer"
new "OpenGL レンダラーを使う"
# renpy/common/00gltest.rpy:67
old "Force Software Renderer"
new "ソフトウェアレンダラーを使う"
# renpy/common/00gltest.rpy:73
old "Changes will take effect the next time this program is run."
new "変更は次回起動時から適用されます"
# renpy/common/00gltest.rpy:112
old "Performance Warning"
new "パフォーマンスに関する注意"
# renpy/common/00gltest.rpy:117
old "This computer is using software rendering."
new "このコンピューターはソフトウェアレンダリングを使用しています。"
# renpy/common/00gltest.rpy:119
old "This computer is not using shaders."
new "このコンピューターはシェーダーを使用していません。"
# renpy/common/00gltest.rpy:121
old "This computer is displaying graphics slowly."
new "このコンピューターは描画速度が遅いです。"
# renpy/common/00gltest.rpy:123
old "This computer has a problem displaying graphics: [problem]."
new "このコンピューターではグラフィックに以下の問題があります:[problem] "
# renpy/common/00gltest.rpy:128
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
new "グラフィックドライバーが古いか、正常に動作していません。表示が遅れたり、正しく表示されない可能性があります。DirectX を更新すると解決することがあります。"
# renpy/common/00gltest.rpy:130
old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
new "グラフィックドライバーが古いか、正常に動作していません。表示が遅れたり、正しく表示されない可能性があります。"
# renpy/common/00gltest.rpy:135
old "Update DirectX"
new "DirectXのアップデート"
# renpy/common/00gltest.rpy:141
old "Continue, Show this warning again"
new "次回もこの注意を表示する。"
# renpy/common/00gltest.rpy:145
old "Continue, Don't show warning again"
new "次回はこの注意を表示しない。"
# renpy/common/00gltest.rpy:171
old "Updating DirectX."
new "DirectXのアップデート中"
# renpy/common/00gltest.rpy:175
old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
new "DirectX ウェブセットアップを開始しました。タスクバーに最小化されていることがありますが、指示通りにインストールしてください。"
# renpy/common/00gltest.rpy:179
old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
new "{b}注意:{/b} MicrosoftのDirectXウェブセットアッププログラムは、デフォルトでBingツールバーをインストールします。このツールバーが不要な場合は、対応したチェックボックスを解除して下さい。"
# renpy/common/00gltest.rpy:183
old "When setup finishes, please click below to restart this program."
new "セットアップが完了したら、下のボタンを押して再起動してください。"
# renpy/common/00gltest.rpy:185
old "Restart"
new "再起動"
# renpy/common/_layout/imagemap_load_save.rpym:115
old "a"
new "a"
# renpy/common/_layout/imagemap_load_save.rpym:124
old "q"
new "q"
# renpy/common/00action_file.rpy:118
old "%b %d, %H:%M"
new "%m月%d日, %H:%M"
# renpy/common/00layout.rpy:427
old "Are you sure you want to begin skipping?"
new "スキップを開始しますか?"
# renpy/common/00layout.rpy:428
old "Are you sure you want to skip to the next choice?"
new "次の選択肢までスキップしますか?"
# renpy/common/00layout.rpy:429
old "Are you sure you want to skip to unseen dialogue or the next choice?"
new "次の選択肢または未読までスキップしますか?"
# renpy/common/00gallery.rpy:521
old "Image [index] of [count] locked."
new "画像 [index] / [count] はロックされています。"
# renpy/common/00gallery.rpy:539
old "prev"
new "前へ"
# renpy/common/00gallery.rpy:540
old "next"
new "次へ"
# renpy/common/00gallery.rpy:541
old "slideshow"
new "スライドショー"
# renpy/common/00gallery.rpy:542
old "return"
new "戻る"
# renpy/common/00action_file.rpy:587
old "Quick save complete."
new "クイックセーブ完了。"
# renpy/common/_developer/inspector.rpym:43
old "Displayable Inspector"
new "Displayable インスペクター"
# renpy/common/_developer/inspector.rpym:49
old "Nothing to inspect."
new "インスペクトするものがありません"
# renpy/common/_developer/inspector.rpym:58
old "Size"
new "サイズ"
# renpy/common/_developer/inspector.rpym:63
old "Style"
new "スタイル"
# renpy/common/_developer/inspector.rpym:123
old "Inspecting Styles of [displayable_name!q]"
new "[displayable_name!q] のスタイルをインスペクト中"
# renpy/common/_developer/inspector.rpym:135
old "displayable:"
new "Displayable:"
# renpy/common/_developer/inspector.rpym:142
old " (no properties affect the displayable)"
new " (Displayable に影響しているプロパティーはありません)"
# renpy/common/_developer/inspector.rpym:144
old " (default properties omitted)"
new " (デフォルトのプロパティーは省略します)"
# renpy/common/_developer/inspector.rpym:174
old "<repr() failed>"
new "<repr() 失敗>"
# renpy/common/_developer/developer.rpym:65
old "Developer Menu"
new "開発者メニュー"
# renpy/common/_developer/developer.rpym:67
old "Reload Game (Shift+R)"
new "ゲームのリロード (Shift+R)"
# renpy/common/_developer/developer.rpym:69
old "Console (Shift+O)"
new "コンソール (Shift+D)"
# renpy/common/_developer/developer.rpym:71
old "Variable Viewer"
new "変数ビューアー"
# renpy/common/_developer/developer.rpym:73
old "Theme Test"
new "テーマのテスト"
# renpy/common/_developer/developer.rpym:75
old "Image Location Picker"
new "画像位置ピッカー"
# renpy/common/_developer/developer.rpym:77
old "Filename List"
new "ファイル名のリスト"
# renpy/common/_developer/developer.rpym:81
old "Show Image Load Log"
new "画像ロード履歴の表示"
# renpy/common/_developer/developer.rpym:84
old "Hide Image Load Log"
new "画像ロード履歴の非表示"
# renpy/common/_developer/developer.rpym:149
old "No variables have changed since the game started."
new "ゲーム起動時から変更された変数はありません。"
# renpy/common/_developer/developer.rpym:152
old "Return to the developer menu"
new "開発者メニューに戻ります"
# renpy/common/_developer/developer.rpym:309
old "Undefined Images"
new "未定義の画像"
# renpy/common/_developer/developer.rpym:409
old "Rectangle: %r"
new "矩形: %r"
# renpy/common/_developer/developer.rpym:414
old "Mouse position: %r"
new "マウス位置: %r"
# renpy/common/_developer/developer.rpym:416
old "Right-click or escape to quit."
new "右クリックまたはEscで終了。"
# renpy/common/_developer/developer.rpym:467
old "Done"
new "完了"
# renpy/common/00console.rpy:179
old "%(version)s console, originally by Shiz, C, and delta.\n"
new "%(version)s コンソール, 作成者: Shiz, C, delta\n"
# renpy/common/00console.rpy:180
old "Press <esc> to exit console. Type help for help.\n"
new "<esc> を押して終了。help と入力してヘルプを表示。\n"
# renpy/common/00console.rpy:184
old "Ren'Py script enabled."
new "Ren'Py スクリプト有効。"
# renpy/common/00console.rpy:186
old "Ren'Py script disabled."
new "Ren'Py スクリプト無効。"
# renpy/common/00console.rpy:392
old "help: show this help"
new "help: このヘルプを表示"
# renpy/common/00console.rpy:397
old "commands:\n"
new "コマンド:\n"
# renpy/common/00console.rpy:407
old " <renpy script statement>: run the statement\n"
new " <Ren'Py スクリプトステートメント>: ステートメントを実行\n"
# renpy/common/00console.rpy:409
old " <python expression or statement>: run the expression or statement"
new " <Python 式またはステートメント>: 式またはステートメントを実行"
# renpy/common/00console.rpy:417
old "clear: clear the console history"
new "clear: コンソール履歴を消去"
# renpy/common/00console.rpy:421
old "exit: exit the console"
new "exit: コンソールを終了"
# renpy/common/00console.rpy:429
old "load <slot>: loads the game from slot"
new "load <スロット>: スロットからゲームをロード"
# renpy/common/00console.rpy:442
old "save <slot>: saves the game in slot"
new "save <スロット>: スロットにゲームを保存"
# renpy/common/00console.rpy:453
old "reload: reloads the game, refreshing the scripts"
new "reload: ゲームをリロードしてスクリプトを再読み込み"
# renpy/common/00console.rpy:461
old "watch <expression>: watch a python expression"
new "watch <式>: Python 式をウォッチ"
# renpy/common/00console.rpy:470
old "unwatch <expression>: stop watching an expression"
new "unwatch <式>: Python 式のウォッチを解除"
# renpy/common/00console.rpy:478
old "unwatchall: stop watching all expressions"
new "unwatchall: すべての式のウォッチを解除"
# renpy/common/00console.rpy:484
old "jump <label>: jumps to label"
new "jump <ラベル>: ラベルにジャンプ"
# renpy/common/00keymap.rpy:332
old "Autoreload"
new "オートリロード"
# renpy/common/_developer/developer.rpym:272
old "{b}Missing Images{/b}"
new "{b}M画像が見付かりません{/b}"
# renpy/common/_developer/inspector.rpym:80
old "Location"
new "ファイル"
# renpy/common/00preferences.rpy:387
old "Clipboard voicing enabled. Press 'shift+C' to disable."
new "クリップボードボイシングが有効化しました。 'shift+C'で無効化します。"
# renpy/common/00preferences.rpy:389
old "Self-voicing enabled. Press 'v' to disable."
new "セルフボイシングが有効化しました。 'v' で無効化します。"
##Lancherでのみ必要###########################################
# renpy/common/00gltest.rpy:95
old "Quit"
new "終了"
# renpy/common/00gltest.rpy:100
old "Return"
new "戻る"
# renpy/common/_compat/gamemenu.rpym:198
old "Empty Slot."
new "空のスロット"
# renpy/common/_compat/gamemenu.rpym:355
old "Previous"
new "前へ"
# renpy/common/_compat/gamemenu.rpym:362
old "Next"
new "次へ"
##templateでのみ必要############################################
#
# # renpy/common/00updater.rpy:1385
# old "An error has occured:"
# new "エラーが派生しました。"
#
# # renpy/common/00updater.rpy:1387
# old "Checking for updates."
# new "更新をチェックしています。"
#
# # renpy/common/00updater.rpy:1399
# old "Finishing up."
# new "更新を完了しました。"
#
# # renpy/common/00updater.rpy:1419
# old "Proceed"
# new "処理中"
#
# # renpy/common/00updater.rpy:1422
# old "Cancel"
# new "キャンセル"
+4
View File
@@ -105,3 +105,7 @@ translate japanese strings:
old "Recompiling all rpy files into rpyc files..."
new "すべての rpy ファイルを rpyc ファイルにコンパイルしています。"
# game/front_page.rpy:245
old "iOS"
new "iOS"
+100
View File
@@ -0,0 +1,100 @@
# TODO: Translation updated at 2015-01-25 08:59
translate japanese strings:
# game/ios.rpy:28
old "To build iOS packages, please download renios, unzip it, and place it into the Ren'Py directory. Then restart the Ren'Py launcher."
new "iOS パッケージをビルドするには、 renios をダウンロードして、Ren'Py ディレクトリーに配置、ランチャーを再起動してください。"
# game/ios.rpy:29
old "The directory in where Xcode projects will be placed has not been selected. Choose 'Select Directory' to select it."
new "'Select Directory' から、 xcode プロジェクトが配置されるディレクトリーを選択してください。"
# game/ios.rpy:30
old "There is no Xcode project corresponding to the current Ren'Py project. Choose 'Create Xcode Project' to create one."
new "現在の Ren'Py プロジェクトに対応する Xcode プロジェクトがありません。'Create Xcode Project' から作成してください。"
# game/ios.rpy:31
old "An Xcode project exists. Choose 'Update Xcode Project' to update it with the latest game files, or use Xcode to build and install it."
new "Xcode プロジェクトが存在します。'Update Xcode Project' を選択して最新のゲームファイルに更新するか、 Xcode を使用してそれをビルド、インストールしてください。"
# game/ios.rpy:33
old "Attempts to emulate an iPhone.\n\nTouch input is emulated through the mouse, but only when the button is held down."
new "iPhone をエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみ反応します"
# game/ios.rpy:34
old "Attempts to emulate an iPad.\n\nTouch input is emulated through the mouse, but only when the button is held down."
new "iPad をエミュレートします。\n\nタッチ入力はマウスを利用してエミュレートされますが、ボタン押下時のみ反応します"
# game/ios.rpy:36
old "Selects the directory where Xcode projects will be placed."
new "Xcode プロジェクトが配置されるディレクトリーを選択します。"
# game/ios.rpy:37
old "Creates an Xcode project corresponding to the current Ren'Py project."
new "現在の Ren'PY プロジェクトに対応する Xcode プロジェクトを作成します。"
# game/ios.rpy:38
old "Updates the Xcode project with the latest game files. This must be done each time the Ren'Py project changes."
new "最新のゲームファイルに Xcode プロジェクトを更新します。これは Ren'Py プロジェクトが変更される度に行わなければなりません。"
# game/ios.rpy:39
old "Opens the Xcode project in Xcode."
new "Xcode から Xcode プロジェクトを開きます。"
# game/ios.rpy:41
old "Opens the directory containing Xcode projects."
new "対応する Xcode プロジェクトを開きます。"
# game/ios.rpy:126
old "The Xcode project already exists. Would you like to rename the old project, and replace it with a new one?"
new "その Xcode プロジェクトは既に存在します。古いプロジェクトをリネームするか、新しいもので置き換えますか?"
# game/ios.rpy:202
old "iOS: [project.current.name!q]"
new "iOS: [project.current.name!q]"
# game/ios.rpy:231
old "iPhone"
new "iPhone"
# game/ios.rpy:235
old "iPad"
new "iPad"
# game/ios.rpy:255
old "Select Xcode Projects Directory"
new "Xcode プロジェクトディレクトリーを選択してください。"
# game/ios.rpy:259
old "Create Xcode Project"
new "Xcode プロジェクトを作成してください。"
# game/ios.rpy:263
old "Update Xcode Project"
new "Xcode プロジェクトを更新してください。"
# game/ios.rpy:268
old "Launch Xcode"
new "Xcode 起動"
# game/ios.rpy:303
old "Open Xcode Projects Directory"
new "Xcode プロジェクトディレクトリーを開いてください。"
# game/ios.rpy:336
old "Before packaging iOS apps, you'll need to download renios, Ren'Py's iOS support. Would you like to download renios now?"
new "iOS アプリをパッケージする前に、reniosをダウンロードする必要があります。 renios をダウンロードしますか?"
# game/ios.rpy:345
old "XCODE PROJECTS DIRECTORY"
new "XCODE PROJECTS DIRECTORY"
# game/ios.rpy:345
old "Please choose the Xcode Projects Directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
new "Xcode プロジェクトディレクトリーを選択してください。\n{b}ディレクトリー選択ウィンドウはこのウィンドウの裏に開くかもしれません。{/b}"
# game/ios.rpy:350
old "Ren'Py has set the Xcode Projects Directory to:"
new "Ren'Py は Xcode プロジェクトディレクトリーを以下に設定しました。:"
+41 -1
View File
@@ -371,7 +371,7 @@ translate spanish strings:
# renpy/common/_developer/developer.rpym:58
old "Image Location Picker"
new "Image Location Picker"
new "Selector de posición en imágenes"
# renpy/common/_developer/developer.rpym:61
old "Filename List"
@@ -505,3 +505,43 @@ translate spanish strings:
old "Self-voicing enabled. Press 'v' to disable."
new "Self-voicing activado. Presiona 'v' para desactivarlo."
# renpy/common/00preferences.rpy:387
old "Clipboard voicing enabled. Press 'shift+C' to disable."
new "'Portapapeles a voz' activado. Pulsa 'Mayús.+C' para desactivarlo."
# renpy/common/00updater.rpy:362
old "The Ren'Py Updater is not supported on mobile devices."
new "El Actualizador de Ren'Py no es compatible con dispositivos móviles."
# renpy/common/00updater.rpy:478
old "An error is being simulated."
new "Se simula un error."
# renpy/common/00updater.rpy:654
old "Either this project does not support updating, or the update status file was deleted."
new "O bien este proyecto no es compatible con la actualización o el archivo de estado de la actualización se ha eliminado."
# renpy/common/00updater.rpy:668
old "This account does not have permission to perform an update."
new "Esta cuenta no tiene permiso para realizar una actualización."
# renpy/common/00updater.rpy:671
old "This account does not have permission to write the update log."
new "Esta cuenta no tiene permiso para escribir en el registro de actualización."
# renpy/common/00updater.rpy:696
old "Could not verify update signature."
new "No se pudo verificar la actualización de firmas."
# renpy/common/00updater.rpy:956
old "The update file was not downloaded."
new "El archivo de actualización no se ha descargado."
# renpy/common/00updater.rpy:974
old "The update file does not have the correct digest - it may have been corrupted."
new "El archivo de actualización no tiene el 'digest' correcto - es posible que esté dañado."
# renpy/common/00updater.rpy:1030
old "While unpacking {}, unknown type {}."
new "Tipo desconocido {1} al desempaquetar {0}."
+5 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -24,6 +24,9 @@ init python:
if persistent.translate_language is None:
persistent.translate_language = "english"
if persistent.generate_empty_strings is None:
persistent.generate_empty_strings = True
label translate:
python:
@@ -41,7 +44,7 @@ label translate:
if language == "rot13":
args.append("--rot13")
else:
elif persistent.generate_empty_strings:
args.append("--empty")
interface.processing(_("Ren'Py is generating translations...."))
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+46 -149
View File
@@ -65,23 +65,23 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
Uint8 *palette_alpha=NULL;
png_byte **row_pointers=NULL;
png_ptr=NULL;info_ptr=NULL;palette=NULL;ret=-1;
funky_format=0;
SDL_BlendMode temp_blend;
Uint32 target_format;
if( !src || !surf) {
goto savedone; /* Nothing to do. */
goto savedone2; /* Nothing to do. */
}
row_pointers=(png_byte **)malloc(surf->h * sizeof(png_byte*));
if (!row_pointers) {
SDL_SetError("Couldn't allocate memory for rowpointers");
goto savedone;
goto savedone2;
}
png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
if (!png_ptr){
SDL_SetError("Couldn't allocate memory for PNG file");
goto savedone;
SDL_SetError("Couldn't allocate memory for PNG file version: " PNG_LIBPNG_VER_STRING);
goto savedone2;
}
info_ptr= png_create_info_struct(png_ptr);
if (!info_ptr){
@@ -104,172 +104,69 @@ int IMG_SavePNG_RW(SDL_RWops *src, SDL_Surface *surf,int compression){
png_set_filter(png_ptr,0,PNG_FILTER_NONE);
png_set_compression_level(png_ptr,Z_NO_COMPRESSION);
}
else if(compression<0) // Default compression
else if(compression<0) // Default compression
png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
else
else
png_set_compression_level(png_ptr,compression);
fmt=surf->format;
if(fmt->BitsPerPixel==8){ /* Paletted */
if (fmt->Amask) {
png_set_IHDR(png_ptr,info_ptr,
surf->w,surf->h,8,PNG_COLOR_TYPE_PALETTE,
surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_set_IHDR(png_ptr,info_ptr,
surf->w,surf->h,8,PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
palette=(png_colorp) malloc(fmt->palette->ncolors * sizeof(png_color));
if (!palette) {
SDL_SetError("Couldn't create memory for palette");
goto savedone;
}
for (i=0;i<fmt->palette->ncolors;i++) {
palette[i].red=fmt->palette->colors[i].r;
palette[i].green=fmt->palette->colors[i].g;
palette[i].blue=fmt->palette->colors[i].b;
}
png_set_PLTE(png_ptr,info_ptr,palette,fmt->palette->ncolors);
// if (surf->flags&SDL_SRCCOLORKEY) {
// palette_alpha=(Uint8 *)malloc((fmt->colorkey+1)*sizeof(Uint8));
// if (!palette_alpha) {
// SDL_SetError("Couldn't create memory for palette transparency");
// goto savedone;
// }
// /* FIXME: memset? */
// for (i=0;i<(fmt->colorkey+1);i++) {
// palette_alpha[i]=255;
// }
// palette_alpha[fmt->colorkey]=0;
// png_set_tRNS(png_ptr,info_ptr,palette_alpha,fmt->colorkey+1,NULL);
// }
}else{ /* Truecolor */
if (fmt->Amask) {
png_set_IHDR(png_ptr,info_ptr,
surf->w,surf->h,8,PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
} else {
png_set_IHDR(png_ptr,info_ptr,
surf->w,surf->h,8,PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
}
}
png_write_info(png_ptr, info_ptr);
if (fmt->BitsPerPixel==8) { /* Paletted */
for(i=0;i<surf->h;i++){
row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch;
}
if(SDL_MUSTLOCK(surf)){
SDL_LockSurface(surf);
}
png_write_image(png_ptr, row_pointers);
if(SDL_MUSTLOCK(surf)){
SDL_UnlockSurface(surf);
}
}else{ /* Truecolor */
if(fmt->BytesPerPixel==3){
if(fmt->Amask){ /* check for 24 bit with alpha */
funky_format=1;
}else{
/* Check for RGB/BGR/GBR/RBG/etc surfaces.*/
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
if(fmt->Rmask!=0xFF0000
|| fmt->Gmask!=0x00FF00
|| fmt->Bmask!=0x0000FF){
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
if (fmt->Amask) {
target_format = SDL_PIXELFORMAT_ABGR8888;
} else {
target_format = SDL_PIXELFORMAT_BGR888;
}
#else
if(fmt->Rmask!=0x0000FF
|| fmt->Gmask!=0x00FF00
|| fmt->Bmask!=0xFF0000){
if (fmt->Amask) {
target_format = SDL_PIXELFORMAT_RGBA8888
} else {
target_format = SDL_PIXELFORMAT_RGB888;
}
#endif
funky_format=1;
}
}
}else if (fmt->BytesPerPixel==4){
if (!fmt->Amask) { /* check for 32bit but no alpha */
funky_format=1;
}else{
/* Check for ARGB/ABGR/GBAR/RABG/etc surfaces.*/
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
if(fmt->Rmask!=0xFF000000
|| fmt->Gmask!=0x00FF0000
|| fmt->Bmask!=0x0000FF00
|| fmt->Amask!=0x000000FF){
#else
if(fmt->Rmask!=0x000000FF
|| fmt->Gmask!=0x0000FF00
|| fmt->Bmask!=0x00FF0000
|| fmt->Amask!=0xFF000000){
#endif
funky_format=1;
}
}
}else{ /* 555 or 565 16 bit color */
funky_format=1;
if (surf->format->format != target_format) {
tempsurf = SDL_ConvertSurfaceFormat(surf, target_format, 0);
surf = tempsurf;
if (!tempsurf){
SDL_SetError("Couldn't allocate temp surface");
goto savedone;
}
if (funky_format) {
/* Allocate non-funky format, and copy pixeldata in*/
if(fmt->Amask){
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
#else
tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
#endif
}else{
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
0xff0000, 0x00ff00, 0x0000ff, 0x00000000);
#else
tempsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, surf->w, surf->h, 24,
0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000);
#endif
}
if(!tempsurf){
SDL_SetError("Couldn't allocate temp surface");
goto savedone;
}
}
SDL_GetSurfaceBlendMode(surf, &temp_blend);
SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE);
for(i=0;i < surf->h;i++){
row_pointers[i]= ((png_byte*) surf->pixels) + i * surf->pitch;
}
if(SDL_BlitSurface(surf,NULL,tempsurf,NULL)!=0){
SDL_SetError("Couldn't blit surface to temp surface");
SDL_FreeSurface(tempsurf);
goto savedone;
}
png_write_image(png_ptr, row_pointers);
SDL_SetSurfaceBlendMode(surf, temp_blend);
for(i=0;i<tempsurf->h;i++){
row_pointers[i]= ((png_byte*)tempsurf->pixels) + i*tempsurf->pitch;
}
if(SDL_MUSTLOCK(tempsurf)){
SDL_LockSurface(tempsurf);
}
png_write_image(png_ptr, row_pointers);
if(SDL_MUSTLOCK(tempsurf)){
SDL_UnlockSurface(tempsurf);
}
SDL_FreeSurface(tempsurf);
} else {
for(i=0;i<surf->h;i++){
row_pointers[i]= ((png_byte*)surf->pixels) + i*surf->pitch;
}
if(SDL_MUSTLOCK(surf)){
SDL_LockSurface(surf);
}
png_write_image(png_ptr, row_pointers);
if(SDL_MUSTLOCK(surf)){
SDL_UnlockSurface(surf);
}
}
if (tempsurf) {
SDL_FreeSurface(tempsurf);
}
png_write_end(png_ptr, NULL);
ret=0; /* got here, so nothing went wrong. YAY! */
savedone: /* clean up and return */
png_destroy_write_struct(&png_ptr,&info_ptr);
savedone2:
if (palette) {
free(palette);
}
+2 -2
View File
@@ -1,5 +1,5 @@
# -*- python -*-
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -421,6 +421,6 @@ def subpixel(pysrc, pydst, xoffset, yoffset, shift):
# Be sure to update scale.py when adding something new here!
import_pygame_sdl2__rwobject()
import_pygame_sdl2()
core_init()
subpixel_init()
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+520
View File
@@ -0,0 +1,520 @@
# Copyright 2004-2015 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.
cdef extern from "steam/steam_api.h":
ctypedef bint bool
ctypedef int int32
ctypedef unsigned int uint32
# Init.
bool SteamAPI_Init()
void SteamAPI_RunCallbacks()
bool SteamAPI_RestartAppIfNecessary(unsigned int)
# Stats & Achievements.
cdef cppclass ISteamUserStats:
bool RequestCurrentStats()
bool StoreStats()
bool GetAchievement(const char *pchName, bool *pbAchieved);
bool SetAchievement(const char *pchName);
bool ClearAchievement(const char *pchName);
bool IndicateAchievementProgress(const char *pchName, uint32 nCurProgress, uint32 nMaxProgress)
int GetNumAchievements()
char *GetAchievementName(int)
bool GetStat(const char *pchName, int32 *pData)
bool GetStat(const char *pchName, float *pData)
bool SetStat(const char *pchName, int32 iData)
bool SetStat(const char *pchName, float fData)
ctypedef struct UserStatsReceived_t
ISteamUserStats *SteamUserStats()
# Utils.
cdef enum ENotificationPosition:
k_EPositionTopLeft
k_EPositionTopRight
k_EPositionBottomLeft
k_EPositionBottomRight
cdef cppclass ISteamUtils:
bint IsOverlayEnabled()
void SetOverlayNotificationPosition(ENotificationPosition eNotificationPosition)
ISteamUtils *SteamUtils()
# Apps.
ctypedef int AppId_t
cdef cppclass ISteamApps:
bool BIsSubscribedApp(AppId_t appID)
const char *GetCurrentGameLanguage()
bool GetCurrentBetaName( char *pchName, int cchNameBufferSize );
bool BIsDlcInstalled(AppId_t nAppID)
void InstallDLC(AppId_t nAppID)
void UninstallDLC(AppId_t nAppID)
ctypedef struct DlcInstalled_t:
AppId_t m_nAppID
ISteamApps *SteamApps()
# Friends.
cdef enum EOverlayToStoreFlag:
k_EOverlayToStoreFlag_None
k_EOverlayToStoreFlag_AddToCart
k_EOverlayToStoreFlag_AddToCartAndShow
cdef cppclass ISteamFriends:
const char *GetPersonaName()
void ActivateGameOverlay(const char *pchDialog)
void ActivateGameOverlayToWebPage(const char *pchURL)
void ActivateGameOverlayToStore(AppId_t nAppID, EOverlayToStoreFlag eFlag)
ISteamFriends *SteamFriends()
# User.
ctypedef uint32 AccountID_t
ctypedef uint32 HAuthTicket
cdef cppclass CSteamID:
AccountID_t GetAccountID()
cdef cppclass ISteamUser:
CSteamID GetSteamID()
HAuthTicket GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket)
void CancelAuthTicket(HAuthTicket hAuthTicket)
ISteamUser *SteamUser()
cdef extern from "steamcallbacks.h":
cdef cppclass SteamCallback[T]:
SteamCallback(void (*)(T *))
import renpy
######################################################### Stats and Achievements
# A callable that is called when the stats are available.
got_stats = None
cdef void call_got_stats(UserStatsReceived_t *s):
if got_stats is not None:
got_stats()
cdef SteamCallback[UserStatsReceived_t] *stats_received_callback = \
new SteamCallback[UserStatsReceived_t](call_got_stats)
def retrieve_stats(callback):
"""
:doc: steam_stats
Retrieves achievements and statistics from Steam. `callback` will be
called with no parameters if and when the statistics become available.
"""
global got_stats
got_stats = callback
print SteamUserStats().RequestCurrentStats()
def store_stats():
"""
:doc: steam_stats
Stores statistics and achievements on the Steam server.
"""
SteamUserStats().StoreStats()
def list_achievements():
"""
:doc: steam_stats
Returns a list of achievement names.
"""
rv = [ ]
cdef int na = SteamUserStats().GetNumAchievements()
cdef char *s
cdef int i
for 0 <= i < na:
s = <char *> SteamUserStats().GetAchievementName(i)
rv.append(s)
return rv
def get_achievement(name):
"""
:doc: steam_stats
Gets the state of the achievements with `name`. This returns True if the
achievement has been granted, False if it hasn't, and None if the achievement
is unknown or an error occurs.
"""
cdef bool rv
if not SteamUserStats().GetAchievement(name, &rv):
return None
return rv
def grant_achievement(name):
"""
:doc: steam_stats
Grants the achievement with `name`. Call :func:`_renpysteam.store_stats` to
push this change to the server.
"""
return SteamUserStats().SetAchievement(name)
def clear_achievement(name):
"""
:doc: steam_stats
Clears the achievement with `name`. Call :func:`_renpysteam.store_stats` to
push this change to the server.
"""
return SteamUserStats().ClearAchievement(name)
def indicate_achievement_progress(name, cur_progress, max_progress):
"""
:doc: steam_stats
Indicates achievement progress to the user. This does *not* unlock the
achievement.
"""
return SteamUserStats().IndicateAchievementProgress(name, cur_progress, max_progress)
def get_float_stat(name):
"""
:doc: steam_stats
Returns the value of the stat with `name`, or None if no such stat
exits.
"""
cdef float rv
if not SteamUserStats().GetStat(<char *> name, &rv):
return None
return rv
def set_float_stat(name, value):
"""
:doc: steam_stats
Sets the value of the stat with `name`, which must have the type of
FLOAT. Call :func:`_renpysteam.store_stats` to push this change to the
server.
"""
cdef float v = value
return SteamUserStats().SetStat(<char *> name, v)
def get_int_stat(name):
"""
:doc: steam_stats
Returns the value of the stat with `name`, or None if no such stat
exits.
"""
cdef int32 rv
if not SteamUserStats().GetStat(<char *> name, &rv):
return None
return rv
def set_int_stat(name, value):
"""
:doc: steam_stats
Sets the value of the stat with `name`, which must have the type of
INT. Call :func:`_renpysteam.store_stats` to push this change to the
server.
"""
cdef int32 v
return SteamUserStats().SetStat(<char *> name, v)
########################################################################### Apps
def is_subscribed_app(appid):
"""
:doc: steam_apps
Returns true if the user owns the app with `appid`, and false otherwise.
"""
return SteamApps().BIsSubscribedApp(appid)
def get_current_game_language():
"""
:doc: steam_apps
Return the name of the language the user has selected.
"""
cdef const char *s = SteamApps().GetCurrentGameLanguage()
return str(s)
def get_current_beta_name():
"""
:doc: steam_apps
Returns the name of the current beta, or None if it can't.
"""
cdef char rv[256]
if not SteamApps().GetCurrentBetaName(rv, 256):
return None
return str(rv)
def dlc_installed(appid):
"""
:doc: steam_apps
Returns True if `dlc` is installed, or False otherwise.
"""
return SteamApps().BIsDlcInstalled(appid)
# A callable that is called when the stats are available.
got_dlc = None
cdef void call_got_dlc(DlcInstalled_t *s):
if got_dlc is not None:
got_dlc(s.m_nAppID)
cdef SteamCallback[DlcInstalled_t] *dlc_callback = \
new SteamCallback[DlcInstalled_t](call_got_dlc)
def install_dlc(appid, callback):
"""
:doc: steam_apps
Requests the DLC with `appid` be installed. If not None, `callback`
will be called with `appid` when the install finishes. Only one
callback can be registered at a time.
"""
global got_dlc
got_dlc = callback
SteamApps().InstallDLC(appid)
def uninstall_dlc(appid):
"""
:doc: steam_apps
Requests that the DLC with `appid` be uninstalled.
"""
SteamApps().UninstallDLC(appid)
######################################################################## Overlay
def is_overlay_enabled():
"""
:doc: steam_overlay
Returns true if the steam overlay is enabled. (This might take a while to
return true once the game starts.)
"""
return SteamUtils().IsOverlayEnabled()
POSITION_TOP_LEFT = k_EPositionTopLeft
POSITION_TOP_RIGHT = k_EPositionTopRight
POSITION_BOTTOM_LEFT = k_EPositionBottomLeft
POSITION_BOTTOM_RIGHT = k_EPositionBottomRight
def set_overlay_notification_position(position):
"""
:doc: steam_overlay
Sets the position of the steam overlay. `Position` should be one of
_renpysteam.POSTION_TOP_LEFT, .POSITION_TOP_RIGHT, .POSITION_BOTTOM_LEFT,
or .POSITION_BOTTOM_RIGHT.
"""
SteamUtils().SetOverlayNotificationPosition(position)
def activate_overlay(dialog):
"""
:doc: steam_overlay
Activates the Steam overlay.
`dialog`
The dialog to open the overlay to. One of "Friends", "Community",
"Players", "Settings", "OfficialGameGroup", "Stats", "Achievements"
"""
SteamFriends().ActivateGameOverlay(dialog)
def activate_overlay_to_web_page(url):
"""
:doc: steam_overlay
Activates the Steam overlay, and opens the web page at `url`.
"""
SteamFriends().ActivateGameOverlayToWebPage(url)
STORE_NONE = k_EOverlayToStoreFlag_None
STORE_ADD_TO_CART = k_EOverlayToStoreFlag_AddToCart
STORE_ADD_TO_CART_AND_SHOW = k_EOverlayToStoreFlag_AddToCartAndShow
def activate_overlay_to_store(appid, flag=STORE_NONE):
"""
:doc: steam_overlay
Opens the steam overlay to the store.
`appid`
The appid to open.
`flag`
One of _renpysteam.STORE_NONE, .STORE_ADD_TO_CART, or .STORE_ADD_TO_CART_AND_SHOW.
"""
SteamFriends().ActivateGameOverlayToStore(appid, flag)
########################################################################### User
def get_persona_name():
"""
:doc: steam_user
Returns the user's publicly-visible name.
"""
return SteamFriends().GetPersonaName().decode("utf-8")
def get_account_id():
"""
:doc: steam_user
Returns the user's account ID.
"""
return SteamUser().GetSteamID().GetAccountID()
cdef HAuthTicket h_ticket = 0
ticket = None
def get_session_ticket():
"""
:doc: steam_user
Gets a ticket that can be sent to the server to authenticate this user.
"""
global ticket
global h_ticket
cdef char ticket_buf[2048]
cdef uint32 ticket_len
if ticket is not None:
return ticket
h_ticket = SteamUser().GetAuthSessionTicket(ticket_buf, 2048, &ticket_len)
if h_ticket:
ticket = ticket_buf[0:ticket_len]
return ticket
def cancel_ticket():
"""
:doc: steam_user
Cancels the ticket returned by :func:`_renpysteam.get_session_ticket`.
"""
global h_ticket
global tocket
SteamUser().CancelAuthTicket(h_ticket)
h_ticket = 0
ticket = None
################################################################# Initialization
# Have we been initialized?
initialized = None
# Called periodically to run callbacks.
def periodic():
SteamAPI_RunCallbacks()
# Initialize the Steam API.
def init():
"""
:doc: steam
Initializes the Steam API. Returns true for success, false for failure.
If a failure has occurred, no other steam functions should be called.
This may be called multiple times, but only attempts initialization the
first time it's been called.
"""
global initialized
if initialized is None:
initialized = SteamAPI_Init()
if initialized:
renpy.config.periodic_callbacks.append(periodic)
set_overlay_notification_position(POSITION_TOP_RIGHT)
return initialized
+2 -2
View File
@@ -1,7 +1,7 @@
#include "renpy.h"
#include "IMG_savepng.h"
#include <SDL.h>
#include <pygame_sdl2/pygame_sdl2.surface_api.h>
#include <pygame_sdl2/pygame_sdl2.h>
#include <stdio.h>
#include <math.h>
@@ -22,7 +22,7 @@
/* Initializes the stuff found in this file.
*/
void core_init() {
import_pygame_sdl2__surface();
import_pygame_sdl2();
}
void save_png_core(PyObject *pysurf, SDL_RWops *rw, int compress) {
+20 -8
View File
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>
#include <SDL.h>
#include <SDL_syswm.h>
#include "pygame_sdl2/pygame_sdl2.h"
#include "EGL/egl.h"
#include "GLES2/gl2.h"
@@ -13,6 +14,7 @@ EGLSurface surface;
EGLConfig config;
EGLContext context;
int imported_pygame = 0;
int initialized = 0;
char error_message[100];
@@ -45,6 +47,7 @@ char *egl_init(int interval) {
SDL_SysWMinfo wminfo;
EGLint major, minor;
EGLint num_config;
HWND new_window;
const EGLint attrs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
@@ -57,12 +60,21 @@ char *egl_init(int interval) {
EGL_NONE
};
if (!imported_pygame) {
import_pygame_sdl2();
imported_pygame = 1;
}
SDL_Window *sdl_window = PyWindow_AsWindow(Py_None);
SDL_VERSION(&wminfo.version);
SDL_GetWMInfo(&wminfo);
SDL_GetWindowWMInfo(sdl_window, &wminfo);
new_window = wminfo.info.win.window;
if (! initialized) {
display = eglGetDisplay(GetDC(wminfo.window));
display = eglGetDisplay(GetDC(new_window));
egl_check("getting display");
eglInitialize(display, &major, &minor);
@@ -77,16 +89,16 @@ char *egl_init(int interval) {
context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attrs);
egl_check("creating EGL context");
surface = eglCreateWindowSurface(display, config, wminfo.window, NULL);
surface = eglCreateWindowSurface(display, config, new_window, NULL);
egl_check("creating EGL surface");
} else if (window != wminfo.window) {
} else if (window != wminfo.info.win.window) {
eglDestroySurface(display, surface);
egl_check("destroying existing EGL surface")
surface = eglCreateWindowSurface(display, config, wminfo.window, NULL);
surface = eglCreateWindowSurface(display, config, new_window, NULL);
egl_check("creating EGL surface");
}
@@ -98,7 +110,7 @@ char *egl_init(int interval) {
egl_check("setting swap interval")
initialized = 1;
window = wminfo.window;
window = new_window;
return NULL;
}
+2 -2
View File
@@ -1,6 +1,6 @@
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_syswm.h>
#include <SDL.h>
#include <SDL_syswm.h>
#include "EGL/egl.h"
#include "GLES2/gl2.h"
+22 -12
View File
@@ -22,6 +22,7 @@
#include <math.h>
#include <limits.h>
#include <libavutil/avstring.h>
#include <libavutil/time.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
@@ -34,7 +35,7 @@
#include <SDL.h>
#include <SDL_thread.h>
#include <pygame_sdl2/pygame_sdl2.surface_api.h>
#include <pygame_sdl2/pygame_sdl2.h>
#ifdef __MINGW32__
#undef main /* We don't want SDL to override our main() */
@@ -176,6 +177,12 @@ typedef struct VideoState {
// The PTS of the first frame.
double first_frame_pts;
// Is the is the first audio?
int first_audio;
// The PTS of the first audio.
double first_audio_clock;
#ifdef HAS_RESAMPLE
// The audio frame, and the audio resample context.
enum AVSampleFormat sdl_sample_fmt;
@@ -489,7 +496,7 @@ static double get_audio_clock(VideoState *is, int adjust)
double altpts;
double offset;
int hw_buf_size, bytes_per_sec;
pts = is->audio_clock;
pts = is->audio_clock - is->first_audio_clock;
hw_buf_size = audio_write_get_buf_size(is);
bytes_per_sec = 0;
if (is->audio_st) {
@@ -519,7 +526,6 @@ static double get_audio_clock(VideoState *is, int adjust)
}
if (adjust) {
if (offset > 0) {
is->start_time += .00025;
} else {
@@ -559,14 +565,12 @@ static int video_refresh(void *opaque)
is->first_frame_pts = vp->pts;
}
delay = get_audio_clock(is, 0) - vp->pts;
delay += is->first_frame_pts;
delay = get_audio_clock(is, 0) - (vp->pts - is->first_frame_pts);
/* The video is ahead of the audio. */
if (delay < 0 && !is->first_frame) {
return 0;
}
// Adjust the audio clock.
get_audio_clock(is, 1);
@@ -574,11 +578,11 @@ static int video_refresh(void *opaque)
video_display(is);
}
is->first_frame = 0;
av_free(vp->frame);
vp->frame = NULL;
is->first_frame = 0;
/* update queue size and signal for next picture */
if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
is->pictq_rindex = 0;
@@ -968,6 +972,11 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
/* if update the audio clock with the pts */
if (pkt->pts != AV_NOPTS_VALUE) {
is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
if (is->first_audio) {
is->first_audio_clock = is->audio_clock;
is->first_audio = 0;
}
}
}
}
@@ -1481,9 +1490,9 @@ static int decode_thread(void *arg)
is->show_audio = 0;
}
if (is->video_stream < 0 && is->audio_stream < 0) {
fprintf(stderr, "could not open codecs\n");
ret = -1;
if (is->audio_stream < 0) {
printf("%s audio stream could not be opened.\n", is->filename);
ret = -1;
goto fail;
}
@@ -1610,6 +1619,7 @@ VideoState *ffpy_stream_open(SDL_RWops *rwops, const char *filename)
is->parse_tid = SDL_CreateThread(decode_thread, "decode_thread", is);
is->first_frame = 1;
is->first_audio = 1;
if (!is->parse_tid) {
av_free(is);
@@ -1666,7 +1676,7 @@ void ffpy_init(int rate, int status) {
ffpy_did_init = 1;
import_pygame_sdl2__surface();
import_pygame_sdl2();
show_status = status;
+21 -21
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -413,6 +413,7 @@ def generate_constants():
g.close()
def generate_property_function(g, prefix, propname, properties):
name = prefix.name + propname
g.write("cdef int {name}_property(PyObject **cache, int *cache_priorities, int priority, object value) except -1:", name=name)
@@ -457,41 +458,41 @@ def generate_property_functions():
This generates code that defines the property functions.
"""
g = CodeGen("module/gen/stylepropertyfunctions.pxi")
for prefix in sorted(prefixes.values(), key=lambda p : p.index):
g = CodeGen("module/gen/style_{}functions.pyx".format(prefix.name))
for propname, proplist in all_properties.items():
for prefix in sorted(prefixes.values(), key=lambda p : p.index):
g.write('include "style_common.pxi"')
g.write('')
for propname, proplist in all_properties.items():
generate_property_function(g, prefix, propname, proplist)
g.close()
g.close()
def generate_property(g, propname, prefix):
def generate_property(g, propname):
"""
This generates the code for a single property on the style object.
"""
name = prefix.name + propname
g.write("property {}:", name)
g.write("property {}:", propname)
g.indent()
if name in style_properties:
# __get__
g.write("def __get__(self):")
g.indent()
g.write("return self._get({})", style_property_index[propname])
g.dedent()
# __get__
g.write("def __get__(self):")
g.indent()
g.write("return self._get({})", style_property_index[propname])
g.dedent()
# __set__
g.write("def __set__(self, value):")
g.indent()
g.write("self.properties.append({{ '{}' : value }})", name)
g.write("self.properties.append({{ '{}' : value }})", propname)
g.dedent()
# __del__
g.write("def __del__(self):")
g.indent()
g.write("self.delattr('{}')", name)
g.write("self.delattr('{}')", propname)
g.dedent()
g.dedent()
@@ -499,16 +500,15 @@ def generate_property(g, propname, prefix):
def generate_properties():
g = CodeGen("module/gen/styleproperties.pxi")
g = CodeGen("module/gen/styleclass.pxi")
g.write("cdef class Style(StyleCore):")
g.write("")
g.indent()
for propname in all_properties:
for prefix in sorted(prefixes.values(), key=lambda p : p.index):
generate_property(g, propname, prefix)
for propname in style_properties:
generate_property(g, propname)
g.dedent()
g.close()
+22 -5
View File
@@ -10,17 +10,28 @@
// identifier. So get rid of it here.
#undef environ
#if defined __APPLE__
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
#define IOS
#endif
#endif
#if defined ANDROID
#define RENPY_GLES_2
#define RENPY_GLES_2
#elif defined ANGLE
#define RENPY_GLES_2
#define RENPY_GLES_2
#elif defined IOS
#define RENPY_GLES_2
#else
#define RENPY_OPENGL
#define RENPY_OPENGL
#endif
@@ -54,11 +65,15 @@
#if defined RENPY_GLES_2
#ifndef ANDROID
#ifdef ANGLE
#include <EGL/egl.h>
#endif
#ifdef IOS
#include <OpenGLES/ES2/gl.h>
#else
#include <GLES2/gl2.h>
#endif
typedef GLuint GLhandleARB;
typedef GLchar GLcharARB;
@@ -66,6 +81,7 @@ typedef GLchar GLcharARB;
#define GL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_IMAGE_UNITS
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER
#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
#define glBindFramebufferEXT glBindFramebuffer
#define glFramebufferTexture2DEXT glFramebufferTexture2D
@@ -113,7 +129,7 @@ typedef GLfloat GLdouble;
#define glClipPlane glClipPlanef
// This isn't defined on GL ES, but that's okay, since we'll disable
// screenshots on Android.
// screenshots on Android/iOS.
#define GL_PACK_ROW_LENGTH 0
#define glClientActiveTextureARB glClientActiveTexture
@@ -121,6 +137,7 @@ typedef GLfloat GLdouble;
#define GL_BGRA GL_RGBA
#define GL_UNSIGNED_INT_8_8_8_8_REV GL_UNSIGNED_BYTE
#define GL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_IMAGE_UNITS
#endif
+1
View File
@@ -597,6 +597,7 @@ cdef extern from "pyfreetype.h":
FT_Fixed miter_limit )
void FT_Glyph_StrokeBorder(FT_Glyph *, FT_Stroker, FT_Bool, FT_Bool)
void FT_Glyph_Stroke(FT_Glyph *, FT_Stroker, FT_Bool)
void FT_Stroker_Done(FT_Stroker)
+4 -6
View File
@@ -1,10 +1,8 @@
from sdl2 cimport SDL_Surface, SDL_RWops
from sdl2 cimport SDL_Surface, SDL_RWops, SDL_Window
cdef extern from "pygame_sdl2/pygame_sdl2.rwobject_api.h":
void import_pygame_sdl2__rwobject()
cdef extern from "pygame_sdl2/pygame_sdl2.h":
int import_pygame_sdl2()
SDL_RWops* RWopsFromPython(object obj)
cdef extern from "pygame_sdl2/pygame_sdl2.surface_api.h":
int import_pygame_sdl2__surface()
SDL_Surface *PySurface_AsSurface(object)
SDL_Window *PyWindow_AsWindow(object)
+39
View File
@@ -0,0 +1,39 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import renpy
from renpy.style cimport register_property_function, assign
from cpython.ref cimport PyObject
from renpy.styledata.styleutil import none_is_null, expand_focus_mask, expand_outlines, expand_anchor
cdef inline object index_0(object v):
return v[0]
cdef inline object index_1(object v):
return v[1]
cdef inline object index_2(object v):
return v[2]
cdef inline object index_3(object v):
return v[3]
+174 -26
View File
@@ -26,11 +26,15 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# Modified in 2010 by PyTom to generate Cython code that uses glew.
from __future__ import print_function
# Modified in 2010,2014 by PyTom to generate Cython code that uses glew.
VERSION = "0.1"
import sys
import os
import re
#-----------------------------------------------------------------------
# Options
@@ -2570,6 +2574,88 @@ GLhandleARB = gltype("GLhandleARB")
GLstring = gltype("GLchar *")
GLcharARB = gltype("GLchar")
def exception_return(t):
if "*" in str(t):
return "NULL"
else:
return "0"
class GLFunction(object):
def __init__(self, type, name, args):
self.type = type
self.name = name
self.args = args
def declare_external(self, f):
print(' %s realGl%s "gl%s\" (%s)' % (
self.type,
self.name,
self.name,
", ".join(str(i) for i in self.args)
), file=f)
def declare_wrapper(self, f):
t = self.type
if t == GLvoid:
t = "int"
print('cdef %s gl%s(%s) except? %s' % (
t,
self.name,
", ".join(str(i) for i in self.args),
exception_return(self.type),
), file=f)
def define_wrapper(self, f):
t = self.type
if t == GLvoid:
t = "int"
print('cdef %s gl%s(%s) except? %s:' % (
t,
self.name,
", ".join(("%s a%d" % (t, i)) for i, t in enumerate(self.args)),
exception_return(self.type),
), file=f)
print(" if check_errors & 4:", file=f)
print(" renpy.display.log.write('gl%s')" % self.name, file=f)
print(" cdef GLenum error", file=f)
if self.type == GLvoid:
print(" realGl%s(%s)" % (
self.name,
", ".join(("a%d" % i) for i in range(len(self.args)))
), file=f)
else:
print(" cdef %s rv = realGl%s(%s)" % (
self.type,
self.name,
", ".join(("a%d" % i) for i in range(len(self.args)))
), file=f)
print(" if check_errors:", file=f)
print(" error = realGlGetError()", file=f)
print(" if error:", file=f)
print(" message = 'GL error %%x in gl%s' %% error" % self.name, file=f)
print(" if check_errors & 1:", file=f)
print(" renpy.display.log.write('%s', message)", file=f)
print(" if check_errors & 2:", file=f)
print(" raise Exception(message)", file=f)
if self.type == GLvoid:
print(" return 1", file=f)
else:
print(" return rv", file=f)
declarations = [ ]
def declare(*args):
global is_enum
is_enum = False
@@ -2579,21 +2665,19 @@ def declare(*args):
if isinstance(args[0], gltype):
type = args.pop(0) #@ReservedAssignment
else:
type = "void" #@ReservedAssignment
type = GLvoid #@ReservedAssignment
name = args.pop(0)
print " %s gl%s(%s)" % (
type,
name,
", ".join(str(i) for i in args))
declarations.append(GLFunction(type, name, args))
constants = [ ]
def constant(name):
constants.append("GL_" + name)
HEADER = """\
PXD_HEADER = """\
cdef extern from "glcompat.h":
ctypedef unsigned int GLenum
ctypedef unsigned char GLboolean
@@ -2618,34 +2702,98 @@ cdef extern from "glcompat.h":
ctypedef char GLcharARB
"""
FOOTER = """\
cdef inline gl_check(where):
cdef GLenum error
error = glGetError()
if error:
import renpy
renpy.display.log.write("GL error 0x%X at %s", error, where)
PYX_HEADER = """\
import os
import renpy
cdef int check_errors
check_errors = int(os.environ.get("RENPY_GL_CHECK_ERRORS", 0))
"""
def main():
out = sys.stdout
out.write(HEADER)
def find_gl_names(dirname, gl1):
names = set()
for i in os.listdir(dirname):
if not i.endswith('.pyx'):
continue
if i in [ "gl.pyx", "gl1.pyx" ]:
continue
GL1_FILES = [ "glenviron_fixed.pyx", "glenviron_limited.pyx" ]
if gl1:
if i not in GL1_FILES:
continue
else:
if i in GL1_FILES:
continue
fn = os.path.join(dirname, i)
with open(fn, "r") as f:
data = f.read()
for m in re.finditer(r'gl([A-Z]\w+)', data):
names.add(m.group(1))
rv = list(names)
rv.sort()
return rv
def generate(dirname, gl1):
if gl1:
prefix = "gl1"
else:
prefix = "gl"
names = find_gl_names(dirname, gl1)
global constants
constants = [ ]
global declarations
declarations = [ ]
generate_tegl()
constant("BGRA")
constant("BGRA")
constants.sort()
constants.append("RENPY_THIRD_TEXTURE")
print
print " enum:"
for i in constants:
print " %s" % i
decl_by_name = dict((i.name, i) for i in declarations)
print
print FOOTER
with open(os.path.join(dirname, prefix + ".pxd"), "w") as f:
print(PXD_HEADER, file=f)
print(file=f)
print(" enum:", file=f)
for i in constants:
print(" %s" % i, file=f)
print(file=f)
for i in declarations:
i.declare_external(f)
print(file=f)
for i in names:
decl_by_name[i].declare_wrapper(f)
with open(os.path.join(dirname, prefix + ".pyx"), "w") as f:
print(PYX_HEADER, file=f)
for i in names:
print(file=f)
decl_by_name[i].define_wrapper(f)
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if __name__ == '__main__':
main()
generate(os.path.join(root, "renpy", "gl"), False)
generate(os.path.join(root, "renpy", "gl"), True)
generate(os.path.join(root, "renpy", "angle"), False)
+3 -1
View File
@@ -26,6 +26,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <SDL.h>
#include <SDL_thread.h>
#include <stdio.h>
#include <strings.h>
/* Declarations of ffdecode functions. */
struct VideoState;
@@ -408,8 +409,9 @@ static void pan_audio(struct Channel *c, Uint8 *stream, int length) {
static void callback(void *userdata, Uint8 *stream, int length) {
int channel = 0;
for (channel = 0; channel < num_channels; channel++) {
bzero(stream, length);
for (channel = 0; channel < num_channels; channel++) {
int mixed = 0;
struct Channel *c = &channels[channel];
+5 -13
View File
@@ -1,5 +1,5 @@
# -*- python -*-
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -20,14 +20,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 extern from "SDL.h":
cdef struct SDL_RWops:
pass
cdef extern from "pygame_sdl2/pygame_sdl2.rwobject_api.h":
void import_pygame_sdl2__rwobject()
SDL_RWops* RWopsFromPythonThreaded(object obj)
from pygame_sdl2 cimport *
import_pygame_sdl2()
cdef extern from "pss.h":
@@ -68,7 +62,7 @@ def check_error():
def play(channel, file, name, paused=False, fadein=0, tight=False):
cdef SDL_RWops *rw
rw = RWopsFromPythonThreaded(file)
rw = RWopsFromPython(file)
if rw == NULL:
raise Exception, "Could not create RWops."
@@ -90,7 +84,7 @@ def play(channel, file, name, paused=False, fadein=0, tight=False):
def queue(channel, file, name, fadein=0, tight=False):
cdef SDL_RWops *rw
rw = RWopsFromPythonThreaded(file)
rw = RWopsFromPython(file)
if tight:
tight = 1
@@ -188,5 +182,3 @@ def movie_size():
def check_version(version):
if version < 2 or version > 4:
raise Exception("pysdlsound version mismatch.")
import_pygame_sdl2__rwobject()
+8 -3
View File
@@ -1,9 +1,14 @@
#include <Python.h>
#include <fribidi/fribidi.h>
#include <stdlib.h>
#ifndef alloca
#include <alloca.h>
#endif
/* This is easier than trying to figure out the header that alloca is */
/* defined in. */
void *alloca(size_t size);
// void *alloca(size_t size);
PyObject *renpybidi_log2vis(PyObject *s, int *direction) {
char *src;
@@ -12,7 +17,7 @@ PyObject *renpybidi_log2vis(PyObject *s, int *direction) {
int unisize;
FriBidiChar *dstuni;
char *dst;
src = PyString_AsString(s);
if (src == NULL) {
@@ -24,7 +29,7 @@ PyObject *renpybidi_log2vis(PyObject *s, int *direction) {
srcuni = (FriBidiChar *) alloca(size * 4);
dstuni = (FriBidiChar *) alloca(size * 4);
dst = (char *) alloca(size * 4);
unisize = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, src, size, srcuni);
fribidi_log2vis(
+47 -25
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -48,9 +48,10 @@ def setup_env(name):
setup_env("CC")
setup_env("LD")
setup_env("CXX")
import setuplib
from setuplib import android, include, library, cython, pymodule, copyfile, find_unnecessary_gen
from setuplib import android, ios, include, library, cython, pymodule, copyfile, find_unnecessary_gen
# These control the level of optimization versus debugging.
setuplib.extra_compile_args = [ "-Wno-unused-function" ]
@@ -86,14 +87,18 @@ has_fribidi = library("fribidi", optional=True)
library("z")
has_libglew = library("GLEW", optional=True)
has_libglew32 = library("glew32", optional=True)
has_angle = windows and library("EGL", optional=True) and library("GLESv2", optional=True)
if android:
sdl = [ 'sdl', 'GLESv2', 'log' ]
sdl = [ 'SDL2', 'GLESv2', 'log' ]
png = 'png16'
else:
sdl = [ 'SDL2' ]
png = 'png'
if has_fribidi:
if has_fribidi and (not android) and (not ios):
try:
# Some versions of fribidi require glib, and it doesn't hurt to include it in
# our path.
@@ -102,49 +107,63 @@ if has_fribidi:
except:
pass
steam_sdk = os.environ.get("RENPY_STEAM_SDK", None)
steam_platform = os.environ.get("RENPY_STEAM_PLATFORM", "")
if steam_sdk:
setuplib.library_dirs.append("{}/redistributable_bin/{}".format(steam_sdk, steam_platform))
setuplib.include_dirs.append("{}/public".format(steam_sdk))
# Modules directory.
cython(
"_renpy",
[ "IMG_savepng.c", "core.c", "subpixel.c"],
sdl + [ 'png', 'z', 'm' ])
sdl + [ png, 'z', 'm' ])
if has_fribidi and not android:
if has_fribidi:
cython(
"_renpybidi",
[ "renpybidicore.c" ],
['fribidi'], define_macros=[ ("FRIBIDI_ENTRY", "") ])
cython("_renpysteam", language="c++", compile_if=steam_sdk, libs=["steam_api"])
# Sound.
pymodule("pysdlsound.__init__")
if not android:
sound = [ "avformat", "avcodec", "avutil", "z" ]
macros = [ ]
sound = [ "avformat", "avcodec", "avutil", "z" ]
macros = [ ]
if has_avresample:
sound.insert(0, "avresample")
macros.append(("HAS_RESAMPLE", 1))
if has_avresample:
sound.insert(0, "avresample")
macros.append(("HAS_RESAMPLE", 1))
if has_swscale:
sound.insert(0, "swscale")
if has_swscale:
sound.insert(0, "swscale")
cython(
"pysdlsound.sound",
[ "pss.c", "ffdecode.c" ],
libs = sdl + sound,
define_macros=macros)
cython(
"pysdlsound.sound",
[ "pss.c", "ffdecode.c" ],
libs = sdl + sound,
define_macros=macros)
# renpy
cython("renpy.style")
cython("renpy.styleclass")
# cython("renpy.styleclass")
# renpy.styledata
cython("renpy.styledata.styleclass")
cython("renpy.styledata.stylesets")
for p in generate_styles.prefixes:
cython("renpy.styledata.style_{}functions".format(p), pyx="gen/style_{}functions.pyx".format(p))
# renpy.display
cython("renpy.display.render", libs=[ 'z', 'm' ])
cython("renpy.display.accelerator", libs=sdl + [ 'z', 'm' ])
# renpy.gl
if android:
if (android or ios):
glew_libs = [ 'GLESv2', 'z', 'm' ]
gl2_only = True
egl = "egl_none.c"
@@ -157,6 +176,8 @@ else:
gl2_only = False
egl = "egl_none.c"
cython("renpy.gl.gl", libs=glew_libs)
cython("renpy.gl.gl1", libs=glew_libs, compile_if=not gl2_only)
cython("renpy.gl.gldraw", libs=glew_libs, source=[ egl ])
cython("renpy.gl.gltexture", libs=glew_libs)
cython("renpy.gl.glenviron_shader", libs=glew_libs)
@@ -167,7 +188,7 @@ cython("renpy.gl.glrtt_fbo", libs=glew_libs)
# renpy.angle
def anglecopy(fn):
if android:
if (android or ios):
return
copyfile("renpy/gl/" + fn, "renpy/angle/" + fn, "DEF ANGLE = False", "DEF ANGLE = True")
@@ -176,17 +197,17 @@ anglecopy("glblacklist.py")
anglecopy("gldraw.pxd")
anglecopy("gldraw.pyx")
anglecopy("glenviron_shader.pyx")
anglecopy("gl.pxd")
anglecopy("glrtt_fbo.pyx")
anglecopy("glrtt_copy.pyx")
anglecopy("gltexture.pxd")
anglecopy("gltexture.pyx")
angle_libs = [ "SDL", "EGL", "GLESv2" ]
angle_libs = [ "SDL2", "EGL", "GLESv2" ]
def anglecython(name, source=[]):
cython(name, libs=angle_libs, compile_if=has_angle, define_macros=[ ( "ANGLE", None ) ], source=source)
anglecython("renpy.angle.gl")
anglecython("renpy.angle.gldraw", source=[ "egl_angle.c" ])
anglecython("renpy.angle.gltexture")
anglecython("renpy.angle.glenviron_shader")
@@ -206,6 +227,7 @@ find_unnecessary_gen()
# Figure out the version, and call setup.
sys.path.insert(0, '..')
import renpy
setuplib.setup("Ren'Py", renpy.version[7:])
+34 -11
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -31,6 +31,9 @@ import distutils.core
# This flag determines if we are compiling for Android or not.
android = "RENPY_ANDROID" in os.environ
# True if we're building on ios.
ios = "RENPY_IOS" in os.environ
# The cython command.
cython_command = os.environ.get("RENPY_CYTHON", "cython")
@@ -40,7 +43,7 @@ cython_command = os.environ.get("RENPY_CYTHON", "cython")
# The install variable is a list of directories that have Ren'Py
# dependencies installed in them.
if not android:
if not android or ios:
install = os.environ.get("RENPY_DEPS_INSTALL", "/usr")
install = install.split("::")
install = [ os.path.abspath(i) for i in install ]
@@ -66,7 +69,7 @@ def include(header, directory=None, optional=True):
If given, returns False rather than abandoning the process.
"""
if android:
if android or ios:
return True
for i in install:
@@ -105,7 +108,7 @@ def library(name, optional=False):
rather than reporting an error.
"""
if android:
if android or ios:
return True
for i in install:
@@ -135,7 +138,7 @@ extensions = [ ]
# A list of macros that are defined for all modules.
global_macros = [ ]
def cmodule(name, source, libs=[], define_macros=[]):
def cmodule(name, source, libs=[], define_macros=[], language="c"):
"""
Compiles the python module `name` from the files given in
`source`, and the libraries in `libs`.
@@ -150,12 +153,13 @@ def cmodule(name, source, libs=[], define_macros=[]):
extra_link_args=extra_link_args,
libraries=libs,
define_macros=define_macros + global_macros,
language=language,
))
necessary_gen = [ ]
def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
def cython(name, source=[], libs=[], compile_if=True, define_macros=[], pyx=None, language="c"):
"""
Compiles a cython module. This takes care of regenerating it as necessary
when it, or any of the files it depends on, changes.
@@ -164,7 +168,10 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
# Find the pyx file.
split_name = name.split(".")
fn = "/".join(split_name) + ".pyx"
if pyx is not None:
fn = pyx
else:
fn = "/".join(split_name) + ".pyx"
if os.path.exists(os.path.join("..", fn)):
fn = os.path.join("..", fn)
@@ -202,8 +209,13 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
deps = [ i for i in deps if (not i.startswith("cpython/")) and (not i.startswith("libc/")) ]
# Determine if any of the dependencies are newer than the c file.
c_fn = os.path.join("gen", name + ".c")
necessary_gen.append(name + ".c")
if language == "c++":
c_fn = os.path.join("gen", name + ".cc")
necessary_gen.append(name + ".cc")
else:
c_fn = os.path.join("gen", name + ".c")
necessary_gen.append(name + ".c")
if os.path.exists(c_fn):
c_mtime = os.path.getmtime(c_fn)
@@ -243,11 +255,18 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
try:
import subprocess
if language == "c++":
lang_args = [ "--cplus" ]
else:
lang_args = [ ]
subprocess.check_call([
cython_command,
"-Iinclude",
"-Igen",
"-a",
"-I..",
] + lang_args + [
fn,
"-o",
c_fn])
@@ -260,7 +279,7 @@ def cython(name, source=[], libs=[], compile_if=True, define_macros=[]):
# Build the module normally once we have the c file.
if compile_if:
cmodule(name, [ c_fn ] + source, libs=libs, define_macros=define_macros)
cmodule(name, [ c_fn ] + source, libs=libs, define_macros=define_macros, language=language)
def find_unnecessary_gen():
@@ -294,6 +313,10 @@ def copyfile(source, dest, replace=None, replace_with=None):
sfn = os.path.join("..", source)
dfn = os.path.join("..", dest)
if os.path.exists(dfn):
if os.path.getmtime(sfn) <= os.path.getmtime(dfn):
return
sf = file(sfn, "rb")
data = sf.read()
sf.close()
+35
View File
@@ -0,0 +1,35 @@
#ifndef STEAMCALLBACKS_H
#define STEAMCALLBACKS_H
#include "steam/steam_api.h"
template <class P>
class SteamCallback : CCallbackBase {
void (*callback)(P*);
public:
SteamCallback(void (*func)(P *)) : callback(func) {
m_iCallback = P::k_iCallback;
SteamAPI_RegisterCallback(this, P::k_iCallback);
}
~SteamCallback() {
SteamAPI_UnregisterCallback(this);
}
protected:
virtual void Run(void *param) {
callback((P *) param);
}
virtual void Run( void *param, bool, SteamAPICall_t ) {
callback((P *) param);
}
int GetCallbackSizeBytes() {
return sizeof(P);
}
};
#endif
+2 -2
View File
@@ -8,12 +8,12 @@
#include "renpy.h"
#include <SDL.h>
#include <pygame_sdl2/pygame_sdl2.surface_api.h>
#include <pygame_sdl2/pygame_sdl2.h>
#include <stdio.h>
#include <math.h>
void subpixel_init() {
import_pygame_sdl2__surface();
import_pygame_sdl2();
}
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+24 -6
View File
@@ -4,7 +4,7 @@
# This file is part of Ren'Py. The license below applies to Ren'Py only.
# Games and other projects that use Ren'Py may use a different license.
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -65,12 +65,34 @@ def path_to_saves(gamedir):
if os.path.isdir(rv) and test_writable(rv):
break
print "Using savedir", rv
print "Saving to", rv
# We return the last path as the default.
return rv
if renpy.ios:
from pyobjus import autoclass
from pyobjus.objc_py_types import enum
NSSearchPathDirectory = enum("NSSearchPathDirectory", NSDocumentDirectory=9)
NSSearchPathDomainMask = enum("NSSearchPathDomainMask", NSUserDomainMask=1)
NSFileManager = autoclass('NSFileManager')
manager = NSFileManager.defaultManager()
url = manager.URLsForDirectory_inDomains_(
NSSearchPathDirectory.NSDocumentDirectory,
NSSearchPathDomainMask.NSUserDomainMask,
).lastObject()
# url.path seems to change type based on iOS version, for some reason.
try:
rv = url.path().UTF8String().decode("utf-8")
except:
rv = url.path.UTF8String().decode("utf-8")
print "Saving to", rv
return rv
# No save directory given.
if not renpy.config.save_directory:
@@ -165,10 +187,6 @@ def main():
print >>sys.stderr, "correctly, preserving the directory structure."
raise
if android:
renpy.linux = False
renpy.android = True
renpy.bootstrap.bootstrap(renpy_base)
if __name__ == "__main__":
+61 -33
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -40,10 +40,10 @@ except ImportError:
vc_version = 0
# The tuple giving the version number.
version_tuple = (6, 18, 3, vc_version)
version_tuple = (6, 99, 0, vc_version)
# The name of this version.
version_name = "... through shared popular culture."
version_name = "Here's to the crazy ones."
# A verbose string giving the version.
version = "Ren'Py " + ".".join(str(i) for i in version_tuple)
@@ -53,6 +53,41 @@ script_version = 5003000
savegame_suffix = "-LT1.save"
bytecode_version = 1
################################################################################
# Platform Information
################################################################################
# Information about the platform we're running on. We break the platforms
# up into 5 groups - windows-like, mac-like, linux-like, android-like,
# and ios-like.
windows = False
macintosh = False
linux = False
android = False
ios = False
import platform
if platform.win32_ver()[0]:
windows = True
elif "RENPY_IOS" in os.environ:
ios = True
elif platform.mac_ver()[0]:
macintosh = True
elif "ANDROID_PRIVATE" in os.environ:
android = True
else:
linux = True
# A flag that's true if we're on a smartphone or tablet-like platform.
mobile = android or ios
################################################################################
# Backup Data for Reload
################################################################################
# True if this is the first time we've started - even including
# utter restarts.
first_utter_start = True
@@ -117,11 +152,8 @@ class Backup():
# A map from module to the set of names in that module.
self.names = { }
try:
import android # @UnresolvedImport
if mobile:
return
except:
pass
for m in sys.modules.values():
if m is None:
@@ -147,6 +179,9 @@ class Backup():
if name in backup_blacklist:
return
if name.startswith("renpy.styledata"):
return
self.names[mod] = set(vars(mod).keys())
for k, v in vars(mod).iteritems():
@@ -197,6 +232,9 @@ class Backup():
# A backup of the Ren'Py modules after initial import.
backup = None
################################################################################
# Import
################################################################################
def update_path(package):
"""
@@ -215,7 +253,6 @@ def update_path(package):
libexec = os.path.dirname(encodings.__path__[0])
package.__path__.append(os.path.join(libexec, *name))
def import_all():
# Note: If we add a new update_path, we have to add an equivalent
@@ -254,7 +291,15 @@ def import_all():
import renpy.python
import renpy.script
import renpy.statements
import renpy.styledata # @UnresolvedImport
update_path(renpy.styledata)
import renpy.style
renpy.styledata.import_style_functions()
sys.modules['renpy.styleclass'] = renpy.style
import renpy.substitutions
import renpy.translation
@@ -306,8 +351,9 @@ def import_all():
import renpy.display.dragdrop
import renpy.display.imagemap
import renpy.display.predict
import renpy.display.emulator # @UnresolvedImport
import renpy.display.tts # @UnresolvedImport
import renpy.display.emulator
import renpy.display.tts
import renpy.display.gesture
import renpy.display.error
@@ -337,6 +383,7 @@ def import_all():
import renpy.exports
import renpy.character # depends on exports. @UnresolvedImport
import renpy.add_from
import renpy.dump
import renpy.config # depends on lots. @UnresolvedImport
@@ -448,7 +495,7 @@ def setup_modulefinder(modulefinder):
libexec = os.path.dirname(_renpy.__file__)
for i in [ "display", "gl", "angle", "text" ]:
for i in [ "display", "gl", "angle", "text", "styledata" ]:
displaypath = os.path.join(libexec, "renpy", i)
@@ -467,6 +514,8 @@ def import_cython():
import renpy.display.accelerator
import renpy.display.render
import renpy.gl.gl
import renpy.gl.gl1
import renpy.gl.gldraw
import renpy.gl.glenviron_fixed
import renpy.gl.glenviron_limited
@@ -475,37 +524,16 @@ def import_cython():
import renpy.gl.glrtt_fbo
import renpy.gl.gltexture
import renpy.angle.gl
import renpy.angle.gldraw
import renpy.angle.glenviron_shader
import renpy.angle.glrtt_copy
import renpy.angle.glrtt_fbo
import renpy.angle.gltexture
import renpy.styleclass # @UnresolvedImport
if False:
import renpy.defaultstore as store
################################################################################
# Platform Information
################################################################################
# Information about the platform we're running on. We break the platforms
# up into 4 groups - windows-like, mac-like, linux-like, and android-like.
windows = False
macintosh = False
linux = False
android = False
import platform
if platform.win32_ver()[0]:
windows = True
elif platform.mac_ver()[0]:
macintosh = True
else:
linux = True
# The android init code in renpy.py will set linux=False and android=True.
+117
View File
@@ -0,0 +1,117 @@
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import collections
import renpy
import os
import codecs
# A map from filename to position, target label pairs.
missing = collections.defaultdict(list)
def report_missing(target, filename, position):
"""
Reports that the call statement ending at `position` in `filename`
is missing a from clause.
`target`
The string
"""
missing[filename].append((position, target))
# Labels that we've created while running add_from.
new_labels = set()
def generate_label(target):
"""
Generate a reasonable and unique new label for a call to `target`.
"""
n = 0
while True:
if n:
label = "_call_{}_{}".format(target, n)
else:
label = "_call_{}".format(target)
if not renpy.exports.has_label(label) and not (label in new_labels):
break
n += 1
new_labels.add(label)
return label
def process_file(fn):
"""
Adds missing from clauses to `fn`.
"""
if not os.path.exists(fn):
return
edits = missing[fn]
edits.sort()
with codecs.open(fn, "r", "utf-8") as f:
data = f.read()
# How much of the input has been consumed.
consumed = 0
# The output.
output = u""
for position, target in edits:
output += data[consumed:position]
consumed = position
output += " from {}".format(generate_label(target))
output += data[consumed:]
with codecs.open(fn + ".new", "w", "utf-8") as f:
f.write(output)
try:
os.unlink(fn + ".bak")
except:
pass
os.rename(fn, fn + ".bak")
os.rename(fn + ".new", fn)
def add_from():
renpy.arguments.takes_no_arguments("Adds from clauses to call statements that are missing them.")
for fn in missing:
if fn.startswith(renpy.config.gamedir):
process_file(fn)
return False
renpy.arguments.register_command("add_from", add_from)
+1572
View File
File diff suppressed because it is too large Load Diff
+711
View File
@@ -0,0 +1,711 @@
import os
import renpy
cdef int check_errors
check_errors = int(os.environ.get("RENPY_GL_CHECK_ERRORS", 0))
cdef int glActiveTextureARB(GLenum a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glActiveTextureARB')
cdef GLenum error
realGlActiveTextureARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glActiveTextureARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glAttachObjectARB(GLhandleARB a0, GLhandleARB a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glAttachObjectARB')
cdef GLenum error
realGlAttachObjectARB(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glAttachObjectARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glBindFramebufferEXT(GLenum a0, GLuint a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glBindFramebufferEXT')
cdef GLenum error
realGlBindFramebufferEXT(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glBindFramebufferEXT' % 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')
cdef GLenum error
realGlBindTexture(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glBindTexture' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glBlendFunc(GLenum a0, GLenum a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glBlendFunc')
cdef GLenum error
realGlBlendFunc(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glBlendFunc' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glClear(GLbitfield a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glClear')
cdef GLenum error
realGlClear(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glClear' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glClearColor(GLclampf a0, GLclampf a1, GLclampf a2, GLclampf a3) except? 0:
if check_errors & 4:
renpy.display.log.write('glClearColor')
cdef GLenum error
realGlClearColor(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glClearColor' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glCompileShaderARB(GLhandleARB a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glCompileShaderARB')
cdef GLenum error
realGlCompileShaderARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glCompileShaderARB' % 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')
cdef GLenum error
realGlCopyTexSubImage2D(a0, a1, a2, a3, a4, a5, a6, a7)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glCopyTexSubImage2D' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef GLhandleARB glCreateProgramObjectARB() except? 0:
if check_errors & 4:
renpy.display.log.write('glCreateProgramObjectARB')
cdef GLenum error
cdef GLhandleARB rv = realGlCreateProgramObjectARB()
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glCreateProgramObjectARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return rv
cdef GLhandleARB glCreateShaderObjectARB(GLenum a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glCreateShaderObjectARB')
cdef GLenum error
cdef GLhandleARB rv = realGlCreateShaderObjectARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glCreateShaderObjectARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return rv
cdef int glDeleteFramebuffersEXT(GLsizei a0, GLuint * a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glDeleteFramebuffersEXT')
cdef GLenum error
realGlDeleteFramebuffersEXT(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDeleteFramebuffersEXT' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glDeleteProgram(GLuint a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glDeleteProgram')
cdef GLenum error
realGlDeleteProgram(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDeleteProgram' % 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')
cdef GLenum error
realGlDeleteShader(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDeleteShader' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glDeleteTextures(GLsizei a0, GLuint * a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glDeleteTextures')
cdef GLenum error
realGlDeleteTextures(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDeleteTextures' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glDisable(GLenum a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glDisable')
cdef GLenum error
realGlDisable(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDisable' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glDisableVertexAttribArrayARB(GLuint a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glDisableVertexAttribArrayARB')
cdef GLenum error
realGlDisableVertexAttribArrayARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDisableVertexAttribArrayARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glDrawArrays(GLenum a0, GLint a1, GLsizei a2) except? 0:
if check_errors & 4:
renpy.display.log.write('glDrawArrays')
cdef GLenum error
realGlDrawArrays(a0, a1, a2)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glDrawArrays' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glEnable(GLenum a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glEnable')
cdef GLenum error
realGlEnable(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glEnable' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glEnableVertexAttribArrayARB(GLuint a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glEnableVertexAttribArrayARB')
cdef GLenum error
realGlEnableVertexAttribArrayARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glEnableVertexAttribArrayARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glFinish() except? 0:
if check_errors & 4:
renpy.display.log.write('glFinish')
cdef GLenum error
realGlFinish()
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glFinish' % 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')
cdef GLenum error
realGlFramebufferTexture2DEXT(a0, a1, a2, a3, a4)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glFramebufferTexture2DEXT' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glGenFramebuffersEXT(GLsizei a0, GLuint * a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glGenFramebuffersEXT')
cdef GLenum error
realGlGenFramebuffersEXT(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGenFramebuffersEXT' % 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')
cdef GLenum error
realGlGenTextures(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGenTextures' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef GLint glGetAttribLocationARB(GLhandleARB a0, GLchar * a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetAttribLocationARB')
cdef GLenum error
cdef GLint rv = realGlGetAttribLocationARB(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetAttribLocationARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return rv
cdef int glGetIntegerv(GLenum a0, GLint * a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetIntegerv')
cdef GLenum error
realGlGetIntegerv(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetIntegerv' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glGetProgramInfoLog(GLhandleARB a0, GLsizei a1, GLsizei * a2, GLchar * a3) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetProgramInfoLog')
cdef GLenum error
realGlGetProgramInfoLog(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetProgramInfoLog' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glGetProgramiv(GLuint a0, GLenum a1, GLint * a2) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetProgramiv')
cdef GLenum error
realGlGetProgramiv(a0, a1, a2)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetProgramiv' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glGetShaderInfoLog(GLhandleARB a0, GLsizei a1, GLsizei * a2, GLchar * a3) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetShaderInfoLog')
cdef GLenum error
realGlGetShaderInfoLog(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetShaderInfoLog' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glGetShaderiv(GLuint a0, GLenum a1, GLint * a2) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetShaderiv')
cdef GLenum error
realGlGetShaderiv(a0, a1, a2)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetShaderiv' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef GLchar * glGetString(GLenum a0) except? NULL:
if check_errors & 4:
renpy.display.log.write('glGetString')
cdef GLenum error
cdef GLchar * rv = realGlGetString(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetString' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return rv
cdef GLint glGetUniformLocationARB(GLhandleARB a0, GLchar * a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glGetUniformLocationARB')
cdef GLenum error
cdef GLint rv = realGlGetUniformLocationARB(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glGetUniformLocationARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return rv
cdef int glLinkProgramARB(GLhandleARB a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glLinkProgramARB')
cdef GLenum error
realGlLinkProgramARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glLinkProgramARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glReadPixels(GLint a0, GLint a1, GLsizei a2, GLsizei a3, GLenum a4, GLenum a5, GLubyte * a6) except? 0:
if check_errors & 4:
renpy.display.log.write('glReadPixels')
cdef GLenum error
realGlReadPixels(a0, a1, a2, a3, a4, a5, a6)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glReadPixels' % 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')
cdef GLenum error
realGlScissor(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glScissor' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glShaderSourceARB(GLhandleARB a0, GLsizei a1, GLchar * * a2, GLint * a3) except? 0:
if check_errors & 4:
renpy.display.log.write('glShaderSourceARB')
cdef GLenum error
realGlShaderSourceARB(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glShaderSourceARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glTexImage2D(GLenum a0, GLint a1, GLint a2, GLsizei a3, GLsizei a4, GLint a5, GLenum a6, GLenum a7, GLubyte * a8) except? 0:
if check_errors & 4:
renpy.display.log.write('glTexImage2D')
cdef GLenum error
realGlTexImage2D(a0, a1, a2, a3, a4, a5, a6, a7, a8)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glTexImage2D' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glTexParameteri(GLenum a0, GLenum a1, GLint a2) except? 0:
if check_errors & 4:
renpy.display.log.write('glTexParameteri')
cdef GLenum error
realGlTexParameteri(a0, a1, a2)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glTexParameteri' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glTexSubImage2D(GLenum a0, GLint a1, GLint a2, GLint a3, GLsizei a4, GLsizei a5, GLenum a6, GLenum a7, GLubyte * a8) except? 0:
if check_errors & 4:
renpy.display.log.write('glTexSubImage2D')
cdef GLenum error
realGlTexSubImage2D(a0, a1, a2, a3, a4, a5, a6, a7, a8)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glTexSubImage2D' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glUniform1fARB(GLint a0, GLfloat a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glUniform1fARB')
cdef GLenum error
realGlUniform1fARB(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glUniform1fARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glUniform1iARB(GLint a0, GLint a1) except? 0:
if check_errors & 4:
renpy.display.log.write('glUniform1iARB')
cdef GLenum error
realGlUniform1iARB(a0, a1)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glUniform1iARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glUniform2fARB(GLint a0, GLfloat a1, GLfloat a2) except? 0:
if check_errors & 4:
renpy.display.log.write('glUniform2fARB')
cdef GLenum error
realGlUniform2fARB(a0, a1, a2)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glUniform2fARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glUniform4fARB(GLint a0, GLfloat a1, GLfloat a2, GLfloat a3, GLfloat a4) except? 0:
if check_errors & 4:
renpy.display.log.write('glUniform4fARB')
cdef GLenum error
realGlUniform4fARB(a0, a1, a2, a3, a4)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glUniform4fARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glUniformMatrix4fvARB(GLint a0, GLsizei a1, GLboolean a2, GLfloat * a3) except? 0:
if check_errors & 4:
renpy.display.log.write('glUniformMatrix4fvARB')
cdef GLenum error
realGlUniformMatrix4fvARB(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glUniformMatrix4fvARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glUseProgramObjectARB(GLhandleARB a0) except? 0:
if check_errors & 4:
renpy.display.log.write('glUseProgramObjectARB')
cdef GLenum error
realGlUseProgramObjectARB(a0)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glUseProgramObjectARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glVertexAttribPointerARB(GLuint a0, GLint a1, GLenum a2, GLboolean a3, GLsizei a4, GLubyte * a5) except? 0:
if check_errors & 4:
renpy.display.log.write('glVertexAttribPointerARB')
cdef GLenum error
realGlVertexAttribPointerARB(a0, a1, a2, a3, a4, a5)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glVertexAttribPointerARB' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
cdef int glViewport(GLint a0, GLint a1, GLsizei a2, GLsizei a3) except? 0:
if check_errors & 4:
renpy.display.log.write('glViewport')
cdef GLenum error
realGlViewport(a0, a1, a2, a3)
if check_errors:
error = realGlGetError()
if error:
message = 'GL error %x in glViewport' % error
if check_errors & 1:
renpy.display.log.write('%s', message)
if check_errors & 2:
raise Exception(message)
return 1
+1 -1
View File
@@ -1,7 +1,7 @@
# This file was automatically generated from renpy/gl/glblacklist.py
# Modifications will be automatically overwritten.
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+10 -4
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -878,6 +878,9 @@ class Image(Node):
renpy.exports.image(self.imgname, img)
def analyze(self):
if getattr(self, 'atl', None) is not None:
self.atl.mark_constant()
class Transform(Node):
@@ -1040,6 +1043,10 @@ class Show(Node):
predict_imspec(self.imspec, atl=getattr(self, "atl", None))
return [ self.next ]
def analyze(self):
if getattr(self, 'atl', None) is not None:
self.atl.mark_constant()
class ShowLayer(Node):
@@ -1127,7 +1134,7 @@ class Scene(Node):
return [ self.next ]
def analyze(self):
if self.atl is not None:
if getattr(self, 'atl', None) is not None:
self.atl.mark_constant()
@@ -1326,9 +1333,8 @@ class Return(Node):
else:
renpy.store._return = None
renpy.game.context().pop_dynamic()
next_node(renpy.game.context().lookup_return(pop=True))
renpy.game.context().pop_dynamic()
def predict(self):
+64 -23
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -227,6 +227,9 @@ class ATLTransformBase(renpy.object.Object):
parent_transform = None
atl_st_offset = 0
# The block, as first compiled for prediction.
predict_block = None
nosave = [ 'parent_transform' ]
def __init__(self, atl, context, parameters):
@@ -248,6 +251,10 @@ class ATLTransformBase(renpy.object.Object):
# The code after it has been compiled into a block.
self.block = None
# The same thing, but only if the code was compiled into a block
# for prediction purposes only.
self.predict_block = None
# The properties of the block, if it contains only an
# Interpolation.
self.properties = None
@@ -281,6 +288,18 @@ class ATLTransformBase(renpy.object.Object):
if renpy.game.context().init_phase:
compile_queue.append(self)
def get_block(self):
"""
Returns the compiled block to use.
"""
if self.block:
return self.block
elif self.predict_block and renpy.display.predict.predicting:
return self.predict_block
else:
return None
def take_execution_state(self, t):
"""
Updates self to begin executing from the same point as t. This
@@ -322,7 +341,6 @@ class ATLTransformBase(renpy.object.Object):
self.child = t.child
self.raw_child = t.raw_child
def __call__(self, *args, **kwargs):
context = self.context.context.copy()
@@ -409,20 +427,25 @@ class ATLTransformBase(renpy.object.Object):
self.block = self.parent_transform.block
self.properties = self.parent_transform.properties
self.parent_transform = None
return
return self.block
old_exception_info = renpy.game.exception_info
self.block = self.atl.compile(self.context)
block = self.atl.compile(self.context)
if len(self.block.statements) == 1 \
and isinstance(self.block.statements[0], Interpolation):
if len(block.statements) == 1 and isinstance(block.statements[0], Interpolation):
interp = self.block.statements[0]
interp = block.statements[0]
if interp.duration == 0 and interp.properties:
self.properties = interp.properties[:]
if not constant and renpy.display.predict.predicting:
self.predict_block = block
else:
self.block = block
self.predict_block = None
renpy.game.exception_info = old_exception_info
if constant and self.parent_transform:
@@ -430,14 +453,17 @@ class ATLTransformBase(renpy.object.Object):
self.parent_transform.properties = self.properties
self.parent_transform = None
return block
def execute(self, trans, st, at):
if self.done:
return None
if not self.block:
self.compile()
block = self.get_block()
if block is None:
block = self.compile()
# Propagate transform_events from children.
if self.child:
@@ -469,11 +495,11 @@ class ATLTransformBase(renpy.object.Object):
else:
timebase = st - self.atl_st_offset
action, arg, pause = self.block.execute(trans, timebase, self.atl_state, event)
action, arg, pause = block.execute(trans, timebase, self.atl_state, event)
renpy.game.exception_info = old_exception_info
if action == "continue":
if action == "continue" and not renpy.display.predict.predicting:
self.atl_state = arg
else:
self.done = True
@@ -484,10 +510,12 @@ class ATLTransformBase(renpy.object.Object):
self.atl.predict(self.context)
def visit(self):
if not self.block:
self.compile()
block = self.get_block()
return self.children + self.block.visit()
if block is None:
block = self.compile()
return self.children + block.visit()
# This is used in mark_constant to analyze expressions for constness.
is_constant_expr = renpy.pyanalysis.Analysis().is_constant_expr
@@ -788,10 +816,11 @@ class RawMultipurpose(RawStatement):
if isinstance(child, (int, float)):
return Interpolation(self.loc, "pause", child, [ ], None, 0, [ ])
child = renpy.easy.displayable(child)
if isinstance(child, ATLTransformBase):
child.compile()
return child.block
return child.get_block()
else:
return Child(self.loc, child, transition)
@@ -905,7 +934,7 @@ class RawContainsExpr(RawStatement):
self.constant = is_constant_expr(self.expression)
# This allows us to have multiple children, inside a Fixed.
# This allows us to have multiple ATL transforms as children.
class RawChild(RawStatement):
def __init__(self, loc, child):
@@ -915,12 +944,23 @@ class RawChild(RawStatement):
self.children = [ child ]
def compile(self, ctx): #@ReservedAssignment
box = renpy.display.layout.MultiBox(layout='fixed')
children = [ ]
for i in self.children:
box.add(renpy.display.motion.ATLTransform(i, context=ctx.context))
children.append(renpy.display.motion.ATLTransform(i, context=ctx.context))
return Child(self.loc, box, None)
if len(children) != 1:
box = renpy.display.layout.MultiBox(layout='fixed')
for i in children:
box.add(i)
return Child(self.loc, box, None)
else:
return Child(self.loc, children[0], None)
def mark_constant(self):
@@ -940,7 +980,7 @@ class Child(Statement):
super(Child, self).__init__(loc)
self.child = renpy.easy.displayable(child)
self.child = child
self.transition = transition
def execute(self, trans, st, state, event):
@@ -948,12 +988,13 @@ class Child(Statement):
executing(self.loc)
old_child = trans.raw_child
child = self.child.parameterize('displayable', [ ])
if (old_child is not None) and (old_child is not renpy.display.motion.null) and (self.transition is not None):
child = self.transition(old_widget=old_child,
new_widget=self.child)
new_widget=child)
else:
child = self.child
child = child
trans.set_child(child)
trans.raw_child = self.child
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+177
View File
@@ -0,0 +1,177 @@
import renpy
import jnius # @UnresolvedImport
from renpy.audio.audio import MusicContext
VideoPlayer = jnius.autoclass("org.renpy.android.VideoPlayer")
class AndroidVideoChannel(object):
def __init__(self, name, file_prefix="", file_suffix="", default_loop=None):
# A list of queued filenames.
self.queue = [ ]
# The filename that's currently playing.
self.filename = None
# The videoplayer that's currently playing.
self.player = None
# The name assigned to this channel. This is used to look up
# information about the channel in the MusicContext object.
self.name = name
# The name of the mixer this channel uses. Set below, as there's
# no good default.
self.mixer = None
# The time the music in this channel was last changed.
self.last_changed = 0
# The callback that is called if the queue becomes empty.
self.callback = None
# Ignored.
self.synchro_start = False
self.wait_stop = False
self.loop = [ ]
# A prefix and suffix that are used to create the full filenames.
self.file_prefix = file_prefix
self.file_suffix = file_suffix
if default_loop is None:
# By default, should we loop the music?
self.default_loop = True
# Was this set explicitly?
self.default_loop_set = False
else:
self.default_loop = default_loop
self.default_loop_set = True
def get_context(self):
"""
Returns the MusicContext corresponding to this channel, taken from
the context object. Allocates a MusicContext if none exists.
"""
mcd = renpy.game.context().music
rv = mcd.get(self.name)
if rv is None:
rv = mcd[self.name] = MusicContext()
return rv
context = property(get_context)
def start(self):
"""
Starts playing the first video in the queue.
"""
if not self.queue:
return
filename = self.queue.pop(0)
print "Playing", filename
f = renpy.loader.load(filename)
real_fn = f.name
base = getattr(f, "base", -1)
length = getattr(f, "length", -1)
self.filename = filename
self.player = VideoPlayer(real_fn, base, length)
def stop(self):
if self.player is not None:
self.player.stop()
self.player = None
self.filename = None
def get_playing(self):
if self.player is None:
return None
if self.player.isPlaying():
return self.filename
def periodic(self):
# This should be set from something that checks to see if our
# mixer is muted.
force_stop = self.context.force_stop
if force_stop:
self.dequeue()
self.stop()
return
if self.get_playing():
return
if self.queue:
self.start()
def dequeue(self, even_tight=False):
"""
Clears the queued music, except for a first item that has
not been started.
"""
if self.get_playing():
self.queue = [ ]
else:
self.queue = self.queue[:1]
def interact(self):
"""
Called (mostly) once per interaction.
"""
self.periodic()
def fadeout(self, secs):
"""
Causes the playing music to be faded out for the given number
of seconds. Also clears any queued music.
"""
self.stop()
self.queue = [ ]
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
self.queue.extend(filenames)
def set_volume(self, volume):
pass
def get_pos(self):
pass
def set_pan(self, pan, delay):
pass
def set_secondary_volume(self, volume, delay):
pass
def pause(self):
if self.player is not None:
self.player.pause()
def unpause(self):
if self.player is not None:
self.player.unpause()
+41 -179
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -28,7 +28,7 @@ import renpy.audio # @UnusedImport
import renpy.display # @UnusedImport
import time
import pygame # @UnusedImport
import pygame_sdl2 # @UnusedImport
import os
import atexit
@@ -36,23 +36,16 @@ import atexit
disable = os.environ.get("RENPY_DISABLE_SOUND", "")
pss = None
if 'pss' not in disable:
try:
import pysdlsound as pss
pss.check_version(4) # @UndefinedVariable
atexit.register(pss.quit) # @UndefinedVariable
except:
pass
if pss is None:
try:
import android.sound as pss #@UnresolvedImport @Reimport
print "Imported android.sound."
except:
pass
import traceback
traceback.print_exc()
pss = None
# Save the mixer, and restore it at exit.
@@ -511,178 +504,29 @@ class Channel(object):
self.secondary_volume_time = self.context.secondary_volume_time
pss.set_secondary_volume(self.number, self.context.secondary_volume, delay)
def pause(self):
pss.pause(self.number)
def unpause(self):
pss.unpause(self.number)
################################################################################
# Android VideoPlayer Channel
################################################################################
if renpy.android:
# Use unconditional imports so these files get compiled during the build
# process.
import jnius # @UnresolvedImport
VideoPlayer = jnius.autoclass("org.renpy.android.VideoPlayer")
class AndroidVideoChannel(object):
def __init__(self, name, file_prefix="", file_suffix="", default_loop=None):
# A list of queued filenames.
self.queue = [ ]
# The filename that's currently playing.
self.filename = None
# The videoplayer that's currently playing.
self.player = None
# The name assigned to this channel. This is used to look up
# information about the channel in the MusicContext object.
self.name = name
# The name of the mixer this channel uses. Set below, as there's
# no good default.
self.mixer = None
# The time the music in this channel was last changed.
self.last_changed = 0
# The callback that is called if the queue becomes empty.
self.callback = None
# Ignored.
self.synchro_start = False
self.wait_stop = False
self.loop = [ ]
# A prefix and suffix that are used to create the full filenames.
self.file_prefix = file_prefix
self.file_suffix = file_suffix
if default_loop is None:
# By default, should we loop the music?
self.default_loop = True
# Was this set explicitly?
self.default_loop_set = False
else:
self.default_loop = default_loop
self.default_loop_set = True
def get_context(self):
"""
Returns the MusicContext corresponding to this channel, taken from
the context object. Allocates a MusicContext if none exists.
"""
mcd = renpy.game.context().music
rv = mcd.get(self.name)
if rv is None:
rv = mcd[self.name] = MusicContext()
return rv
context = property(get_context)
def start(self):
"""
Starts playing the first video in the queue.
"""
if not self.queue:
return
filename = self.queue.pop(0)
f = renpy.loader.load(filename)
real_fn = f.name
base = getattr(f, "base", -1)
length = getattr(f, "length", -1)
self.filename = filename
self.player = VideoPlayer(real_fn, base, length)
def stop(self):
if self.player is not None:
self.player.stop()
self.player = None
self.filename = None
def get_playing(self):
if self.player is None:
return None
if self.player.isPlaying():
return self.filename
def periodic(self):
# This should be set from something that checks to see if our
# mixer is muted.
force_stop = self.context.force_stop
if force_stop:
self.dequeue()
self.stop()
return
if self.get_playing():
return
if self.queue:
self.start()
def dequeue(self, even_tight=False):
"""
Clears the queued music, except for a first item that has
not been started.
"""
if self.get_playing():
self.queue = [ ]
else:
self.queue = self.queue[:1]
def interact(self):
"""
Called (mostly) once per interaction.
"""
self.periodic()
def fadeout(self, secs):
"""
Causes the playing music to be faded out for the given number
of seconds. Also clears any queued music.
"""
self.stop()
self.queue = [ ]
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
self.queue.extend(filenames)
def set_volume(self, volume):
pass
def get_pos(self):
pass
def set_pan(self, pan, delay):
pass
def set_secondary_volume(self, volume, delay):
pass
try:
from renpy.audio.androidhw import AndroidVideoChannel
except:
pass
try:
from renpy.audio.ioshw import IOSVideoChannel
except:
pass
# A list of channels we know about.
all_channels = [ ]
@@ -732,8 +576,10 @@ def register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False
if not renpy.game.context().init_phase:
raise Exception("Can't register channel outside of init phase.")
if renpy.android and name == "movie":
if renpy.android and renpy.config.hw_video and name == "movie":
c = AndroidVideoChannel(name, default_loop=loop, file_prefix=file_prefix, file_suffix=file_suffix)
elif renpy.ios and renpy.config.hw_video and name == "movie":
c = IOSVideoChannel(name, default_loop=loop, file_prefix=file_prefix, file_suffix=file_suffix)
else:
c = Channel(name, loop, stop_on_mute, tight, file_prefix, file_suffix, buffer_queue)
@@ -953,3 +799,19 @@ def rollback():
for c in all_channels:
if not c.loop:
c.fadeout(0)
def pause_all():
"""
Pause all playback channels.
"""
for c in channels.values():
c.pause()
def unpause_all():
"""
Unpause all playback channels.
"""
for c in channels.values():
c.unpause()
+175
View File
@@ -0,0 +1,175 @@
import renpy
import pyobjus # @UnresolvedImport
from renpy.audio.audio import MusicContext
VideoPlayer = pyobjus.autoclass("VideoPlayer")
class IOSVideoChannel(object):
def __init__(self, name, file_prefix="", file_suffix="", default_loop=None):
# A list of queued filenames.
self.queue = [ ]
# The filename that's currently playing.
self.filename = None
# The videoplayer that's currently playing.
self.player = None
# The name assigned to this channel. This is used to look up
# information about the channel in the MusicContext object.
self.name = name
# The name of the mixer this channel uses. Set below, as there's
# no good default.
self.mixer = None
# The time the music in this channel was last changed.
self.last_changed = 0
# The callback that is called if the queue becomes empty.
self.callback = None
# Ignored.
self.synchro_start = False
self.wait_stop = False
self.loop = [ ]
# A prefix and suffix that are used to create the full filenames.
self.file_prefix = file_prefix
self.file_suffix = file_suffix
if default_loop is None:
# By default, should we loop the music?
self.default_loop = True
# Was this set explicitly?
self.default_loop_set = False
else:
self.default_loop = default_loop
self.default_loop_set = True
def get_context(self):
"""
Returns the MusicContext corresponding to this channel, taken from
the context object. Allocates a MusicContext if none exists.
"""
mcd = renpy.game.context().music
rv = mcd.get(self.name)
if rv is None:
rv = mcd[self.name] = MusicContext()
return rv
context = property(get_context)
def start(self):
"""
Starts playing the first video in the queue.
"""
if not self.queue:
return
filename = self.queue.pop(0)
f = renpy.loader.load(filename)
real_fn = f.name
self.filename = filename
self.player = VideoPlayer.alloc().initWithFile_(real_fn)
def stop(self):
if self.player is not None:
self.player.stop()
self.player = None
self.filename = None
def get_playing(self):
if self.player is None:
return None
if self.player.isPlaying():
return self.filename
def periodic(self):
# This should be set from something that checks to see if our
# mixer is muted.
force_stop = self.context.force_stop
if force_stop:
self.dequeue()
self.stop()
return
if self.get_playing():
return
if self.queue:
self.start()
def dequeue(self, even_tight=False):
"""
Clears the queued music, except for a first item that has
not been started.
"""
if self.get_playing():
self.queue = [ ]
else:
self.queue = self.queue[:1]
def interact(self):
"""
Called (mostly) once per interaction.
"""
self.periodic()
def fadeout(self, secs):
"""
Causes the playing music to be faded out for the given number
of seconds. Also clears any queued music.
"""
self.stop()
self.queue = [ ]
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
self.queue.extend(filenames)
def pause(self):
if self.player is not None:
self.player.pause()
pass
def unpause(self):
if self.player is not None:
self.player.unpause()
pass
def set_volume(self, volume):
pass
def get_pos(self):
pass
def set_pan(self, pan, delay):
pass
def set_secondary_volume(self, volume, delay):
pass
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+13 -14
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -57,9 +57,6 @@ def extra_imports():
import tarfile; tarfile
import bz2; bz2 # @UnresolvedImport
import webbrowser; webbrowser
import pygame.locals; pygame.locals
import pygame.color; pygame.color
import pygame.colordict; pygame.colordict
import posixpath; posixpath
import ctypes; ctypes
import ctypes.wintypes; ctypes.wintypes
@@ -74,6 +71,7 @@ def extra_imports():
import rsa; rsa
import decimal; decimal
import plistlib; plistlib
import _renpysteam; _renpysteam
class NullFile(io.IOBase):
"""
@@ -135,6 +133,10 @@ def bootstrap(renpy_base):
os.environ["RENPY_BASE"] = os.path.abspath(renpy_base)
# Remove a legacy environment setting.
if os.environ.get("SDL_VIDEODRIVER", "") == "windib":
del os.environ["SDL_VIDEODRIVER"]
renpy_base = unicode(renpy_base, FSENCODING, "replace")
# If environment.txt exists, load it into the os.environ dictionary.
@@ -212,10 +214,6 @@ def bootstrap(renpy_base):
sys.path.insert(0, basedir)
# Force windib on windows, unless the user explicitly overrides.
if renpy.windows and not 'SDL_VIDEODRIVER' in os.environ:
os.environ['SDL_VIDEODRIVER'] = 'windib'
# If we're not given a command, show the presplash.
if args.command == "run":
import renpy.display.presplash #@Reimport
@@ -225,19 +223,17 @@ def bootstrap(renpy_base):
if renpy.macintosh:
os.startfile = mac_start
import pygame_sdl2
pygame_sdl2.import_as_pygame()
# Check that we have installed pygame properly. This also deals with
# weird cases on Windows and Linux where we can't import modules. (On
# windows ";" is a directory separator in PATH, so if it's in a parent
# directory, we won't get the libraries in the PATH, and hence pygame
# won't import.)
try:
import pygame; pygame
import pygame_sdl2
pygame_sdl2.import_as_pygame()
except:
print >>sys.stderr, """\
Could not import pygame. Please ensure that this program has been built
Could not import pygame_sdl2. Please ensure that this program has been built
and unpacked properly. Also, make sure that the directories containing
this program do not contain : or ; in their names.
@@ -306,7 +302,10 @@ You may be using a system install of python. Please run {0}.sh,
exit_status = e.status
if e.relaunch:
subprocess.Popen([sys.executable, "-EO"] + sys.argv)
if hasattr(sys, "renpy_executable"):
subprocess.Popen([sys.renpy_executable] + sys.argv[1:])
else:
subprocess.Popen([sys.executable, "-EO"] + sys.argv)
except renpy.game.ParseErrorException:
pass
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+3 -11
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -45,11 +45,7 @@ init -1200 python:
if _preferences.show_empty_window:
renpy.with_statement(None)
store._window = True
try:
_voice.ignore_interaction = True
renpy.with_statement(trans)
finally:
_voice.ignore_interaction = False
renpy.with_statement(trans)
else:
store._window = True
@@ -63,11 +59,7 @@ init -1200 python:
if _preferences.show_empty_window:
renpy.with_statement(None)
store._window = False
try:
_voice.ignore_interaction = True
renpy.with_statement(trans)
finally:
_voice.ignore_interaction = False
renpy.with_statement(trans)
else:
store._window = False
+262
View File
@@ -0,0 +1,262 @@
# Copyright 2004-2015 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.
init -1500 python in achievement:
from store import persistent, renpy
# A list of backends that have been registered.
backends = [ ]
class Backend(object):
"""
Achievement backends should inherit from this class, so new methods
will be ignored.
"""
def register(self, name, **kwargs):
"""
Called to register a new achievement.
"""
def grant(self, name):
"""
Grants the achievement with `name`, if it has not already been
granted.
"""
def clear(self, name):
"""
Clears the achievement with `name`, if it has been granted.
"""
def clear_all(self):
"""
Clears all achievements.
"""
def progress(self, name, complete, total):
"""
Reports progress towards the achievement with `name`.
"""
def has(self, name):
"""
Returns true if the achievement with `name` is unlocked.
"""
return False
class PersistentBackend(Backend):
"""
A backend that stores achievements in persistent._achievements.
"""
def __init__(self):
if persistent._achievements is None:
persistent._achievements = _set()
def grant(self, name):
persistent._achievements.add(name)
def clear(self, name):
persistent._achievements.discard(name)
def clear_all(self):
persistent._achievements.clear()
def has(self, name):
return name in persistent._achievements
def merge(old, new, current):
return old | new
renpy.register_persistent("_achievements", merge)
backends.append(PersistentBackend())
class SteamBackend(Backend):
"""
A backend that sends achievements to Steam. This is only used if steam
has loaded and initialized successfully.
"""
def __init__(self):
# A map from achievement name to steam name.
self.names = { }
steam.retrieve_stats(self.got_stats)
def got_stats(self):
renpy.restart_interaction()
def register(self, name, steam=None, **kwargs):
if steam is not None:
self.names[name] = steam
def grant(self, name):
name = self.names.get(name, name)
steam.grant_achievement(name)
steam.store_stats()
def clear(self, name):
name = self.names.get(name, name)
steam.clear_achievement(name)
steam.store_stats()
def clear_all(self):
for i in steam.list_achievements():
steam.clear_achievement(i)
steam.store_stats()
def progress(self, name, completed, total):
name = self.names.get(name, name)
steam.indicate_achievement_progress(name, completed, total)
steam.store_stats()
def has(self, name):
name = self.names.get(name, name)
return steam.get_achievement(name)
try:
import _renpysteam as steam
if steam.init():
backends.append(SteamBackend())
except:
pass
def register(name, **kwargs):
"""
:doc: achievement
Registers an achievement. Achievements are not required to be
registered, but doing so allows one to pass information to the
backends.
`name`
The name of the achievement to register.
The following keyword parameters are optional.
`steam`
The name to use on steam. If not given, defaults to `name`.
"""
for i in backends:
i.register(name, **kwargs)
def grant(name):
"""
:doc: achievement
Grants the achievement with `name`, if it has not already been
granted.
"""
if not has(name):
for i in backends:
i.grant(name)
def clear(name):
"""
:doc: achievement
Clears the achievement with `name`.
"""
if has(name):
for i in backends:
i.clear(name)
def clear_all():
"""
:doc: achievement
Clears all achievements.
"""
for i in backends:
i.clear_all()
def progress(name, complete, total):
"""
:doc: achievement
Reports progress towards the achievement with `name`, if that
achievement has not been granted.
`complete`
An integer giving the number of units completed towards the
achievement.
`total`
An integer giving the total number of units required to consider
the achievement complete.
"""
if has(name):
return
for i in backends:
i.progress(name, complete, total)
def grant_progress(name, complete, total):
"""
:doc: achievement
If `complete` is less than `total`, reports progress towards the
achievement with `name`, if that achievement has not been
granted.
Otherwise, grants the achievement with `name`, if that achievement
has not been granted.
"""
if complete < total:
progress(name, complete, total)
else:
grant(name)
def has(name):
"""
:doc: achievement
Returne true if the plater has been grnted the achievement with
`name`.
"""
for i in backends:
if i.has(name):
return True
return False
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+2 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -121,7 +121,7 @@ init -1500 python:
the current interaction completes.
"""
return Show(screen, _transient=True, *args, **kwargs)
return Show(screen, None, _transient=True, *args, **kwargs)
@renpy.pure
class Hide(Action, DictEquality):
+102 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -94,7 +94,8 @@ init -1600 python:
be set to `value`.
"""
identity_fields = [ "name", "value" ]
identity_fields = [ "value" ]
equality_fields = [ "name" ]
def __init__(self, name, value):
self.name = name
@@ -253,7 +254,8 @@ init -1600 python:
If not None, then this is the false value we use.
"""
identity_fields = [ "name", "true_value", "false_value" ]
identity_fields = [ "true_value", "false_value" ]
equality_fields = [ "name" ]
def __init__(self, name, true_value=None, false_value=None):
self.name = name
@@ -298,3 +300,100 @@ init -1600 python:
return rv
@renpy.pure
class AddToSet(Action, FieldEquality):
"""
:data: data_action
Adds `value` to `set`.
`set`
The set to add to. This may be a python set or list, in which
case the value is appended to the list.
`value`
The value to add or append.
"""
identity_fields = [ 'set', 'value' ]
def __init__(self, set, value):
self.set = set
self.value = value
def get_sensitive(self):
return self.value not in self.set
def __call__(self):
if isinstance(self.set, list):
self.set.append(self.value)
else:
self.set.add(self.value)
renpy.restart_interaction()
@renpy.pure
class RemoveFromSet(Action, FieldEquality):
"""
:data: data_action
Removes `value` from `set`.
`set`
The set to remove from. This may be a set or list.
`value`
The value to add or append.
"""
identity_fields = [ 'set', 'value' ]
def __init__(self, set, value):
self.set = set
self.value = value
def get_sensitive(self):
return self.value in self.set
def __call__(self):
if self.value in self.set:
self.set.remove(self.value)
renpy.restart_interaction()
@renpy.pure
class ToggleSetMembership(Action, FieldEquality):
"""
:data: data_action
Toggles the membership of `value` in `set`. If the value is not
in the set, it's added. Otherwise, it is removed.
Buttons with this action are marked as selected if and only if the
value is in the set.
`set`
The set to add to or remove from. This may be a set or list. In the
case of a list, new items are appended.
`value`
The value to add or append.
"""
identity_fields = [ 'set', 'value' ]
def __init__(self, set, value):
self.set = set
self.value = value
def get_selected(self):
return self.value in self.set
def __call__(self):
if self.value in self.set:
self.set.remove(self.value)
else:
if isinstance(self.set, list):
self.set.append(self.value)
else:
self.set.add(self.value)
renpy.restart_interaction()
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+2 -2
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -342,7 +342,7 @@ init -1500 python:
def get_sensitive(self):
if self.locked is not None:
return self.locked
return not self.locked
return renpy.seen_label(self.label)
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+14 -5
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
@@ -96,7 +96,6 @@ init -1500 python in build:
( "renpy.sh", "linux mac"),
])
def classify_renpy(pattern, groups):
"""
Classifies files in the Ren'Py base directory according to pattern.
@@ -141,11 +140,12 @@ init -1500 python in build:
(".android.json", "android"),
("android-icon.png", "android"),
("android-presplash.jpg", "android"),
("android-presplash.*", "android"),
("android-*-icon.png", "android"),
("android-*-presplash.jpg", "android"),
("ouya-icon.png", "android"),
("android-*-presplash.*", "android"),
("ouya_icon.png", "android"),
("ios-presplash.*", "ios"),
])
base_patterns = [ ]
@@ -308,6 +308,7 @@ init -1500 python in build:
package("mac", "app-zip", "mac renpy all", "Macintosh x86")
package("win", "zip", "windows renpy all", "Windows x86")
package("android", "directory", "android renpy all", hidden=True, update=False, dlc=True)
package("ios", "directory", "ios renpy all", hidden=True, update=False, dlc=True)
# Data that we expect the user to set.
@@ -341,9 +342,14 @@ init -1500 python in build:
# The destination things are built in.
destination = "{directory_name}-dists"
# Should we allow the use of an integrated GPU on platforms that support
# both discrete and integrated GPUs?
allow_integrated_gpu = True
# This function is called by the json_dump command to dump the build data
# into the json file.
def dump():
rv = { }
rv["directory_name"] = directory_name
@@ -361,8 +367,11 @@ init -1500 python in build:
rv["exclude_empty_directories"] = exclude_empty_directories
rv["allow_integrated_gpu"] = allow_integrated_gpu
rv["renpy"] = renpy
rv["destination"] = destination.format(
directory_name=directory_name,
executable_name=executable_name,
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
+3 -3
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -290,8 +290,8 @@ init -1500 python:
if not _preferences.performance_test and "RENPY_PERFORMANCE_TEST" not in os.environ:
return
# Don't bother on androuid - there's nothing the user can do.
if renpy.renpy.android:
# Don't bother on android or ios - there's nothing the user can do.
if renpy.mobile:
return
renpy.renpy.display.log.write("Performance test:")
+208 -33
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -31,11 +31,16 @@ init -1500 python in iap:
A data object representing a product.
"""
def __init__(self, product, identifier, google, amazon):
def __init__(self, product, identifier, google, amazon, ios):
self.product = product
self.identifier = identifier
self.google = google
self.amazon = amazon
self.ios = ios
# None if the item is not purchasable. Otherwise, a string that
# gives the price in the local language.
self.price = None
class NoneBackend(object):
"""
@@ -74,15 +79,35 @@ init -1500 python in iap:
return False
def is_deferred(self, p):
"""
Returns True if the purchase of `p` has been deferred, and False otherwise.
"""
return False
def get_price(self, p):
"""
Returns the price of the item, or None if the item is not
purchasable.
"""
return None
class AndroidBackend(object):
"""
The IAP backend that is used when IAP is supported.
"""
def __init__(self, devicePurchase, store_name):
self.devicePurchase = devicePurchase
def __init__(self, store, store_name):
self.store = store
self.store_name = store_name
self.store.clearSKUs()
for p in products.values():
self.store.addSKU(self.identifier(p))
def get_store_name(self):
return self.store_name
@@ -105,35 +130,110 @@ init -1500 python in iap:
renpy.pause.
"""
while True:
rv = self.devicePurchase.checkPurchaseResult()
if rv:
break
while not self.store.getFinished():
if interact:
renpy.pause(.1)
else:
time.sleep(.1)
if rv == 1:
return True
else:
return False
def purchase(self, p, interact=True):
identifier = self.identifier(p)
self.devicePurchase.beginPurchase(identifier)
return self.wait_for_result(interact=interact)
self.store.beginPurchase(identifier)
self.wait_for_result(interact=interact)
def restore_purchases(self, interact=True):
self.devicePurchase.restorePurchases()
self.store.updatePrices();
self.wait_for_result(interact)
self.store.restorePurchases();
self.wait_for_result(interact)
def has_purchased(self, p):
identifier = self.identifier(p)
return self.devicePurchase.isPurchaseOwned(identifier)
return self.store.hasPurchased(identifier)
def is_deferred(self, p):
return False
def get_price(self, p):
identifier = self.identifier(p)
return self.store.getPrice(identifier)
if renpy.ios:
import pyobjus
IAPHelper = pyobjus.autoclass("IAPHelper")
NSMutableArray = pyobjus.autoclass("NSMutableArray")
from pyobjus import objc_str, objc_arr
class IOSBackend(object):
def __init__(self):
self.helper = IAPHelper.alloc().init()
identifiers = NSMutableArray.alloc().init()
for p in products.values():
identifiers.addObject_(objc_str(p.ios))
self.helper.productIdentifiers = identifiers
def get_store_name(self):
if self.helper.canMakePayments():
return "ios"
else:
return None
def identifier(self, p):
"""
Returns the identifier for a store purchase.
"""
return p.ios
def wait_for_result(self, interact=True):
"""
Waits for a result.
`interact`
If true, waits interactively. If false, waits using
renpy.pause.
"""
while not self.helper.finished:
if interact:
renpy.pause(.1)
else:
import pygame
pygame.event.pump()
time.sleep(.1)
def purchase(self, p, interact=True):
identifier = objc_str(self.identifier(p))
self.helper.beginPurchase_(identifier)
self.wait_for_result(interact=interact)
def restore_purchases(self, interact=True):
self.helper.validateProductIdentifiers()
self.helper.restorePurchases()
self.wait_for_result(interact)
def has_purchased(self, p):
identifier = objc_str(self.identifier(p))
return self.helper.hasPurchased_(identifier)
def is_deferred(self, p):
identifier = objc_str(self.identifier(p))
return self.helper.isDeferred_(identifier)
def get_price(self, p):
identifier = objc_str(self.identifier(p))
rv = self.helper.formatPrice_(identifier)
if rv is not None:
rv = rv.UTF8String().decode("utf-8")
return rv
# The backend we're using.
backend = NoneBackend()
@@ -141,7 +241,7 @@ init -1500 python in iap:
# A map from product identifier to the product object.
products = { }
def register(product, identifier=None, amazon=None, google=None):
def register(product, identifier=None, amazon=None, google=None, ios=None):
"""
:doc: iap
@@ -166,6 +266,10 @@ init -1500 python in iap:
`google`
A string that identifies the product in the Google Play store.
If not given, defaults to `identifier`.
`ios`
A string that identifies the product in the Apple App store for
iOS. If not given, defaults to `identifier`.
"""
if product in products:
@@ -174,8 +278,9 @@ init -1500 python in iap:
identifier = identifier or product
amazon = amazon or identifier
google = google or identifier
ios = ios or identifier
p = Product(product, identifier, google, amazon)
p = Product(product, identifier, google, amazon, ios)
products[product] = p
def with_background(f, *args, **kwargs):
@@ -185,6 +290,8 @@ init -1500 python in iap:
renpy.scene()
renpy.show(background)
renpy.pause(0)
return f(*args, **kwargs)
def restore(interact=True):
@@ -238,12 +345,13 @@ init -1500 python in iap:
if persistent._iap_purchases[p.identifier]:
return True
rv = backend.purchase(p, interact)
backend.purchase(p, interact)
if rv:
if backend.has_purchased(p):
persistent._iap_purchases[p.identifier] = True
return rv
return True
else:
return False
class Purchase(Action):
"""
@@ -256,13 +364,34 @@ init -1500 python in iap:
def __init__(self, product):
self.product = product
self.sensitive = True
def __call__(self):
renpy.invoke_in_new_context(with_background, purchase, self.product)
renpy.restart_interaction()
def should_be_sensitive(self):
if not get_store_name():
return False
if has_purchased(self.product):
return False
if is_deferred(self.product):
return False
return True
def get_sensitive(self):
return get_store_name() and not has_purchased(self.product)
self.sensitive = self.should_be_sensitive()
return self.sensitive
def periodic(self, st):
if self.should_be_sensitive() != self.sensitive:
renpy.restart_interaction()
return 5.0
def has_purchased(product):
"""
@@ -274,15 +403,53 @@ init -1500 python in iap:
p = get_product(product)
return persistent._iap_purchases[p.identifier]
# Check the cache first, since we might be off line.
if persistent._iap_purchases.get(p.identifier, False):
return True
# Then ask the backend, in case we bought the product
# recently.
return backend.has_purchased(p)
def is_deferred(product):
"""
:doc: iap
Returns True if the user has asked to purchase `product`, but that
request has to be approved by a third party, such as a parent or
guardian.
"""
p = get_product(product)
# Then ask the backend, in case we bought the product
# recently.
return backend.is_deferred(p)
def get_price(product):
"""
:doc: iap
Returns a string giving the price of the `product` in the user's
local currency. Returns None if the price of the product is unknown -
which indicates the product cannot be purchased.
"""
p = get_product(product)
if p.price is None:
p.price = backend.get_price(p)
return p.price
def get_store_name():
"""
:doc: iap
Returns the name of the enabled store for in-app purchase. This
currently returns one of "amazon", "google", or None if no store
is configured.
currently returns one of "amazon", "google", "ios" or None if no store
is available.
"""
return backend.get_store_name()
@@ -304,13 +471,15 @@ init -1500 python in iap:
"""
from jnius import autoclass
devicePurchase = autoclass('com.puzzlebrothers.renpurchase.devicePurchase')
Store = autoclass('org.renpy.iap.Store')
store = Store.getStore()
store_name = store.getStoreName()
store_name = devicePurchase.getStoreName()
if store_name == "none":
return NoneBackend()
return AndroidBackend(devicePurchase, store_name)
return AndroidBackend(store, store_name)
def init():
"""
@@ -329,6 +498,12 @@ init -1500 python in iap:
# Set up the back end.
if renpy.android:
backend = init_android()
elif renpy.ios:
backend = IOSBackend()
if backend.get_store_name() is None:
backend = NoneBackend()
else:
backend = NoneBackend()
+44 -7
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 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
@@ -25,21 +25,26 @@ init -1600 python:
# Bindings present almost everywhere, unless explicitly
# disabled.
rollback = [ 'K_PAGEUP', 'mousedown_4', 'joy_rollback' ],
rollback = [ 'K_PAGEUP', 'K_AC_BACK', 'mousedown_4', 'joy_rollback' ],
screenshot = [ 's' ],
toggle_fullscreen = [ 'f', 'alt_K_RETURN', 'alt_K_KP_ENTER', 'K_F11' ],
game_menu = [ 'K_ESCAPE', 'mouseup_3', 'joy_menu' ],
game_menu = [ 'K_ESCAPE', 'K_MENU', 'mouseup_3', 'joy_menu' ],
hide_windows = [ 'mouseup_2', 'h', 'joy_hide' ],
launch_editor = [ 'E' ],
dump_styles = [ ],
reload_game = [ 'R' ],
inspector = [ 'I' ],
full_inspector = [ 'alt_I' ],
developer = [ 'D' ],
quit = [ 'meta_q', 'alt_K_F4', 'alt_q' ],
iconify = [ 'meta_m', 'alt_m' ],
quit = [ ],
iconify = [ ],
help = [ 'K_F1', 'meta_shift_/' ],
choose_renderer = [ 'G' ],
progress_screen = [ 'alt_P' ],
# Accessibility.
self_voicing = [ 'v', 'V' ],
clipboard_voicing = [ 'C' ],
# Say.
rollforward = [ 'mousedown_5', 'K_PAGEDOWN' ],
@@ -101,9 +106,9 @@ init -1600 python:
# Ignored (kept for backwards compatibility).
toggle_music = [ 'm' ],
# Profile one frame
# Profile commands.
profile_once = [ 'K_F8' ],
memory_profile = [ 'K_F7' ],
)
@@ -240,6 +245,35 @@ init -1600 python:
renpy.display.interface.profile_once = True
renpy.restart_interaction()
def _memory_profile():
renpy.memory.diff_memory()
def _progress_screen():
if renpy.context_nesting_level():
return
if renpy.get_screen("_progress"):
renpy.hide_screen("_progress")
else:
renpy.show_screen("_progress")
renpy.restart_interaction()
screen _progress:
$ seen = renpy.count_seen_dialogue_blocks()
$ total = renpy.count_dialogue_blocks()
drag:
draggable True
focus_mask None
xpos 0
ypos 0
text "[seen]/[total]":
size 14
color "#fff"
outlines [ (1, "#000", 0, 0) ]
init -1100 python:
# The default keymap. We might also want to put some of this into
@@ -261,7 +295,10 @@ init -1100 python:
choose_renderer = renpy.curried_call_in_new_context("_choose_renderer"),
console = _console.enter,
profile_once = _profile_once,
memory_profile = _memory_profile,
self_voicing = Preference("self voicing", "toggle"),
clipboard_voicing = Preference("clipboard voicing", "toggle"),
progress_screen = _progress_screen,
)
config.underlay = [ km ]
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files

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