Compare commits

...

31 Commits

Author SHA1 Message Date
Tom Rothamel 66125b2e10 Bump version. 2009-04-16 21:03:48 -04:00
Tom Rothamel e6becffc4c Blacklist obsolete file formats.
Properly deallocate VideoStates of short/invalid media files.
2009-04-16 19:31:50 -04:00
Tom Rothamel d281e57879 Fix reported bugs.
Make scaling more accurate.
2009-04-16 18:04:10 -04:00
Tom Rothamel 5196a970a0 Channels now have a default tightness. 2009-04-15 12:12:40 -04:00
Tom Rothamel efcbc92e7a Reimplement smoothscale in terms of _renpy.pixellate and _renpy.bilinear. 2009-04-15 01:10:13 -04:00
Tom Rothamel 142fa33548 Changelog updates. 2009-04-13 23:49:39 -04:00
Tom Rothamel 4b6e871ac6 6.9.1d 2009-04-13 23:40:13 -04:00
Tom Rothamel 1fbbad053a Add _rollback. 2009-04-13 23:11:39 -04:00
Tom Rothamel 61aa933d97 Fix rendering of empty image-based fonts. 2009-04-13 19:31:11 -04:00
Tom Rothamel 70c3ea773e Fix conflict between window show and shift+>. 2009-04-13 11:54:40 -04:00
Tom Rothamel a16de04682 The demo now passes with RENPY_SCALE_FACTOR=1.5. This required various fixes.
Prevent blit_lock from being held over a traceback.
2009-04-13 01:27:34 -04:00
Tom Rothamel 0280a12589 In SayBehavior, when a click comes in at the same time as a skip
timeout, favor the click.
2009-04-12 23:53:22 -04:00
Tom Rothamel 4dc8fef9c1 Fix a problems in scaling caused when images of different physical
sizes map to the same virtual size.

