Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ee017f4bc6 | |||
| 4d089f9a0e | |||
| e7f9c5c2ac | |||
| 2df8d38c2f | |||
| 17ac44d610 | |||
| 3c52c2ae3f | |||
| 5a5115e29f | |||
| 5c7ff1c97b | |||
| cc820a3595 | |||
| 48fff48d28 | |||
| 1684243e57 | |||
| 45e14781eb | |||
| 5ceea7b4a5 | |||
| 17e716b4c3 | |||
| adfdbf3246 | |||
| 03b757d60e | |||
| 12c6d77990 | |||
| 8a7373f412 | |||
| df28ff5bdc | |||
| 2afc2beb5d | |||
| 3896bf3aad | |||
| 744ace5ab6 | |||
| 4bf0b74b6c | |||
| 5c6e624ff7 | |||
| 6c0d5a7a10 | |||
| b34cb21f0c | |||
| b77eb7ed0b | |||
| 34193c510e | |||
| 55f1eaf5da | |||
| 9b74b5a367 | |||
| 008922edc6 | |||
| 82edca785f | |||
| b271baecd5 | |||
| 9b48cd2a35 | |||
| 183f6ace88 | |||
| b5987cd6ea | |||
| 6e153a5070 | |||
| 56e59d91dd | |||
| fd91c6811f |
@@ -0,0 +1,24 @@
|
||||
build
|
||||
dist
|
||||
dists
|
||||
renpy.app
|
||||
**/*.rpyc
|
||||
**/*.rpyb
|
||||
**/*.rpymc
|
||||
_renpy.c
|
||||
nativemidi.c
|
||||
sound.c
|
||||
winmixer.c
|
||||
jedit
|
||||
lint.txt
|
||||
renpy.code
|
||||
traceback.txt
|
||||
doc/common.css
|
||||
doc/images
|
||||
doc/index.html
|
||||
doc/monobook.css
|
||||
doc/monobook2.css
|
||||
doc/reference
|
||||
doc/shared.css
|
||||
doc/tutorials
|
||||
doc/www.renpy.org
|
||||
@@ -1,3 +1,115 @@
|
||||
New in Ren'Py 6.8.0
|
||||
-------------------
|
||||
|
||||
Ren'Py now includes its own font-handling library, derived from
|
||||
pygame.font/SDL_ttf, which it uses in place of them when
|
||||
possible. This gives two advantages:
|
||||
|
||||
* Outlined text is now possible. The new outlines style property
|
||||
allows you to specify one or more outlines, including offset
|
||||
ones. This allows for several fairly complicated text effects, similar
|
||||
to what you'd see in modern subtitles.
|
||||
|
||||
* The bug preventing fonts from being archived has probably been
|
||||
fixed. It should now be possible to include a font in an archive, and
|
||||
have that work. The archiver has been modified to allow ttf files to
|
||||
be archived again. Please report any bugs/crashes that occur.
|
||||
|
||||
|
||||
There is now a new justify style property, that causes lines of text
|
||||
to have additional whitespace inserted between words so that the left
|
||||
and right margins are even, except on the last line of a paragraph.
|
||||
|
||||
|
||||
Ren'Py now supports the MudgeFont image-based file format. The new
|
||||
renpy.register_mudgefont function is used to register a
|
||||
MudgeFont.
|
||||
|
||||
|
||||
Newly-created games will have a Help option on the main and game
|
||||
menus. This is controlled by the config.help variable. By default
|
||||
the help system shows the README.html file in the game's base directory.
|
||||
|
||||
|
||||
If the file icon.ico is present in the base directory, it will be used
|
||||
as the icon of the windows exe when building the windows
|
||||
distribution. Similarly, the file icon.icns will be used as the icon
|
||||
of the Macintosh application. (Note that .icns is a different file format
|
||||
from .ico.)
|
||||
|
||||
|
||||
On Mac OS X, Ren'Py will not change the application icon unless
|
||||
config.window_icon is set. More specifically, it will default to the
|
||||
launcher icon rather than a generic pygame icon.
|
||||
|
||||
|
||||
The Macintosh application will now show the name of the game in the
|
||||
menu bar, rather than "Ren'Py Launcher".
|
||||
|
||||
|
||||
The "Continue Game" option on the main menu has been renamed "Load
|
||||
Game", for consistency with the game menu.
|
||||
|
||||
|
||||
When config.developer is set and an undefined image is used in a show
|
||||
or scene statement, a list of undefined images will appear centered at
|
||||
the top of the screen. A black screen (configurable with
|
||||
config.missing_background) will be shown instead of any missing
|
||||
background. This makes it easier to write a script before all images
|
||||
are present.
|
||||
|
||||
|
||||
The newly-documented Style.set_parent method lets you change the
|
||||
parent of a style. The new style.rebuild function allows styles to be
|
||||
rebuilt even after the game has begun running, with some
|
||||
caveats. (Changes are not persisted, for one thing.)
|
||||
|
||||
|
||||
The new unscrollable style property allows one to choose how
|
||||
unscrollbable scrollbars are displays. None keeps the current
|
||||
behavior, which shows the bar normally. If set to "insensitive", the
|
||||
bar becomes insensitive, while if set to "hide", the bar is not
|
||||
drawn at all.
|
||||
|
||||
|
||||
The new renpy.easy_displayable method can be used by user-defined
|
||||
displayables to convert strings into Solid or Image displayables.
|
||||
|
||||
|
||||
Alt-F4 and Command-Q now trigger the quit event, as if you pressed the
|
||||
quit button on the top of the window. The first press brings up the
|
||||
quit prompt, and a second press forcibly terminates the game.
|
||||
|
||||
Alt-M and Command-M iconify the window.
|
||||
|
||||
|
||||
The new RENPY_SCREENSHOT_PATTERN environment variable lets you
|
||||
configure the name of screenshot files. Ren'Py can now write out
|
||||
screenshots as JPGs, as well as PNGs.
|
||||
|
||||
|
||||
Several of the libraries underlying Ren'Py have been updated. Pygame
|
||||
has been updated to version 1.8.1, while Freetype is now at version
|
||||
2.3.7.
|
||||
|
||||
|
||||
The presplash code now looks for presplash.jpg in the game directory
|
||||
if presplash.png is not found.
|
||||
|
||||
|
||||
On Windows, config.window_icon will be scaled to 32x32 if it is wider
|
||||
than 32 pixels. This allows the same icon to be used across platforms.
|
||||
|
||||
|
||||
Custom mouse cursors should now be properly hidden when the mouse
|
||||
leaves the window. Previously, this failed to work on the Mac OS X
|
||||
platform.
|
||||
|
||||
|
||||
The launcher has been moved into the launcher/ directory. This really
|
||||
shouldn't matter much, but may affect packaging and translation.
|
||||
|
||||
|
||||
New in Ren'Py 6.7.1
|
||||
-------------------
|
||||
|
||||
@@ -48,11 +160,20 @@ what to archive. This makes it easier to break the files up into
|
||||
multiple archives, in a single game.
|
||||
|
||||
|
||||
The new renpy.copy_images function copies images with one prefix to a
|
||||
second prefix.
|
||||
|
||||
|
||||
The launcher will no longer include directories beginning with a dot
|
||||
(like .svn and .bzr) when copying the template directory to create a
|
||||
new project.
|
||||
|
||||
|
||||
This version includes a refresh of the character art included with
|
||||
"The Question". The new art is by Deji, and the full-color version of
|
||||
the art is available from http://wiki.renai.us/.
|
||||
|
||||
|
||||
|
||||
New in Ren'Py 6.7.0
|
||||
-------------------
|
||||
|
||||
@@ -18,7 +18,8 @@ def main():
|
||||
setup(name="RenPy",
|
||||
windows=[ dict(script="renpy.py",
|
||||
dest_base="renpy",
|
||||
icon_resources=[ (1, "newicon.ico") ] ) ],
|
||||
icon_resources=[ (1, "newicon.ico") ] ),
|
||||
],
|
||||
|
||||
console=[ dict(script="renpy.py", dest_base="console") ],
|
||||
|
||||
|
||||
@@ -196,6 +196,9 @@ label _style_hierarchy:
|
||||
jump _developer_screen
|
||||
|
||||
|
||||
init -1050 python:
|
||||
config.missing_background = "black"
|
||||
|
||||
init 1050 python:
|
||||
|
||||
if renpy.game.options.remote:
|
||||
@@ -214,4 +217,73 @@ init 1050 python:
|
||||
config.underlay.append(Remote())
|
||||
del Remote
|
||||
|
||||
|
||||
|
||||
if config.developer:
|
||||
|
||||
# This is used to indicate that a scene has just occured,
|
||||
# and so if the next thing is a missing_show, we should
|
||||
# blank the screen.
|
||||
__missing_scene = False
|
||||
|
||||
# This returns the __missing dictionary from the current
|
||||
# context object.
|
||||
def __missing():
|
||||
try:
|
||||
return renpy.context().__missing
|
||||
except AttributeError:
|
||||
rv = dict()
|
||||
renpy.context().__missing = rv
|
||||
return rv
|
||||
|
||||
def __missing_show_callback(name, what, layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
if __missing_scene:
|
||||
renpy.show(name, what=config.missing_background)
|
||||
__missing_scene = False
|
||||
|
||||
what = " ".join(what).replace("{", "{{")
|
||||
__missing()[name[0]] = what
|
||||
return True
|
||||
|
||||
def __missing_hide_callback(name, layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
__missing_scene = False
|
||||
|
||||
__missing().pop(name[0], None)
|
||||
return True
|
||||
|
||||
def __missing_scene_callback(layer):
|
||||
if layer != 'master':
|
||||
return False
|
||||
|
||||
global __missing_scene
|
||||
__missing_scene = True
|
||||
__missing().clear()
|
||||
|
||||
return True
|
||||
|
||||
def __missing_overlay():
|
||||
missing = __missing()
|
||||
|
||||
if not missing:
|
||||
return
|
||||
|
||||
ui.vbox(xalign=0.5, yalign=0.0)
|
||||
ui.text(_("Undefined Images"), xalign=0.5)
|
||||
|
||||
for what in sorted(missing.values()):
|
||||
ui.text(what, xalign=0.5)
|
||||
|
||||
ui.close()
|
||||
|
||||
|
||||
config.missing_scene = __missing_scene_callback
|
||||
config.missing_show = __missing_show_callback
|
||||
config.missing_hide = __missing_hide_callback
|
||||
config.overlay_functions.append(__missing_overlay)
|
||||
|
||||
@@ -111,16 +111,35 @@ init -1180 python:
|
||||
renpy.jump("_noisy_return")
|
||||
else:
|
||||
renpy.restart_interaction()
|
||||
|
||||
config.help = None
|
||||
|
||||
def _help():
|
||||
if not config.help:
|
||||
return
|
||||
|
||||
if renpy.has_label(config.help):
|
||||
renpy.call_in_new_context(config.help)
|
||||
return
|
||||
|
||||
_preferences.fullscreen = False
|
||||
|
||||
import webbrowser
|
||||
webbrowser.open_new("file:///" + config.basedir + "/" + config.help)
|
||||
|
||||
|
||||
init -1180 python hide:
|
||||
|
||||
# Called to make a screenshot happen.
|
||||
def screenshot():
|
||||
import os.path
|
||||
import os
|
||||
|
||||
pattern = os.environ.get("RENPY_SCREENSHOT_PATTERN", "screenshot%04d.png")
|
||||
|
||||
i = 1
|
||||
while True:
|
||||
fn = "screenshot%04d.png" % i
|
||||
fn = pattern % i
|
||||
if not os.path.exists(fn):
|
||||
break
|
||||
i += 1
|
||||
@@ -143,7 +162,6 @@ init -1180 python hide:
|
||||
|
||||
toggle_skipping()
|
||||
|
||||
|
||||
def fast_skip():
|
||||
if config.fast_skipping or config.developer:
|
||||
config.skipping = "fast"
|
||||
@@ -163,8 +181,9 @@ init -1180 python hide:
|
||||
|
||||
filename, line = renpy.get_filename_line()
|
||||
renpy.launch_editor([ filename ], line)
|
||||
|
||||
# The default keymap.
|
||||
|
||||
# The default keymap. We might also want to put some of this into
|
||||
# the launcher.
|
||||
km = renpy.Keymap(
|
||||
rollback = renpy.rollback,
|
||||
screenshot = screenshot,
|
||||
@@ -178,6 +197,9 @@ init -1180 python hide:
|
||||
dump_styles = dump_styles,
|
||||
reload_game = reload_game,
|
||||
developer = renpy.curried_call_in_new_context("_developer"),
|
||||
quit = renpy.quit_event,
|
||||
iconify = renpy.iconify,
|
||||
help = _help,
|
||||
)
|
||||
|
||||
config.underlay = [ km ]
|
||||
|
||||
@@ -12,9 +12,10 @@ init -1150 python:
|
||||
|
||||
config.main_menu = [
|
||||
(u"Start Game", "start", "True"),
|
||||
(u"Continue Game", _intra_jumps("load_screen", "main_game_transition"), "True"),
|
||||
(u"Load Game", _intra_jumps("load_screen", "main_game_transition"), "True"),
|
||||
(u"Preferences", _intra_jumps("preferences_screen", "main_game_transition"), "True"),
|
||||
(u"Quit", ui.jumps("_quit"), "True")
|
||||
(u"Help", _help, "True", "config.help"),
|
||||
(u"Quit", ui.jumps("_quit"), "True"),
|
||||
]
|
||||
|
||||
config.game_menu = [
|
||||
@@ -23,6 +24,7 @@ init -1150 python:
|
||||
( "save", u"Save Game", _intra_jumps("save_screen", "intra_transition"), 'not main_menu' ),
|
||||
( "load", u"Load Game", _intra_jumps("load_screen", "intra_transition"), 'True'),
|
||||
( None, u"Main Menu", ui.callsinnewcontext("_main_menu_prompt"), 'not main_menu' ),
|
||||
( "help", u"Help", _help, "True", "config.help"),
|
||||
( None, u"Quit", ui.callsinnewcontext("_quit_prompt"), 'True' ),
|
||||
]
|
||||
|
||||
|
||||
@@ -132,8 +132,10 @@ init -1090 python:
|
||||
style.default.strikethrough = False
|
||||
style.default.drop_shadow = None
|
||||
style.default.drop_shadow_color = (0, 0, 0, 255)
|
||||
style.default.outlines = [ ]
|
||||
style.default.minwidth = 0
|
||||
style.default.textalign = 0
|
||||
style.default.text_align = 0
|
||||
style.default.justify = False
|
||||
style.default.text_y_fudge = 0
|
||||
style.default.first_indent = 0
|
||||
style.default.rest_indent = 0
|
||||
@@ -185,6 +187,7 @@ init -1090 python:
|
||||
style.default.left_gutter = 0
|
||||
style.default.right_gutter = 0
|
||||
style.default.thumb_offset = 0
|
||||
style.default.unscrollable = None
|
||||
|
||||
# Misc.
|
||||
style.default.activate_sound = None
|
||||
|
||||
@@ -480,14 +480,6 @@ init -1110 python hide:
|
||||
style.gm_root.background = "#e9d8bc"
|
||||
|
||||
|
||||
theme.outline_drop_shadow = [
|
||||
(0, -2),
|
||||
(-1, -1), (0, -1), (1, -1),
|
||||
(-2, 0), (-1, 0), (1, 0), (2, 0),
|
||||
(-1, 1), (0, 1), (1, 1),
|
||||
(0, 2)
|
||||
]
|
||||
|
||||
@theme
|
||||
def outline_frames():
|
||||
theme.clear_frames()
|
||||
@@ -507,12 +499,11 @@ init -1110 python hide:
|
||||
|
||||
style.button_text.size = text_size
|
||||
style.button_text.color = inside
|
||||
style.button_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.button_text.drop_shadow_color = idle
|
||||
style.button_text.hover_drop_shadow_color = hover
|
||||
style.button_text.selected_drop_shadow_color = selected
|
||||
style.button_text.selected_hover_drop_shadow_color = hover
|
||||
style.button_text.insensitive_drop_shadow_color = insensitive
|
||||
style.button_text.outlines = [ (2, idle) ]
|
||||
style.button_text.hover_outlines = [ (2, hover) ]
|
||||
style.button_text.selected_outlines = [ (2, selected) ]
|
||||
style.button_text.selected_hover_outlines = [ (2, hover) ]
|
||||
style.button_text.insensitive_outlines = [ (2, insensitive) ]
|
||||
|
||||
|
||||
@theme
|
||||
@@ -534,12 +525,12 @@ init -1110 python hide:
|
||||
|
||||
style.large_button_text.size = text_size
|
||||
style.large_button_text.color = inside
|
||||
style.large_button_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.large_button_text.drop_shadow_color = idle
|
||||
style.large_button_text.hover_drop_shadow_color = hover
|
||||
style.large_button_text.selected_drop_shadow_color = selected
|
||||
style.large_button_text.selected_hover_drop_shadow_color = hover
|
||||
style.large_button_text.insensitive_drop_shadow_color = insensitive
|
||||
|
||||
style.large_button_text.outlines = [ (2, idle) ]
|
||||
style.large_button_text.hover_outlines = [ (2, hover) ]
|
||||
style.large_button_text.selected_outlines = [ (2, selected) ]
|
||||
style.large_button_text.selected_hover_outlines = [ (2, hover) ]
|
||||
style.large_button_text.insensitive_outlines = [ (2, insensitive) ]
|
||||
|
||||
@theme
|
||||
def outline_prompts(
|
||||
@@ -550,8 +541,7 @@ init -1110 python hide:
|
||||
theme.clear_prompts()
|
||||
|
||||
style.prompt_text.color = inside
|
||||
style.prompt_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.prompt_text.drop_shadow_color = prompt
|
||||
style.prompt_text.outlines = [ (2, prompt) ]
|
||||
style.prompt_text.size = text_size
|
||||
|
||||
@theme
|
||||
@@ -563,8 +553,7 @@ init -1110 python hide:
|
||||
theme.clear_labels()
|
||||
|
||||
style.label_text.color = inside
|
||||
style.label_text.drop_shadow = theme.outline_drop_shadow
|
||||
style.label_text.drop_shadow_color = label
|
||||
style.label_text.outlines = [ (2, label) ]
|
||||
style.label_text.size = text_size
|
||||
|
||||
@theme
|
||||
@@ -622,8 +611,6 @@ init -1110 python hide:
|
||||
style.vscrollbar.hover_bottom_bar = Frame(color("vbar", hover), 0, 0)
|
||||
style.vscrollbar.hover_thumb = Frame(color("circle", hover), 0, 7)
|
||||
|
||||
|
||||
|
||||
@theme
|
||||
def outline(
|
||||
inside="#fff",
|
||||
|
||||
@@ -22,7 +22,7 @@ init python:
|
||||
style.prefs_column.box_spacing = 5
|
||||
style.prefs_frame.top_margin = 5
|
||||
|
||||
style.prefs_left.xpos = 100
|
||||
style.prefs_left.xpos = 110
|
||||
style.prefs_center.xpos = 320
|
||||
style.prefs_right.xpos = 530
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
dist/console.exe
|
||||
@@ -1,3 +0,0 @@
|
||||
init -50:
|
||||
$ config.script_version = (6, 7, 1)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../help.html
|
||||
|
Before Width: | Height: | Size: 19 KiB |
@@ -2,41 +2,41 @@
|
||||
# capabilities of Ren'Py.
|
||||
|
||||
init:
|
||||
python:
|
||||
# Register an sfont.
|
||||
$ renpy.register_sfont('new_sfont', 22,
|
||||
filename="new_sfont.png",
|
||||
spacewidth=6)
|
||||
|
||||
# This imports in the asfont22 module, which contains a list of
|
||||
# kerning pairs.
|
||||
import asfont22
|
||||
|
||||
# Register the sfont contained in asfont22 as "subfont".
|
||||
renpy.register_sfont('subfont', 22,
|
||||
filename="asfont22.png",
|
||||
kerns=asfont22.kerns,
|
||||
spacewidth=4)
|
||||
|
||||
# Declare some characters that speak in the subfont.
|
||||
|
||||
# Just use the subfont.
|
||||
$ esub = Character("Eileen",
|
||||
color="#c8ffc8",
|
||||
what_font="subfont",
|
||||
what_black_color="#282")
|
||||
# Declare a character that uses the sfont.
|
||||
$ esfont = Character("Eileen",
|
||||
color="#c8ffc8",
|
||||
what_font="new_sfont")
|
||||
|
||||
# Slow text.
|
||||
$ eslow = Character("Eileen",
|
||||
color="#c8ffc8",
|
||||
what_slow_cps=20)
|
||||
|
||||
|
||||
# Outlined text.
|
||||
$ eoutline = Character("Eileen",
|
||||
color="#c8ffc8",
|
||||
what_outlines=[ (1, "#282") ])
|
||||
|
||||
# Use it in subtitle mode.
|
||||
$ esubtitle = Character(None,
|
||||
what_font="subfont",
|
||||
what_black_color="#282",
|
||||
what_size=28,
|
||||
what_outlines=[(3, "#0008", 2, 2), (3, "#282", 0, 0)],
|
||||
what_layout="subtitle",
|
||||
what_xalign=0.5,
|
||||
what_text_align=0.5,
|
||||
window_background=None,
|
||||
window_yminimum=0,
|
||||
show_say_vbox_properties=dict(xalign=0.5))
|
||||
window_xfill=False,
|
||||
window_xalign=0.5)
|
||||
|
||||
|
||||
# This is used to show the defintion text, by the hyperlink demostration
|
||||
# code.
|
||||
$ definition = Character(None,
|
||||
window_yfill=True,
|
||||
window_xmargin=20,
|
||||
@@ -48,7 +48,7 @@ init:
|
||||
$ style.pink.color = "#ffc0c0"
|
||||
|
||||
label demo_text:
|
||||
|
||||
|
||||
e "Ren'Py gives you quite a bit of control over how text appears."
|
||||
|
||||
e "Text tags let us control the appearance of text that is shown to the user."
|
||||
@@ -86,13 +86,23 @@ label demo_text:
|
||||
|
||||
e "And we want to give you all the power you need."
|
||||
|
||||
esub "For even more control, Ren'Py supports SFonts, image files containing font information."
|
||||
e "There are a couple of text adjustements that don't corrrespond to text tags."
|
||||
|
||||
eoutline "The outlines setting lets you put outlines around the text."
|
||||
|
||||
eoutline "You can have more than one outline, and each has its own color and offset."
|
||||
|
||||
esubtitle "Here, we have two outlines around the white text."
|
||||
|
||||
esubtitle "The bottom one is a translucent black that's offset a little, while the top one is green."
|
||||
|
||||
esub "SFonts let you use fonts you otherwise couldn't, and apply special effects to fonts... like I'm doing now, applying an outline to the font."
|
||||
esubtitle "By hiding the window and adjusting the layout method, we are able to create reasonable subtitles."
|
||||
|
||||
esubtitle "Finally, you can adjust the line breaking algorithm. The subtitle line-breaking algorithm tries to make lines even in length."
|
||||
|
||||
esubtitle "Along with sfonts and the ability to change the text window, this lets us render reasonable subtitles."
|
||||
esubtitle "This might be an interesting look for a game."
|
||||
|
||||
esfont "For even more control, Ren'Py supports SFonts, image files containing font information."
|
||||
|
||||
esfont "SFonts let you use fonts you otherwise couldn't, and apply special effects to fonts using your favorite image editor."
|
||||
|
||||
e "Well, that's it for fonts and text tags."
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ init:
|
||||
("demo_multimedia", "Music and Sound", "5.6.3"),
|
||||
("demo_imageops", "Image Operations", "6.5.0"),
|
||||
("demo_ui", "User Interaction", "6.5.0"),
|
||||
("demo_text", "Fonts and Text Tags", "6.6.2"),
|
||||
("demo_text", "Fonts and Text Tags", "6.8.0"),
|
||||
("demo_character", "Character Objects", "6.2.0"),
|
||||
("demo_advanced", "Advanced Features", "6.7.0"),
|
||||
]
|
||||
|
||||
|
After Width: | Height: | Size: 33 KiB |
@@ -194,7 +194,20 @@ init -1 python hide:
|
||||
|
||||
# config.main_menu_music = "main_menu_theme.ogg"
|
||||
|
||||
|
||||
#########################################
|
||||
## Help.
|
||||
|
||||
## This lets you configure the help option on the Ren'Py menus.
|
||||
## It may be:
|
||||
## - A label in the script, in which case that label is called to
|
||||
## show help to the user.
|
||||
## - A file name relative to the base directory, which is opened in a
|
||||
## web browser.
|
||||
## - None, to disable help.
|
||||
config.help = "README.html"
|
||||
|
||||
|
||||
#########################################
|
||||
## Transitions.
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ def main():
|
||||
os.chmod("./renpy.app/Contents/MacOS/Ren'Py Launcher", 0755)
|
||||
|
||||
# Compile the various games
|
||||
for i in [ 'demo/game', 'data', 'template/game', 'the_question/game' ]:
|
||||
for i in [ 'demo/game', 'launcher', 'template/game', 'the_question/game' ]:
|
||||
os.system("./renpy.sh --compile --game " + i)
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ def main():
|
||||
files.append("LICENSE.txt")
|
||||
files.extend(tree("common"))
|
||||
more_files.append("console.exe")
|
||||
files.extend(tree("data"))
|
||||
files.extend(tree("launcher"))
|
||||
files.extend(tree("demo"))
|
||||
# files.extend(tree("dse"))
|
||||
files.extend(tree("the_question"))
|
||||
@@ -177,6 +177,9 @@ def main():
|
||||
"winmixer.pyx",
|
||||
"IMG_savepng.c",
|
||||
"IMG_savepng.h",
|
||||
"renpy_font.c",
|
||||
"renpy_ttf.c",
|
||||
"renpy_ttf.h",
|
||||
]
|
||||
|
||||
for i in module_files:
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>README</title>
|
||||
<style>
|
||||
HTML {
|
||||
background: #eed;
|
||||
}
|
||||
|
||||
BODY {
|
||||
background: #fff;
|
||||
margin: 0px 10% 0px 10%;
|
||||
border-left: 1px solid #888;
|
||||
border-right: 1px solid #888;
|
||||
padding-left: 4em;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
DT {
|
||||
font-weight: bold;
|
||||
margin-top: .33em;
|
||||
}
|
||||
|
||||
H3 {
|
||||
color: #600;
|
||||
margin-left: -2.5em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="renpy_help"></div>
|
||||
<p><a name="Basic_Help" id="Basic_Help"></a></p>
|
||||
<h3><span class="mw-headline">Basic Help</span></h3>
|
||||
<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="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="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-H, Command-H</dt>
|
||||
<dd>Hides (iconifies) the window.</dd>
|
||||
<dt>Alt-F4, Command-Q</dt>
|
||||
<dd>Quits the game.</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
import sys
|
||||
import os
|
||||
|
||||
try:
|
||||
import Image
|
||||
except ImportError:
|
||||
print "Could not import the Image module. Please ensure that the Python Imaging"
|
||||
print "Library (PIL) is properly installed."
|
||||
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ init python:
|
||||
import sys
|
||||
import zlib
|
||||
|
||||
import pefile
|
||||
|
||||
# Returns true if a file or directory should not be included in
|
||||
# the distribution
|
||||
|
||||
@@ -16,7 +18,8 @@ init python:
|
||||
"launcherinfo.py",
|
||||
"traceback.txt",
|
||||
"errors.txt",
|
||||
"completion.lua",)
|
||||
"icon.ico",
|
||||
"icon.icns")
|
||||
|
||||
def ignored(fn):
|
||||
if fn[0] == ".":
|
||||
@@ -173,7 +176,7 @@ label distribute:
|
||||
spacer()
|
||||
|
||||
if windows:
|
||||
text(u"Windows 98+", style='launcher_input')
|
||||
text(u"Windows 2000+", style='launcher_input')
|
||||
|
||||
if linux:
|
||||
text(u"Linux x86", style='launcher_input')
|
||||
@@ -275,6 +278,13 @@ label distribute:
|
||||
( config.renpy_base + "/msvcr71.dll", "msvcr71.dll" ),
|
||||
]
|
||||
|
||||
win_data = { }
|
||||
if os.path.exists(project.path + "/icon.ico"):
|
||||
win_data[config.renpy_base + "/renpy.exe"] = pefile.change_icons(
|
||||
config.renpy_base + "/renpy.exe",
|
||||
project.path + "/icon.ico",
|
||||
)
|
||||
|
||||
zf = zipfile.ZipFile(name + ".zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
progress_len = len(multi) + len(win_files)
|
||||
@@ -296,6 +306,8 @@ label distribute:
|
||||
zi.external_attr = long(0100666) << 16
|
||||
data = file(fn, "rb").read()
|
||||
|
||||
data = win_data.get(fn, data)
|
||||
|
||||
zf.writestr(zi, data)
|
||||
|
||||
|
||||
@@ -360,6 +372,19 @@ label distribute:
|
||||
mac_files = tree(config.renpy_base + "/renpy.app",
|
||||
project.name + ".app")
|
||||
|
||||
mac_files = [ (fn, an.replace("Ren'Py Launcher", project.name)) for (fn, an) in mac_files ]
|
||||
|
||||
# Data replacement for macintosh.
|
||||
mac_data = { }
|
||||
|
||||
quoted_name = project.name.replace("&", "&").replace("<", "<")
|
||||
info_plist = file(config.renpy_base + "/renpy.app/Contents/Info.plist", "rb").read().replace("Ren'Py Launcher", quoted_name)
|
||||
mac_data[config.renpy_base + "/renpy.app/Contents/Info.plist"] = info_plist
|
||||
|
||||
if os.path.exists(project.path + "/icon.icns"):
|
||||
icon_data = file(project.path + "/icon.icns", "rb").read()
|
||||
mac_data[config.renpy_base + "/renpy.app/Contents/Resources/launcher.icns"] = icon_data
|
||||
|
||||
zf = zipfile.ZipFile(name + "-mac.zip", "w", zipfile.ZIP_DEFLATED)
|
||||
|
||||
progress_len = len(multi) + len(mac_files)
|
||||
@@ -371,7 +396,6 @@ label distribute:
|
||||
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
|
||||
|
||||
zi = zipfile.ZipInfo(name + "-mac/" + an)
|
||||
|
||||
@@ -387,6 +411,7 @@ label distribute:
|
||||
zi.external_attr = long(0100666) << 16
|
||||
data = file(fn, "rb").read()
|
||||
|
||||
data = mac_data.get(fn, data)
|
||||
zf.writestr(zi, data)
|
||||
|
||||
zf.close()
|
||||
@@ -4,11 +4,12 @@
|
||||
init:
|
||||
python hide:
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
if not config.editor:
|
||||
|
||||
editor = config.renpy_base + "/jedit/jedit.jar"
|
||||
editor = os.path.normpath(config.renpy_base + "/jedit/jedit.jar")
|
||||
editor = renpy.shell_escape(editor)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
@@ -36,6 +36,13 @@ init:
|
||||
|
||||
style.hyperlink_text.color = "#0ff"
|
||||
|
||||
config.underlay = [
|
||||
renpy.Keymap(
|
||||
quit = renpy.quit_event,
|
||||
iconify = renpy.iconify,
|
||||
)
|
||||
]
|
||||
|
||||
def quote(c):
|
||||
n = ord(c)
|
||||
if 0x20 <= n <= 0x7f:
|
||||
@@ -58,13 +65,14 @@ init:
|
||||
ui.add(DynamicDisplayable("Text(_(store.message), size=14, color='#fff', xpos=100, ypos=375, xmaximum=240)"))
|
||||
ui.text(renpy.version(), xalign=0, yalign=1.0, size=12, color='#000')
|
||||
|
||||
return ui.interact(suppress_underlay=True)
|
||||
return ui.interact()
|
||||
|
||||
def title(name):
|
||||
ui.window(style='mm_root')
|
||||
ui.null()
|
||||
|
||||
ui.frame(xminimum=350, yminimum=370)
|
||||
ui.viewport(child_size=(2000, None), draggable=True, ymaximum=34)
|
||||
_label_factory(name, "launcher_title", size=28)
|
||||
|
||||
# ui.text(name, xpos=4, ypos=4, size=30, color="#559")
|
||||
@@ -93,7 +101,7 @@ init:
|
||||
|
||||
# ui.button(clicked=clicked, hovered=hovered)
|
||||
# ui.text(text, style="button_text")
|
||||
_button_factory(text, 'launcher', clicked=clicked, hovered=hovered, selected=selected)
|
||||
_button_factory(text, 'launcher', clicked=clicked, hovered=hovered, selected=selected, xmaximum=200)
|
||||
|
||||
|
||||
def prompt(name, message, cancel, default='', hint=''):
|
||||
@@ -151,6 +159,8 @@ init:
|
||||
mid(focus="paged_menu")
|
||||
|
||||
for name, desc, ret, hovered, selected in choices[page * per_page:(page + 1) * per_page]:
|
||||
if len(name) > 19:
|
||||
name = name[:18] + u"\u2026"
|
||||
button(name, desc, clicked=ui.returns(("return", ret)), hovered=hovered, selected=selected)
|
||||
|
||||
ui.close()
|
||||
@@ -273,6 +283,7 @@ init:
|
||||
contents.sort()
|
||||
|
||||
for dd in contents:
|
||||
|
||||
dir = d + "/" + dd
|
||||
|
||||
if os.path.isdir(dir):
|
||||
@@ -482,7 +493,8 @@ label edit:
|
||||
files.remove(i)
|
||||
files.insert(0, i)
|
||||
|
||||
renpy.launch_editor(files)
|
||||
if not renpy.launch_editor(files):
|
||||
error(u"Error", u"Launching the editor failed. You may need Java, which can be downloaded for free from {a=http://www.java.com}java.com{/a}.", "start")
|
||||
|
||||
store.message = _(u"Launched editor with %d script files.") % len(files)
|
||||
|
||||
@@ -625,6 +637,8 @@ label archive_files:
|
||||
|
||||
if fn == "presplash.png":
|
||||
return False
|
||||
if fn == "presplash.jpg":
|
||||
return False
|
||||
|
||||
for e in extensions:
|
||||
if fnmatch.fnmatch(fn, e):
|
||||
@@ -0,0 +1,291 @@
|
||||
|
||||
# http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html
|
||||
# Contains a reasonable description of the format.
|
||||
|
||||
import struct
|
||||
import sys
|
||||
import array
|
||||
|
||||
# The starting point of the resource segment in the file.
|
||||
RESOURCE_BASE=0x3400
|
||||
|
||||
# The virtual memory location the resource segment is loaded
|
||||
# to.
|
||||
RESOURCE_VIRTUAL=0x6000
|
||||
|
||||
# The offset of the field that tells us with the alignment need be.
|
||||
ALIGNMENT_FIELD = 0x138
|
||||
|
||||
# Locations in the file where we need to patch in the resource
|
||||
# segment length.
|
||||
RESOURCE_LENGTH_PATCHES = [ 0x018c, 0x278 ]
|
||||
|
||||
# Locations in the file where we need to patch in the padded
|
||||
# resource segment length.
|
||||
RESOURCE_PADDED_PATCHES = [ 0x280 ]
|
||||
|
||||
# Locations in the file where we need to patch in the change in the
|
||||
# size of the resource segement (and hence the change in the file's
|
||||
# total size.)
|
||||
SIZE_DELTA_PATCHES = [ 0x150 ]
|
||||
|
||||
# A location in the file that will be checked to be sure it matches
|
||||
# RESOURCE_BASE.
|
||||
CHECK_ADDRESS = 0x284
|
||||
|
||||
# This class performs various operations on memory-loaded binary files,
|
||||
# including modifications.
|
||||
class BinFile(object):
|
||||
|
||||
def set_u32(self, addr, value):
|
||||
self.a[addr+0] = (value >> 0) & 0xff
|
||||
self.a[addr+1] = (value >> 8) & 0xff
|
||||
self.a[addr+2] = (value >> 16) & 0xff
|
||||
self.a[addr+3] = (value >> 24) & 0xff
|
||||
|
||||
def u32(self):
|
||||
addr = self.addr
|
||||
rv = self.a[addr]
|
||||
rv |= self.a[addr+1] << 8
|
||||
rv |= self.a[addr+2] << 16
|
||||
rv |= self.a[addr+3] << 24
|
||||
self.addr += 4
|
||||
return rv
|
||||
|
||||
def u16(self):
|
||||
addr = self.addr
|
||||
rv = self.a[addr]
|
||||
rv |= self.a[addr+1] << 8
|
||||
self.addr += 2
|
||||
return rv
|
||||
|
||||
def u8(self):
|
||||
rv = self.a[self.addr]
|
||||
self.addr += 1
|
||||
return rv
|
||||
|
||||
def name(self):
|
||||
c = self.u16()
|
||||
|
||||
rv = u""
|
||||
for i in range(c):
|
||||
rv += unichr(self.u16())
|
||||
|
||||
return rv
|
||||
|
||||
def seek(self, addr):
|
||||
self.addr = addr
|
||||
|
||||
def tostring(self):
|
||||
return self.a.tostring()
|
||||
|
||||
def substring(self, start, len):
|
||||
return self.a[start:start+len].tostring()
|
||||
|
||||
def __init__(self, fn):
|
||||
data = open(fn, "rb").read()
|
||||
self.a = array.array('B')
|
||||
self.a.fromstring(data)
|
||||
|
||||
##############################################################################
|
||||
# These functions parse data out of the file. In these functions, offset is
|
||||
# relative to the start of the file.
|
||||
|
||||
# This parses a data block out of the resources.
|
||||
def parse_data(offset):
|
||||
pe.seek(RESOURCE_BASE + offset)
|
||||
data_offset = pe.u32()
|
||||
data_len = pe.u32()
|
||||
code_page = pe.u32()
|
||||
pe.u32()
|
||||
|
||||
l = [ ]
|
||||
|
||||
pe.seek(data_offset + RESOURCE_BASE - RESOURCE_VIRTUAL)
|
||||
for i in range(data_len):
|
||||
l.append(chr(pe.u8()))
|
||||
|
||||
return (code_page, "".join(l))
|
||||
|
||||
# This parses a resource directory.
|
||||
def parse_directory(offset):
|
||||
|
||||
pe.seek(RESOURCE_BASE + offset)
|
||||
char = pe.u32()
|
||||
timedate = pe.u32()
|
||||
major = pe.u16()
|
||||
minor = pe.u16()
|
||||
n_named = pe.u16()
|
||||
n_id = pe.u16()
|
||||
|
||||
entries = [ ]
|
||||
|
||||
for i in range(n_named + n_id):
|
||||
entries.append((pe.u32(), pe.u32()))
|
||||
|
||||
rv = { }
|
||||
|
||||
for name, value in entries:
|
||||
|
||||
if name & 0x80000000:
|
||||
pe.seek((name & 0x7fffffff) + RESOURCE_BASE)
|
||||
name = pe.name()
|
||||
|
||||
if value & 0x80000000:
|
||||
value = parse_directory(value & 0x7fffffff)
|
||||
else:
|
||||
value = parse_data(value)
|
||||
|
||||
rv[name] = value
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
##############################################################################
|
||||
# This utility function displays the tree of resources that have been loaded.
|
||||
def show_resources(d, prefix):
|
||||
|
||||
if not isinstance(d, dict):
|
||||
print prefix, "Codepage", d[0], "length", len(d[1])
|
||||
return
|
||||
|
||||
for k in d:
|
||||
print prefix, k
|
||||
show_resources(d[k], prefix + " ")
|
||||
|
||||
##############################################################################
|
||||
# These functions repack the resources into a new resource segment. Here,
|
||||
# the offset is relative to the start of the resource segment.
|
||||
|
||||
def repack_name(s):
|
||||
l = len(s)
|
||||
s = s.encode("utf-16le")
|
||||
return struct.pack("<H", l) + s + "\0\0"
|
||||
|
||||
def repack_tuple(o, offset):
|
||||
codepage, data = o
|
||||
# print "REPACK OFFSET IS", offset
|
||||
return struct.pack("<IIII", offset + 16 + RESOURCE_VIRTUAL, len(data), codepage, 0) + data
|
||||
|
||||
def repack_dict(o, offset):
|
||||
name_entries = sorted((a, b) for a, b in o.iteritems() if isinstance(a, unicode))
|
||||
id_entries = sorted((a, b) for a, b in o.iteritems() if isinstance(a, int))
|
||||
|
||||
rv = struct.pack("<IIHHHH", 0, 0, 4, 0, len(name_entries), len(id_entries))
|
||||
|
||||
offset += len(rv) + (len(name_entries) + len(id_entries)) * 8
|
||||
|
||||
rest = ""
|
||||
|
||||
for (name, value) in name_entries + id_entries:
|
||||
if isinstance(name, unicode):
|
||||
packed = repack_name(name)
|
||||
name = 0x80000000 | offset
|
||||
offset += len(packed)
|
||||
rest += packed
|
||||
|
||||
pad = 8 - (offset % 8)
|
||||
offset += pad
|
||||
rest += "RENPYVNE"[:pad]
|
||||
|
||||
addr = offset
|
||||
if isinstance(value, dict):
|
||||
addr = addr | 0x80000000
|
||||
|
||||
rv += struct.pack("<II", name, addr)
|
||||
|
||||
if isinstance(value, dict):
|
||||
packed = repack_dict(value, offset)
|
||||
elif isinstance(value, tuple):
|
||||
packed = repack_tuple(value, offset)
|
||||
|
||||
offset += len(packed)
|
||||
rest += packed
|
||||
|
||||
if offset % 8:
|
||||
pad = 8 - (offset % 8)
|
||||
offset += pad
|
||||
rest += "RENPYVNE"[:pad]
|
||||
|
||||
return rv + rest
|
||||
|
||||
##############################################################################
|
||||
# This loads in an icon file, and returns a dictionary that is suitable for
|
||||
# use in the resources of an exe file.
|
||||
def load_icon(fn):
|
||||
f = BinFile(fn)
|
||||
|
||||
f.seek(0)
|
||||
f.u16()
|
||||
f.u16()
|
||||
count = f.u16()
|
||||
|
||||
rv = { }
|
||||
|
||||
for i in range(count):
|
||||
width = f.u8()
|
||||
height = f.u8()
|
||||
colors = f.u8()
|
||||
reserved = f.u8()
|
||||
planes = f.u16()
|
||||
bpp = f.u16()
|
||||
size = f.u32()
|
||||
offset = f.u32()
|
||||
|
||||
rv[i + 1] = { 0 : (1252, f.substring(offset, size)) }
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
##############################################################################
|
||||
# This is the main function that should be called externally, that copies over
|
||||
# the icons.
|
||||
def change_icons(oldexe, icofn):
|
||||
global pe
|
||||
pe = BinFile(oldexe)
|
||||
|
||||
# Check that RESOURCE_BASE is still valid.
|
||||
pe.seek(CHECK_ADDRESS)
|
||||
if pe.u32() != RESOURCE_BASE:
|
||||
raise Exception("RESOURCE_BASE is no longer correct. Please check all relocations.")
|
||||
|
||||
resources = parse_directory(0)
|
||||
# show_resources(resources, "")
|
||||
resources[3] = load_icon(icofn)
|
||||
# show_resources(resources, "")
|
||||
|
||||
rsrc = repack_dict(resources, 0)
|
||||
rsrc_len = len(rsrc)
|
||||
|
||||
pe.seek(ALIGNMENT_FIELD)
|
||||
alignment = pe.u32()
|
||||
|
||||
if len(rsrc) % alignment:
|
||||
pad = alignment - (len(rsrc) % alignment)
|
||||
padding = "RENPYVNE" * (pad / 8 + 1)
|
||||
padding = padding[:pad]
|
||||
rsrc += padding
|
||||
|
||||
padded_len = len(rsrc)
|
||||
|
||||
for addr in RESOURCE_LENGTH_PATCHES:
|
||||
pe.set_u32(addr, rsrc_len)
|
||||
|
||||
for addr in RESOURCE_PADDED_PATCHES:
|
||||
pe.seek(addr)
|
||||
size_delta = padded_len - pe.u32()
|
||||
pe.set_u32(addr, padded_len)
|
||||
|
||||
for addr in SIZE_DELTA_PATCHES:
|
||||
pe.seek(addr)
|
||||
pe.set_u32(addr, pe.u32() + size_delta)
|
||||
|
||||
|
||||
return pe.tostring()[:RESOURCE_BASE] + rsrc
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
f = file(sys.argv[3], "wb")
|
||||
f.write(change_icons(sys.argv[1], sys.argv[2]))
|
||||
f.close()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
init -999:
|
||||
$ config.script_version = (6, 8, 0)
|
||||
|
||||
@@ -0,0 +1,858 @@
|
||||
/*
|
||||
pygame - Python Game Library
|
||||
Copyright (C) 2000-2001 Pete Shinners
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Pete Shinners
|
||||
pete@shinners.org
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* font module for pygame
|
||||
*/
|
||||
#include <Python.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "pygame.h"
|
||||
#include "structmember.h"
|
||||
#include "renpy_ttf.h"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
RENPY_TTF_Font* font;
|
||||
PyObject* weakreflist;
|
||||
} PyFontObject;
|
||||
#define PyFont_AsFont(x) (((PyFontObject*)x)->font)
|
||||
|
||||
static int font_initialized = 0;
|
||||
static char* font_defaultname = "freesansbold.ttf";
|
||||
static PyObject* self_module = NULL;
|
||||
|
||||
static char* pkgdatamodule_name = "pygame.pkgdata";
|
||||
static char* resourcefunc_name = "getResource";
|
||||
|
||||
static PyObject *font_resource(char *filename) {
|
||||
PyObject* load_basicfunc = NULL;
|
||||
PyObject* pkgdatamodule = NULL;
|
||||
PyObject* resourcefunc = NULL;
|
||||
PyObject* result = NULL;
|
||||
|
||||
pkgdatamodule = PyImport_ImportModule(pkgdatamodule_name);
|
||||
if (!pkgdatamodule) goto font_resource_end;
|
||||
|
||||
resourcefunc = PyObject_GetAttrString(pkgdatamodule, resourcefunc_name);
|
||||
if (!resourcefunc) goto font_resource_end;
|
||||
|
||||
result = PyObject_CallFunction(resourcefunc, "s", filename);
|
||||
if (!result) goto font_resource_end;
|
||||
|
||||
if (PyFile_Check(result)) {
|
||||
PyObject *tmp = PyFile_Name(result);
|
||||
Py_INCREF(tmp);
|
||||
Py_DECREF(result);
|
||||
result = tmp;
|
||||
}
|
||||
|
||||
font_resource_end:
|
||||
Py_XDECREF(pkgdatamodule);
|
||||
Py_XDECREF(resourcefunc);
|
||||
Py_XDECREF(load_basicfunc);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void font_autoquit(void)
|
||||
{
|
||||
if(font_initialized)
|
||||
{
|
||||
font_initialized = 0;
|
||||
RENPY_TTF_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static PyObject* font_autoinit(PyObject* self, PyObject* arg)
|
||||
{
|
||||
if(!PyArg_ParseTuple(arg, ""))
|
||||
return NULL;
|
||||
|
||||
if(!font_initialized)
|
||||
{
|
||||
PyGame_RegisterQuit(font_autoquit);
|
||||
|
||||
if(RENPY_TTF_Init())
|
||||
return PyInt_FromLong(0);
|
||||
font_initialized = 1;
|
||||
|
||||
}
|
||||
return PyInt_FromLong(font_initialized);
|
||||
}
|
||||
|
||||
|
||||
/*DOC*/ static char doc_quit[] =
|
||||
/*DOC*/ "pygame.font.quit() -> none\n"
|
||||
/*DOC*/ "uninitialize the font module\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Manually uninitialize SDL_ttf's font system. It is safe to call\n"
|
||||
/*DOC*/ "this if font is currently not initialized.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* fontmodule_quit(PyObject* self, PyObject* arg)
|
||||
{
|
||||
if(!PyArg_ParseTuple(arg, ""))
|
||||
return NULL;
|
||||
|
||||
font_autoquit();
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*DOC*/ static char doc_init[] =
|
||||
/*DOC*/ "pygame.font.init() -> None\n"
|
||||
/*DOC*/ "initialize the display module\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Manually initialize the font module. Will raise an exception if\n"
|
||||
/*DOC*/ "it cannot be initialized. It is safe to call this function if\n"
|
||||
/*DOC*/ "font is currently initialized.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* fontmodule_init(PyObject* self, PyObject* arg)
|
||||
{
|
||||
PyObject* result;
|
||||
int istrue;
|
||||
|
||||
if(!PyArg_ParseTuple(arg, ""))
|
||||
return NULL;
|
||||
|
||||
result = font_autoinit(self, arg);
|
||||
istrue = PyObject_IsTrue(result);
|
||||
Py_DECREF(result);
|
||||
if(!istrue)
|
||||
return RAISE(PyExc_SDLError, SDL_GetError());
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_get_init[] =
|
||||
/*DOC*/ "pygame.font.get_init() -> bool\n"
|
||||
/*DOC*/ "get status of font module initialization\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Returns true if the font module is currently intialized.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* get_init(PyObject* self, PyObject* arg)
|
||||
{
|
||||
if(!PyArg_ParseTuple(arg, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong(font_initialized);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* font object methods */
|
||||
|
||||
/*DOC*/ static char doc_font_get_height[] =
|
||||
/*DOC*/ "Font.get_height() -> int\n"
|
||||
/*DOC*/ "average height of font glyph\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Returns the average size of each glyph in the font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_height(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong(RENPY_TTF_FontHeight(font));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_get_descent[] =
|
||||
/*DOC*/ "Font.get_descent() -> int\n"
|
||||
/*DOC*/ "gets the font descent\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Returns the descent for the font. The descent is the number of\n"
|
||||
/*DOC*/ "pixels from the font baseline to the bottom of the font.\n"
|
||||
/*DOC*/ "With most fonts this is a negative number.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_descent(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong(RENPY_TTF_FontDescent(font));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_get_ascent[] =
|
||||
/*DOC*/ "Font.get_ascent() -> int\n"
|
||||
/*DOC*/ "gets the font ascent\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Returns the ascent for the font. The ascent is the number of\n"
|
||||
/*DOC*/ "pixels from the font baseline to the top of the font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_ascent(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong(RENPY_TTF_FontAscent(font));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_get_linesize[] =
|
||||
/*DOC*/ "Font.get_linesize() -> int\n"
|
||||
/*DOC*/ "gets the font recommended linesize\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Returns the linesize for the font. Each font comes with it's own\n"
|
||||
/*DOC*/ "recommendation for the spacing number of pixels between each line\n"
|
||||
/*DOC*/ "of the font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_linesize(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong(RENPY_TTF_FontLineSkip(font));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_get_bold[] =
|
||||
/*DOC*/ "Font.get_bold() -> bool\n"
|
||||
/*DOC*/ "status of the bold attribute\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Get the current status of the font's bold attribute\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_bold(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong((RENPY_TTF_GetFontStyle(font)&RENPY_TTF_STYLE_BOLD) != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_set_bold[] =
|
||||
/*DOC*/ "Font.set_bold(bool) -> None\n"
|
||||
/*DOC*/ "assign the bold attribute\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Enables or disables the bold attribute for the font. Making the\n"
|
||||
/*DOC*/ "font bold does not work as well as you expect.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_set_bold(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
int style, val;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "i", &val))
|
||||
return NULL;
|
||||
|
||||
style = RENPY_TTF_GetFontStyle(font);
|
||||
if(val)
|
||||
style |= RENPY_TTF_STYLE_BOLD;
|
||||
else
|
||||
style &= ~RENPY_TTF_STYLE_BOLD;
|
||||
RENPY_TTF_SetFontStyle(font, style);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_get_italic[] =
|
||||
/*DOC*/ "Font.get_italic() -> bool\n"
|
||||
/*DOC*/ "status of the italic attribute\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Get the current status of the font's italic attribute\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_italic(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong((RENPY_TTF_GetFontStyle(font)&RENPY_TTF_STYLE_ITALIC) != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_set_italic[] =
|
||||
/*DOC*/ "Font.set_italic(bool) -> None\n"
|
||||
/*DOC*/ "assign the italic attribute\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Enables or disables the italic attribute for the font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_set_italic(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
int style, val;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "i", &val))
|
||||
return NULL;
|
||||
|
||||
style = RENPY_TTF_GetFontStyle(font);
|
||||
if(val)
|
||||
style |= RENPY_TTF_STYLE_ITALIC;
|
||||
else
|
||||
style &= ~RENPY_TTF_STYLE_ITALIC;
|
||||
RENPY_TTF_SetFontStyle(font, style);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_get_underline[] =
|
||||
/*DOC*/ "Font.get_underline() -> bool\n"
|
||||
/*DOC*/ "status of the underline attribute\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Get the current status of the font's underline attribute\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_get_underline(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return PyInt_FromLong((RENPY_TTF_GetFontStyle(font)&RENPY_TTF_STYLE_UNDERLINE) != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_set_underline[] =
|
||||
/*DOC*/ "Font.set_underline(bool) -> None\n"
|
||||
/*DOC*/ "assign the underline attribute\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Enables or disables the underline attribute for the font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_set_underline(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
int style, val;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "i", &val))
|
||||
return NULL;
|
||||
|
||||
style = RENPY_TTF_GetFontStyle(font);
|
||||
if(val)
|
||||
style |= RENPY_TTF_STYLE_UNDERLINE;
|
||||
else
|
||||
style &= ~RENPY_TTF_STYLE_UNDERLINE;
|
||||
RENPY_TTF_SetFontStyle(font, style);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_render[] =
|
||||
/*DOC*/ "Font.render(text, antialias, fore_RGBA, [back_RGBA]) -> Surface\n"
|
||||
/*DOC*/ "render text to a new image\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Render the given text onto a new image surface. The given text\n"
|
||||
/*DOC*/ "can be standard python text or unicode. Antialiasing will smooth\n"
|
||||
/*DOC*/ "the edges of the font for a much cleaner look. The foreground\n"
|
||||
/*DOC*/ "and background color are both RGBA, the alpha component is ignored\n"
|
||||
/*DOC*/ "if given. If the background color is omitted, the text will have a\n"
|
||||
/*DOC*/ "transparent background.\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Note that font rendering is not thread safe, therefore only one\n"
|
||||
/*DOC*/ "thread can render text at any given time.\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Also, rendering smooth text with underlines will crash with SDL_ttf\n"
|
||||
/*DOC*/ "less that version 2.0, be careful.\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "If you pass an empty string, render() will return a blank surface\n"
|
||||
/*DOC*/ "1 pixel wide and the same height as the font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_render(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
int aa;
|
||||
PyObject* text, *final;
|
||||
PyObject* fg_rgba_obj, *bg_rgba_obj = NULL;
|
||||
Uint8 rgba[4];
|
||||
SDL_Surface* surf;
|
||||
SDL_Color foreg, backg;
|
||||
if(!PyArg_ParseTuple(args, "OiO|O", &text, &aa, &fg_rgba_obj, &bg_rgba_obj))
|
||||
return NULL;
|
||||
|
||||
if(!RGBAFromObj(fg_rgba_obj, rgba))
|
||||
return RAISE(PyExc_TypeError, "Invalid foreground RGBA argument");
|
||||
foreg.r = rgba[0]; foreg.g = rgba[1]; foreg.b = rgba[2];
|
||||
if(bg_rgba_obj)
|
||||
{
|
||||
if(!RGBAFromObj(bg_rgba_obj, rgba))
|
||||
return RAISE(PyExc_TypeError, "Invalid background RGBA argument");
|
||||
backg.r = rgba[0];
|
||||
backg.g = rgba[1];
|
||||
backg.b = rgba[2];
|
||||
backg.unused = 0;
|
||||
} else {
|
||||
backg.r = 0;
|
||||
backg.g = 0;
|
||||
backg.b = 0;
|
||||
backg.unused = 0;
|
||||
}
|
||||
|
||||
|
||||
if(!PyObject_IsTrue(text))
|
||||
{
|
||||
int height = RENPY_TTF_FontHeight(font);
|
||||
surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, height, 32, 0xff<<16, 0xff<<8, 0xff, 0);
|
||||
if(bg_rgba_obj)
|
||||
{
|
||||
Uint32 c = SDL_MapRGB(surf->format, backg.r, backg.g, backg.b);
|
||||
SDL_FillRect(surf, NULL, c);
|
||||
}
|
||||
else
|
||||
SDL_SetColorKey(surf, SDL_SRCCOLORKEY, 0);
|
||||
}
|
||||
else if(PyUnicode_Check(text))
|
||||
{
|
||||
PyObject* strob = PyEval_CallMethod(text, "encode", "(s)", "utf-8");
|
||||
char *string = PyString_AsString(strob);
|
||||
|
||||
if(aa)
|
||||
{
|
||||
if(!bg_rgba_obj)
|
||||
surf = RENPY_TTF_RenderUTF8_Blended(font, string, foreg);
|
||||
else
|
||||
surf = RENPY_TTF_RenderUTF8_Shaded(font, string, foreg, backg);
|
||||
}
|
||||
else
|
||||
surf = RENPY_TTF_RenderUTF8_Solid(font, string, foreg);
|
||||
|
||||
Py_DECREF(strob);
|
||||
}
|
||||
else if(PyString_Check(text))
|
||||
{
|
||||
char* string = PyString_AsString(text);
|
||||
if(aa)
|
||||
{
|
||||
if(!bg_rgba_obj)
|
||||
surf = RENPY_TTF_RenderText_Blended(font, string, foreg);
|
||||
else
|
||||
surf = RENPY_TTF_RenderText_Shaded(font, string, foreg, backg);
|
||||
}
|
||||
else
|
||||
surf = RENPY_TTF_RenderText_Solid(font, string, foreg);
|
||||
}
|
||||
else
|
||||
return RAISE(PyExc_TypeError, "text must be a string or unicode");
|
||||
|
||||
if(!surf)
|
||||
return RAISE(PyExc_SDLError, "SDL_ttf render failed");
|
||||
|
||||
if(!aa && bg_rgba_obj) /*turn off transparancy*/
|
||||
{
|
||||
SDL_SetColorKey(surf, 0, 0);
|
||||
surf->format->palette->colors[0].r = backg.r;
|
||||
surf->format->palette->colors[0].g = backg.g;
|
||||
surf->format->palette->colors[0].b = backg.b;
|
||||
}
|
||||
|
||||
final = PySurface_New(surf);
|
||||
if(!final)
|
||||
SDL_FreeSurface(surf);
|
||||
return final;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_font_size[] =
|
||||
/*DOC*/ "Font.size(text) -> width, height\n"
|
||||
/*DOC*/ "size of rendered text\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Computes the rendered size of the given text. The text can be\n"
|
||||
/*DOC*/ "standard python text or unicode. Changing the bold and italic\n"
|
||||
/*DOC*/ "attributes can change the size of the rendered text.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* font_size(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
int w, h;
|
||||
PyObject* text;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "O", &text))
|
||||
return NULL;
|
||||
|
||||
if(PyUnicode_Check(text))
|
||||
{
|
||||
PyObject* strob = PyEval_CallMethod(text, "encode", "(s)", "utf-8");
|
||||
char *string = PyString_AsString(strob);
|
||||
|
||||
RENPY_TTF_SizeUTF8(font, string, &w, &h);
|
||||
|
||||
Py_DECREF(strob);
|
||||
}
|
||||
else if(PyString_Check(text))
|
||||
{
|
||||
char* string = PyString_AsString(text);
|
||||
RENPY_TTF_SizeText(font, string, &w, &h);
|
||||
}
|
||||
else
|
||||
return RAISE(PyExc_TypeError, "text must be a string or unicode");
|
||||
|
||||
return Py_BuildValue("(ii)", w, h);
|
||||
}
|
||||
|
||||
static PyObject* font_set_expand(PyObject* self, PyObject* args)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
float expand;
|
||||
|
||||
if(!PyArg_ParseTuple(args, "f", &expand))
|
||||
return NULL;
|
||||
|
||||
RENPY_TTF_SetExpand(font, expand);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PyMethodDef font_methods[] =
|
||||
{
|
||||
{ "get_height", font_get_height, 1, doc_font_get_height },
|
||||
{ "get_descent", font_get_descent, 1, doc_font_get_descent },
|
||||
{ "get_ascent", font_get_ascent, 1, doc_font_get_ascent },
|
||||
{ "get_linesize", font_get_linesize, 1, doc_font_get_linesize },
|
||||
|
||||
{ "get_bold", font_get_bold, 1, doc_font_get_bold },
|
||||
{ "set_bold", font_set_bold, 1, doc_font_set_bold },
|
||||
{ "get_italic", font_get_italic, 1, doc_font_get_italic },
|
||||
{ "set_italic", font_set_italic, 1, doc_font_set_italic },
|
||||
{ "get_underline", font_get_underline, 1, doc_font_get_underline },
|
||||
{ "set_underline", font_set_underline, 1, doc_font_set_underline },
|
||||
|
||||
{ "render", font_render, 1, doc_font_render },
|
||||
{ "size", font_size, 1, doc_font_size },
|
||||
|
||||
{ "set_expand", font_set_expand, 1, ""},
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*font object internals*/
|
||||
|
||||
static void font_dealloc(PyFontObject* self)
|
||||
{
|
||||
RENPY_TTF_Font* font = PyFont_AsFont(self);
|
||||
|
||||
if(font && font_initialized)
|
||||
RENPY_TTF_CloseFont(font);
|
||||
|
||||
if(self->weakreflist)
|
||||
PyObject_ClearWeakRefs((PyObject*)self);
|
||||
self->ob_type->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
|
||||
static int font_init(PyFontObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int fontsize;
|
||||
RENPY_TTF_Font* font = NULL;
|
||||
PyObject* fileobj;
|
||||
|
||||
self->font = NULL;
|
||||
if(!PyArg_ParseTuple(args, "Oi|iff", &fileobj, &fontsize))
|
||||
return -1;
|
||||
|
||||
if(!font_initialized)
|
||||
{
|
||||
RAISE(PyExc_SDLError, "font not initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_INCREF(fileobj);
|
||||
|
||||
if(fontsize <= 1)
|
||||
fontsize = 1;
|
||||
|
||||
if(fileobj == Py_None) {
|
||||
Py_DECREF(fileobj);
|
||||
fileobj = font_resource(font_defaultname);
|
||||
if(!fileobj)
|
||||
{
|
||||
RAISE(PyExc_RuntimeError, "default font not found");
|
||||
return -1;
|
||||
}
|
||||
fontsize = (int)(fontsize * .6875);
|
||||
if(fontsize <= 1)
|
||||
fontsize = 1;
|
||||
}
|
||||
|
||||
if(PyString_Check(fileobj) || PyUnicode_Check(fileobj))
|
||||
{
|
||||
FILE* test;
|
||||
char* filename = PyString_AsString(fileobj);
|
||||
Py_DECREF(fileobj);
|
||||
fileobj = NULL;
|
||||
|
||||
if(!filename)
|
||||
return -1;
|
||||
|
||||
/*check if it is a valid file, else SDL_ttf segfaults*/
|
||||
test = fopen(filename, "rb");
|
||||
if(!test)
|
||||
{
|
||||
if (!strcmp(filename, font_defaultname))
|
||||
{
|
||||
fileobj = font_resource(font_defaultname);
|
||||
}
|
||||
if (!fileobj) {
|
||||
PyErr_SetString(PyExc_IOError, "unable to read font filename");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fclose(test);
|
||||
// Py_BEGIN_ALLOW_THREADS
|
||||
font = RENPY_TTF_OpenFont(filename, fontsize);
|
||||
// Py_END_ALLOW_THREADS
|
||||
}
|
||||
}
|
||||
if (!font)
|
||||
{
|
||||
#ifdef RENPY_TTF_MAJOR_VERSION
|
||||
SDL_RWops *rw;
|
||||
rw = RWopsFromPython(fileobj);
|
||||
if (!rw) {
|
||||
Py_DECREF(fileobj);
|
||||
return -1;
|
||||
}
|
||||
// Py_BEGIN_ALLOW_THREADS
|
||||
font = RENPY_TTF_OpenFontIndexRW(rw, 1, fontsize, 0);
|
||||
// Py_END_ALLOW_THREADS
|
||||
#else
|
||||
Py_DECREF(fileobj);
|
||||
RAISE(PyExc_NotImplementedError, "nonstring fonts require SDL_ttf-2.0.6");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(!font)
|
||||
{
|
||||
RAISE(PyExc_RuntimeError, SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->font = font;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*DOC*/ static char doc_Font_MODULE[] =
|
||||
/*DOC*/ "The font object is created only from pygame.font.Font(). Once a\n"
|
||||
/*DOC*/ "font is created it's size and TTF file cannot be changed. The\n"
|
||||
/*DOC*/ "Font objects are mainly used to render() text into a new Surface.\n"
|
||||
/*DOC*/ "The Font objects also have a few states that can be set with\n"
|
||||
/*DOC*/ "set_underline(bool), set_bold(bool), set_italic(bool). Each of\n"
|
||||
/*DOC*/ "these functions contains an equivalent get_XXX() routine to find\n"
|
||||
/*DOC*/ "the current state. There are also many routines to query the\n"
|
||||
/*DOC*/ "dimensions of the text. The rendering functions work with both\n"
|
||||
/*DOC*/ "normal python strings, as well as with unicode strings.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyTypeObject PyFont_Type =
|
||||
{
|
||||
PyObject_HEAD_INIT(NULL)
|
||||
0,
|
||||
"pygame.font.Font",
|
||||
sizeof(PyFontObject),
|
||||
0,
|
||||
(destructor)font_dealloc,
|
||||
0,
|
||||
0, /*getattr*/
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
(hashfunc)NULL,
|
||||
(ternaryfunc)NULL,
|
||||
(reprfunc)NULL,
|
||||
0L,0L,0L,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
doc_Font_MODULE, /* Documentation string */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(PyFontObject, weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
font_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)font_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
||||
//PyType_GenericNew, /* tp_new */
|
||||
|
||||
|
||||
/*font module methods*/
|
||||
|
||||
/*DOC*/ static char doc_get_default_font[] =
|
||||
/*DOC*/ "pygame.font.get_default_font() -> string\n"
|
||||
/*DOC*/ "get the name of the default font\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "returns the filename for the default truetype font.\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
static PyObject* get_default_font(PyObject* self, PyObject* args)
|
||||
{
|
||||
if(!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
return PyString_FromString(font_defaultname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*font module methods*/
|
||||
#if 0
|
||||
/*DOC*/ static char doc_Font[] =
|
||||
/*DOC*/ "pygame.font.Font(file, size) -> Font\n"
|
||||
/*DOC*/ "create a new font object\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "This will create a new font object. The given file can\n"
|
||||
/*DOC*/ "be a filename or any python file-like object.\n"
|
||||
/*DOC*/ "The size represents the height of the font in\n"
|
||||
/*DOC*/ "pixels. The file argument can be 'None', which will\n"
|
||||
/*DOC*/ "use a plain default font.\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "You must have at least SDL_ttf-2.0.6 for file object\n"
|
||||
/*DOC*/ "support. You can load TTF and FON fonts.\n"
|
||||
/*DOC*/ ;
|
||||
#endif
|
||||
|
||||
|
||||
static PyMethodDef font_builtins[] =
|
||||
{
|
||||
{ "__PYGAMEinit__", font_autoinit, 1, doc_init },
|
||||
{ "init", fontmodule_init, 1, doc_init },
|
||||
{ "quit", fontmodule_quit, 1, doc_quit },
|
||||
{ "get_init", get_init, 1, doc_get_init },
|
||||
{ "get_default_font", get_default_font, 1, doc_get_default_font },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
static PyObject* PyFont_New(RENPY_TTF_Font* font)
|
||||
{
|
||||
PyFontObject* fontobj;
|
||||
|
||||
if(!font)
|
||||
return RAISE(PyExc_RuntimeError, "unable to load font.");
|
||||
fontobj = (PyFontObject *)PyFont_Type.tp_new(&PyFont_Type, NULL, NULL);
|
||||
|
||||
if(fontobj)
|
||||
fontobj->font = font;
|
||||
|
||||
return (PyObject*)fontobj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*DOC*/ static char doc_pygame_font_MODULE[] =
|
||||
/*DOC*/ "The font module allows for rendering TrueType fonts into a new\n"
|
||||
/*DOC*/ "Surface object. This module is optional and requires SDL_ttf as a\n"
|
||||
/*DOC*/ "dependency. You may want to check for pygame.font to import and\n"
|
||||
/*DOC*/ "initialize before attempting to use the module.\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "Most of the work done with fonts are done by using the actual\n"
|
||||
/*DOC*/ "Font objects. The module by itself only has routines to\n"
|
||||
/*DOC*/ "initialize the module and create Font objects with\n"
|
||||
/*DOC*/ "pygame.font.Font().\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ "You can load fonts from the standard system fonts by using the\n"
|
||||
/*DOC*/ "pygame.font.SysFont() method. There are also other functions to\n"
|
||||
/*DOC*/ "help you work with system fonts.\n"
|
||||
/*DOC*/ "\n"
|
||||
/*DOC*/ ;
|
||||
|
||||
PYGAME_EXPORT
|
||||
void init_renpy_font(void)
|
||||
{
|
||||
PyObject *module;
|
||||
|
||||
if (PyType_Ready(&PyFont_Type) < 0)
|
||||
return;
|
||||
|
||||
/* create the module */
|
||||
PyFont_Type.ob_type = &PyType_Type;
|
||||
PyFont_Type.tp_new = &PyType_GenericNew;
|
||||
|
||||
module = Py_InitModule3("_renpy_font", font_builtins, doc_pygame_font_MODULE);
|
||||
self_module = module;
|
||||
|
||||
Py_INCREF((PyObject*)&PyFont_Type);
|
||||
PyModule_AddObject(module, "FontType", (PyObject *)&PyFont_Type);
|
||||
Py_INCREF((PyObject*)&PyFont_Type);
|
||||
PyModule_AddObject(module, "Font", (PyObject *)&PyFont_Type);
|
||||
|
||||
import_pygame_base();
|
||||
import_pygame_surface();
|
||||
import_pygame_rwobject();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts
|
||||
Copyright (C) 1997-2004 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
/* $Id: SDL_ttf.h 2387 2006-05-11 09:03:37Z slouken $ */
|
||||
|
||||
/* This library is a wrapper around the excellent FreeType 2.0 library,
|
||||
available at:
|
||||
http://www.freetype.org/
|
||||
*/
|
||||
|
||||
#ifndef _RENPY_TTF_H
|
||||
#define _RENPY_TTF_H
|
||||
|
||||
#include "SDL.h"
|
||||
#include "begin_code.h"
|
||||
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Printable format: "%d.%d.%d", MAJOR, MINOR, PATCHLEVEL
|
||||
*/
|
||||
#define RENPY_RENPY_TTF_MAJOR_VERSION 2
|
||||
#define RENPY_RENPY_TTF_MINOR_VERSION 0
|
||||
#define RENPY_RENPY_TTF_PATCHLEVEL 8
|
||||
|
||||
/* This macro can be used to fill a version structure with the compile-time
|
||||
* version of the SDL_ttf library.
|
||||
*/
|
||||
#define RENPY_RENPY_TTF_VERSION(X) \
|
||||
{ \
|
||||
(X)->major = RENPY_RENPY_TTF_MAJOR_VERSION; \
|
||||
(X)->minor = RENPY_RENPY_TTF_MINOR_VERSION; \
|
||||
(X)->patch = RENPY_RENPY_TTF_PATCHLEVEL; \
|
||||
}
|
||||
|
||||
/* Backwards compatibility */
|
||||
#define RENPY_TTF_MAJOR_VERSION RENPY_RENPY_TTF_MAJOR_VERSION
|
||||
#define RENPY_TTF_MINOR_VERSION RENPY_RENPY_TTF_MINOR_VERSION
|
||||
#define RENPY_TTF_PATCHLEVEL RENPY_RENPY_TTF_PATCHLEVEL
|
||||
#define RENPY_TTF_VERSION(X) RENPY_RENPY_TTF_VERSION(X)
|
||||
|
||||
/* This function gets the version of the dynamically linked SDL_ttf library.
|
||||
it should NOT be used to fill a version structure, instead you should
|
||||
use the RENPY_RENPY_TTF_VERSION() macro.
|
||||
*/
|
||||
extern DECLSPEC const SDL_version * SDLCALL RENPY_TTF_Linked_Version(void);
|
||||
|
||||
/* ZERO WIDTH NO-BREAKSPACE (Unicode byte order mark) */
|
||||
#define UNICODE_BOM_NATIVE 0xFEFF
|
||||
#define UNICODE_BOM_SWAPPED 0xFFFE
|
||||
|
||||
/* This function tells the library whether UNICODE text is generally
|
||||
byteswapped. A UNICODE BOM character in a string will override
|
||||
this setting for the remainder of that string.
|
||||
*/
|
||||
extern DECLSPEC void SDLCALL RENPY_TTF_ByteSwappedUNICODE(int swapped);
|
||||
|
||||
/* The internal structure containing font information */
|
||||
typedef struct _RENPY_TTF_Font RENPY_TTF_Font;
|
||||
|
||||
/* Initialize the TTF engine - returns 0 if successful, -1 on error */
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_Init(void);
|
||||
|
||||
/* Open a font file and create a font of the specified point size.
|
||||
* Some .fon fonts will have several sizes embedded in the file, so the
|
||||
* point size becomes the index of choosing which size. If the value
|
||||
* is too high, the last indexed size will be the default. */
|
||||
extern DECLSPEC RENPY_TTF_Font * SDLCALL RENPY_TTF_OpenFont(const char *file, int ptsize);
|
||||
extern DECLSPEC RENPY_TTF_Font * SDLCALL RENPY_TTF_OpenFontIndex(const char *file, int ptsize, long index);
|
||||
extern DECLSPEC RENPY_TTF_Font * SDLCALL RENPY_TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize);
|
||||
extern DECLSPEC RENPY_TTF_Font * SDLCALL RENPY_TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index);
|
||||
|
||||
/* Set and retrieve the font style
|
||||
This font style is implemented by modifying the font glyphs, and
|
||||
doesn't reflect any inherent properties of the truetype font file.
|
||||
*/
|
||||
#define RENPY_TTF_STYLE_NORMAL 0x00
|
||||
#define RENPY_TTF_STYLE_BOLD 0x01
|
||||
#define RENPY_TTF_STYLE_ITALIC 0x02
|
||||
#define RENPY_TTF_STYLE_UNDERLINE 0x04
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_GetFontStyle(RENPY_TTF_Font *font);
|
||||
extern DECLSPEC void SDLCALL RENPY_TTF_SetFontStyle(RENPY_TTF_Font *font, int style);
|
||||
|
||||
/* Get the total height of the font - usually equal to point size */
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_FontHeight(RENPY_TTF_Font *font);
|
||||
|
||||
/* Get the offset from the baseline to the top of the font
|
||||
This is a positive value, relative to the baseline.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_FontAscent(RENPY_TTF_Font *font);
|
||||
|
||||
/* Get the offset from the baseline to the bottom of the font
|
||||
This is a negative value, relative to the baseline.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_FontDescent(RENPY_TTF_Font *font);
|
||||
|
||||
/* Get the recommended spacing between lines of text for this font */
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_FontLineSkip(RENPY_TTF_Font *font);
|
||||
|
||||
/* Get the number of faces of the font */
|
||||
extern DECLSPEC long SDLCALL RENPY_TTF_FontFaces(RENPY_TTF_Font *font);
|
||||
|
||||
/* Get the font face attributes, if any */
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_FontFaceIsFixedWidth(RENPY_TTF_Font *font);
|
||||
extern DECLSPEC char * SDLCALL RENPY_TTF_FontFaceFamilyName(RENPY_TTF_Font *font);
|
||||
extern DECLSPEC char * SDLCALL RENPY_TTF_FontFaceStyleName(RENPY_TTF_Font *font);
|
||||
|
||||
/* Get the metrics (dimensions) of a glyph
|
||||
To understand what these metrics mean, here is a useful link:
|
||||
http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_GlyphMetrics(RENPY_TTF_Font *font, Uint16 ch,
|
||||
int *minx, int *maxx,
|
||||
int *miny, int *maxy, int *advance);
|
||||
|
||||
/* Get the dimensions of a rendered string of text */
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_SizeText(RENPY_TTF_Font *font, const char *text, int *w, int *h);
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_SizeUTF8(RENPY_TTF_Font *font, const char *text, int *w, int *h);
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_SizeUNICODE(RENPY_TTF_Font *font, const Uint16 *text, int *w, int *h);
|
||||
|
||||
/* Create an 8-bit palettized surface and render the given text at
|
||||
fast quality with the given font and color. The 0 pixel is the
|
||||
colorkey, giving a transparent background, and the 1 pixel is set
|
||||
to the text color.
|
||||
This function returns the new surface, or NULL if there was an error.
|
||||
*/
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderText_Solid(RENPY_TTF_Font *font,
|
||||
const char *text, SDL_Color fg);
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderUTF8_Solid(RENPY_TTF_Font *font,
|
||||
const char *text, SDL_Color fg);
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderUNICODE_Solid(RENPY_TTF_Font *font,
|
||||
const Uint16 *text, SDL_Color fg);
|
||||
|
||||
/* Create an 8-bit palettized surface and render the given glyph at
|
||||
fast quality with the given font and color. The 0 pixel is the
|
||||
colorkey, giving a transparent background, and the 1 pixel is set
|
||||
to the text color. The glyph is rendered without any padding or
|
||||
centering in the X direction, and aligned normally in the Y direction.
|
||||
This function returns the new surface, or NULL if there was an error.
|
||||
*/
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderGlyph_Solid(RENPY_TTF_Font *font,
|
||||
Uint16 ch, SDL_Color fg);
|
||||
|
||||
/* Create an 8-bit palettized surface and render the given text at
|
||||
high quality with the given font and colors. The 0 pixel is background,
|
||||
while other pixels have varying degrees of the foreground color.
|
||||
This function returns the new surface, or NULL if there was an error.
|
||||
*/
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderText_Shaded(RENPY_TTF_Font *font,
|
||||
const char *text, SDL_Color fg, SDL_Color bg);
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderUTF8_Shaded(RENPY_TTF_Font *font,
|
||||
const char *text, SDL_Color fg, SDL_Color bg);
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderUNICODE_Shaded(RENPY_TTF_Font *font,
|
||||
const Uint16 *text, SDL_Color fg, SDL_Color bg);
|
||||
|
||||
/* Create an 8-bit palettized surface and render the given glyph at
|
||||
high quality with the given font and colors. The 0 pixel is background,
|
||||
while other pixels have varying degrees of the foreground color.
|
||||
The glyph is rendered without any padding or centering in the X
|
||||
direction, and aligned normally in the Y direction.
|
||||
This function returns the new surface, or NULL if there was an error.
|
||||
*/
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderGlyph_Shaded(RENPY_TTF_Font *font,
|
||||
Uint16 ch, SDL_Color fg, SDL_Color bg);
|
||||
|
||||
/* Create a 32-bit ARGB surface and render the given text at high quality,
|
||||
using alpha blending to dither the font with the given color.
|
||||
This function returns the new surface, or NULL if there was an error.
|
||||
*/
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderText_Blended(RENPY_TTF_Font *font,
|
||||
const char *text, SDL_Color fg);
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderUTF8_Blended(RENPY_TTF_Font *font,
|
||||
const char *text, SDL_Color fg);
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderUNICODE_Blended(RENPY_TTF_Font *font,
|
||||
const Uint16 *text, SDL_Color fg);
|
||||
|
||||
/* Create a 32-bit ARGB surface and render the given glyph at high quality,
|
||||
using alpha blending to dither the font with the given color.
|
||||
The glyph is rendered without any padding or centering in the X
|
||||
direction, and aligned normally in the Y direction.
|
||||
This function returns the new surface, or NULL if there was an error.
|
||||
*/
|
||||
extern DECLSPEC SDL_Surface * SDLCALL RENPY_TTF_RenderGlyph_Blended(RENPY_TTF_Font *font,
|
||||
Uint16 ch, SDL_Color fg);
|
||||
|
||||
/* For compatibility with previous versions, here are the old functions */
|
||||
#define RENPY_TTF_RenderText(font, text, fg, bg) \
|
||||
RENPY_TTF_RenderText_Shaded(font, text, fg, bg)
|
||||
#define RENPY_TTF_RenderUTF8(font, text, fg, bg) \
|
||||
RENPY_TTF_RenderUTF8_Shaded(font, text, fg, bg)
|
||||
#define RENPY_TTF_RenderUNICODE(font, text, fg, bg) \
|
||||
RENPY_TTF_RenderUNICODE_Shaded(font, text, fg, bg)
|
||||
|
||||
/* Close an opened font file */
|
||||
extern DECLSPEC void SDLCALL RENPY_TTF_CloseFont(RENPY_TTF_Font *font);
|
||||
|
||||
/* De-initialize the TTF engine */
|
||||
extern DECLSPEC void SDLCALL RENPY_TTF_Quit(void);
|
||||
|
||||
/* Check if the TTF engine is initialized */
|
||||
extern DECLSPEC int SDLCALL RENPY_TTF_WasInit(void);
|
||||
|
||||
extern DECLSPEC void SDLCALL RENPY_TTF_SetExpand(RENPY_TTF_Font *, float);
|
||||
|
||||
/* We'll use SDL for reporting errors */
|
||||
#define RENPY_TTF_SetError SDL_SetError
|
||||
#define RENPY_TTF_GetError SDL_GetError
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include "close_code.h"
|
||||
|
||||
#endif /* _RENPY_TTF_H */
|
||||
@@ -28,7 +28,7 @@ if not os.path.isdir(install):
|
||||
sys.exit(-1)
|
||||
|
||||
# Default compile arguements for everybody.
|
||||
include_dirs = [ install + "/include", install + "/include/SDL" ]
|
||||
include_dirs = [ install + "/include", install + "/include/SDL", install + "/include/freetype2", install + "/include/pygame"]
|
||||
library_dirs = [ install + "/lib" ]
|
||||
extra_compile_args = [ "-O3", "-funroll-loops", "-ffast-math" ]
|
||||
extra_link_args = [ ]
|
||||
@@ -75,6 +75,18 @@ rpe = distutils.core.Extension(
|
||||
|
||||
extensions.append(rpe)
|
||||
|
||||
renpy_font = distutils.core.Extension(
|
||||
"_renpy_font",
|
||||
[ "renpy_ttf.c", "renpy_font.c"],
|
||||
include_dirs=include_dirs,
|
||||
library_dirs=library_dirs,
|
||||
extra_compile_args=extra_compile_args,
|
||||
extra_link_args=extra_link_args,
|
||||
libraries=sdl_libraries + ['freetype'],
|
||||
)
|
||||
|
||||
extensions.append(renpy_font)
|
||||
|
||||
psse = distutils.core.Extension(
|
||||
"pysdlsound.sound",
|
||||
[ "pss.c", "rwobject.c", "sound.c" ],
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -Rf cardgame/*~
|
||||
rm -Rf cardgame/game/*~
|
||||
rm -Rf cardgame/game/*.rpyc
|
||||
rm -Rf cardgame/game/*.rpyb
|
||||
rm -Rf cardgame/game/saves
|
||||
|
||||
rm cardgame-$1.zip
|
||||
zip -9r cardgame-$1.zip cardgame -x \*.svn\*
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
zip -r renpygame-$1.zip renpygame-demo -x \*.svn\* -x \*saves\* -x \*.pyc -x \*.pyo -x \*~
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -Rf spline_editor/*~
|
||||
rm -Rf spline_editor/game/*~
|
||||
rm -Rf spline_editor/game/*.rpyc
|
||||
rm -Rf spline_editor/game/*.rpyb
|
||||
rm -Rf spline_editor/game/saves
|
||||
|
||||
rm spline_editor.zip
|
||||
zip -9r spline_editor.zip spline_editor -x \*.svn\*
|
||||
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ def path_to_renpy_base():
|
||||
##############################################################################
|
||||
|
||||
# The version of the Mac Launcher and py4renpy that we use.
|
||||
macos_version = (6, 7, 1)
|
||||
linux_version = (6, 7, 1)
|
||||
macos_version = (6, 8, 0)
|
||||
linux_version = (6, 8, 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
# Some version numbers and things.
|
||||
|
||||
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
|
||||
# Be sure to change script_version in data/script_version.rpy, too!
|
||||
# Be sure to change script_version in launcher/script_version.rpy, too!
|
||||
# Also check to see if we have to update renpy.py.
|
||||
version = "Ren'Py 6.7.1b"
|
||||
version = "Ren'Py 6.8.0b"
|
||||
script_version = 5003000
|
||||
savegame_suffix = "-LT1.save"
|
||||
|
||||
@@ -59,7 +59,8 @@ def import_all():
|
||||
import renpy.display.module
|
||||
import renpy.display.render # Most display stuff depends on this.
|
||||
import renpy.display.core # object
|
||||
import renpy.display.text # core
|
||||
import renpy.display.font
|
||||
import renpy.display.text # core, font
|
||||
import renpy.display.layout # core
|
||||
import renpy.display.behavior # layout
|
||||
import renpy.display.transition # core, layout
|
||||
|
||||
@@ -34,6 +34,8 @@ def extra_imports():
|
||||
import encodings.string_escape
|
||||
import encodings.raw_unicode_escape
|
||||
import encodings.mbcs
|
||||
import encodings.utf_16_be
|
||||
import encodings.utf_16_le
|
||||
import math
|
||||
import glob
|
||||
import pickle
|
||||
|
||||
@@ -174,6 +174,9 @@ keymap = dict(
|
||||
reload_game = [ 'R' ],
|
||||
inspector = [ 'I' ],
|
||||
developer = [ 'D' ],
|
||||
quit = [ 'meta_q', 'alt_K_F4' ],
|
||||
iconify = [ 'meta_m', 'alt_m' ],
|
||||
help = [ 'K_F1', 'meta_shift_/' ],
|
||||
|
||||
# Say.
|
||||
rollforward = [ 'mousedown_5', 'K_PAGEDOWN' ],
|
||||
@@ -369,6 +372,11 @@ auto_save_extra_info = None
|
||||
# game-specific data is saved.
|
||||
save_directory = None
|
||||
|
||||
# These are used to deal with the case where a picture is missing.
|
||||
missing_scene = None
|
||||
missing_show = None
|
||||
missing_hide = None
|
||||
|
||||
del renpy
|
||||
del sets
|
||||
|
||||
|
||||
@@ -84,6 +84,12 @@ def compile_event(key, keydown):
|
||||
else:
|
||||
rv += " and not (ev.mod & %d)" % pygame.KMOD_ALT
|
||||
|
||||
if part[0] == "meta":
|
||||
part.pop(0)
|
||||
rv += " and (ev.mod & %d)" % pygame.KMOD_META
|
||||
else:
|
||||
rv += " and not (ev.mod & %d)" % pygame.KMOD_META
|
||||
|
||||
if part[0] == "shift":
|
||||
part.pop(0)
|
||||
rv += " and (ev.mod & %d)" % pygame.KMOD_SHIFT
|
||||
@@ -618,6 +624,15 @@ class Bar(renpy.display.core.Displayable):
|
||||
value = self.adjustment.value
|
||||
page = self.adjustment.page
|
||||
|
||||
if range <= 0:
|
||||
if self.style.unscrollable == "hide":
|
||||
self.hidden = True
|
||||
return renpy.display.render.Render(width, height)
|
||||
elif self.style.unscrollable == "insensitive":
|
||||
self.set_style_prefix("insensitive_")
|
||||
|
||||
self.hidden = False
|
||||
|
||||
if self.style.bar_invert ^ self.style.bar_vertical:
|
||||
value = range - value
|
||||
|
||||
@@ -712,11 +727,14 @@ class Bar(renpy.display.core.Displayable):
|
||||
def event(self, ev, x, y, st):
|
||||
|
||||
if not self.focusable:
|
||||
return
|
||||
return None
|
||||
|
||||
if not self.is_focused():
|
||||
return
|
||||
return None
|
||||
|
||||
if self.hidden:
|
||||
return None
|
||||
|
||||
range = self.adjustment.range
|
||||
old_value = self.adjustment.value
|
||||
value = old_value
|
||||
|
||||
@@ -32,12 +32,17 @@ import time
|
||||
import cStringIO
|
||||
import threading
|
||||
|
||||
on_windows = (sys.platform == 'win32')
|
||||
|
||||
try:
|
||||
import pygame.macosx
|
||||
except:
|
||||
pass
|
||||
|
||||
# Is the cpu idle enough to do other things?
|
||||
cpu_idle = threading.Event()
|
||||
cpu_idle.clear()
|
||||
|
||||
|
||||
|
||||
TIMEEVENT = USEREVENT + 1
|
||||
PERIODIC = USEREVENT + 2
|
||||
JOYEVENT = USEREVENT + 3
|
||||
@@ -658,6 +663,9 @@ class Display(object):
|
||||
# Ensure that we kill off the movie when changing screen res.
|
||||
renpy.display.video.movie_stop(clear=False)
|
||||
|
||||
if pygame.version.vernum < (1, 8, 1):
|
||||
raise Exception("Ren'Py requires pygame 1.8.1 to run.")
|
||||
|
||||
try:
|
||||
pygame.macosx.init()
|
||||
except:
|
||||
@@ -710,10 +718,16 @@ class Display(object):
|
||||
|
||||
# Window icon.
|
||||
if renpy.config.window_icon:
|
||||
pygame.display.set_icon(
|
||||
renpy.display.scale.image_load_unscaled(
|
||||
renpy.loader.load(renpy.config.window_icon),
|
||||
renpy.config.window_icon))
|
||||
|
||||
im = renpy.display.scale.image_load_unscaled(
|
||||
renpy.loader.load(renpy.config.window_icon),
|
||||
renpy.config.window_icon)
|
||||
|
||||
if on_windows and im.get_width() > 32:
|
||||
im = renpy.display.scale.real_bilinear(im, (32, 32))
|
||||
|
||||
pygame.display.set_icon(im)
|
||||
|
||||
|
||||
# If a window exists of the right size and flags, use it. Otherwise,
|
||||
# make our own window.
|
||||
@@ -774,6 +788,9 @@ class Display(object):
|
||||
self.window_caption = caption
|
||||
pygame.display.set_caption(caption.encode("utf-8"))
|
||||
|
||||
def iconify(self):
|
||||
pygame.display.iconify()
|
||||
|
||||
def can_redraw(self, first_pass):
|
||||
"""
|
||||
Uses the framerate to determine if we can and should redraw.
|
||||
@@ -976,12 +993,7 @@ class Display(object):
|
||||
Saves a full-size screenshot in the given filename.
|
||||
"""
|
||||
|
||||
if filename.endswith(".png"):
|
||||
f = file(filename, "wb")
|
||||
renpy.display.module.save_png(self.window, f)
|
||||
f.close()
|
||||
else:
|
||||
pygame.image.save(self.window, filename)
|
||||
pygame.image.save(self.window, filename)
|
||||
|
||||
def screenshot(self, scale):
|
||||
"""
|
||||
@@ -1272,7 +1284,19 @@ class Interface(object):
|
||||
rv[None] = root
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
def quit_event(self):
|
||||
"""
|
||||
This is called to handle the user invoking a quit.
|
||||
"""
|
||||
|
||||
if renpy.game.script.has_label("_confirm_quit") and not self.quick_quit:
|
||||
self.quick_quit = True
|
||||
renpy.game.call_in_new_context("_confirm_quit")
|
||||
self.quick_quit = False
|
||||
else:
|
||||
raise renpy.game.QuitException()
|
||||
|
||||
def interact(self, clear=True, **kwargs):
|
||||
"""
|
||||
@@ -1741,12 +1765,7 @@ class Interface(object):
|
||||
|
||||
# Handle quit specially for now.
|
||||
if ev.type == QUIT:
|
||||
if renpy.game.script.has_label("_confirm_quit") and not self.quick_quit:
|
||||
self.quick_quit = True
|
||||
renpy.game.call_in_new_context("_confirm_quit")
|
||||
self.quick_quit = False
|
||||
else:
|
||||
raise renpy.game.QuitException()
|
||||
self.quit_event()
|
||||
|
||||
# Merge mousemotion events.
|
||||
if ev.type == MOUSEMOTION:
|
||||
@@ -1754,7 +1773,8 @@ class Interface(object):
|
||||
if len(evs):
|
||||
ev = evs[-1]
|
||||
|
||||
self.focused = True
|
||||
if on_windows:
|
||||
self.focused = True
|
||||
|
||||
# Handle focus notifications.
|
||||
if ev.type == ACTIVEEVENT:
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
# Copyright 2004-2008 PyTom <pytom@bishoujo.us>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import pygame
|
||||
from pygame.constants import *
|
||||
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
try:
|
||||
import _renpy_font
|
||||
pygame.font = _renpy_font
|
||||
except:
|
||||
pass
|
||||
|
||||
import renpy
|
||||
|
||||
# This contains a map from (fn, size, bold, italics, underline) to the
|
||||
# unloaded font object corresponding to that specification.
|
||||
fonts = { }
|
||||
|
||||
# This contains a map from (fn, size, bold, italics, underline) to the
|
||||
# loaded font object corresponding to that specification.
|
||||
font_cache = { }
|
||||
|
||||
class ImageFont(object):
|
||||
|
||||
def size(self, text):
|
||||
w = 0
|
||||
|
||||
if not text:
|
||||
return (0, self.height)
|
||||
|
||||
for a, b in zip(text, text[1:]):
|
||||
try:
|
||||
w += self.sizes[a] + self.kerns.get(a + b, self.default_kern)
|
||||
except KeyError:
|
||||
raise Exception("Character %r not found in %s." % (a, type(self).__name__))
|
||||
|
||||
w += self.sizes[text[-1]]
|
||||
|
||||
return (w, self.height)
|
||||
|
||||
def render(self, text, antialias, color, black_color=(0, 0, 0, 255), background=None):
|
||||
surf = pygame.Surface(self.size(text), 0,
|
||||
renpy.game.interface.display.sample_surface)
|
||||
|
||||
if not text:
|
||||
return surf
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
|
||||
for a, b in zip(text, text[1:]):
|
||||
surf.blit(self.chars[a], (x, y))
|
||||
x += self.sizes[a] + self.kerns.get(a + b, self.default_kern)
|
||||
|
||||
surf.blit(self.chars[text[-1]], (x, y))
|
||||
|
||||
if renpy.config.recolor_sfonts and \
|
||||
(color != (255, 255, 255, 255) or black_color != (0, 0, 0, 255) ) and \
|
||||
renpy.display.module.can_twomap:
|
||||
|
||||
newsurf = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
|
||||
renpy.display.module.twomap(surf, newsurf, color, black_color)
|
||||
renpy.display.render.mutated_surface(newsurf)
|
||||
|
||||
surf = newsurf
|
||||
|
||||
return surf
|
||||
|
||||
def get_linesize(self):
|
||||
return self.height
|
||||
|
||||
def get_height(self):
|
||||
return self.height
|
||||
|
||||
def get_ascent(self):
|
||||
return self.height
|
||||
|
||||
def get_descent(self):
|
||||
return 0
|
||||
|
||||
|
||||
class SFont(ImageFont):
|
||||
|
||||
def __init__(self,
|
||||
filename,
|
||||
spacewidth,
|
||||
default_kern,
|
||||
kerns,
|
||||
charset):
|
||||
|
||||
self.filename = filename
|
||||
self.spacewidth = spacewidth
|
||||
self.default_kern = default_kern
|
||||
self.kerns = kerns
|
||||
self.charset = charset
|
||||
|
||||
def load(self):
|
||||
|
||||
# Map from character to subsurface.
|
||||
self.chars = { }
|
||||
|
||||
# Map from character to width, height.
|
||||
self.sizes = { }
|
||||
|
||||
# Load in the image.
|
||||
surf = renpy.display.im.Image(self.filename).load(unscaled=True)
|
||||
|
||||
sw, sh = surf.get_size()
|
||||
height = sh
|
||||
self.height = height
|
||||
|
||||
# Create space characters.
|
||||
self.chars[u' '] = pygame.Surface((self.spacewidth, height), 0, surf)
|
||||
self.sizes[u' '] = self.spacewidth
|
||||
self.chars[u'\u00a0'] = self.chars[u' ']
|
||||
self.sizes[u'\u00a0'] = self.sizes[u' ']
|
||||
|
||||
# The color key used to separate characters.
|
||||
i = 0
|
||||
while True:
|
||||
key = surf.get_at((i, 0))
|
||||
if key[3] != 0:
|
||||
break
|
||||
i += 1
|
||||
|
||||
ci = 0
|
||||
|
||||
# Find real characters, create them.
|
||||
while i < sw and ci < len(self.charset):
|
||||
|
||||
if surf.get_at((i, 0)) != key:
|
||||
start = i
|
||||
i += 1
|
||||
|
||||
while i < sw:
|
||||
if surf.get_at((i, 0)) == key:
|
||||
break
|
||||
|
||||
i += 1
|
||||
|
||||
c = self.charset[ci]
|
||||
ci += 1
|
||||
|
||||
ss = surf.subsurface((start, 0, i - start, height))
|
||||
ss = renpy.display.scale.surface_scale(ss)
|
||||
|
||||
self.chars[c] = ss
|
||||
self.sizes[c] = i - start
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
|
||||
class MudgeFont(ImageFont):
|
||||
|
||||
def __init__(self,
|
||||
filename,
|
||||
xml,
|
||||
spacewidth,
|
||||
default_kern,
|
||||
kerns):
|
||||
|
||||
self.filename = filename
|
||||
self.xml = xml
|
||||
self.spacewidth = spacewidth
|
||||
self.default_kern = default_kern
|
||||
self.kerns = kerns
|
||||
|
||||
def load(self):
|
||||
|
||||
# Map from character to subsurface.
|
||||
self.chars = { }
|
||||
|
||||
# Map from character to width, height.
|
||||
self.sizes = { }
|
||||
|
||||
# Load in the image.
|
||||
surf = renpy.display.im.Image(self.filename).load(unscaled=True)
|
||||
self.surf = surf
|
||||
|
||||
# Parse the xml file.
|
||||
tree = etree.fromstring(renpy.loader.load(self.xml).read())
|
||||
|
||||
height = 0
|
||||
|
||||
# Find each character.
|
||||
for e in tree.findall("char"):
|
||||
|
||||
char = int(e.attrib["id"])
|
||||
if char < 0:
|
||||
continue
|
||||
|
||||
c = unichr(char)
|
||||
x = int(e.attrib["x"])
|
||||
y = int(e.attrib["y"])
|
||||
w = int(e.attrib["width"])
|
||||
h = int(e.attrib["height"])
|
||||
|
||||
ss = surf.subsurface((x, y, w, h))
|
||||
ss = renpy.display.scale.surface_scale(ss)
|
||||
|
||||
self.chars[c] = ss
|
||||
self.sizes[c] = w
|
||||
|
||||
height = max(height, h)
|
||||
|
||||
self.height = height
|
||||
|
||||
# Create space characters.
|
||||
if u' ' not in self.chars:
|
||||
self.chars[u' '] = pygame.Surface((self.spacewidth, height), 0, surf)
|
||||
self.sizes[u' '] = self.spacewidth
|
||||
|
||||
if u'\u00a0' not in self.chars:
|
||||
self.chars[u'\u00a0'] = self.chars[u' ']
|
||||
self.sizes[u'\u00a0'] = self.sizes[u' ']
|
||||
|
||||
|
||||
def register_sfont(name=None, size=None, bold=False, italics=False, underline=False,
|
||||
filename=None, spacewidth=10, default_kern=0, kerns={},
|
||||
charset=u"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"):
|
||||
|
||||
if name is None or size is None or filename is None:
|
||||
raise Exception("When registering an SFont, the font name, font size, and filename are required.")
|
||||
|
||||
sf = SFont(filename, spacewidth, default_kern, kerns, charset)
|
||||
fonts[(name, size, bold, italics, underline)] = sf
|
||||
|
||||
|
||||
def register_mudgefont(name=None, size=None, bold=False, italics=False, underline=False,
|
||||
filename=None, xml=None, spacewidth=10, default_kern=0, kerns={}):
|
||||
|
||||
if name is None or size is None or filename is None:
|
||||
raise Exception("When registering a Mudge Font, the font name, font size, filename, and xmlfilename are required.")
|
||||
|
||||
mf = MudgeFont(filename, xml, spacewidth, default_kern, kerns)
|
||||
fonts[(name, size, bold, italics, underline)] = mf
|
||||
|
||||
|
||||
|
||||
def load_ttf(fn, size, bold, italics, underline, expand):
|
||||
|
||||
try:
|
||||
rv = pygame.font.Font(renpy.loader.load(fn), size)
|
||||
rv.set_bold(bold)
|
||||
rv.set_italic(italics)
|
||||
except:
|
||||
# Let's try to find the font on our own.
|
||||
fonts = [ i.strip().lower() for i in fn.split(",") ]
|
||||
|
||||
pygame.sysfont.initsysfonts()
|
||||
|
||||
rv = None
|
||||
|
||||
for k, v in pygame.sysfont.Sysfonts.iteritems():
|
||||
for flags, ffn in v.iteritems():
|
||||
for i in fonts:
|
||||
if ffn.lower().endswith(i):
|
||||
rv = pygame.font.Font(ffn, size)
|
||||
rv.set_bold(bold)
|
||||
rv.set_italic(italics)
|
||||
break
|
||||
if rv:
|
||||
break
|
||||
if rv:
|
||||
break
|
||||
else:
|
||||
# Let pygame try to find the font for us.
|
||||
rv = pygame.font.SysFont(fn, size, bold, italics)
|
||||
|
||||
rv.set_underline(underline)
|
||||
|
||||
try:
|
||||
rv.set_expand(expand)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def get_font(origfn, size, origbold=False, origitalics=False, underline=False, expand=0):
|
||||
|
||||
rv = font_cache.get((origfn, size, origbold, origitalics, underline, expand), None)
|
||||
if rv is not None:
|
||||
return rv
|
||||
|
||||
t = (origfn, origbold, origitalics)
|
||||
fn, bold, italics = renpy.config.font_replacement_map.get(t, t)
|
||||
|
||||
rv = fonts.get((fn, size, bold, italics, underline), None)
|
||||
if rv is not None:
|
||||
rv.load()
|
||||
else:
|
||||
try:
|
||||
rv = load_ttf(fn, size, bold, italics, underline, expand)
|
||||
except:
|
||||
if renpy.config.debug:
|
||||
raise
|
||||
raise Exception("Could not find font: %r" % ((fn, size, bold, italics, underline), ))
|
||||
|
||||
font_cache[(origfn, size, origbold, origitalics, underline, expand)] = rv
|
||||
|
||||
return rv
|
||||
|
||||
def free_memory():
|
||||
"""
|
||||
Clears the font cache.
|
||||
"""
|
||||
|
||||
font_cache.clear()
|
||||
@@ -65,7 +65,6 @@ class UncachedImage(renpy.display.core.Displayable):
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
class ImageReference(renpy.display.core.Displayable):
|
||||
"""
|
||||
ImageReference objects are used to reference images by their name,
|
||||
@@ -93,7 +92,7 @@ class ImageReference(renpy.display.core.Displayable):
|
||||
|
||||
if isinstance(name, renpy.display.core.Displayable):
|
||||
self.target = name
|
||||
return
|
||||
return True
|
||||
|
||||
if not isinstance(name, tuple):
|
||||
name = tuple(name.split())
|
||||
@@ -121,15 +120,16 @@ class ImageReference(renpy.display.core.Displayable):
|
||||
|
||||
error(str(e))
|
||||
|
||||
return
|
||||
return True
|
||||
|
||||
else:
|
||||
parameters.insert(0, name[-1])
|
||||
name = name[:-1]
|
||||
|
||||
error("Image '%s' not found." % ' '.join(self.name))
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def event(self, ev, x, y, st):
|
||||
if not self.target:
|
||||
self.find_target()
|
||||
|
||||
@@ -34,12 +34,15 @@ def start(gamedir):
|
||||
import os.path
|
||||
|
||||
global proc
|
||||
|
||||
fn = gamedir + "/presplash.png"
|
||||
|
||||
if not os.path.exists(fn):
|
||||
|
||||
filenames = [ "/presplash.png", "/presplash.jpg" ]
|
||||
for fn in filenames:
|
||||
fn = gamedir + fn
|
||||
if os.path.exists(fn):
|
||||
break
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@ import math
|
||||
import pygame
|
||||
import renpy
|
||||
|
||||
try:
|
||||
import _renpy_font as font_module
|
||||
except ImportError:
|
||||
import pygame.font as font_module
|
||||
|
||||
# This needs to be done before we mess too hard with pygame.
|
||||
try:
|
||||
import _renpy
|
||||
@@ -314,7 +319,7 @@ else:
|
||||
# Ignoring scale2x and chop. The former due to a pending api change,
|
||||
# the latter due to general uselessness.
|
||||
|
||||
PygameFont = pygame.font.Font
|
||||
PygameFont = font_module.Font
|
||||
|
||||
class Font(object):
|
||||
|
||||
@@ -364,7 +369,7 @@ else:
|
||||
# Anything involving the parents of subsurfaces.
|
||||
# get_pitch, get_shifts, get_losses
|
||||
|
||||
pygame.font.Font = Font
|
||||
font_module.Font = Font
|
||||
|
||||
old_image_save = pygame.image.save
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ import re
|
||||
import renpy
|
||||
import sys
|
||||
|
||||
get_font = renpy.display.font.get_font
|
||||
ImageFont = renpy.display.font.ImageFont
|
||||
|
||||
# A list of text tags, mapping from the text tag prefix to if it
|
||||
# requires a closing tag.
|
||||
text_tags = dict(
|
||||
@@ -48,236 +51,6 @@ text_tags = dict(
|
||||
|
||||
text_tags[""] = True
|
||||
|
||||
# This contains a map from (fn, size, bold, italics, underline) to the
|
||||
# unloaded font object corresponding to that specification.
|
||||
fonts = { }
|
||||
|
||||
# This contains a map from (fn, size, bold, italics, underline) to the
|
||||
# loaded font object corresponding to that specification.
|
||||
font_cache = { }
|
||||
|
||||
class SFont(object):
|
||||
|
||||
def __init__(self,
|
||||
filename,
|
||||
spacewidth,
|
||||
default_kern,
|
||||
kerns,
|
||||
charset):
|
||||
|
||||
self.filename = filename
|
||||
self.spacewidth = spacewidth
|
||||
self.default_kern = default_kern
|
||||
self.kerns = kerns
|
||||
self.charset = charset
|
||||
|
||||
def load(self):
|
||||
|
||||
# Map from character to subsurface.
|
||||
self.chars = { }
|
||||
|
||||
# Map from character to width, height.
|
||||
self.sizes = { }
|
||||
|
||||
# Load in the image.
|
||||
surf = renpy.display.im.Image(self.filename).load(unscaled=True)
|
||||
self.surf = surf
|
||||
|
||||
sw, sh = surf.get_size()
|
||||
height = sh - 1
|
||||
self.height = height
|
||||
|
||||
# Create space characters.
|
||||
self.chars[u' '] = pygame.Surface((self.spacewidth, height), 0, surf)
|
||||
self.sizes[u' '] = self.spacewidth
|
||||
self.chars[u'\u00a0'] = self.chars[u' ']
|
||||
self.sizes[u'\u00a0'] = self.sizes[u' ']
|
||||
|
||||
# The color key used to separate characters.
|
||||
i = 0
|
||||
while True:
|
||||
key = surf.get_at((i, 0))
|
||||
if key[3] != 0:
|
||||
break
|
||||
i += 1
|
||||
|
||||
ci = 0
|
||||
|
||||
# Find real characters, create them.
|
||||
while i < sw and ci < len(self.charset):
|
||||
|
||||
if surf.get_at((i, 0)) != key:
|
||||
start = i
|
||||
i += 1
|
||||
|
||||
while i < sw:
|
||||
if surf.get_at((i, 0)) == key:
|
||||
break
|
||||
|
||||
i += 1
|
||||
|
||||
c = self.charset[ci]
|
||||
ci += 1
|
||||
|
||||
ss = surf.subsurface((start, 1, i - start, height))
|
||||
ss = renpy.display.scale.surface_scale(ss)
|
||||
|
||||
self.chars[c] = ss
|
||||
self.sizes[c] = i - start
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
def size(self, text):
|
||||
w = 0
|
||||
|
||||
if not text:
|
||||
return (0, self.height)
|
||||
|
||||
for a, b in zip(text, text[1:]):
|
||||
w += self.sizes[a] + self.kerns.get(a + b, self.default_kern)
|
||||
|
||||
w += self.sizes[text[-1]]
|
||||
|
||||
return (w, self.height)
|
||||
|
||||
def render(self, text, antialias, color, black_color=(0, 0, 0, 255), background=None):
|
||||
surf = pygame.Surface(self.size(text), 0,
|
||||
renpy.game.interface.display.sample_surface)
|
||||
|
||||
if not text:
|
||||
return surf
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
|
||||
for a, b in zip(text, text[1:]):
|
||||
surf.blit(self.chars[a], (x, y))
|
||||
x += self.sizes[a] + self.kerns.get(a + b, self.default_kern)
|
||||
|
||||
surf.blit(self.chars[text[-1]], (x, y))
|
||||
|
||||
if renpy.config.recolor_sfonts and \
|
||||
(color != (255, 255, 255, 255) or black_color != (0, 0, 0, 255) ) and \
|
||||
renpy.display.module.can_twomap:
|
||||
|
||||
newsurf = pygame.Surface(surf.get_size(), surf.get_flags(), surf)
|
||||
renpy.display.module.twomap(surf, newsurf, color, black_color)
|
||||
renpy.display.render.mutated_surface(newsurf)
|
||||
|
||||
surf = newsurf
|
||||
|
||||
return surf
|
||||
|
||||
def get_linesize(self):
|
||||
return self.height
|
||||
|
||||
def get_height(self):
|
||||
return self.height
|
||||
|
||||
def get_ascent(self):
|
||||
return self.height
|
||||
|
||||
def get_descent(self):
|
||||
return 0
|
||||
|
||||
def register_sfont(name=None, size=None, bold=False, italics=False, underline=False,
|
||||
filename=None, spacewidth=10, default_kern=0, kerns={},
|
||||
charset=u"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"):
|
||||
"""
|
||||
This registers an SFont with the given details. Please note that
|
||||
size, bold, italic, and underline are all advisory (used for matching), and
|
||||
do not change the appearance of the font.
|
||||
|
||||
@param name: The name of the font being registered.
|
||||
@param size: The size of the font being registered.
|
||||
@param bold: The boldness of the font being registered.
|
||||
@param italics: The italicness of the font being registered.
|
||||
@param underline: The underline of the font being registered.
|
||||
|
||||
@param filename: The file containing the sfont image.
|
||||
@param spacewidth: The width of a space character.
|
||||
@param default_kern: The default kern spacing between characters.
|
||||
@param kerns: A map from two-character strings to the kern that should
|
||||
be used between those characters.
|
||||
@param charset: The character set of the font. A string containing characters
|
||||
in the order in which they are found in the image.
|
||||
"""
|
||||
|
||||
if name is None or size is None or filename is None:
|
||||
raise Exception("When registering an SFont, the font name, font size, and filename are required.")
|
||||
|
||||
sf = SFont(filename, spacewidth, default_kern, kerns, charset)
|
||||
fonts[(name, size, bold, italics, underline)] = sf
|
||||
|
||||
|
||||
|
||||
def load_ttf(fn, size, bold, italics, underline):
|
||||
|
||||
try:
|
||||
rv = pygame.font.Font(renpy.loader.load(fn), size)
|
||||
rv.set_bold(bold)
|
||||
rv.set_italic(italics)
|
||||
except:
|
||||
# Let's try to find the font on our own.
|
||||
fonts = [ i.strip().lower() for i in fn.split(",") ]
|
||||
|
||||
pygame.sysfont.initsysfonts()
|
||||
|
||||
rv = None
|
||||
|
||||
for k, v in pygame.sysfont.Sysfonts.iteritems():
|
||||
for flags, ffn in v.iteritems():
|
||||
for i in fonts:
|
||||
if ffn.lower().endswith(i):
|
||||
rv = pygame.font.Font(ffn, size)
|
||||
rv.set_bold(bold)
|
||||
rv.set_italic(italics)
|
||||
break
|
||||
if rv:
|
||||
break
|
||||
if rv:
|
||||
break
|
||||
else:
|
||||
# Let pygame try to find the font for us.
|
||||
rv = pygame.font.SysFont(fn, size, bold, italics)
|
||||
|
||||
rv.set_underline(underline)
|
||||
return rv
|
||||
|
||||
|
||||
# TODO: Something sane if the font file can't be found.
|
||||
def get_font(fn, size, bold=False, italics=False, underline=False):
|
||||
from renpy.loader import transfn
|
||||
|
||||
if (fn, bold, italics) in renpy.config.font_replacement_map:
|
||||
fn, bold, italics = renpy.config.font_replacement_map[fn, bold, italics]
|
||||
|
||||
if (fn, size, bold, italics, underline) in font_cache:
|
||||
return font_cache[(fn, size, bold, italics, underline)]
|
||||
|
||||
rv = fonts.get((fn, size, bold, italics, underline), None)
|
||||
if rv is not None:
|
||||
rv.load()
|
||||
else:
|
||||
try:
|
||||
rv = load_ttf(fn, size, bold, italics, underline)
|
||||
except:
|
||||
if renpy.config.debug:
|
||||
raise
|
||||
raise Exception("Could not find font: %r" % ((fn, size, bold, italics, underline), ))
|
||||
|
||||
font_cache[(fn, size, bold, italics, underline)] = rv
|
||||
|
||||
return rv
|
||||
|
||||
def free_memory():
|
||||
"""
|
||||
Clears the font cache.
|
||||
"""
|
||||
|
||||
font_cache.clear()
|
||||
|
||||
def color(s):
|
||||
"""
|
||||
This function converts a hexcode into a color/alpha tuple. Leading
|
||||
@@ -332,7 +105,7 @@ class TextStyle(object):
|
||||
self.wcache = { }
|
||||
|
||||
def update(self):
|
||||
self.f = get_font(self.font, self.size, self.bold, self.italic, self.underline)
|
||||
self.f = get_font(self.font, self.size, self.bold, self.italic, self.underline, 0)
|
||||
|
||||
def get_font(self):
|
||||
return self.f
|
||||
@@ -351,16 +124,18 @@ class TextStyle(object):
|
||||
def sizes(self, text):
|
||||
return self.get_width(text), self.f.get_ascent() - self.f.get_descent()
|
||||
|
||||
def render(self, text, antialias, color, black_color, use_colors, time, at):
|
||||
def render(self, text, antialias, color, black_color, use_colors, time, at, expand):
|
||||
|
||||
if use_colors:
|
||||
color = self.color or color
|
||||
black_color = self.black_color or black_color
|
||||
|
||||
if expand:
|
||||
font = get_font(self.font, self.size, self.bold, self.italic, self.underline, expand)
|
||||
else:
|
||||
font = self.f
|
||||
|
||||
font = self.f
|
||||
|
||||
|
||||
if isinstance(font, SFont):
|
||||
if isinstance(font, ImageFont):
|
||||
rv = font.render(text, antialias, color, black_color)
|
||||
|
||||
if self.strikethrough:
|
||||
@@ -428,7 +203,7 @@ class WidgetStyle(object):
|
||||
def sizes(self, widget):
|
||||
return self.width, self.height
|
||||
|
||||
def render(self, widget, antialias, color, black_color, foreground, st, at):
|
||||
def render(self, widget, antialias, color, black_color, foreground, st, at, expand):
|
||||
|
||||
# If in the foreground
|
||||
if foreground:
|
||||
@@ -439,7 +214,23 @@ class WidgetStyle(object):
|
||||
def length(self, text):
|
||||
return 1
|
||||
|
||||
class SpacerStyle(object):
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
# The actual size is computed at render time.
|
||||
def sizes(self, ignored):
|
||||
return (0, 0)
|
||||
|
||||
def get_ascent(self):
|
||||
return 0
|
||||
|
||||
def get_width(self, text):
|
||||
return 0
|
||||
|
||||
def length(self, text):
|
||||
return 0
|
||||
|
||||
# The line breaking algorithm for western languages.
|
||||
western_text_regexp = re.compile(ur"""(?x)
|
||||
@@ -591,6 +382,9 @@ def greedy_text_layout(triples, width, style):
|
||||
|
||||
lines = [ ]
|
||||
line = [ ]
|
||||
|
||||
# Is this the last line in a paragraph?
|
||||
lines_last = [ ]
|
||||
|
||||
target = width - style.first_indent
|
||||
|
||||
@@ -600,7 +394,8 @@ def greedy_text_layout(triples, width, style):
|
||||
|
||||
if type == "newline":
|
||||
lines.append(line)
|
||||
line = [ triple ]
|
||||
lines_last.append(True)
|
||||
line = [ ]
|
||||
target = width - style.rest_indent
|
||||
|
||||
continue
|
||||
@@ -614,20 +409,22 @@ def greedy_text_layout(triples, width, style):
|
||||
else:
|
||||
if layout_width(line + [ triple ]) > target:
|
||||
lines.append(line)
|
||||
lines_last.append(False)
|
||||
line = [ triple ]
|
||||
target = width - style.rest_indent
|
||||
else:
|
||||
line.append(triple)
|
||||
|
||||
lines.append(line)
|
||||
|
||||
lines_last.append(True)
|
||||
|
||||
# Remove trailing whitespace, except on the last line, where it
|
||||
# might be intentional.
|
||||
for l in lines[:-1]:
|
||||
if l and l[-1][0] == "space":
|
||||
l.pop()
|
||||
|
||||
return lines
|
||||
return lines, lines_last
|
||||
|
||||
|
||||
def subtitle_text_layout_core(triples, width, style, soft, n):
|
||||
@@ -636,7 +433,7 @@ def subtitle_text_layout_core(triples, width, style, soft, n):
|
||||
|
||||
lines = [ ]
|
||||
line = [ ]
|
||||
|
||||
|
||||
target = width
|
||||
|
||||
total = soft * n
|
||||
@@ -725,7 +522,8 @@ def subtitle_text_layout(triples, width, style):
|
||||
|
||||
|
||||
# Deal with each paragraph separately.
|
||||
rrv = [ ] # Real return value.
|
||||
lines = [ ]
|
||||
lines_last = [ ]
|
||||
|
||||
for triples in pars:
|
||||
|
||||
@@ -740,10 +538,13 @@ def subtitle_text_layout(triples, width, style):
|
||||
if len(rv) == i:
|
||||
break
|
||||
i += 1
|
||||
|
||||
rrv.extend(rv)
|
||||
|
||||
return rrv
|
||||
lines.extend(rv)
|
||||
for i in range(len(lines) - 1):
|
||||
lines_last.append(False)
|
||||
lines_last.append(True)
|
||||
|
||||
return lines, lines_last
|
||||
|
||||
def text_layout(triples, width, style):
|
||||
|
||||
@@ -760,8 +561,8 @@ class Text(renpy.display.core.Displayable):
|
||||
|
||||
nosave = [ 'laidout', 'laidout_lineheights', 'laidout_linewidths',
|
||||
'laidout_width', 'laidout_height', 'laidout_start',
|
||||
'laidout_length', 'laidout_hyperlinks', 'width', 'tokens', 'children',
|
||||
'child_pos']
|
||||
'laidout_length', 'laidout_hyperlinks', 'laidout_lines_last',
|
||||
'width', 'tokens', 'children', 'child_pos']
|
||||
|
||||
__version__ = 2
|
||||
|
||||
@@ -1257,7 +1058,6 @@ class Text(renpy.display.core.Displayable):
|
||||
raise Exception("Unknown text token kind %s." % kind)
|
||||
|
||||
if kind == "widget":
|
||||
|
||||
wstyle = WidgetStyle(tsl[-1], i, width, time)
|
||||
triples.append(("word", wstyle, i))
|
||||
|
||||
@@ -1269,9 +1069,8 @@ class Text(renpy.display.core.Displayable):
|
||||
|
||||
# Give text_layout a list of triples, get back a list of lists of
|
||||
# triples, one per line.
|
||||
linetriples = renpy.config.text_layout(triples, width, self.style)
|
||||
|
||||
|
||||
linetriples, lines_last = renpy.config.text_layout(triples, width, self.style)
|
||||
|
||||
# Now, we need to go through these lines, to generate the data
|
||||
# we need to render text.
|
||||
|
||||
@@ -1282,12 +1081,16 @@ class Text(renpy.display.core.Displayable):
|
||||
self.laidout_start = 0
|
||||
self.laidout_width = self.style.min_width
|
||||
self.laidout_height = 0
|
||||
|
||||
self.laidout_lines_last = lines_last
|
||||
|
||||
# Add something to empty lines.
|
||||
for l in linetriples:
|
||||
if not l:
|
||||
l.append(('word', tsl[-1], ' '))
|
||||
|
||||
|
||||
justify = self.style.justify
|
||||
|
||||
for l in linetriples:
|
||||
|
||||
line = [ ]
|
||||
@@ -1304,7 +1107,7 @@ class Text(renpy.display.core.Displayable):
|
||||
self.laidout_length += len(i)
|
||||
except:
|
||||
self.laidout_length += ts.length(i)
|
||||
|
||||
|
||||
if ts is not oldts:
|
||||
if oldts is not None:
|
||||
line.append((oldts, cur))
|
||||
@@ -1314,6 +1117,12 @@ class Text(renpy.display.core.Displayable):
|
||||
else:
|
||||
cur += i
|
||||
|
||||
if justify and kind == "space":
|
||||
if cur:
|
||||
line.append((oldts, cur))
|
||||
cur = ""
|
||||
line.append((SpacerStyle(), ""))
|
||||
|
||||
if oldts:
|
||||
line.append((oldts, cur))
|
||||
|
||||
@@ -1383,7 +1192,7 @@ class Text(renpy.display.core.Displayable):
|
||||
|
||||
|
||||
|
||||
def render_pass(self, r, offsets, color, black_color, user_colors, length, time, at, child_pos, add_focus):
|
||||
def render_pass(self, r, xo, yo, color, black_color, user_colors, length, time, at, child_pos, add_focus, expand):
|
||||
"""
|
||||
Renders the text to r at the offsets. Color is the base color,
|
||||
and user_colors controls if the user can override those colors.
|
||||
@@ -1397,18 +1206,39 @@ class Text(renpy.display.core.Displayable):
|
||||
rest_indent = self.style.rest_indent
|
||||
antialias = self.style.antialias
|
||||
line_spacing = self.style.line_spacing
|
||||
|
||||
for line, line_height, line_width in zip(self.laidout, self.laidout_lineheights, self.laidout_linewidths):
|
||||
x = indent + self.style.text_align * (self.laidout_width - line_width)
|
||||
text_align = self.style.text_align
|
||||
justify = self.style.justify
|
||||
|
||||
lines = len(self.laidout)
|
||||
|
||||
for line, line_height, line_width, last in zip(self.laidout, self.laidout_lineheights, self.laidout_linewidths, self.laidout_lines_last):
|
||||
if justify and not last:
|
||||
empty_space = (self.laidout_width - line_width - indent)
|
||||
x = indent
|
||||
else:
|
||||
empty_space = 0
|
||||
x = indent + text_align * (self.laidout_width - line_width)
|
||||
|
||||
indent = rest_indent
|
||||
|
||||
|
||||
max_ascent = 0
|
||||
|
||||
spacers = 0
|
||||
|
||||
for ts, text in line:
|
||||
max_ascent = max(ts.get_ascent(), max_ascent)
|
||||
|
||||
for ts, text in line:
|
||||
if isinstance(ts, SpacerStyle):
|
||||
spacers += 1
|
||||
|
||||
for ts, text in line:
|
||||
|
||||
if isinstance(ts, SpacerStyle):
|
||||
space = empty_space / spacers
|
||||
x += space
|
||||
empty_space -= space
|
||||
spacers -= 1
|
||||
continue
|
||||
|
||||
length -= ts.length(text)
|
||||
|
||||
if length < 0:
|
||||
@@ -1417,20 +1247,21 @@ class Text(renpy.display.core.Displayable):
|
||||
else:
|
||||
return False
|
||||
|
||||
surf, (sw, sh) = ts.render(text, antialias, color, black_color, user_colors, time, at)
|
||||
surf, (sw, sh) = ts.render(text, antialias, color, black_color, user_colors, time, at, expand)
|
||||
|
||||
if expand:
|
||||
(sw, sh) = ts.sizes(text)
|
||||
|
||||
actual_y = y + max_ascent - ts.get_ascent()
|
||||
|
||||
for xo, yo in offsets:
|
||||
if surf:
|
||||
r.blit(surf, (x + xo, actual_y + yo))
|
||||
|
||||
if surf:
|
||||
r.blit(surf, (x + xo, actual_y + yo))
|
||||
if add_focus and ts.hyperlink is not None:
|
||||
r.add_focus(self, ts.hyperlink, x + xo, y + yo, sw, sh)
|
||||
|
||||
if add_focus and ts.hyperlink is not None:
|
||||
r.add_focus(self, ts.hyperlink, x + xo, y + yo, sw, sh)
|
||||
|
||||
if not isinstance(text, (str, unicode)):
|
||||
child_pos.append((text, x + xo, actual_y + yo))
|
||||
if not isinstance(text, (str, unicode)):
|
||||
child_pos.append((text, x + xo, actual_y + yo))
|
||||
|
||||
x = x + sw
|
||||
|
||||
@@ -1480,7 +1311,8 @@ class Text(renpy.display.core.Displayable):
|
||||
|
||||
|
||||
dslist = self.style.drop_shadow
|
||||
|
||||
outlines = self.style.outlines
|
||||
|
||||
if dslist is None:
|
||||
dslist = [ ]
|
||||
elif not isinstance(dslist, list):
|
||||
@@ -1497,6 +1329,12 @@ class Text(renpy.display.core.Displayable):
|
||||
maxdsx = max(maxdsx, dsx)
|
||||
maxdsy = max(maxdsy, dsy)
|
||||
|
||||
for expand, color, dsx, dsy in outlines:
|
||||
mindsx = min(mindsx, dsx - expand)
|
||||
mindsy = min(mindsy, dsy - expand)
|
||||
maxdsx = max(maxdsx, dsx + expand)
|
||||
maxdsy = max(maxdsy, dsy + expand)
|
||||
|
||||
# minds{x,y} are negative (or 0), maxds{x,y} are positive (or 0).
|
||||
|
||||
self.layout(width + mindsx - maxdsx, st)
|
||||
@@ -1510,13 +1348,15 @@ class Text(renpy.display.core.Displayable):
|
||||
|
||||
rv = renpy.display.render.Render(self.laidout_width - mindsx + maxdsx, self.laidout_height - mindsy + maxdsy)
|
||||
|
||||
if dslist:
|
||||
dsoffsets = [ (dsxo - mindsx, dsyo - mindsy) for dsxo, dsyo in dslist ]
|
||||
self.render_pass(rv, dsoffsets, self.style.drop_shadow_color, self.style.drop_shadow_color, False, length, st, at, [ ], False)
|
||||
for dsxo, dsyo in dslist:
|
||||
self.render_pass(rv, dsxo - mindsx, dsyo - mindsy, self.style.drop_shadow_color, self.style.drop_shadow_color, False, length, st, at, [ ], False, 0)
|
||||
|
||||
for expand, color, dsxo, dsyo in outlines:
|
||||
self.render_pass(rv, dsxo - mindsx - expand, dsyo - mindsy - expand, color, color, False, length, st, at, [ ], False, expand)
|
||||
|
||||
self.child_pos = [ ]
|
||||
|
||||
if self.render_pass(rv, [ (-mindsx, -mindsy) ], self.style.color, self.style.black_color, True, length, st, at, self.child_pos, True):
|
||||
if self.render_pass(rv, -mindsx, -mindsy, self.style.color, self.style.black_color, True, length, st, at, self.child_pos, True, 0):
|
||||
if self.slow:
|
||||
self.call_slow_done(st)
|
||||
|
||||
|
||||
@@ -28,16 +28,12 @@
|
||||
_file = file
|
||||
|
||||
import renpy
|
||||
|
||||
# Many of these shouldn't be used directly.
|
||||
# from renpy.display.layout import *
|
||||
from renpy.display.text import ParameterizedText, register_sfont
|
||||
from renpy.display.text import ParameterizedText
|
||||
from renpy.display.font import register_sfont, register_mudgefont
|
||||
from renpy.display.behavior import Keymap
|
||||
from renpy.display.minigame import Minigame
|
||||
# from renpy.display.image import *
|
||||
|
||||
from renpy.curry import curry
|
||||
# from renpy.display.audio import music_start, music_stop
|
||||
from renpy.audio.sound import play
|
||||
from renpy.display.video import movie_start_fullscreen, movie_start_displayable, movie_stop
|
||||
from renpy.loadsave import load, save, list_saved_games, can_load, rename_save, unlink_save, scan_saved_game
|
||||
@@ -135,6 +131,22 @@ def image(name, img):
|
||||
img = renpy.easy.displayable(img)
|
||||
|
||||
images[name] = img
|
||||
|
||||
def copy_images(old, new):
|
||||
if not isinstance(old, tuple):
|
||||
old = tuple(old.split())
|
||||
|
||||
if not isinstance(new, tuple):
|
||||
new = tuple(new.split())
|
||||
|
||||
lenold = len(old)
|
||||
|
||||
for k in list(images.keys()):
|
||||
if len(k) < lenold:
|
||||
continue
|
||||
|
||||
if k[:lenold] == old:
|
||||
images[new + k[lenold:]] = images[k]
|
||||
|
||||
def showing(name, layer='master'):
|
||||
"""
|
||||
@@ -169,8 +181,11 @@ def show(name, at_list=[ ], layer='master', what=None, zorder=0, tag=None, behin
|
||||
|
||||
if what is None:
|
||||
what = name
|
||||
elif isinstance(what, basestring):
|
||||
what = tuple(what.split())
|
||||
|
||||
base = img = renpy.display.image.ImageReference(what, style='image_placement')
|
||||
|
||||
img = renpy.display.image.ImageReference(what, style='image_placement')
|
||||
for i in at_list:
|
||||
img = i(img)
|
||||
|
||||
@@ -180,6 +195,13 @@ def show(name, at_list=[ ], layer='master', what=None, zorder=0, tag=None, behin
|
||||
if tag:
|
||||
name = (tag,) + name[1:]
|
||||
|
||||
if not base.find_target() and renpy.config.missing_show:
|
||||
if renpy.config.missing_show(name, what, layer):
|
||||
return
|
||||
|
||||
if renpy.config.missing_hide:
|
||||
renpy.config.missing_hide(name, layer)
|
||||
|
||||
sls.add(layer, img, key, zorder, behind, at_list=at_list, name=name)
|
||||
|
||||
|
||||
@@ -204,6 +226,9 @@ def hide(name, layer='master'):
|
||||
sls = scene_lists()
|
||||
key = name[0]
|
||||
sls.remove(layer, key)
|
||||
|
||||
if renpy.config.missing_hide:
|
||||
renpy.config.missing_hide(name, layer)
|
||||
|
||||
|
||||
def scene(layer='master'):
|
||||
@@ -215,7 +240,9 @@ def scene(layer='master'):
|
||||
|
||||
sls = scene_lists()
|
||||
sls.clear(layer)
|
||||
|
||||
|
||||
if renpy.config.missing_scene:
|
||||
renpy.config.missing_scene(layer)
|
||||
|
||||
def watch(expression, style='default', **properties):
|
||||
"""
|
||||
@@ -890,13 +917,41 @@ def get_filename_line():
|
||||
|
||||
def shell_escape(s):
|
||||
s = s.replace("\\", "\\\\")
|
||||
s = s.replace("\'", "\\\'")
|
||||
s = s.replace("\"", "\\\"")
|
||||
s = s.replace("\$", "\\\$")
|
||||
s = s.replace("\%", "\\\%")
|
||||
s = s.replace("\`", "\\\`")
|
||||
return s
|
||||
|
||||
def split_args(s):
|
||||
|
||||
rv = [ ]
|
||||
word = ""
|
||||
quoted = False
|
||||
|
||||
i = 0
|
||||
while i < len(s):
|
||||
c = s[i]
|
||||
i += 1
|
||||
|
||||
if not quoted and c == ' ' and word:
|
||||
if word:
|
||||
rv.append(word)
|
||||
word = ""
|
||||
continue
|
||||
|
||||
if c == '"':
|
||||
quoted = not quoted
|
||||
continue
|
||||
|
||||
if c == '\\':
|
||||
c = s[i]
|
||||
i += 1
|
||||
|
||||
word += c
|
||||
|
||||
if word:
|
||||
rv.append(word)
|
||||
|
||||
return rv
|
||||
|
||||
def launch_editor(filenames, line=1, transient=0):
|
||||
"""
|
||||
This causes an editor to be launched at the location of the current
|
||||
@@ -913,16 +968,8 @@ def launch_editor(filenames, line=1, transient=0):
|
||||
if not len(filenames):
|
||||
return
|
||||
|
||||
# join = '" "'
|
||||
shell = True
|
||||
|
||||
# if hasattr(sys, "winver"):
|
||||
# shell = False
|
||||
# # join = '" "'
|
||||
# else:
|
||||
# shell = True
|
||||
# # join = "' '"
|
||||
|
||||
filenames = [ shell_escape(os.path.normpath(i)) for i in filenames ]
|
||||
filename = filenames[0]
|
||||
|
||||
@@ -938,11 +985,12 @@ def launch_editor(filenames, line=1, transient=0):
|
||||
cmd = cmd.replace('""', '')
|
||||
|
||||
try:
|
||||
return subprocess.Popen(cmd, shell=shell)
|
||||
subprocess.Popen(split_args(cmd))
|
||||
return True
|
||||
except:
|
||||
if renpy.config.debug:
|
||||
raise
|
||||
return None
|
||||
return False
|
||||
|
||||
# A file that log logs to.
|
||||
logfile = None
|
||||
@@ -1050,9 +1098,21 @@ def layer_at_list(at_list, layer='master'):
|
||||
def free_memory():
|
||||
force_full_redraw()
|
||||
renpy.display.im.free_memory()
|
||||
renpy.display.text.free_memory()
|
||||
renpy.display.font.free_memory()
|
||||
renpy.display.render.free_memory()
|
||||
|
||||
def easy_displayable(d, none=False):
|
||||
if none:
|
||||
return renpy.easy.displayable(d)
|
||||
else:
|
||||
return renpy.easy.displayable_or_none(d)
|
||||
|
||||
def quit_event():
|
||||
renpy.game.interface.quit_event()
|
||||
|
||||
def iconify():
|
||||
renpy.game.interface.display.iconify()
|
||||
|
||||
# New context stuff.
|
||||
call_in_new_context = renpy.game.call_in_new_context
|
||||
curried_call_in_new_context = renpy.curry.curry(renpy.game.call_in_new_context)
|
||||
|
||||
@@ -443,7 +443,7 @@ class Script(object):
|
||||
if self.bytecode_dirty:
|
||||
try:
|
||||
data = (BYTECODE_VERSION, self.bytecode_newcache)
|
||||
f = file(os.path.join(renpy.config.searchpath[0], "bytecode.rpyb"), "w")
|
||||
f = file(os.path.join(renpy.config.searchpath[0], "bytecode.rpyb"), "wb")
|
||||
f.write(dumps(data, 2).encode("zlib"))
|
||||
f.close()
|
||||
except:
|
||||
|
||||
@@ -72,6 +72,18 @@ def none_is_null(d):
|
||||
else:
|
||||
return renpy.easy.displayable(d)
|
||||
|
||||
# This expands the outlines list.
|
||||
def expand_outlines(l):
|
||||
rv = [ ]
|
||||
|
||||
for i in l:
|
||||
if len(i) == 2:
|
||||
rv.append((i[0], renpy.easy.color(i[1]), 0, 0))
|
||||
else:
|
||||
rv.append((i[0], renpy.easy.color(i[1]), i[2], i[3]))
|
||||
|
||||
return rv
|
||||
|
||||
# A map of properties that we know about. The properties may take a
|
||||
# function that is called to convert the argument to something more
|
||||
# useful.
|
||||
@@ -82,6 +94,7 @@ style_properties = dict(
|
||||
background = renpy.easy.displayable_or_none,
|
||||
bar_invert = None,
|
||||
bar_resizing = None,
|
||||
unscrollable = None,
|
||||
bar_vertical = None,
|
||||
black_color = renpy.easy.color,
|
||||
bold = None,
|
||||
@@ -103,6 +116,7 @@ style_properties = dict(
|
||||
foreground = renpy.easy.displayable_or_none,
|
||||
sound = None,
|
||||
italic = None,
|
||||
justify = None,
|
||||
language = None,
|
||||
layout = None,
|
||||
left_margin = None,
|
||||
@@ -110,6 +124,7 @@ style_properties = dict(
|
||||
line_spacing = None,
|
||||
mouse = None,
|
||||
min_width = None,
|
||||
outlines = expand_outlines,
|
||||
rest_indent = None,
|
||||
right_margin = None,
|
||||
right_padding = None,
|
||||
@@ -292,6 +307,9 @@ class StyleManager(object):
|
||||
|
||||
s = Style(parent, { }, heavy=True, help=description)
|
||||
setattr(self, name, s)
|
||||
|
||||
def rebuild(self):
|
||||
renpy.style.rebuild()
|
||||
|
||||
def exists(self, name):
|
||||
"""
|
||||
@@ -472,10 +490,12 @@ def build_styles():
|
||||
styles_built = True
|
||||
|
||||
def rebuild():
|
||||
|
||||
global style_pending
|
||||
global styles_built
|
||||
|
||||
if renpy.game.init_phase:
|
||||
return
|
||||
|
||||
styles_pending = [ j for i in style_parts.values() for j in i.values() ]
|
||||
styles_built = False
|
||||
|
||||
|
||||
@@ -71,8 +71,8 @@ def archive(prefix, files):
|
||||
|
||||
for fullfn, shortfn in files:
|
||||
|
||||
if shortfn.lower().endswith(".ttf"):
|
||||
continue
|
||||
# if shortfn.lower().endswith(".ttf"):
|
||||
# continue
|
||||
|
||||
shortfn = shortfn.replace("\\", "/")
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright 2004-2007 PyTom <pytom@bishoujo.us>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import lsprofcalltree
|
||||
|
||||
# Functions to be customized by distributors. ################################
|
||||
|
||||
# Given the Ren'Py base directory (usually the directory containing
|
||||
# this file), this is expected to return the path to the common directory.
|
||||
def path_to_common(renpy_base):
|
||||
return renpy_base + "/common"
|
||||
|
||||
# Given a directory holding a Ren'Py game, this is expected to return
|
||||
# the path to a directory that will hold save files.
|
||||
def path_to_saves(gamedir):
|
||||
return gamedir + "/saves"
|
||||
|
||||
# Returns the path to the Ren'Py base directory (containing common and
|
||||
# the launcher, usually.)
|
||||
def path_to_renpy_base():
|
||||
renpy_base = os.path.dirname(sys.argv[0])
|
||||
renpy_base = os.environ.get('RENPY_BASE', renpy_base)
|
||||
renpy_base = os.path.abspath(renpy_base)
|
||||
|
||||
return renpy_base
|
||||
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
|
||||
# The version of the Mac Launcher and py4renpy that we use.
|
||||
macos_version = (6, 1, 0)
|
||||
linux_version = (6, 1, 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if not 'RENPY_NO_VERSION_CHECK' in os.environ:
|
||||
|
||||
# Check for mac compatibility.
|
||||
if "mac_version" in globals():
|
||||
mac_version(macos_version)
|
||||
|
||||
# Check py4renpy compatibility.
|
||||
try:
|
||||
import py4renpy
|
||||
if py4renpy.version < linux_version:
|
||||
print "The version of py4renpy that you are using is too old. Please go to"
|
||||
print "http://www.bishoujo.us/renpy/linux.html, and download the latest"
|
||||
print "version."
|
||||
sys.exit(-1)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
renpy_base = path_to_renpy_base()
|
||||
|
||||
# Add paths.
|
||||
if os.path.exists(renpy_base + "/module"):
|
||||
sys.path.append(renpy_base + "/module")
|
||||
|
||||
sys.path.append(renpy_base)
|
||||
|
||||
# This is looked for by the mac launcher.
|
||||
if os.path.exists(renpy_base + "/renpy.zip"):
|
||||
sys.path.append(renpy_base + "/renpy.zip")
|
||||
|
||||
|
||||
# Start Ren'Py proper.
|
||||
try:
|
||||
import renpy.bootstrap
|
||||
except ImportError:
|
||||
print >>sys.stderr, "Could not import renpy.bootstrap. Please ensure you decompressed Ren'Py"
|
||||
print >>sys.stderr, "correctly, preserving the directory structure."
|
||||
raise
|
||||
|
||||
import cProfile
|
||||
prof = cProfile.Profile()
|
||||
|
||||
try:
|
||||
prof = prof.run('renpy.bootstrap.bootstrap(renpy_base)')
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
prof.dump_stats('renpy.stats')
|
||||
|
||||
import pstats
|
||||
stats = pstats.Stats('renpy.stats')
|
||||
stats.sort_stats('time')
|
||||
stats.print_stats(20)
|
||||
|
||||
kg = lsprofcalltree.KCacheGrind(prof)
|
||||
kg.output(file("renpy.kcg", "w"))
|
||||
|
||||
@@ -13,18 +13,18 @@ init:
|
||||
|
||||
if platform.mac_ver()[0]:
|
||||
config.editor = "open -t '%(allfiles)s'"
|
||||
|
||||
else:
|
||||
|
||||
if sys.platform == 'win32':
|
||||
editor = config.renpy_base + "/editor/scite.exe"
|
||||
else:
|
||||
editor = config.renpy_base + "/editor/scite"
|
||||
|
||||
editor = os.path.normpath(editor)
|
||||
editor = renpy.shell_escape(editor)
|
||||
|
||||
if os.path.exists(editor):
|
||||
editor = renpy.shell_escape(editor)
|
||||
config.editor = '"' + editor + '" "%(allfiles)s" "-open:%(filename)s" -goto:%(line)d'
|
||||
config.editor_transient = config.editor+' -revert:'
|
||||
config.editor = '"' + editor + '" "%(allfiles)s" -goto:%(line)d'
|
||||
config.editor_transient = config.editor+' -revert:'
|
||||
|
||||
if config.editor:
|
||||
os.environ['RENPY_EDITOR'] = config.editor
|
||||
@@ -6,6 +6,8 @@ version = renpy.version[7:]
|
||||
|
||||
import sys
|
||||
if "retag" in sys.argv[1:]:
|
||||
renpy.subprocess.call([ "svn", "rm", 'http://www.bishoujo.us/svn/renpy/tags/' + version, "-m", "Tagging " + version ])
|
||||
renpy.subprocess.call([ "bzr", "tag", "--delete", version ])
|
||||
|
||||
renpy.subprocess.call([ "svn", "copy", ".", 'http://www.bishoujo.us/svn/renpy/tags/' + version, "-m", "Tagging " + version ])
|
||||
renpy.subprocess.call([ "bzr", "tag", version ])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../help.html
|
||||
@@ -192,6 +192,19 @@ init -1 python hide:
|
||||
# config.main_menu_music = "main_menu_theme.ogg"
|
||||
|
||||
|
||||
#########################################
|
||||
## Help.
|
||||
|
||||
## This lets you configure the help option on the Ren'Py menus.
|
||||
## It may be:
|
||||
## - A label in the script, in which case that label is called to
|
||||
## show help to the user.
|
||||
## - A file name relative to the base directory, which is opened in a
|
||||
## web browser.
|
||||
## - None, to disable help.
|
||||
config.help = "README.html"
|
||||
|
||||
|
||||
#########################################
|
||||
## Transitions.
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../help.html
|
||||
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 125 KiB |
@@ -195,6 +195,19 @@ init -1 python hide:
|
||||
# config.main_menu_music = "main_menu_theme.ogg"
|
||||
|
||||
|
||||
#########################################
|
||||
## Help.
|
||||
|
||||
## This lets you configure the help option on the Ren'Py menus.
|
||||
## It may be:
|
||||
## - A label in the script, in which case that label is called to
|
||||
## show help to the user.
|
||||
## - A file name relative to the base directory, which is opened in a
|
||||
## web browser.
|
||||
## - None, to disable help.
|
||||
config.help = "README.html"
|
||||
|
||||
|
||||
#########################################
|
||||
## Miscellaneous customizations
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 81 KiB |
@@ -1,3 +1,2 @@
|
||||
description="A simple and complete Ren'Py game."
|
||||
ro=True
|
||||
special=True
|
||||
|
||||
|
||||