Fix a problem with restart.
2009-04-12 23:47:42 -04:00
Tom Rothamel 2c02645ec7 Lint now reports all uses of missing files, rather than just the first. 2009-04-12 15:14:19 -04:00
Tom Rothamel 40bad327fe renpy.full_restart now takes a target parameter, which is a screen on
the main menu to target.
2009-04-12 14:48:26 -04:00
Tom Rothamel f5653d3c4d Releasing 6.9.1c. 2009-04-11 14:16:14 -04:00
Tom Rothamel 4026d7818b Provide a basic mechanism for invoking the main menu with a particular screen. 2009-04-11 14:04:54 -04:00
Tom Rothamel a0fda2f058 Do not offer an editor if none exists.
Modified setup.py to check dependencies. It can now be used to build
on a stock ubuntu system, if all dependencies are in place.
2009-04-11 13:47:35 -04:00
Tom Rothamel 93546e2d5c Allow the movie channel to play back while muted. 2009-04-11 01:41:29 -04:00
Tom Rothamel 85a562713a Fix memory leak in the redraw queue. 2009-04-11 00:47:51 -04:00
Tom Rothamel 4e9beb1a5d Minor tweaks to the includes of ffdecode.c 2009-04-10 11:01:12 -04:00
Tom Rothamel 522333e0f5 Update help file to include a link to renpy/LICENSE.txt. 2009-04-10 10:15:06 -04:00
Tom Rothamel b4c4d0264c Make scale correct and higher quality. 2009-04-10 02:40:15 -04:00
Tom Rothamel 21c3187fa3 Fix help on an imagemap menu. 2009-04-10 00:03:42 -04:00
Tom Rothamel b377cfcdef Only play activate and hover sounds if defined. 2009-04-09 22:52:09 -04:00
Tom Rothamel 5d384e531d Drop log level in ffdecode.
Bump version to 6.9.1b.
2009-04-09 18:41:25 -04:00
Tom Rothamel 2b00c64973 More accurate durations on streams. 2009-04-09 14:44:48 -04:00
Tom Rothamel 7c777dea22 Scaling is now automatically enabled if the window won't fit on the screen. 2009-04-08 00:41:10 -04:00
Tom Rothamel 9d0c77917d Remove debugging code in nvl mode. 2009-04-07 11:59:32 -04:00
Tom Rothamel 6d40ced435 Updated renpy.sh to work on the Mac again. 2009-04-07 02:13:36 -04:00
Tom Rothamel 0675ee7f79 Fix clipping of BMFonts. 2009-04-06 23:43:38 -04:00
36 changed files with 942 additions and 411 deletions
+12
View File
@@ -62,6 +62,10 @@ There is a new config.windows_icon variable, that lets one set the
window icon for Windows separately from Mac OS X and Linux.
Ren'Py now automatically scales itself down when it detects that the
game window is too large for the screen.
The define.move_transitions function can now pass keyword arguments to
the moves it creates. The most useful thing with this is to pass
subpixel=True, in order to create subpixel move transitions.
@@ -93,6 +97,14 @@ Added more verbose diagnostics when illegal statements are run in the
init phase.
Added _rollback, which controls if rollback is enabled.
Added a target parameter to renpy.full_restart, which allows the main
menu screen to be selected after a restart.
Fixed a bug that caused layout.imagemap_main_menu to call a label even
though there was a button with the same name.
+1 -1
View File
@@ -35,7 +35,7 @@ launchers may contain code taken from the following projects:
* SDL_ttf (LGPL)
* SDL_mixer (LGPL)
* Freetype (LGPL)
* ffmpeg (LGPL)
* FFmpeg (LGPL)
* jpeg (JPEG License)
* libpng (PNG license)
* zlib (Zlib License)
+11 -11
View File
@@ -607,7 +607,7 @@ label _return:
if renpy.context().main_menu:
$ renpy.transition(config.game_main_transition)
jump _main_menu
jump _main_menu_screen
$ renpy.transition(config.exit_transition)
@@ -682,12 +682,6 @@ label _start:
$ renpy.block_rollback()
python hide:
for i in range(0, 7):
# renpy.music.stop(channel=i)
# renpy.sound.stop(channel=i)
pass
if config.main_menu_music:
$ renpy.music.play(config.main_menu_music, if_changed=True)
else:
@@ -703,15 +697,19 @@ label _start:
jump expression _restart[1]
label _invoke_main_menu:
$ renpy.call_in_new_context("_enter_main_menu")
if _restart:
$ renpy.call_in_new_context(_restart[2])
else:
$ renpy.call_in_new_context("_main_menu")
# If the main menu returns, then start the game.
jump start
# At this point, we've been switched into a new context. So we
# initialize it.
label _enter_main_menu:
label _main_menu(_main_menu_screen="_main_menu_screen"):
call _enter_menu from _call__enter_menu_1
@@ -721,9 +719,11 @@ label _enter_main_menu:
renpy.context().main_menu = True
store.main_menu = True
jump expression _main_menu_screen
# This is called to show the main menu to the user.
label _main_menu:
label _main_menu_screen:
# Let the user completely override the main menu. (But please note
# it still lives in the menu context, rather than the game context.)
+1 -1
View File
@@ -18,7 +18,7 @@ init -1130 python hide:
for i in xrange(0, 8):
renpy.music.register_channel(i)
renpy.music.register_channel("movie", "music", False)
renpy.music.register_channel("movie", "music", False, stop_on_mute=False)
# Set up default names for some of the channels.
renpy.music.alias_channel(0, "sound")
-4
View File
@@ -78,10 +78,6 @@ init -1100 python:
return s
def nvl_show_core():
print "NVL Show"
import inspect
print inspect.stack()
if renpy.in_rollback():
nvl_window = __s(style.nvl_window)['rollback']
+2 -1
View File
@@ -49,6 +49,7 @@ label main_menu_screen:
else:
ui.jumpsoutofcontext(rv)()
jump main_menu_screen
+2
View File
@@ -49,6 +49,8 @@ label start:
e "We look forward to seeing what you can make with this! Good luck!"
window hide
# Returning from the top level quits the game.
return
+1
View File
@@ -228,6 +228,7 @@ def main():
print "Did you remember to rebuild the exe after the last change?"
print "Did you run me with renpython -OO?"
print "Was ming using the right crt?"
print "Did you update renpy.py and launcher/script_version.rpy?"
if __name__ == "__main__":
main()
+5 -1
View File
@@ -29,9 +29,10 @@ 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>
<h2><span class="mw-headline">Basic Help</span></h2>
<p>To advance through the game, <tt>left-click</tt> or press the <tt>space</tt> or <tt>enter</tt> keys. When at a menu, <tt>left-click</tt> to make a choice, or use the arrow keys to select a choice and <tt>enter</tt> to activate it.</p>
<p><a name="Game_Menu" id="Game_Menu"></a></p>
<h3><span class="mw-headline">Game Menu</span></h3>
@@ -105,5 +106,8 @@ margin-left: -2.5em;
<dt>Alt-F4, Command-Q</dt>
<dd>Quits the game.</dd>
</dl>
<p><a name="Legal_Notice" id="Legal_Notice"></a></p>
<h2><span class="mw-headline">Legal Notice</span></h2>
<p>This game uses source code from a number of open source projects. For a list, and a location where the source code can be downloaded from, please view the <a href="./renpy/LICENSE.txt">LICENSE.txt</a> file in the renpy directory.</p>
</body>
</html>
+10 -7
View File
@@ -10,14 +10,17 @@ init:
if not config.editor:
editor = os.path.normpath(config.renpy_base + "/jedit/jedit.jar")
editor = renpy.shell_escape(editor)
if sys.platform == 'win32':
config.editor = 'javaw.exe -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
config.editor_transient = 'javaw.exe -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
else:
config.editor = 'java -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
config.editor_transient = 'java -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
if os.path.exists(editor):
editor = renpy.shell_escape(editor)
if sys.platform == 'win32':
config.editor = 'javaw.exe -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
config.editor_transient = 'javaw.exe -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
else:
config.editor = 'java -jar "' + editor + '" -reuseview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
config.editor_transient = 'java -jar "' + editor + '" -newplainview "%(filename)s" +line:%(line)d "%(otherfiles)s"'
if config.editor:
os.environ['RENPY_EDITOR'] = config.editor
+1 -1
View File
@@ -1,3 +1,3 @@
init -999:
$ config.script_version = (6, 9, 0)
$ config.script_version = (6, 9, 1)
+25 -25
View File
@@ -1000,18 +1000,18 @@ void transform32_std(PyObject *pysrc, PyObject *pydst,
unsigned int amul = (int) (a * 256);
lsx = corner_x * 256;
lsy = corner_y * 256;
lsx = corner_x * 65536;
lsy = corner_y * 65536;
xdx *= 256;
ydx *= 256;
xdy *= 256;
ydy *= 256;
xdx *= 65536;
ydx *= 65536;
xdy *= 65536;
ydy *= 65536;
// Scaled subtracted srcw and srch.
float fsw = (srcw - 2) * 256;
float fsh = (srch - 2) * 256;
float fsw = (srcw - 1) * 65536 - 1;
float fsh = (srch - 1) * 65536 - 1;
for (y = 0; y < dsth; y++, lsx += xdy, lsy += ydy) {
@@ -1058,7 +1058,7 @@ void transform32_std(PyObject *pysrc, PyObject *pydst,
sx = lsx + minx * xdx;
sy = lsy + minx * ydx;
int sxi = (int) sx;
int syi = (int) sy;
int xdxi = (int) xdx;
@@ -1066,13 +1066,13 @@ void transform32_std(PyObject *pysrc, PyObject *pydst,
while (d <= dend) {
int px, py;
px = sxi >> 8;
py = syi >> 8;
px = sxi >> 16;
py = syi >> 16;
unsigned char *sp = srcpixels + py * srcpitch + px * 4;
int yfrac = syi & 0xff; // ((short) sy) & 0xff;
int xfrac = sxi & 0xff; // ((short) sx) & 0xff;
int yfrac = (syi >> 8) & 0xff; // ((short) sy) & 0xff;
int xfrac = (sxi >> 8) & 0xff; // ((short) sx) & 0xff;
unsigned int pal = *(unsigned int *) sp;
unsigned int pbl = *(unsigned int *) (sp + 4);
@@ -1164,17 +1164,17 @@ int transform32_mmx(PyObject *pysrc, PyObject *pydst,
// Compute the coloring multiplier.
unsigned int amul = (unsigned int) (a * 256);
lsx = corner_x * 256;
lsy = corner_y * 256;
lsx = corner_x * 65536;
lsy = corner_y * 65536;
xdx *= 256;
ydx *= 256;
xdy *= 256;
ydy *= 256;
xdx *= 65536;
ydx *= 65536;
xdy *= 65536;
ydy *= 65536;
// Scaled subtracted srcw and srch.
float fsw = (srcw - 2) * 256;
float fsh = (srch - 2) * 256;
float fsw = (srcw - 1) * 65536 - 1;
float fsh = (srch - 1) * 65536 - 1;
for (y = 0; y < dsth; y++, lsx += xdy, lsy += ydy) {
@@ -1235,13 +1235,13 @@ int transform32_mmx(PyObject *pysrc, PyObject *pydst,
while (d <= dend) {
px = sxi >> 8;
py = syi >> 8;
px = sxi >> 16;
py = syi >> 16;
unsigned char *sp = srcpixels + py * srcpitch + px * 4;
unsigned int yfrac = syi & 0xff; // ((short) sy) & 0xff;
unsigned int xfrac = sxi & 0xff; // ((short) sx) & 0xff;
unsigned int yfrac = (syi >> 8) & 0xff; // ((short) sy) & 0xff;
unsigned int xfrac = (sxi >> 8) & 0xff; // ((short) sx) & 0xff;
// Put xfrac in mm5, yfrac in m6
pxor_r2r(mm5, mm5);
+117 -14
View File
@@ -22,11 +22,12 @@
#include <pygame/pygame.h>
#include <math.h>
#include <limits.h>
#include "libavutil/avstring.h"
#include "libavformat/avformat.h"
#include <libavutil/avstring.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
// #include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/audioconvert.h"
#include <libswscale/swscale.h>
// #include "libavcodec/audioconvert.h"
// #include "libavcodec/opt.h"
// #include "cmdutils.h"
@@ -143,6 +144,7 @@ typedef struct VideoState {
// AVAudioConvert *reformat_ctx;
ReSampleContext *reformat_ctx;
int resample_frac;
int show_audio; /* if true, display audio samples */
int16_t sample_array[SAMPLE_ARRAY_SIZE];
@@ -196,6 +198,12 @@ typedef struct VideoState {
// Do we need to have a picture allocated?
int needs_alloc;
// The audio duration.
unsigned int audio_duration;
// The amount of audio we've played, in samples.
unsigned int audio_played;
} VideoState;
@@ -1483,14 +1491,13 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
continue;
if (!is->reformat_ctx &&
(1 || dec->channels != 2
|| dec->sample_rate != audio_sample_rate
|| dec->sample_fmt != SAMPLE_FMT_S16)) {
(dec->channels != 2 || dec->sample_fmt != SAMPLE_FMT_S16)) {
is->reformat_ctx = av_audio_resample_init(
2,
dec->channels,
audio_sample_rate,
// audio_sample_rate,
dec->sample_rate,
dec->sample_rate,
SAMPLE_FMT_S16,
dec->sample_fmt,
@@ -1506,17 +1513,83 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
if (is->reformat_ctx) {
int len = data_size / (av_get_bits_per_sample_format(dec->sample_fmt) / 8);
len /= dec->channels;
data_size = audio_resample(is->reformat_ctx, (short *) is->audio_buf2, (short *) is->audio_buf1, len);
data_size *= 4; // 2 channels of 16-bit samples
len = audio_resample(is->reformat_ctx, (short *) is->audio_buf2, (short *) is->audio_buf1, len);
data_size = len * 4;
is->audio_buf = is->audio_buf2;
} else {
is->audio_buf = is->audio_buf1;
}
if (dec->sample_rate != audio_sample_rate) {
short *in;
short *out;
int outpos;
int in_per_out;
int inpos;
int len = data_size / 4;
if (is->audio_buf == is->audio_buf1) {
in = (short *) is->audio_buf1;
out = (short *) is->audio_buf2;
} else {
in = (short *) is->audio_buf2;
out = (short *) is->audio_buf1;
}
// Pad the buffer a bit. We pad with the difference
// between the last sample and the one before it,
// which seems reasonable.
in[2 * len] = 2 * in[2 * len - 2] - in[2 * len - 4];
in[2 * len + 1] = 2 * in[2 * len - 1] - in[2 * len - 3];
// The number of bytes of input consumed per output
// sample. Scaled by 1 << 14.
in_per_out = (dec->sample_rate << 14) / audio_sample_rate;
len *= (1 << 14);
// The positions in the input. Scaled by 1 << 14.
inpos = is->resample_frac;
// The position in the output. Unscaled.
outpos = 0;
// While we still have samples.
while (inpos < len) {
short a;
short b;
// Compute position and fraction.
int pos = inpos >> 14;
int frac = inpos & ((1 << 14) - 1);
// Interpolate the two channels.
a = in[2 * pos];
b = in[2 * pos + 2];
out[2 * outpos] = a + (((b - a) * frac) >> 14);
a = in[2 * pos + 1];
b = in[2 * pos + 3];
out[2 * outpos + 1] = a + (((b - a) * frac) >> 14);
outpos++;
inpos += in_per_out;
}
// Store the fraction.
is->resample_frac = inpos & ((1 << 14) - 1);
data_size = outpos * 4;
is->audio_buf = (uint8_t *) out;
}
/* if no pts, then compute it */
pts = is->audio_clock;
*pts_ptr = pts;
@@ -1533,6 +1606,22 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
last_clock = is->audio_clock;
}
#endif
// Deal with a reduced duration, like in an ogg file.
if (is->audio_duration) {
int len = data_size / 4;
int maxlen = is->audio_duration - is->audio_played;
if (len > maxlen) {
len = maxlen;
}
is->audio_played += len;
data_size = len * 4;
}
return data_size;
}
@@ -1980,9 +2069,19 @@ static int decode_thread(void *arg)
goto fail;
}
is->started = 1;
// Compute the number of samples we need to play back.
{
long long duration = ((long long) is->ic->duration) * audio_sample_rate;
is->audio_duration = (unsigned int) (duration / AV_TIME_BASE);
if (show_status) {
printf("Duration of '%s' is %d samples.\n", is->filename, is->audio_duration);
}
}
SDL_UnlockMutex(codec_mutex);
codecs_locked = 0;
@@ -2214,8 +2313,12 @@ void ffpy_init(int rate, int status) {
avcodec_register_all();
av_register_all();
av_log_set_level(AV_LOG_ERROR);
if (status) {
av_log_set_level(AV_LOG_INFO);
} else {
av_log_set_level(AV_LOG_ERROR);
}
av_init_packet(&flush_pkt);
flush_pkt.data = (unsigned char *) "FLUSH";
+43 -20
View File
@@ -1,4 +1,3 @@
/*
Copyright 2005-2009 PyTom <pytom@bishoujo.us>
@@ -112,9 +111,6 @@ struct Channel {
/* The queued up sample. */
struct VideoState *queued;
/* A sample that's dying, and needs to be deallocated. */
struct VideoState *dying;
/* The name of the queued up sample. */
PyObject *queued_name;
@@ -173,6 +169,13 @@ struct Channel {
unsigned int vol2_done;
};
struct Dying {
struct VideoState *stream;
struct Dying *next;
};
static struct Dying *dying = NULL;
/*
* The number of channels the system knows about.
*/
@@ -247,8 +250,12 @@ static void start_sample(struct Channel* c, int reset_fade) {
c->fade_off = 0;
c->fade_vol = 0;
c->fade_step_len = ms_to_bytes(c->playing_fadein) / fade_steps;
c->fade_step_len &= ~0x7; // Even sample.
if (fade_steps) {
c->fade_step_len = ms_to_bytes(c->playing_fadein) / fade_steps;
c->fade_step_len &= ~0x7; // Even sample.
} else {
c->fade_step_len = 0;
}
}
c->stop_bytes = -1;
@@ -440,10 +447,15 @@ static void callback(void *userdata, Uint8 *stream, int length) {
if (c->stop_bytes == 0 || bytes == 0) {
int old_tight = c->playing_tight;
struct Dying *d;
post_event(c);
c->dying = c->playing;
d = malloc(sizeof(struct Dying));
d->next = dying;
d->stream = c->playing;
dying = d;
decref(c->playing_name);
c->playing = c->queued;
@@ -488,7 +500,6 @@ static int check_channel(int c) {
channels[i].queued = NULL;
channels[i].playing_name = NULL;
channels[i].queued_name = NULL;
channels[i].dying = NULL;
channels[i].volume = SDL_MIX_MAXVOLUME;
channels[i].paused = 1;
channels[i].event = 0;
@@ -786,14 +797,20 @@ void PSS_fadeout(int channel, int ms) {
return;
}
fade_steps = c->volume;
c->fade_delta = -1;
c->fade_off = 0;
c->fade_vol = c->volume;
c->fade_step_len = ms_to_bytes(ms) / fade_steps;
c->fade_step_len &= ~0x7; // Even sample.
if (fade_steps) {
c->fade_step_len = ms_to_bytes(ms) / fade_steps;
c->fade_step_len &= ~0x7; // Even sample.
} else {
c->fade_step_len = 0;
}
c->stop_bytes = ms_to_bytes(ms);
c->queued_tight = 0;
@@ -1035,7 +1052,7 @@ void PSS_init(int freq, int stereo, int samples, int status) {
audio_spec.callback = callback;
audio_spec.userdata = NULL;
if (SDL_OpenAudio(&audio_spec, NULL)) {
if (SDL_OpenAudio(&audio_spec, &audio_spec)) {
error(SDL_ERROR);
return;
}
@@ -1080,14 +1097,20 @@ void PSS_periodic() {
int i;
for (i = 0; i < num_channels; i++) {
if (channels[i].dying) {
ENTER();
ffpy_stream_close(channels[i].dying);
channels[i].dying = NULL;
EXIT();
}
if (!dying) {
return;
}
ENTER();
while (dying) {
struct Dying *d = dying;
ffpy_stream_close(d->stream);
dying = d->next;
free(d);
}
EXIT();
}
/* This should be called in response to an FF_ALLOC_EVENT, with a pygame
+1 -1
View File
@@ -27,7 +27,7 @@
#include <Python.h>
#include <stdio.h>
#include <string.h>
#include "pygame.h"
#include <pygame/pygame.h>
#include "structmember.h"
#include "renpy_ttf.h"
Regular → Executable
+102 -35
View File
@@ -1,6 +1,4 @@
#!/usr/bin/env python
import distutils.core
import os
import os.path
@@ -12,45 +10,118 @@ try:
except:
pass
# These control the level of optimization versus debugging.
extra_compile_args = [ "-O3", "-funroll-loops" ]
# extra_compile_args = [ "-O0", "-ggdb" ]
# This environment variable should have the full path to the installed
# Ren'Py dependencies.
install = os.environ.get("RENPY_DEPS_INSTALL", "/does/not/exist")
install = os.environ.get("RENPY_DEPS_INSTALL", None)
# Check to see if that's the case.
if not os.path.isdir(install):
print "The Ren'Py dependencies install directory:"
print
print install
print
print "does not exist. Please set RENPY_DEPS_INSTALL to the correct"
print "location of the Ren'Py dependencies install directory, and "
print "re-run this script."
if install is None:
print """
The RENPY_DEPS_INSTALL environment variable has not been set. This
should be set to a double-colon-delimited list of places where the
Ren'Py dependencies can be found. (To use system libraries, this can
be set to a system directory, like /usr.)
"""
sys.exit(-1)
ffmpeg = os.environ.get("FFMPEG_BUILD_PATH", "/does/not/exist")
install = install.split("::")
if not os.path.isdir(install):
print "The FFMPEG build path:"
print
print ffmpeg
print
print "does not exist. Please set FFMPEG_BUILD_PATH to the correct"
print "location and re-run this script."
sys.exit(-1)
include_dirs = [ ]
library_dirs = [ ]
def add_include(prefix, file):
"""
Search for prefix/file underneath <i> and <i>/include, for each of the
directories <i> in install. When found, puts the directory it was found
in into include_dirs.
"""
checked = [ ]
for i in install:
dir = os.path.join(i, prefix)
fn = os.path.join(dir, file)
fn = os.path.normpath(fn)
checked.append(fn)
if os.path.exists(fn):
break
dir = os.path.join(i, "include", prefix)
fn = os.path.join(dir, file)
fn = os.path.normpath(fn)
checked.append(fn)
if os.path.exists(fn):
break
else:
print "Could not find include %s." % file
print "The paths searched were:"
for i in checked:
print "-", i
sys.exit(-1)
dir = os.path.normpath(dir)
print "Found %s in %s." % (file, dir)
if dir not in include_dirs:
include_dirs.append(dir)
def add_library(name):
"""
This looks for a library named name in the <i> and <i>/lib, for all
<i> in install. When found, it adds it to library_dirs.
"""
checked = [ ]
# Default compile arguements for everybody.
include_dirs = [ install + "/include",
install + "/include/SDL",
install + "/include/freetype2",
install + "/include/pygame",
ffmpeg]
for i in install:
for d in ('', 'lib'):
for suffix in (".so", ".dylib", ".a"):
library_dirs = [ install + "/lib" ]
dir = os.path.join(i, d)
fn = os.path.join(dir, name + suffix)
checked.append(fn)
if os.path.exists(fn):
print "Found %s." % fn
if dir not in library_dirs:
library_dirs.append(dir)
return
print "Couldn't find library %s." % name
print "The paths searched were:"
for i in checked:
print "-", i
sys.exit(-1)
add_include("", "zlib.h")
add_include("", "png.h")
add_include("SDL", "SDL.h")
add_include("", "ft2build.h")
add_include("freetype2", "freetype/freetype.h")
add_include("", "libavutil/avstring.h")
add_include("", "libavformat/avformat.h")
add_include("", "libavcodec/avcodec.h")
add_include("", "libswscale/swscale.h")
add_library("libSDL")
add_library("libz")
add_library("libpng")
add_library("libavformat")
add_library("libavcodec")
add_library("libavutil")
add_library("libfreetype")
# Fast math breaks on windows. :-(
extra_compile_args = [ "-O3", "-funroll-loops" ] # , "-ffast-math" ]
# extra_compile_args = [ "-O0", "-ggdb" ]
extra_link_args = [ ]
@@ -67,10 +138,6 @@ if platform.win32_ver()[0]:
extra_compile_args.append("-fno-strict-aliasing")
winmixer = True
# Detect mac.
if platform.mac_ver()[0]:
nativemidi_libs = [ 'SDL' ]
# Detect OSS.
try:
import ossaudiodev
+5 -1
View File
@@ -124,7 +124,11 @@ def get_pos(channel):
return PSS_get_pos(channel)
def set_volume(channel, volume):
PSS_set_volume(channel, 10 ** volume / 10 )
if volume == 0:
PSS_set_volume(channel, 0)
else:
PSS_set_volume(channel, 10 ** volume / 10 )
check_error()
def set_pan(channel, pan, delay):
+1 -1
View File
@@ -1 +1 @@
dist/MSVCR71.dll
dist/msvcr71.dll
+11 -4
View File
@@ -3,11 +3,18 @@
# We assume Darwin means Mac OS X. Sorry, Darwin guys.
if [ "x`uname -s`" = "xDarwin" ]; then
dir=`dirname "$0"`
dir=`cd $dir; pwd`
dir=`cd "$dir"; pwd`
base=`basename "$0"`
export RENPY_LAUNCHER_DIR="`pwd`"
exec "${0%.sh}.app/Contents/MacOS/Ren'Py Launcher" "$dir/${base%.sh}.py" "$@"
export RENPY_LAUNCHER_DIR="$dir"
if [ -e "$dir/${base%.sh}.app/Contents/MacOS/${base%.sh}" ] ; then
launcher="$dir/${base%.sh}.app/Contents/MacOS/${base%.sh}"
else
launcher="$dir/${base%.sh}.app/Contents/MacOS/Ren'Py Launcher"
fi
exec "$launcher" "${0%.sh}.py" "$@"
fi
exec "`dirname \"$0\"`/lib/python" "-O" "${0%.sh}.py" "$@"
exec "`dirname \"$0\"`/lib/python" "-OO" "${0%.sh}.py" "$@"
+1 -1
View File
@@ -27,7 +27,7 @@
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
# 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.9.1a"
version = "Ren'Py 6.9.1f"
script_version = 5003000
savegame_suffix = "-LT1.save"
+39 -30
View File
@@ -181,7 +181,7 @@ class Channel(object):
This stores information about the currently-playing music.
"""
def __init__(self, name, default_loop):
def __init__(self, name, default_loop, stop_on_mute, tight):
# The name assigned to this channel. This is used to look up
# information about the channel in the MusicContext object.
@@ -235,6 +235,12 @@ class Channel(object):
# The time the secondary volume of this channel was last set.
self.secondary_volume_time = None
# Should we stop playing on mute?
self.stop_on_mute = stop_on_mute
# Is this channel tight?
self.tight = tight
if default_loop is None:
# By default, should we loop the music?
self.default_loop = True
@@ -287,10 +293,9 @@ class Channel(object):
# This should be set from something that checks to see if our
# mixer is muted.
force_stop = self.context.force_stop or renpy.game.preferences.mute[self.mixer]
force_stop = self.context.force_stop or (renpy.game.preferences.mute[self.mixer] and self.stop_on_mute)
if self.playing and force_stop:
pss.stop(self.number)
self.playing = False
self.wait_stop = False
@@ -335,14 +340,18 @@ class Channel(object):
break
# Otherwise, we might be able to enqueue something.
topq = self.queue[0]
topq = self.queue.pop(0)
# At this point, we've decided to try to play
# top. So let's see how far we can get.
# Update the queue
self.queue = self.queue[1:]
# Blacklist of old file formats we used to support, but we now
# ignore.
lfn = topq.filename.lower()
for i in (".mod", ".xm", ".mid", ".midi"):
if lfn.endswith(i):
topq = None
if not topq:
continue
try:
topf = load(topq.filename)
@@ -429,7 +438,7 @@ class Channel(object):
pss.fadeout(self.number, int(secs * 1000))
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=False):
def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None):
for filename in filenames:
renpy.game.persistent._seen_audio[filename] = True
@@ -437,6 +446,9 @@ class Channel(object):
if not pcm_ok:
return
if tight is None:
tight = self.tight
for filename in filenames:
qe = QueueEntry(filename, int(fadein * 1000), tight)
self.queue.append(qe)
@@ -494,11 +506,11 @@ all_channels = [ ]
channels = { }
def register_channel(name, mixer=None, loop=None):
def register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False):
if not renpy.game.init_phase:
raise Exception("Can't register channel outside of init phase.")
c = Channel(name, loop)
c = Channel(name, loop, stop_on_mute, tight)
c.mixer = mixer
all_channels.append(c)
channels[name] = c
@@ -634,7 +646,7 @@ def periodic():
max_volume = -1.0
volumes = renpy.game.preferences.volumes
if mix_ok:
anything_playing = False
@@ -646,28 +658,26 @@ def periodic():
if vol != 0:
anything_playing = True
if not anything_playing:
disable_mixer()
return
enable_mixer()
if max_volume == -1.0:
return
if max_volume == 0.0:
return
if not anything_playing:
disable_mixer()
pcm_volume = -1.0
else:
enable_mixer()
if max_volume != pcm_volume:
mix.set_wave(max_volume)
pcm_volume = max_volume
if max_volume != pcm_volume:
mix.set_wave(max_volume)
pcm_volume = max_volume
for c in all_channels:
vol = c.chan_volume * volumes[c.mixer]
vol /= max_volume
if c.actual_volume != vol:
pss.set_volume(c.number, vol)
c.actual_volume = vol
@@ -676,9 +686,6 @@ def periodic():
for c in all_channels:
if not c.playing:
continue
vol = c.chan_volume * volumes[c.mixer]
if vol != c.actual_volume:
@@ -748,9 +755,11 @@ def event(ev):
if ev.type == ALLOC_EVENT:
if renpy.display.video.fullscreen or not renpy.display.video.surface:
pss.alloc_event(pygame.display.get_surface())
surf = pygame.display.get_surface()
else:
pss.alloc_event(renpy.display.video.surface)
surf = renpy.display.video.surface
pss.alloc_event(renpy.display.scale.real(surf))
return True
+2 -2
View File
@@ -35,7 +35,7 @@ from renpy.audio.audio import get_channel, get_serial
# Part of the public api:
from renpy.audio.audio import register_channel, alias_channel
def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=False, fadein=0, tight=False, if_changed=False):
def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=False, fadein=0, tight=None, if_changed=False):
"""
This stops the music currently playing on the numbered channel, dequeues
any queued music, and begins playing the specified file or files. If loop
@@ -108,7 +108,7 @@ def play(filenames, channel="music", loop=None, fadeout=None, synchro_start=Fals
raise
def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tight=False):
def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tight=None):
"""
This queues the given filenames on the specified channel. If
clear_queue is True, then the queue is cleared, making these files
+1 -1
View File
@@ -214,7 +214,7 @@ def display_say(show_function,
# If we're in fast skipping mode, don't bother with say
# statements at all.
if renpy.config.skipping == "fast":
if interact and renpy.config.skipping == "fast":
# Clears out transients.
renpy.exports.with_statement(None)
+21 -19
View File
@@ -276,22 +276,6 @@ class SayBehavior(renpy.display.layout.Null):
def event(self, ev, x, y, st):
skip_delay = renpy.config.skip_delay / 1000.0
if renpy.config.allow_skipping and renpy.config.skipping and \
st >= skip_delay:
if renpy.game.preferences.skip_unseen:
return True
elif renpy.config.skipping == "fast":
return True
elif renpy.game.context().seen_current(True):
return True
if renpy.config.allow_skipping and renpy.config.skipping and \
st < skip_delay:
renpy.game.interface.timeout(skip_delay - st)
if self.afm_length and renpy.game.preferences.afm_time and renpy.game.preferences.afm_enable:
afm_delay = ( 1.0 * ( renpy.config.afm_bonus + self.afm_length ) / renpy.config.afm_characters ) * renpy.game.preferences.afm_time
@@ -311,7 +295,7 @@ class SayBehavior(renpy.display.layout.Null):
renpy.game.interface.timeout(afm_delay - st)
for dismiss in self.dismiss:
if map_event(ev, dismiss) and self.is_focused():
if renpy.config.skipping:
@@ -325,6 +309,23 @@ class SayBehavior(renpy.display.layout.Null):
return True
skip_delay = renpy.config.skip_delay / 1000.0
if renpy.config.allow_skipping and renpy.config.skipping and \
st >= skip_delay:
if renpy.game.preferences.skip_unseen:
return True
elif renpy.config.skipping == "fast":
return True
elif renpy.game.context().seen_current(True):
return True
if renpy.config.allow_skipping and renpy.config.skipping and \
st < skip_delay:
renpy.game.interface.timeout(skip_delay - st)
return None
@@ -423,8 +424,9 @@ class Button(renpy.display.layout.Window):
self.activated = True
self.style.set_prefix(self.role + 'activate_')
renpy.audio.sound.play(self.style.sound)
if self.style.sound:
renpy.audio.music.play(self.style.sound, channel="sound")
rv = self.clicked()
+5 -4
View File
@@ -119,7 +119,8 @@ class Displayable(renpy.object.Object):
self.set_style_prefix(self.role + "hover_")
if not default and not self.activated:
renpy.audio.sound.play(self.style.sound)
if self.style.sound:
renpy.audio.music.play(self.style.sound, channel="sound")
def unfocus(self):
"""
@@ -671,11 +672,11 @@ class Display(object):
except:
pass
renpy.display.scale.init()
pygame.display.init()
pygame.font.init()
renpy.display.scale.init()
renpy.audio.audio.init()
renpy.display.joystick.init()
@@ -1023,7 +1024,7 @@ class Display(object):
contents of the window.
"""
surf = renpy.display.module.scale(self.window, scale)
surf = renpy.display.scale.smoothscale(self.window, scale)
sio = cStringIO.StringIO()
renpy.display.module.save_png(surf, sio, 0)
+9 -8
View File
@@ -58,10 +58,12 @@ class ImageFont(object):
# chars - A map from a character to the surface containing that character.
def size(self, text):
w = 0
if not text:
return (0, self.height)
xoff, _ = self.offsets[text[0]]
w = -xoff
for a, b in zip(text, text[1:]):
try:
@@ -74,18 +76,17 @@ class ImageFont(object):
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
return pygame.Surface((0, self.height), 0,
renpy.game.interface.display.sample_surface)
# Compensate for the offset of the first character, when determining
# the initial position.
xoff, yoff = self.offsets[text[0]]
xoff, _ = self.offsets[text[0]]
x = -xoff
y = 0
surf = pygame.Surface(self.size(text), 0,
renpy.game.interface.display.sample_surface)
for a, b in zip(text, text[1:]):
xoff, yoff = self.offsets[a]
surf.blit(self.chars[a], (x + xoff, y + yoff))
+39 -21
View File
@@ -687,7 +687,7 @@ class FrameImage(ImageBase):
tilew, tileh = srcsize
dstw, dsth = dstsize
surf2 = pygame.Surface(dstsize, 0, surf)
surf2 = renpy.display.scale.PygameSurface(dstsize, 0, surf)
for y in range(0, dsth, tileh):
for x in range(0, dstw, tilew):
@@ -707,6 +707,7 @@ class FrameImage(ImageBase):
# Blit.
dest.blit(surf, (dx0, dy0))
# Top row.
draw(0, xb, 0, yb)
draw(xb, -xb, 0, yb)
@@ -721,7 +722,7 @@ class FrameImage(ImageBase):
draw(0, xb, -yb, 0)
draw(xb, -xb, -yb, 0)
draw(-xb, 0, -yb, 0)
# And, finish up.
return rv
@@ -770,15 +771,20 @@ class Scale(ImageBase):
def load(self):
child = cache.get(self.image)
if self.bilinear:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.smoothscale(cache.get(self.image), (self.width, self.height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = renpy.display.scale.smoothscale(child, (self.width, self.height))
finally:
renpy.display.render.blit_lock.release()
else:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(cache.get(self.image), (self.width, self.height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(child, (self.width, self.height))
finally:
renpy.display.render.blit_lock.release()
return rv
@@ -813,14 +819,18 @@ class FactorScale(ImageBase):
height = int(height * self.height)
if self.bilinear:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.smoothscale(surf, (width, height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = renpy.display.scale.smoothscale(surf, (width, height))
finally:
renpy.display.render.blit_lock.release()
else:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(surf, (width, height))
renpy.display.render.blit_lock.release()
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.scale(surf, (width, height))
finally:
renpy.display.render.blit_lock.release()
return rv
@@ -856,9 +866,13 @@ class Flip(ImageBase):
def load(self):
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.flip(cache.get(self.image), self.horizontal, self.vertical)
renpy.display.render.blit_lock.release()
child = cache.get(self.image)
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.flip(child, self.horizontal, self.vertical)
finally:
renpy.display.render.blit_lock.release()
return rv
@@ -893,9 +907,13 @@ class Rotozoom(ImageBase):
def load(self):
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.rotozoom(cache.get(self.image), self.angle, self.zoom)
renpy.display.render.blit_lock.release()
child = cache.get(self.image)
try:
renpy.display.render.blit_lock.acquire()
rv = pygame.transform.rotozoom(child, self.angle, self.zoom)
finally:
renpy.display.render.blit_lock.release()
return rv
+1
View File
@@ -383,6 +383,7 @@ else:
if version >= 6009000:
def subpixel(src, dst, x, y):
shift = renpy.game.interface.display.sample_surface.get_shifts()[3]
_renpy.subpixel(src, dst, x, y, shift)
+121 -81
View File
@@ -27,6 +27,7 @@ import math
import renpy
# We grab the blit lock each time it is necessary to blit
# something. This allows call to the pygame.transform functions to
# disable blitting, should it prove necessary.
@@ -177,30 +178,43 @@ def process_redraws():
need to redraw the screen now, false otherwise.
"""
global redraw_queue
redraw_queue.sort()
now = renpy.display.core.get_time()
rv = invalidated
new_redraw_queue = [ ]
seen = set()
while redraw_queue:
when, d = redraw_queue[0]
for t in redraw_queue:
when, d = t
if when > now:
break
if d in seen:
continue
redraw_queue.pop(0)
seen.add(d)
# Remove this displayable and all its parents from the
# render cache. But don't kill them yet, as that will kill the
# children that we want to reuse.
if d not in render_cache:
continue
if d in render_cache:
if when <= now:
# Remove this displayable and all its parents from the
# render cache. But don't kill them yet, as that will kill the
# children that we want to reuse.
for v in render_cache[d].values():
v.kill_cache()
rv = True
else:
new_redraw_queue.append(t)
redraw_queue = new_redraw_queue
return rv
@@ -222,7 +236,7 @@ def redraw(d, when):
if not renpy.game.interface:
return
redraw_queue.append((when + renpy.game.interface.frame_time, d))
@@ -475,10 +489,12 @@ def draw(dest, clip, what, xo, yo, screen):
if clip:
w, h = what.get_size()
dest.blits.append((xo, yo, xo + w, yo + h, clip, what, None))
else:
blit_lock.acquire()
dest.blit(what, (xo, yo))
blit_lock.release()
else:
try:
blit_lock.acquire()
dest.blit(what, (xo, yo))
finally:
blit_lock.release()
# Subpixel blit.
else:
@@ -611,10 +627,10 @@ def draw_transformed(dest, clip, what, xo, yo, alpha, forward, reverse):
else:
dw, dh = dest.get_size()
x0, y0 = 0, 0
x1, y1 = reverse.transform(sw, 0)
x0, y0 = 0.0, 0.0
x1, y1 = reverse.transform(sw, 0.0)
x2, y2 = reverse.transform(sw, sh)
x3, y3 = reverse.transform(0, sh)
x3, y3 = reverse.transform(0.0, sh)
minx = math.floor(min(x0, x1, x2, x3) + xo)
maxx = math.ceil(max(x0, x1, x2, x3) + xo)
@@ -631,6 +647,9 @@ def draw_transformed(dest, clip, what, xo, yo, alpha, forward, reverse):
if maxy > dh:
maxy = dh
if minx > dw or miny > dh:
return
cx, cy = forward.transform(minx - xo, miny - yo)
if clip:
@@ -1259,7 +1278,7 @@ class Render(object):
vc = [ ]
rv = True
else:
if not source.get_masks()[3]:
if not child.get_masks()[3]:
vc = [ ]
rv = True
@@ -1330,82 +1349,103 @@ class Canvas(object):
self.surf = surf
def rect(self, color, rect, width=0):
blit_lock.acquire()
pygame.draw.rect(self.surf,
renpy.easy.color(color),
rect,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.rect(self.surf,
renpy.easy.color(color),
rect,
width)
finally:
blit_lock.release()
def polygon(self, color, pointlist, width=0):
blit_lock.acquire()
pygame.draw.polygon(self.surf,
renpy.easy.color(color),
pointlist,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.polygon(self.surf,
renpy.easy.color(color),
pointlist,
width)
finally:
blit_lock.release()
def circle(self, color, pos, radius, width=0):
blit_lock.acquire()
pygame.draw.circle(self.surf,
renpy.easy.color(color),
pos,
radius,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.circle(self.surf,
renpy.easy.color(color),
pos,
radius,
width)
finally:
blit_lock.release()
def ellipse(self, color, rect, width=0):
blit_lock.acquire()
pygame.draw.ellipse(self.surf,
renpy.easy.color(color),
rect,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.ellipse(self.surf,
renpy.easy.color(color),
rect,
width)
finally:
blit_lock.release()
def arc(self, color, rect, start_angle, stop_angle, width=1):
blit_lock.acquire()
pygame.draw.arc(self.surf,
renpy.easy.color(color),
rect,
start_angle,
stop_angle,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.arc(self.surf,
renpy.easy.color(color),
rect,
start_angle,
stop_angle,
width)
finally:
blit_lock.release()
def line(self, color, start_pos, end_pos, width=1):
blit_lock.acquire()
pygame.draw.line(self.surf,
renpy.easy.color(color),
start_pos,
end_pos,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.line(self.surf,
renpy.easy.color(color),
start_pos,
end_pos,
width)
finally:
blit_lock.release()
def lines(self, color, closed, pointlist, width=1):
blit_lock.acquire()
pygame.draw.lines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
width)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.lines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
width)
finally:
blit_lock.release()
def aaline(self, color, startpos, endpos, blend=1):
blit_lock.acquire()
pygame.draw.aaline(self.surf,
renpy.easy.color(color),
startpos,
endpos,
blend)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.aaline(self.surf,
renpy.easy.color(color),
startpos,
endpos,
blend)
finally:
blit_lock.release()
def aalines(self, color, closed, pointlist, blend=1):
blit_lock.acquire()
pygame.draw.aalines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
blend)
blit_lock.release()
try:
blit_lock.acquire()
pygame.draw.aalines(self.surf,
renpy.easy.color(color),
closed,
pointlist,
blend)
finally:
blit_lock.release()
+298 -90
View File
@@ -39,80 +39,180 @@ try:
import _renpy
except ImportError:
_renpy = None
# The factor we're scaling by.
factor = 1.0
if ('RENPY_SCALE_FACTOR' in os.environ) or ('RENPY_SCALE_WIDTH' in os.environ):
enable_scaling = True
else:
enable_scaling = False
# Should we scale fast or scale good-looking?
scale_fast = False
if not enable_scaling:
# The public api other modules use.
##############################################################################
# The scaling API that's used if we don't enable scaling.
# Gets the real pygame surface.
def real(s):
return s
def init():
return
# Scales the number, n.
def scale(n):
return n
def real_bilinear(src, size):
rv = pygame.Surface(size, 0, src)
renpy.display.module.bilinear_scale(src, rv)
return rv
# Does pygame.transform.scale.
def real_transform_scale(surf, size):
global real_transform_scale
real_transform_scale = pygame.transform.scale
return real_transform_scale(surf, size)
# Loads an image, without scaling it.
def image_load_unscaled(f, hint, convert=True):
rv = pygame.image.load(f, hint)
if convert:
rv = rv.convert_alpha()
return rv
# Scales down a surface.
def surface_scale(full):
return full
# Saves an image without rescaling.
def image_save_unscaled(surf, dest):
pygame.image.save(surf, dest)
if _renpy:
real_renpy_pixellate = _renpy.pixellate
real_renpy_transform = _renpy.transform
def real_smoothscale(src, size, dest=None):
"""
This scales src up or down to size. This uses both the pixellate
and the bilinear operations to handle the scaling.
"""
width, height = size
srcwidth, srcheight = src.get_size()
iwidth, iheight = srcwidth, srcheight
if dest is None:
dest = PygameSurface(size, src.get_flags(), src)
if width == 0 or height == 0:
return dest
# Gets the real pygame surface.
def real(s):
return s
xshrink = 1
yshrink = 1
# Scales the number, n.
def scale(n):
return n
while iwidth >= width * 2:
xshrink *= 2
iwidth /= 2
def real_bilinear(src, size):
rv = pygame.Surface(size, 0, src)
renpy.display.module.bilinear_scale(src, rv)
return rv
# Does pygame.transform.scale.
def real_transform_scale(surf, size):
global real_transform_scale
real_transform_scale = pygame.transform.scale
while iheight >= height * 2:
yshrink *= 2
iheight /= 2
return real_transform_scale(surf, size)
if iwidth != srcwidth or iheight != srcheight:
inter = PygameSurface((iwidth, iheight), src.get_flags(), src)
real_renpy_pixellate(src, inter, xshrink, yshrink, 1, 1)
src = inter
# Loads an image, without scaling it.
def image_load_unscaled(f, hint, convert=True):
rv = pygame.image.load(f, hint)
real_renpy_transform(src, dest,
0, 0,
1.0 * iwidth / width , 0,
0, 1.0 * iheight / height,
)
if convert:
rv = rv.convert_alpha()
return rv
# Scales down a surface.
def surface_scale(full):
return full
# Saves an image without rescaling.
def image_save_unscaled(surf, dest):
pygame.image.save(surf, dest)
return dest
else:
def init():
global factor
if 'RENPY_SCALE_FACTOR' in os.environ:
factor = float(os.environ['RENPY_SCALE_FACTOR'])
elif 'RENPY_SCALE_WIDTH' in os.environ:
width = float(os.environ['RENPY_SCALE_WIDTH'])
if width < renpy.config.screen_width:
factor = float(os.environ['RENPY_SCALE_WIDTH']) / renpy.config.screen_width
else:
factor = 1.0
real_smoothscale = pygame.transform.smoothscale
smoothscale = real_smoothscale
def init():
global factor
global scale_fast
if 'RENPY_SCALE_FACTOR' in os.environ:
factor = float(os.environ['RENPY_SCALE_FACTOR'])
elif 'RENPY_SCALE_WIDTH' in os.environ:
width = float(os.environ['RENPY_SCALE_WIDTH'])
if width < renpy.config.screen_width:
factor = float(os.environ['RENPY_SCALE_WIDTH']) / renpy.config.screen_width
else:
factor = 1.0
else:
# Automatically scale to screen if too small.
info = pygame.display.Info()
factor = min(1.0,
1.0 * info.current_w / renpy.config.screen_width,
1.0 * info.current_h / renpy.config.screen_height)
if factor <= 0:
factor = 1.0
if factor != 1.0:
print "Using scale factor of %f." % factor
load_scaling()
if 'RENPY_SCALE_FAST' in os.environ:
scale_fast = True
else:
scale_fast = False
scaling_loaded = False
# The virtual screen scaling creates.
screen = None
def load_scaling():
global scaling_loaded
if scaling_loaded:
return
scaling_loaded = True
def real(s):
return s.surface
def same_size(*args):
"""
If all the surfaces in args are the same size, return them all
unchanged. Otherwise, compute smallest width and height, and
take subsurfaces of anythign bigger.
"""
w = min(i.get_width() for i in args)
h = min(i.get_height() for i in args)
size = (w, h)
rv = [ ]
for i in args:
if i.get_size() != size:
i = i.subsurface((0, 0) + size)
rv.append(i)
return rv
def scale(n):
if n is None:
return n
@@ -134,13 +234,19 @@ else:
return rv
def surface_scale(full):
return Surface(old_transform_scale(full, v2p(full.get_size())), wh=full.get_size())
if scale_fast:
scaled = old_transform_scale(full, v2p(full.get_size()))
else:
scaled = real_smoothscale(full, v2p(full.get_size()))
return Surface(scaled, wh=full.get_size())
# Project a tuple from virtual to physical coordinates.
def v2p(n):
if n is None:
return None
return tuple([ int(i * factor) for i in n ])
# Similar, but include an extra pixel to deal with rounding.
@@ -163,8 +269,9 @@ else:
func = getattr(PygameSurface, name)
def rv(self, *args, **kwargs):
return func(self.surface, *args, **kwargs)
return rv
class Surface(object):
def __init__(self, what, flags=0, sample=None, wh=None):
@@ -182,7 +289,10 @@ else:
else:
w, h = what
self.width, self.height = w, h
w = int(w)
h = int(h)
self.width = w
self.height = h
w = int(w * factor)
h = int(h * factor)
@@ -194,16 +304,68 @@ else:
sample = sample.surface
self.surface = PygameSurface((w, h), flags, sample)
self.virtx = 0
self.virty = 0
self.physx = 0
self.physy = 0
def transform_pos(self, (x, y)):
"""
Converts a virtual position into a physical one.
"""
x0 = x + self.virtx
y0 = y + self.virty
x0 *= factor
y0 *= factor
x0 = int(x0)
y0 = int(y0)
return (x0 - self.physx, y0 - self.physy)
def transform_rect(self, (x, y, w, h)):
"""
Converts a virtual rectangle into a physical one.
"""
x0 = x + self.virtx
y0 = y + self.virty
x1 = x0 + w
y1 = y0 + h
x0 *= factor
y0 *= factor
x1 *= factor
y1 *= factor
x0 = int(x0)
y0 = int(y0)
x1 = int(x1)
y1 = int(y1)
rv = (x0 - self.physx, y0 - self.physy, x1 - x0, y1 - y0)
return rv
def __repr__(self):
return "<scale.Surface %r %r>" % (self.get_size(), self.surface)
def blit(self, s, destpos, sourcerect=None):
if sourcerect is None:
self.surface.blit(s.surface, v2p(destpos))
self.surface.blit(
s.surface,
self.transform_pos(destpos))
else:
self.surface.blit(s.surface, v2p(destpos), v2p(sourcerect))
self.surface.blit(
s.surface,
self.transform_pos(destpos),
self.transform_rect(sourcerect))
def convert(self, *args):
if args:
@@ -225,7 +387,7 @@ else:
return self.surface.get_alpha()
def get_at(self, pos):
x, y = v2p(pos)
x, y = self.transform_pos(pos)
w, h = self.surface.get_size()
return self.surface.get_at((min(x, w - 1), min(y, h - 1)))
@@ -256,9 +418,6 @@ else:
def get_bitsize(self):
return self.surface.get_bitsize()
def get_clip(self):
return p2v(self.surface.get_clip())
def get_colorkey(self):
return self.surface.get_colorkey()
@@ -274,13 +433,23 @@ else:
def set_alpha(self, alpha, flags):
self.surface.set_alpha(alpha, flags)
def set_clip(self, rect):
self.surface.set_clip(v2pplus(rect))
pass
def subsurface(self, rect):
return Surface(self.surface.subsurface(v2p(rect)), wh=rect[2:])
prect = self.transform_rect(rect)
surf = self.surface.subsurface(prect)
rv = Surface(surf, wh=rect[2:])
vx, vy, vw, vh = rect
px, py, pw, ph = prect
rv.virtx = vx + self.virtx
rv.virty = vy + self.virty
rv.physx = px + self.physx
rv.physy = py + self.physy
return rv
def mustlock(self):
return False
@@ -304,15 +473,9 @@ else:
setattr(rv, k, v)
return rv
pygame.Surface = Surface
# Our pygame screen.
screen = None
old_set_mode = pygame.display.set_mode
def set_mode((w, h), flags, bpp):
@@ -348,15 +511,19 @@ else:
pygame.display.get_surface = get_surface
old_image_load = pygame.image.load
old_transform_scale = pygame.transform.scale
def image_load(*args, **kwargs):
full = old_image_load(*args, **kwargs)
full = full.convert_alpha()
return surface_scale(full)
pygame.image.load = image_load
old_transform_scale = pygame.transform.scale
def transform_scale(surf, size):
rv = old_transform_scale(surf.surface, v2p(size))
@@ -366,6 +533,21 @@ else:
pygame.transform.scale = transform_scale
old_transform_smoothscale = pygame.transform.smoothscale
def transform_smoothscale(surf, size, dest=None):
if dest is not None:
rv = old_transform_smoothscale(surf.surface, v2p(size), dest.surface)
else:
rv = old_transform_smoothscale(surf.surface, v2p(size))
rv = Surface(rv, wh=size)
return rv
pygame.transform.smoothscale = transform_smoothscale
old_transform_flip = pygame.transform.flip
def transform_flip(surf, xbool, ybool):
@@ -390,7 +572,7 @@ else:
# Ignoring scale2x and chop. The former due to a pending api change,
# the latter due to general uselessness.
PygameFont = font_module.Font
class Font(object):
@@ -434,13 +616,9 @@ else:
def get_descent(self):
return int(self.font.get_descent() / factor)
# Ignored:
#
# set_at
# Anything involving palettes.
# Anything involving the parents of subsurfaces.
# get_pitch, get_shifts, get_losses
def set_expand(self, value):
self.font.set_expand(value * factor)
font_module.Font = Font
old_image_save = pygame.image.save
@@ -494,7 +672,8 @@ else:
old_map = _renpy.map
def map(pysrc, pydst, r, g, b, a):
old_map(pysrc.surface, pydst.surface, r, g, b, a)
pysrc, pydst = same_size(pysrc.surface, pydst.surface)
old_map(pysrc, pydst, r, g, b, a)
_renpy.map = map
@@ -502,7 +681,8 @@ else:
old_linmap = _renpy.linmap
def linmap(pysrc, pydst, r, g, b, a):
old_linmap(pysrc.surface, pydst.surface, r, g, b, a)
pysrc, pydst = same_size(pysrc.surface, pydst.surface)
old_linmap(pysrc, pydst, r, g, b, a)
_renpy.linmap = linmap
@@ -544,8 +724,8 @@ else:
def alpha_munge(pysrc, pydst, srcchan, dstchan, amap):
old_alpha_munge(pysrc.surface, pydst.surface,
srcchan, dstchan, amap)
pysrc, pydst = same_size(pysrc.surface, pydst.surface)
old_alpha_munge(pysrc, pydst, srcchan, dstchan, amap)
_renpy.alpha_munge = alpha_munge
@@ -573,18 +753,27 @@ else:
old_blend = _renpy.blend
def blend(pysrca, pysrcb, pydst, alpha):
old_blend(pysrca.surface, pysrcb.surface, pydst.surface, alpha)
pysrca, pysrcb, pydst = same_size(pysrca.surface, pysrcb.surface, pydst.surface)
old_blend(pysrca, pysrcb, pydst, alpha)
_renpy.blend = blend
old_imageblend = _renpy.imageblend
def imageblend(pysrca, pysrcb, pydst, pyimg, aoff, amap):
old_imageblend(pysrca.surface, pysrcb.surface, pydst.surface,
pyimg.surface, aoff, amap)
pysrca, pysrcb, pydst, pyimg = same_size(pysrca.surface, pysrcb.surface, pydst.surface, pyimg.surface)
old_imageblend(pysrca, pysrcb, pydst, pyimg, aoff, amap)
_renpy.imageblend = imageblend
old_colormatrix = _renpy.colormatrix
def colormatrix(src, dst, *args):
src, dst = same_size(src.surface, dst.surface)
old_colormatrix(src, dst, *args)
_renpy.colormatrix = colormatrix
def draw_scale(o):
if isinstance(o, int):
@@ -619,3 +808,22 @@ else:
pygame.draw.lines = draw_wrap(pygame.draw.lines)
pygame.draw.aaline = draw_wrap(pygame.draw.aaline)
pygame.draw.aalines = draw_wrap(pygame.draw.aalines)
# Smoothscale:
def smoothscale(surf, size, dest=None):
if dest is not None:
dest = dest.surface
rv = real_smoothscale(surf.surface, v2p(size), dest)
if rv is None:
return rv
else:
return Surface(rv, wh=size)
# Now, put everything from this function's namespace into the
# module namespace.
globals().update(locals())
reload(renpy.display.module)
+28 -13
View File
@@ -122,6 +122,7 @@ class TextStyle(object):
return rv
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, expand):
@@ -167,6 +168,7 @@ class TextStyle(object):
rv = surf
renpy.display.render.mutated_surface(rv)
return rv, rv.get_size()
def length(self, text):
@@ -343,28 +345,35 @@ def input_tokenizer(l, style, pauses=None):
return rv
def layout_width(triples):
def layout_width(triples, justify=False):
"""
Returns the width of the given list of triples. Cache
should be a dictionary, which is used to cache results.
Returns the width of the given list of triples.
"""
rv = 0
curts = None
cur = None
cur = ""
for type, ts, i in triples:
if ts is not curts:
if curts:
if cur:
rv += curts.get_width(cur)
curts = ts
cur = i
elif justify and type == "space":
cur += i
rv += curts.get_width(cur)
cur = ""
else:
cur += i
if curts:
rv += curts.get_width(cur)
return rv
@@ -379,6 +388,7 @@ def greedy_text_layout(triples, width, style):
@param style: The style of the text widget.
"""
lines = [ ]
line = [ ]
@@ -388,6 +398,8 @@ def greedy_text_layout(triples, width, style):
target = width - style.first_indent
justify = style.justify
after_newline = True
for triple in triples:
@@ -414,14 +426,15 @@ def greedy_text_layout(triples, width, style):
after_newline = False
if layout_width(line + [ triple ]) > target:
if layout_width(line + [ triple ], justify) > 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)
@@ -434,7 +447,7 @@ def greedy_text_layout(triples, width, style):
return lines, lines_last
def subtitle_text_layout_core(triples, width, style, soft, n):
def subtitle_text_layout_core(triples, width, style, soft, n, justify):
sizecache = { }
@@ -458,7 +471,7 @@ def subtitle_text_layout_core(triples, width, style, soft, n):
else:
lw = layout_width(line + [ triple ])
lw = layout_width(line + [ triple ], justify)
if lw > target or type == "newline":
@@ -468,7 +481,7 @@ def subtitle_text_layout_core(triples, width, style, soft, n):
if line and line[-1][0] == "space":
line.pop()
total -= layout_width(line)
total -= layout_width(line, justify)
linesoft = total / n
else:
linesoft = soft
@@ -513,6 +526,8 @@ def subtitle_text_layout_core(triples, width, style, soft, n):
def subtitle_text_layout(triples, width, style):
justify = style.justify
softwidth = style.subtitle_width
if isinstance(softwidth, float):
softwidth = int(softwidth * width)
@@ -534,14 +549,14 @@ def subtitle_text_layout(triples, width, style):
for triples in pars:
sumwidths = layout_width(triples)
sumwidths = layout_width(triples, justify)
i = 1
while sumwidths / i > min(width, softwidth):
i += 1
while True:
rv = subtitle_text_layout_core(triples, width, style, sumwidths / i, i)
rv = subtitle_text_layout_core(triples, width, style, sumwidths / i, i, justify)
if len(rv) == i:
break
i += 1
+5 -6
View File
@@ -286,8 +286,7 @@ class Pixellate(Transition):
rdr = render(visible, width, height, st, at)
# No alpha support.
surf = rdr.pygame_surface(False)
surf = rdr.pygame_surface()
if surf.get_size() != self.surface_size:
self.surface_size = surf.get_size()
@@ -349,8 +348,8 @@ class Dissolve(Transition):
bottom = render(self.old_widget, width, height, st, at)
top = render(self.new_widget, width, height, st, at)
bottom_surface = bottom.pygame_surface(self.alpha)
top_surface = top.pygame_surface(self.alpha)
bottom_surface = bottom.pygame_surface()
top_surface = top.pygame_surface()
width = min(top.width, bottom.width)
height = min(top.height, bottom.height)
@@ -1064,8 +1063,8 @@ class ImageDissolve(Transition):
bottom = render(self.old_widget, width, height, st, at)
top = render(self.new_widget, width, height, st, at)
bottom_surface = bottom.pygame_surface(self.alpha)
top_surface = top.pygame_surface(self.alpha)
bottom_surface = bottom.pygame_surface()
top_surface = top.pygame_surface()
iw, ih = image.get_size()
+7 -3
View File
@@ -67,7 +67,8 @@ def checkpoint(data=None):
statement.
"""
renpy.game.log.checkpoint(data)
if renpy.store._rollback:
renpy.game.log.checkpoint(data)
def block_rollback():
"""
@@ -684,6 +685,9 @@ def rollback():
Rolls the state of the game back to the last checkpoint.
"""
if not renpy.store._rollback:
return
if not renpy.game.context().rollback:
return
@@ -734,7 +738,7 @@ def take_screenshot(scale=None):
renpy.game.interface.take_screenshot(scale)
def full_restart(transition=False, label="_invoke_main_menu"):
def full_restart(transition=False, label="_invoke_main_menu", target="_main_menu"):
"""
This causes a full restart of Ren'Py.
"""
@@ -742,7 +746,7 @@ def full_restart(transition=False, label="_invoke_main_menu"):
if transition is False:
transition = renpy.config.end_game_transition
raise renpy.game.FullRestartException((transition, label))
raise renpy.game.FullRestartException((transition, label, target))
def utter_restart():
"""
+9 -3
View File
@@ -108,15 +108,21 @@ def image_exists(name, expression, tag):
check_file_cache = { }
def check_file(what, fn):
if fn in check_file_cache:
return True
check_file_cache[fn] = True
present = check_file_cache.get(fn, None)
if present is True:
return
if present is False:
report("%s uses file '%s', which is not loadable.", what.capitalize(), fn)
return
if not renpy.loader.loadable(fn):
report("%s uses file '%s', which is not loadable.", what.capitalize(), fn)
check_file_cache[fn] = False
return
check_file_cache[fn] = True
try:
renpy.loader.transfn(fn)
except:
+1 -1
View File
@@ -307,7 +307,7 @@ def main():
try:
run(restart)
finally:
restart = (renpy.config.end_game_transition, "_invoke_main_menu")
restart = (renpy.config.end_game_transition, "_invoke_main_menu", "_main_menu")
save_persistent()
except game.QuitException, e:
+4
View File
@@ -44,9 +44,13 @@ _window = False
# The window subtitle.
_window_subtitle = ''
# Should rollback be allowed?
_rollback = True
# config.
_config = renpy.config
class _Config(object):
def __init__(self, name):