Compare commits

...

54 Commits

Author SHA1 Message Date
Tom Rothamel c12adecf9f Bump versions. 2013-06-26 08:05:53 -04:00
Tom Rothamel fc6013c5de Use the correct shader program for imageblends. 2013-06-26 07:57:29 -04:00
Tom Rothamel 3dd9f07fe2 Add changelog. 2013-06-26 07:53:04 -04:00
Tom Rothamel 5308fdd0b8 Skip sets proper values for config.skipping.
This:

* Displays the skip indicator.
* Allows for fast (to-next-menu) skipping.
* Fixes #97.
2013-06-24 22:37:49 -04:00
Tom Rothamel 273d1e296c Apply drag-drop fix. (Thank you, Kinsman.)
Fixes #99.
2013-06-24 22:24:10 -04:00
Tom Rothamel 152af7dc7b Changes to improve compatibility with very old Ren'Py games.
These were required to get the Ren'Py 5.0 demo to run. (You'll need
to create a script_version.rpy file set to (5, 0, 0) to get things
actually working.)
2013-06-20 17:58:15 -04:00
Tom Rothamel 43b34f22a3 Bump version. 2013-06-17 20:22:49 -04:00
Tom Rothamel 3330b451d0 Build on android-8. 2013-06-17 20:22:38 -04:00
Tom Rothamel 5290296952 Print the android savedir to stdout/logcat.
I just have the feeling this will come in handy one day.
2013-06-17 01:58:14 -04:00
Tom Rothamel 8fc784aef5 Place logs and traceback.txt into renpy.config.logdir.
On android, this is always placed on external storage, so we can
get to it.
2013-06-17 01:51:19 -04:00
Tom Rothamel 110c8b890b Change the search path for saves on android.
We look in:

* The public directory used by very old RAPT versions.
* The private directory used by newer RAPT versions.
* The getExternalFilesDir directory, used by the newest RAPT versions.

This means that saves will now be placed in a public place, so they
can be copied and otherwise shared.
2013-06-17 01:36:27 -04:00
Tom Rothamel b6c686d770 Do not looks for assets on the android filesystem.
In recent RAPTs we won't put anything there. What's worse, older games
might have left files there, which will interfere with our newer
code.
2013-06-17 00:07:54 -04:00
Tom Rothamel 6358db88ff Never invoke the editor on android. 2013-06-17 00:07:44 -04:00
Tom Rothamel b2611fd613 Use different shaders for clipping and no-clipping cases.
The clipping support in the shaders causes a noticable performance
hit on Android, and is rarely used. This fixes that in the common
case.
2013-06-16 22:25:46 -04:00
Tom Rothamel 5eb3af0188 Update android packaging docs to match the new RAPT. 2013-06-10 01:45:13 -04:00
Tom Rothamel ad71c17f77 Prevent import recursion that took place if utf-8 was not imported
before the Ren'Py loader was initialized.

This actually happend on Android.
2013-06-10 01:36:52 -04:00
Tom Rothamel 0d7dec8e4e Merge pull request #109 from JaHIY/master
add a variable set the minimum number of component in automatic_images
2013-06-07 20:26:29 -07:00
Tom Rothamel 112fbbfc08 Return the correct value from renpy.call_in_new_context. 2013-06-07 23:02:15 -04:00
JaHIY 4ee5240c72 change config.automatic_images_minimum_component to
config.automatic_images_minimum_components
2013-06-07 22:29:34 +08:00
JaHIY 025e359394 Now developers can set the minimum number of component 2013-06-07 20:04:31 +08:00
Tom Rothamel 143bcfad08 Enable minimize and quit shortcuts in the launcher. 2013-06-05 10:11:27 -04:00
Tom Rothamel a39ebd13e0 Check in the changelog. 2013-06-04 23:43:42 -04:00
Tom Rothamel e7c0a5f19f Check in problems.rst. 2013-06-03 23:26:46 -04:00
Tom Rothamel f0b03dc426 Add the Flatten displayable to Ren'Py. 2013-06-03 23:24:53 -04:00
Tom Rothamel 3d2ad79b6b Document additive blending. 2013-06-03 23:04:13 -04:00
Tom Rothamel 9f28a93c56 Deal with r.over in the sprite manager. 2013-06-03 23:00:25 -04:00
Tom Rothamel 386dd1d799 Deal (improperly) with additive blending in the software renderer.
When additive blending is 1.0, the software renderer will not
display an image. This is probably preferable to the image
displaying incorrectly, since they're likely to be effect
images.
2013-06-03 22:55:28 -04:00
Tom Rothamel e85ebf3a50 Add additive blending to Transform. 2013-06-03 22:30:05 -04:00
Tom Rothamel 81eb2e6f42 Additive blending in the GL renderer.
This commit adds in the backend support, for varying the additive
blending factor.

Additive blending will not be added to the (mostly obsolete) software
renderer. Instead, added a way to test if the current renderer
supports additive blending.
2013-06-03 22:11:29 -04:00
Tom Rothamel 9d021a2ec1 Bump version to 6.15.5. 2013-06-02 23:32:06 -04:00
Tom Rothamel 439fac65e2 Remove assert statements.
Thes won't run when optimization is enabled, which is the default
for Ren'Py. It's better to eliminate them entirely, so we have
the same configuration in testing and production.
2013-06-02 20:46:19 -04:00
Tom Rothamel dee484a16b Error message fix. 2013-06-02 16:57:16 -04:00
Tom Rothamel 90457d6f20 Fix translation problem.
Returned the wrong value when we used RENPY_UPDATE_STRINGS
to translate a string with a {#translation_comment} in it.
2013-06-02 13:42:16 -04:00
Tom Rothamel 245c30d7a7 Force font autohinting.
This was the behavior of of Ren'Py until switching to Freetype 2.4. The
autohinter more resembles the older Ren'Pys, seems to produce better
forms on most fonts, and fixes spacing issues on broken fonts.
2013-05-27 23:39:07 -04:00
Tom Rothamel 81b28293ca Allow * in classification patterns to match directories as well as
files.

Fixes #106.
2013-05-26 00:10:08 -04:00
Tom Rothamel 392f71b214 Use secure permissions in zip and tar files.
Previously, we used 666 and 777, and expected the user's umask to take
care of adjusting the permissions. Unfortunately, info-zip overrides
the umask, writing world-writable files to disk.

Thanks to Spiky Caterpillar for the bug and the fix.
2013-05-23 00:37:26 -04:00
Tom Rothamel 257a5281ed Make use of avresample optional.
This lets us compile on platforms that do not support it, using
the old audio_resample code.
2013-05-21 00:25:09 -04:00
Tom Rothamel d44f70a145 Revert "Update ffdecode.c to work with newer libav."
This reverts commit 1ffd4f97fc.
2013-05-21 00:00:45 -04:00
Tom Rothamel ec9198f25d Fix one more deprecation with newer libav. 2013-05-20 23:54:37 -04:00
Tom Rothamel 1ffd4f97fc Update ffdecode.c to work with newer libav.
This gets rid of deprecation warnings when building ffdecode.c, and
adds a dependency on the avsample library.
2013-05-20 23:28:14 -04:00
Tom Rothamel e8968252ab Skip whitespace before default parameters and arguments.
Fixes #101.
2013-05-06 22:58:34 -04:00
Tom Rothamel ae618ddd76 Allow the creator to cancel out of create file and generate translation.
Fixes #100.
2013-05-04 12:24:30 -04:00
Tom Rothamel 005aa1a64c Read assets from an expansion file if one is available on Android. 2013-04-14 22:51:55 -04:00
Tom Rothamel a63231d36f Merge branch 'master' into android 2013-04-13 23:06:26 -04:00
Tom Rothamel db530f7def Document config.start_callbacks. 2013-04-07 20:00:47 -04:00
Tom Rothamel 627261f51d Clarify what the Ren'Py license applies to. 2013-04-07 19:43:58 -04:00
Tom Rothamel d080b71f29 Make exclude_empty_directories deal with non-terminal directories. 2013-04-07 11:13:00 -04:00
Tom Rothamel f6bfeefc8e Merge branch 'master' into android 2013-04-02 20:05:55 -04:00
Tom Rothamel b0070122f8 Merge branch 'master' into android 2013-03-31 21:42:49 -04:00
Tom Rothamel cc004c00f0 Merge branch 'master' into android 2013-03-19 23:30:51 -04:00
Tom Rothamel 83ad789654 Improve OpenGL ES2 support. 2013-03-08 23:44:10 -05:00
Tom Rothamel 21eaa5ee9c Merge branch 'master' into android 2013-03-08 21:31:50 -05:00
Tom Rothamel fd5ee77f1c Force use of shaders on android.
The auto-detect code fails on ES.
2013-03-04 01:15:56 -05:00
Tom Rothamel b9acbfccd7 Changes required to support android.
The new android support uses GL2, so we need to change some defines
to use it.
2013-03-04 00:00:08 -05:00
61 changed files with 915 additions and 260 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ label add_file:
import os
import codecs
filename = interface.input(_("FILENAME"), _("Enter the name of the script file to create."), filename="withslash")
filename = interface.input(_("FILENAME"), _("Enter the name of the script file to create."), filename="withslash", cancel=Jump("navigation"))
if "." in filename and not filename.endswith(".rpy"):
interface.error(_("The filename must have the .rpy extension."), label="navigation")
+3 -3
View File
@@ -47,7 +47,7 @@ init python in distribute:
regexp += r'.*'
pattern = pattern[2:]
elif pattern[0] == "*":
regexp += r'[^/]*'
regexp += r'[^/]*/?'
pattern = pattern[1:]
elif pattern[0] == '[':
regexp += r'['
@@ -167,8 +167,8 @@ init python in distribute:
if (not i.directory) or (i.name in needed_dirs):
rv.insert(0, i.copy())
directory, _sep, _filename = i.name.rpartition("/")
needed_dirs.add(directory)
directory, _sep, _filename = i.name.rpartition("/")
needed_dirs.add(directory)
return rv
+8 -1
View File
@@ -174,7 +174,14 @@ init -1 python hide:
_game_menu_screen = None
config.underlay = [ ]
config.underlay = [
renpy.Keymap(
quit = renpy.quit_event,
iconify = renpy.iconify,
choose_renderer = renpy.curried_call_in_new_context("_choose_renderer"),
),
]
config.rollback_enabled = False
+5 -5
View File
@@ -103,9 +103,9 @@ init python in distribute:
zi.create_system = 3
if xbit:
zi.external_attr = long(0100777) << 16
zi.external_attr = long(0100755) << 16
else:
zi.external_attr = long(0100666) << 16
zi.external_attr = long(0100644) << 16
self.zipfile.write_with_info(zi, path)
@@ -119,7 +119,7 @@ init python in distribute:
zi.date_time = time.gmtime(s.st_mtime)[:6]
zi.compress_type = zipfile.ZIP_STORED
zi.create_system = 3
zi.external_attr = (long(0040777) << 16) | 0x10
zi.external_attr = (long(0040755) << 16) | 0x10
self.zipfile.write_with_info(zi, path)
@@ -150,9 +150,9 @@ init python in distribute:
info.type = tarfile.DIRTYPE
if xbit:
info.mode = 0777
info.mode = 0755
else:
info.mode = 0666
info.mode = 0644
info.uid = 1000
info.gid = 1000
+1 -1
View File
@@ -1,4 +1,4 @@
init -999:
$ config.script_version = (6, 15, 4)
$ config.script_version = (6, 15, 7)
+1 -1
View File
@@ -7,7 +7,7 @@ label translate:
python:
language = interface.input(_("Create or Update Translations"), _("Please enter the name of the language for which you want to create or update translations."), filename=True, default=persistent.translate_language)
language = interface.input(_("Create or Update Translations"), _("Please enter the name of the language for which you want to create or update translations."), filename=True, default=persistent.translate_language, cancel=Jump("front_page"))
language = language.strip()
+228 -19
View File
@@ -25,12 +25,12 @@
#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 "libavcodec/opt.h"
// #include "cmdutils.h"
#ifdef HAS_RESAMPLE
#include <libavutil/opt.h>
#include <libavresample/avresample.h>
#endif
#include <SDL.h>
#include <SDL_thread.h>
@@ -100,17 +100,24 @@ typedef struct VideoState {
/* samples output by the codec. we reserve more space for avsync
compensation */
#ifndef HAS_RESAMPLE
uint8_t audio_buf1[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2] __attribute__ ((aligned (16))) ;
uint8_t audio_buf2[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2] __attribute__ ((aligned (16))) ;
#else
uint8_t *audio_buf1;
#endif
uint8_t *audio_buf;
unsigned int audio_buf_size; /* in bytes */
int audio_buf_index; /* in bytes */
AVPacket audio_pkt;
AVPacket audio_pkt_temp;
// AVAudioConvert *reformat_ctx;
#ifndef HAS_RESAMPLE
ReSampleContext *reformat_ctx;
#endif
int resample_frac;
int show_audio; /* if true, display audio samples */
@@ -165,6 +172,19 @@ typedef struct VideoState {
// Should we force the display of the current video frame?
int first_frame;
#ifdef HAS_RESAMPLE
// The audio frame, and the audio resample context.
enum AVSampleFormat sdl_sample_fmt;
uint64_t sdl_channel_layout;
int sdl_channels;
int sdl_sample_rate;
enum AVSampleFormat resample_sample_fmt;
uint64_t resample_channel_layout;
int resample_sample_rate;
AVAudioResampleContext *avr;
AVFrame *frame;
#endif
} VideoState;
SDL_mutex *codec_mutex = NULL;
@@ -183,7 +203,6 @@ static int debug_mv = 0;
static int workaround_bugs = 1;
static int fast = 0;
static int genpts = 0;
static int lowres = 0;
static int idct = FF_IDCT_AUTO;
static enum AVDiscard skip_frame= AVDISCARD_DEFAULT;
static enum AVDiscard skip_idct= AVDISCARD_DEFAULT;
@@ -770,8 +789,181 @@ static int video_thread(void *arg)
return 0;
}
#ifdef HAS_RESAMPLE
/* decode one audio frame and returns its uncompressed size */
static int audio_decode_frame(VideoState *is, double *pts_ptr)
{
AVPacket *pkt_temp = &is->audio_pkt_temp;
AVPacket *pkt = &is->audio_pkt;
AVCodecContext *dec = is->audio_st->codec;
int n, len1, data_size, got_frame;
double pts;
int new_packet = 0;
int flush_complete = 0;
for (;;) {
/* NOTE: the audio packet can contain several frames */
while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
int resample_changed, audio_resample;
if (!is->frame) {
if (!(is->frame = avcodec_alloc_frame()))
return AVERROR(ENOMEM);
} else
avcodec_get_frame_defaults(is->frame);
if (flush_complete)
break;
new_packet = 0;
len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp);
if (len1 < 0) {
/* if error, we skip the frame */
pkt_temp->size = 0;
break;
}
pkt_temp->data += len1;
pkt_temp->size -= len1;
if (!got_frame) {
/* stop sending empty packets if the decoder is finished */
if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY)
flush_complete = 1;
continue;
}
data_size = av_samples_get_buffer_size(NULL, dec->channels,
is->frame->nb_samples,
is->frame->format, 1);
audio_resample = is->frame->format != is->sdl_sample_fmt ||
is->frame->channel_layout != is->sdl_channel_layout ||
is->frame->sample_rate != is->sdl_sample_rate;
resample_changed = is->frame->format != is->resample_sample_fmt ||
is->frame->channel_layout != is->resample_channel_layout ||
is->frame->sample_rate != is->resample_sample_rate;
if ((!is->avr && audio_resample) || resample_changed) {
int ret;
if (is->avr)
avresample_close(is->avr);
else if (audio_resample) {
is->avr = avresample_alloc_context();
if (!is->avr) {
fprintf(stderr, "error allocating AVAudioResampleContext\n");
break;
}
}
if (audio_resample) {
av_opt_set_int(is->avr, "in_channel_layout", is->frame->channel_layout, 0);
av_opt_set_int(is->avr, "in_sample_fmt", is->frame->format, 0);
av_opt_set_int(is->avr, "in_sample_rate", is->frame->sample_rate, 0);
av_opt_set_int(is->avr, "out_channel_layout", is->sdl_channel_layout, 0);
av_opt_set_int(is->avr, "out_sample_fmt", is->sdl_sample_fmt, 0);
av_opt_set_int(is->avr, "out_sample_rate", is->sdl_sample_rate, 0);
if ((ret = avresample_open(is->avr)) < 0) {
fprintf(stderr, "error initializing libavresample\n");
break;
}
}
is->resample_sample_fmt = is->frame->format;
is->resample_channel_layout = is->frame->channel_layout;
is->resample_sample_rate = is->frame->sample_rate;
}
if (audio_resample) {
void *tmp_out;
int out_samples, out_size, out_linesize;
int osize = av_get_bytes_per_sample(is->sdl_sample_fmt);
int nb_samples = is->frame->nb_samples;
int max_samples = 2 * (avresample_get_delay(is->avr) + nb_samples) * is->sdl_sample_rate / is->frame->sample_rate;
out_size = av_samples_get_buffer_size(
&out_linesize,
is->sdl_channels,
max_samples,
is->sdl_sample_fmt, 0);
tmp_out = av_realloc(is->audio_buf1, out_size);
if (!tmp_out)
return AVERROR(ENOMEM);
is->audio_buf1 = tmp_out;
out_samples = avresample_convert(is->avr,
&is->audio_buf1,
out_linesize, max_samples,
is->frame->data,
is->frame->linesize[0],
is->frame->nb_samples);
if (out_samples < 0) {
fprintf(stderr, "avresample_convert() failed\n");
break;
}
is->audio_buf = is->audio_buf1;
data_size = out_samples * osize * is->sdl_channels;
} else {
is->audio_buf = is->frame->data[0];
}
/* if no pts, then compute it */
pts = is->audio_clock;
*pts_ptr = pts;
n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
is->audio_clock += (double)data_size /
(double)(n * is->sdl_sample_rate);
// This is Ren'Py specific code, to deal with ogg files with
// more data than their duration.
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;
}
/* free the current packet */
if (pkt->data)
av_free_packet(pkt);
memset(pkt_temp, 0, sizeof(*pkt_temp));
if (is->paused || is->audioq.abort_request) {
return -1;
}
/* read next packet */
if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
return -1;
if (pkt->data == flush_pkt.data) {
avcodec_flush_buffers(dec);
flush_complete = 0;
}
*pkt_temp = *pkt;
/* if update the audio clock with the pts */
if (pkt->pts != AV_NOPTS_VALUE) {
is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
}
}
}
#else
/* decode one audio frame and returns its uncompressed size */
static int audio_decode_frame(VideoState *is, double *pts_ptr)
@@ -823,17 +1015,17 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
}
// Moved by tom, from below next block. Is this right?
if (is->reformat_ctx) {
int len = data_size / av_get_bytes_per_sample(dec->sample_fmt);
len /= dec->channels;
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;
is->audio_buf = is->audio_buf2;
} else {
is->audio_buf = is->audio_buf1;
}
@@ -846,7 +1038,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
int inpos;
int len = data_size / 4;
if (is->audio_buf == is->audio_buf1) {
in = (short *) is->audio_buf1;
out = (short *) is->audio_buf2;
@@ -860,9 +1052,9 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
// 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.
// sample. Scaled by 1 << 14.
in_per_out = (dec->sample_rate << 14) / audio_sample_rate;
len *= (1 << 14);
@@ -892,14 +1084,14 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
out[2 * outpos + 1] = a + (((b - a) * frac) >> 14);
outpos++;
inpos += in_per_out;
inpos += in_per_out;
}
// Store the fraction.
is->resample_frac = inpos & ((1 << 14) - 1);
data_size = outpos * 4;
is->audio_buf = (uint8_t *) out;
is->audio_buf = (uint8_t *) out;
}
@@ -915,7 +1107,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
if (is->audio_duration) {
int len = data_size / 4;
int maxlen = is->audio_duration - is->audio_played;
if (len > maxlen) {
len = maxlen;
}
@@ -923,7 +1115,7 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
is->audio_played += len;
data_size = len * 4;
}
return data_size;
}
@@ -953,6 +1145,9 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr)
}
}
#endif
/* get the current audio output buffer size, in samples. With SDL, we
cannot have a precise information */
static int audio_write_get_buf_size(VideoState *is)
@@ -1038,8 +1233,6 @@ static int stream_component_open(VideoState *is, int stream_index)
enc->debug_mv = debug_mv;
enc->debug = debug;
enc->workaround_bugs = workaround_bugs;
enc->lowres = lowres;
if(lowres) enc->flags |= CODEC_FLAG_EMU_EDGE;
enc->idct_algo= idct;
if(fast) enc->flags2 |= CODEC_FLAG2_FAST;
enc->skip_frame= skip_frame;
@@ -1069,6 +1262,20 @@ static int stream_component_open(VideoState *is, int stream_index)
is->audio_buf_size = 0;
is->audio_buf_index = 0;
#ifdef HAS_RESAMPLE
if (!enc->channel_layout)
enc->channel_layout = av_get_default_channel_layout(enc->channels);
if (!enc->channel_layout) {
fprintf(stderr, "%s: unable to guess channel layout\n", is->filename);
return -1;
}
is->sdl_sample_rate = audio_sample_rate;
is->sdl_channel_layout = AV_CH_LAYOUT_STEREO;
is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout);
is->sdl_sample_fmt = AV_SAMPLE_FMT_S16;
#endif
memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
packet_queue_init(&is->audioq);
break;
@@ -1102,8 +1309,10 @@ static void stream_component_close(VideoState *is, int stream_index)
case AVMEDIA_TYPE_AUDIO:
packet_queue_abort(&is->audioq);
packet_queue_end(&is->audioq);
#ifndef HAS_RESAMPLE
if (is->reformat_ctx)
audio_resample_close(is->reformat_ctx);
#endif
break;
case AVMEDIA_TYPE_VIDEO:
packet_queue_abort(&is->videoq);
@@ -1353,7 +1562,7 @@ fail:
if (is->video_stream >= 0)
stream_component_close(is, is->video_stream);
if (is->ic) {
av_close_input_file(is->ic);
avformat_close_input(&(is->ic));
is->ic = NULL;
}
+4 -1
View File
@@ -12,7 +12,7 @@
#if defined ANDROID
#define RENPY_GLES_1
#define RENPY_GLES_2
#elif defined ANGLE
@@ -54,7 +54,10 @@
#if defined RENPY_GLES_2
#ifndef ANDROID
#include <EGL/egl.h>
#endif
#include <GLES2/gl2.h>
typedef GLuint GLhandleARB;
+19 -16
View File
@@ -373,25 +373,28 @@ cdef extern from "pyfreetype.h":
FT_Error FT_Set_Char_Size(FT_Face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt hres, FT_UInt vres)
FT_Error FT_Set_Pixel_Sizes(FT_Face face, FT_UInt pixel_width, FT_UInt pixel_height)
ctypedef enum FT_Load_Flags:
FT_LOAD_DEFAULT
FT_LOAD_NO_SCALE
FT_LOAD_NO_HINTING
FT_LOAD_RENDER
FT_LOAD_NO_BITMAP
FT_LOAD_VERTICAL_LAYOUT
FT_LOAD_FORCE_AUTOHINT
FT_LOAD_CROP_BITMAP
FT_LOAD_PEDANTIC
FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
FT_LOAD_NO_RECURSE
FT_LOAD_IGNORE_TRANSFORM
FT_LOAD_MONOCHROME
FT_LOAD_LINEAR_DESIGN
FT_LOAD_SBITS_ONLY
FT_LOAD_NO_AUTOHINT
FT_Error FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 flags)
FT_Error FT_Load_Char(FT_Face face, FT_ULong char_code, FT_Int32 flags)
DEF FT_LOAD_DEFAULT = 0
DEF FT_LOAD_NO_SCALE = 1 << 0
DEF FT_LOAD_NO_HINTING = 1 << 1
DEF FT_LOAD_RENDER = 1 << 2
DEF FT_LOAD_NO_BITMAP = 1 << 3
DEF FT_LOAD_VERTICAL_LAYOUT = 1 << 4
DEF FT_LOAD_FORCE_AUTOHINT = 1 << 5
DEF FT_LOAD_CROP_BITMAP = 1 << 6
DEF FT_LOAD_PEDANTIC = 1 << 7
DEF FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH = 1 << 9
DEF FT_LOAD_NO_RECURSE = 1 << 10
DEF FT_LOAD_IGNORE_TRANSFORM = 1 << 11
DEF FT_LOAD_MONOCHROME = 1 << 12
DEF FT_LOAD_LINEAR_DESIGN = 1 << 13
DEF FT_LOAD_SBITS_ONLY = 1 << 14
DEF FT_LOAD_NO_AUTOHINT = 1 << 15
void FT_Set_Transform(FT_Face face, FT_Matrix *matrix, FT_Vector *delta)
+14 -6
View File
@@ -37,6 +37,7 @@ library("png")
library("avformat")
library("avcodec")
library("avutil")
has_avresample = library("avresample", optional=True)
has_swscale = library("swscale", optional=True)
library("freetype")
has_fribidi = library("fribidi", optional=True)
@@ -46,7 +47,7 @@ has_libglew32 = library("glew32", optional=True)
has_angle = windows and library("EGL", optional=True) and library("GLESv2", optional=True)
if android:
sdl = [ 'sdl', 'GLESv1_CM', 'log' ]
sdl = [ 'sdl', 'GLESv2', 'log' ]
else:
sdl = [ 'SDL' ]
@@ -69,13 +70,20 @@ pymodule("pysdlsound.__init__")
if not android:
sound = [ "avformat", "avcodec", "avutil", "z" ]
macros = [ ]
if has_avresample:
sound.insert(0, "avresample")
macros.append(("HAS_RESAMPLE", 1))
if has_swscale:
sound.insert(0, "swscale")
cython(
"pysdlsound.sound",
[ "pss.c", "ffdecode.c" ],
libs = sdl + sound)
libs = sdl + sound,
define_macros=macros)
# Display.
@@ -84,7 +92,7 @@ cython("renpy.display.accelerator", libs=sdl + [ 'z', 'm' ])
# Gl.
if android:
glew_libs = [ 'GLESv1_CM', 'z', 'm' ]
glew_libs = [ 'GLESv2', 'z', 'm' ]
elif has_libglew:
glew_libs = [ 'GLEW' ]
else:
@@ -92,9 +100,9 @@ else:
cython("renpy.gl.gldraw", libs=glew_libs )
cython("renpy.gl.gltexture", libs=glew_libs)
cython("renpy.gl.glenviron_shader", libs=glew_libs)
cython("renpy.gl.glenviron_fixed", libs=glew_libs, compile_if=not android)
cython("renpy.gl.glenviron_shader", libs=glew_libs, compile_if=not android)
cython("renpy.gl.glenviron_limited", libs=glew_libs)
cython("renpy.gl.glenviron_limited", libs=glew_libs, compile_if=not android)
cython("renpy.gl.glrtt_copy", libs=glew_libs)
cython("renpy.gl.glrtt_fbo", libs=glew_libs)
+25 -5
View File
@@ -1,5 +1,9 @@
#!/usr/bin/env python
#@PydevCodeAnalysisIgnore
# This file is part of Ren'Py. The license below applies to Ren'Py only.
# Games and other projects that use Ren'Py may use a different license.
# Copyright 2004-2012 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
@@ -37,6 +41,26 @@ def path_to_common(renpy_base):
def path_to_saves(gamedir):
import renpy #@UnresolvedImport
# Android.
if renpy.android:
paths = [
os.path.join(os.environ["ANDROID_OLD_PUBLIC"], "game/saves"),
os.path.join(os.environ["ANDROID_PRIVATE"], "saves"),
os.path.join(os.environ["ANDROID_PUBLIC"], "saves"),
]
for rv in paths:
if os.path.isdir(rv):
break
print "Using savedir", rv
# We return the last path as the default.
return rv
# No save directory given.
if not renpy.config.save_directory:
return gamedir + "/saves"
@@ -54,10 +78,7 @@ def path_to_saves(gamedir):
path = newpath
# Otherwise, put the saves in a platform-specific location.
if renpy.android:
return gamedir + "/saves"
elif renpy.macintosh:
if renpy.macintosh:
rv = "~/Library/RenPy/" + renpy.config.save_directory
return os.path.expanduser(rv)
@@ -107,7 +128,6 @@ if android:
__main__.path_to_common = path_to_common
__main__.path_to_saves = path_to_saves
os.environ["RENPY_RENDERER"] = "gl"
os.environ["RENPY_GL_ENVIRON"] = "limited"
def main():
+2 -2
View File
@@ -34,9 +34,9 @@ except ImportError:
# The tuple giving the version. This needs to be updated when
# we bump the version.
#
# Be sure to change script_version in launcher/script_version.rpy.
# Be sure to change script_version in launcher/game/script_version.rpy.
# Be sure to change config.version in tutorial/game/options.rpy.
version_tuple = (6, 15, 4, vc_version)
version_tuple = (6, 15, 7, vc_version)
# A verbose string computed from that version.
version = "Ren'Py " + ".".join(str(i) for i in version_tuple)
+1 -1
View File
@@ -278,7 +278,7 @@ class Node(object):
be executed after this one.
"""
assert False, "Node subclass forgot to define execute."
raise Exception("Node subclass forgot to define execute.")
def early_execute(self):
"""
+1
View File
@@ -75,6 +75,7 @@ PROPERTIES = {
"yzoom" : float,
"zoom" : float,
"alpha" : float,
"additive" : float,
"around" : (position, position),
"alignaround" : (float, float),
"angle" : float,
+23 -6
View File
@@ -87,12 +87,15 @@ class NullFile(io.IOBase):
raise IOError("Not implemented.")
def null_files():
if sys.stderr.fileno() < 0:
sys.stderr = NullFile()
try:
if sys.stderr.fileno() < 0:
sys.stderr = NullFile()
if sys.stdout.fileno() < 0:
sys.stdout = NullFile()
except:
pass
if sys.stdout.fileno() < 0:
sys.stdout = NullFile()
null_files()
@@ -250,6 +253,14 @@ this program do not contain : or ; in their names.
renpy.config.basedir = basedir
renpy.config.gamedir = gamedir
renpy.config.args = [ ]
if renpy.android:
renpy.config.logdir = os.environ['ANDROID_PUBLIC']
else:
renpy.config.logdir = basedir
if not os.path.exists(renpy.config.logdir):
os.makedirs(renpy.config.logdir, 0777)
renpy.main.main()
keep_running = False
@@ -370,7 +381,11 @@ def open_error_file(fn, mode):
was opened.
"""
import tempfile
try:
f = file(os.path.join(renpy.config.logdir, fn), mode)
return f, fn
except:
pass
try:
f = file(fn, mode)
@@ -378,6 +393,8 @@ def open_error_file(fn, mode):
except:
pass
import tempfile
fn = os.path.join(tempfile.gettempdir(), "renpy-" + fn)
return file(fn, mode), fn
+18 -2
View File
@@ -165,8 +165,16 @@ init -1500 python:
Causes the game to begin skipping. If the game is in a menu
context, then this returns to the game. Otherwise, it just
enables skipping.
`fast`
If True, skips directly to the next menu choice.
"""
fast = False
def __init__(self, fast=False):
self.fast = fast
def __call__(self):
if not self.get_sensitive():
return
@@ -174,7 +182,15 @@ init -1500 python:
if renpy.context()._menu:
renpy.jump("_return_skipping")
else:
config.skipping = not config.skipping
if not config.skipping:
if self.fast:
config.skipping = "fast"
else:
config.skipping = "slow"
else:
config.skipping = None
renpy.restart_interaction()
def get_selected(self):
+5 -2
View File
@@ -49,6 +49,9 @@ init -1900 python:
# Prefixes to strip from automatic images.
config.automatic_images_strip = [ ]
# The minimum number of components which the image name consists of is 2 by default.
config.automatic_images_minimum_components = 2
init 1900 python hide:
@@ -86,8 +89,8 @@ init 1900 python hide:
else:
break
# Only names of 2 components or more.
if len(name) < 2:
# Only names of 2 components or more by default.
if len(name) < config.automatic_images_minimum_components:
continue
# Reject if it already exists.
+3
View File
@@ -86,6 +86,9 @@ init -1800 python hide:
style.list_text = Style(style.default)
style.tile = Style(style.default, help='default style of tile')
# Not used - but some old games might customize it.
style.error_root = Style(style.default)
# The base styles that can be customized by themes.
+19 -9
View File
@@ -1,7 +1,7 @@
# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us>
# See LICENSE.txt for license details.
init python hide:
init python:
style.menu_button = Style(style.button, heavy=True, help='Buttons that are part of the main or game menus.')
style.menu_button_text = Style(style.button_text, heavy=True, help='The label of buttons that are part of the main or game menus.')
@@ -43,7 +43,6 @@ init python hide:
style.yesno_button = Style(style.menu_button, heavy=True, help='A Yes/No button.')
style.yesno_button_text = Style(style.menu_button_text, heavy=True, help='A Yes/No button label.')
style.prefs_frame = Style(style.default, heavy=True, help='')
style.prefs_pref_frame = Style(style.default, heavy=True, help='')
style.prefs_pref_vbox = Style(style.thin_vbox, heavy=True, help='')
@@ -323,15 +322,25 @@ init python hide:
store._selected_compat = [ ]
class _SelectedCompat(object):
class _SelectedCompat(renpy.style.Style):
def __init__(self, target):
self.__dict__["target"] = target
self.__dict__["property_updates"] = [ ]
self.target = target
self.property_updates = [ ]
super(_SelectedCompat, self).__init__(target)
store._selected_compat.append(self)
def __setattr__(self, k, v):
def setattr(self, k, v):
super(_SelectedCompat, self).setattr(k, v)
try:
super(_SelectedCompat, self).setattr("selected_" + k, v)
except:
pass
self.property_updates.append((k, v))
def apply(self):
@@ -340,7 +349,8 @@ init python hide:
setattr(target, "selected_" + k, v)
def clear(self):
self.__dict__["property_updates"] = [ ]
super(_SelectedCompat, self).clear()
self.property_updates = [ ]
style.selected_button = _SelectedCompat('button')
@@ -350,8 +360,8 @@ init python hide:
style.prefs_selected_button = _SelectedCompat('prefs_button')
style.prefs_selected_button_text = _SelectedCompat('prefs_button_text')
def apply_selected_compat():
def _apply_selected_compat():
for scs in _selected_compat:
scs.apply()
layout.compat_funcs.append(apply_selected_compat)
layout.compat_funcs.append(_apply_selected_compat)
+1
View File
@@ -379,6 +379,7 @@ gamedir = None
basedir = None
renpy_base = None
commondir = None
logdir = None # Where log and error files go.
# Should we enable OpenGL mode?
gl_enable = True
+1
View File
@@ -108,6 +108,7 @@ Solid = renpy.display.imagelike.Solid
LiveComposite = renpy.display.layout.LiveComposite
LiveCrop = renpy.display.layout.LiveCrop
LiveTile = renpy.display.layout.LiveTile
Flatten = renpy.display.layout.Flatten
Null = renpy.display.layout.Null
Window = renpy.display.layout.Window
+2 -3
View File
@@ -255,8 +255,6 @@ def transform_render(self, widtho, heighto, st, at):
xo += width / 2.0
yo += height / 2.0
alpha = state.alpha
rv = Render(width, height)
# Default case - no transformation matrix.
@@ -279,7 +277,8 @@ def transform_render(self, widtho, heighto, st, at):
-rydx / inv_det,
rxdx / inv_det)
rv.alpha = alpha
rv.alpha = state.alpha
rv.over = 1.0 - state.additive
rv.clipping = clipping
pos = (xo, yo)
+1 -1
View File
@@ -213,7 +213,7 @@ class Displayable(renpy.object.Object):
in seconds.
"""
assert False, "Draw not implemented."
raise Exception("Render not implemented.")
def event(self, ev, x, y, st):
"""
+2 -2
View File
@@ -463,9 +463,9 @@ class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
new_x = par_x - self.grab_x + xo
new_y = par_y - self.grab_y + yo
new_x = max(new_x, 0)
new_x = min(new_x, i.parent_width - i.w)
new_x = min(new_x, int(i.parent_width - i.w))
new_y = max(new_y, 0)
new_y = min(new_y, i.parent_height - i.h)
new_y = min(new_y, int(i.parent_height - i.h))
if i.drag_group is not None and i.drag_name is not None:
i.drag_group.positions[i.drag_name] = (new_x, new_y)
+2 -8
View File
@@ -294,11 +294,9 @@ def horiz_line_dist(ax0, ay0, ax1, ay1, bx0, by0, bx1, by1):
# The right end of a is to the left of the left end of b.
if ax0 <= ax1 <= bx0 <= bx1:
return points_dist(ax1, ay1, bx0, by0, renpy.config.focus_crossrange_penalty, 1.0)
if bx0 <= bx1 <= ax0 <= ax1:
else:
return points_dist(ax0, ay0, bx1, by1, renpy.config.focus_crossrange_penalty, 1.0)
assert False
# This computes the distance between two vertical lines. (So the
# distance is either hortizontal, or has a horizontal component to it.)
@@ -316,13 +314,9 @@ def verti_line_dist(ax0, ay0, ax1, ay1, bx0, by0, bx1, by1):
# The right end of a is to the left of the left end of b.
if ay0 <= ay1 <= by0 <= by1:
return points_dist(ax1, ay1, bx0, by0, 1.0, renpy.config.focus_crossrange_penalty)
if by0 <= by1 <= ay0 <= ay1:
else:
return points_dist(ax0, ay0, bx1, by1, 1.0, renpy.config.focus_crossrange_penalty)
assert False
# This focuses the widget that is nearest to the current widget. To
# determine nearest, we compute points on the widgets using the
+1 -1
View File
@@ -458,7 +458,7 @@ class ImageBase(renpy.display.core.Displayable):
would override this.
"""
assert False
raise Exception("load method not implemented.")
def render(self, w, h, st, at):
+38
View File
@@ -1742,3 +1742,41 @@ class LiveTile(Container):
rv.blit(cr, (x, y), focus=False)
return rv
class Flatten(Container):
"""
:doc: disp_imagelike
This flattens `child`, which may be made up of multiple textures, into
a single texture.
Certain operations, like the alpha transform property, apply to every
texture making up a displayable, which can yield incorrect results
when the textures overlap on screen. Flatten creates a single texture
from multiple textures, which can prevent this problem.
Flatten is a relatively expensive operation, and so should only be used
when absolutely required.
"""
def __init__(self, child, **properties):
super(Flatten, self).__init__(**properties)
self.add(child)
def render(self, width, height, st, at):
cr = renpy.display.render.render(self.child, width, height, st, at)
cw, ch = cr.get_size()
tex = cr.render_to_texture(True)
rv = renpy.display.render.Render(cw, ch)
rv.blit(tex, (0, 0))
rv.depends_on(cr, focus=True)
return rv
+6 -1
View File
@@ -95,9 +95,11 @@ class TransformState(renpy.object.Object):
default_xoffset = None
default_yoffset = None
transform_anchor = False
additive = 0.0
def __init__(self): # W0231
self.alpha = 1
self.additive = 0.0
self.rotate = None
self.rotate_pad = True
self.transform_anchor = False
@@ -142,6 +144,7 @@ class TransformState(renpy.object.Object):
def take_state(self, ts):
self.alpha = ts.alpha
self.additive = ts.additive
self.rotate = ts.rotate
self.rotate_pad = ts.rotate_pad
self.transform_anchor = ts.transform_anchor
@@ -196,6 +199,7 @@ class TransformState(renpy.object.Object):
rv[prop] = (old_value, new_value)
diff2("alpha", newts.alpha, self.alpha)
diff2("additive", newts.additive, self.additive)
diff2("rotate", newts.rotate, self.rotate)
diff2("rotate_pad", newts.rotate_pad, self.rotate_pad)
diff2("transform_anchor", newts.transform_anchor, self.transform_anchor)
@@ -380,6 +384,7 @@ class Transform(Container):
# Proxying things over to our state.
alpha = Proxy("alpha")
additive = Proxy("additive")
rotate = Proxy("rotate")
rotate_pad = Proxy("rotate_pad")
transform_anchor = Proxy("rotate_pad")
@@ -514,7 +519,7 @@ class Transform(Container):
raise Exception("Unknown transform property prefix: %r" % prefix)
if prop not in renpy.atl.PROPERTIES:
raise Exception("Unknown transform property: %r")
raise Exception("Unknown transform property: %r" % prop)
self.arguments[prefix][prop] = v
-4
View File
@@ -191,8 +191,6 @@ def OldMoveTransition(delay, old_widget=None, new_widget=None, factory=None, ent
# for each layer.
if new.layers:
assert old.layers
rv = renpy.display.layout.MultiBox(layout='fixed')
rv.layers = { }
@@ -502,8 +500,6 @@ def MoveTransition(delay, old_widget=None, new_widget=None, enter=None, leave=No
# for each layer.
if new.layers:
assert old.layers
rv = renpy.display.layout.MultiBox(layout='fixed')
for layer in renpy.config.layers:
+1 -1
View File
@@ -282,7 +282,7 @@ class SpriteManager(renpy.display.core.Displayable):
cst = st - cache.st
cache.render = r = render(cache.child, width, height, cst, cst)
cache.fast = (r.operation == BLIT) and (r.forward is None) and (r.alpha == 1.0)
cache.fast = (r.operation == BLIT) and (r.forward is None) and (r.alpha == 1.0) and (r.over == 1.0)
rv.depends_on(r)
caches.append(cache)
+1
View File
@@ -24,6 +24,7 @@ cdef class Render:
cdef public Matrix2D forward, reverse
cdef public double alpha
cdef public double over
cdef public list focuses
cdef public list pass_focuses
+4
View File
@@ -508,6 +508,10 @@ cdef class Render:
# This is used to adjust the alpha of children of this render.
self.alpha = 1
# The over blending factor. When this is 1.0, we get fully additive
# blending. When set to 0.0, we get additive blending.
self.over = 1.0
# A list of focus regions in this displayable.
self.focuses = None
+4 -4
View File
@@ -478,10 +478,10 @@ def draw(dest, clip, what, xo, yo, screen):
dest = dest.subsurface((x, y, width, height))
# Deal with alpha and transforms by passing them off to draw_transformed.
if what.alpha != 1 or (what.forward is not None and what.forward is not IDENTITY):
if what.alpha != 1 or what.over != 1.0 or (what.forward is not None and what.forward is not IDENTITY):
for child, cxo, cyo, _focus, _main in what.visible_children:
draw_transformed(dest, clip, child, xo + cxo, yo + cyo,
what.alpha, what.forward, what.reverse)
what.alpha * what.over, what.forward, what.reverse)
return
for child, cxo, cyo, _focus, _main in what.visible_children:
@@ -629,7 +629,7 @@ def draw_transformed(dest, clip, what, xo, yo, alpha, forward, reverse):
child_forward = forward
child_reverse = reverse
draw_transformed(dest, clip, child, xo + cxo, yo + cyo, alpha * what.alpha, child_forward, child_reverse)
draw_transformed(dest, clip, child, xo + cxo, yo + cyo, alpha * what.alpha * what.over, child_forward, child_reverse)
@@ -695,7 +695,7 @@ class SWDraw(object):
self.fullscreen_surface = None
# Info.
self.info = { "renderer" : "sw", "resizable" : False }
self.info = { "renderer" : "sw", "resizable" : False, "additive" : False }
pygame.display.init()
renpy.display.interface.post_init()
+4
View File
@@ -127,6 +127,10 @@ def launch_editor(filenames, line=1, transient=False):
Causes the editor to be launched.
"""
# On android, we will never be able to launch the editor.
if renpy.android:
return True
if editor is None:
init()
+6 -2
View File
@@ -507,8 +507,12 @@ def run_context(top):
label = None
context.run()
rv = renpy.store._return
context.pop_all_dynamic()
break
return rv
except renpy.game.RestartContext as e:
@@ -532,5 +536,5 @@ def run_context(top):
context.pop_all_dynamic()
raise
+4 -1
View File
@@ -1668,9 +1668,12 @@ def get_renderer_info():
One of ``"gl"`` or ``"sw"``, corresponding to the OpenGL and
software renderers, respectively.
``"resizable``
``"resizable"``
True if and only if the window is resizable.
``"additive"``
True if and only if the renderer supports additive blending.
Other, renderer-specific, keys may also exist. The dictionary should
be treated as immutable. This should only be called once the display
has been started (that is, after the init code is finished).
+1 -5
View File
@@ -366,11 +366,7 @@ def call_in_new_context(label, *args, **kwargs):
try:
context.goto_label(label)
renpy.execution.run_context(False)
rv = renpy.store._return #@UndefinedVariable
return rv
return renpy.execution.run_context(False)
except renpy.game.JumpOutException, e:
+2
View File
@@ -26,6 +26,7 @@ cdef class GLDraw:
cdef bint fast_dissolve
cdef bint always_opaque
cdef bint allow_fixed
cdef tuple default_clip
cdef public tuple clip_rtt_box
@@ -43,6 +44,7 @@ cdef class GLDraw:
double xo,
double yo,
double alpha,
double over,
render.Matrix2D reverse)
cdef class Environ:
+39 -27
View File
@@ -111,7 +111,7 @@ cdef class GLDraw:
self.redraw_period = .2
# Info.
self.info = { "resizable" : True }
self.info = { "resizable" : True, "additive" : True }
if not ANGLE:
self.info["renderer"] = "gl"
@@ -206,19 +206,21 @@ cdef class GLDraw:
# Handle swap control.
vsync = int(os.environ.get("RENPY_GL_VSYNC", "1"))
# Switch the
IF not ANGLE:
if ANGLE:
opengl = 0
resizable = 0
elif renpy.android:
opengl = pygame.OPENGL
resizable = 0
else:
opengl = pygame.OPENGL
pygame.display.gl_set_attribute(pygame.GL_SWAP_CONTROL, vsync)
pygame.display.gl_set_attribute(pygame.GL_ALPHA_SIZE, 8)
ELSE:
opengl = 0
# EGL automatically handles vsync for us.
if renpy.config.gl_resize:
resizable = pygame.RESIZABLE
else:
resizable = 0
if renpy.config.gl_resize:
resizable = pygame.RESIZABLE
else:
resizable = 0
try:
if fullscreen:
@@ -382,12 +384,13 @@ cdef class GLDraw:
return False
if ANGLE:
gltexture.use_angle()
elif version.startswith("OpenGL ES"):
gltexture.use_gles()
elif renpy.android:
self.redraw_period = 1.0
self.always_opaque = True
gltexture.use_gles()
else:
gltexture.use_gl()
@@ -433,7 +436,7 @@ cdef class GLDraw:
# Pick a texture environment subsystem.
if ANGLE or (allow_shader and use_subsystem(
if ANGLE or renpy.android or (allow_shader and use_subsystem(
glenviron_shader,
"RENPY_GL_ENVIRON",
"shader",
@@ -646,17 +649,18 @@ cdef class GLDraw:
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
clip = (0, 0, self.virtual_size[0], self.virtual_size[1])
self.default_clip = (0, 0, self.virtual_size[0], self.virtual_size[1])
clip = self.default_clip
self.upscale_factor = 1.0 * self.physical_size[0] / self.virtual_size[0]
if renpy.audio.music.get_playing("movie") and renpy.display.video.fullscreen:
surf = renpy.display.video.render_movie(self.virtual_size[0], self.virtual_size[1])
if surf is not None:
self.draw_transformed(surf, clip, 0, 0, 1.0, reverse)
self.draw_transformed(surf, clip, 0, 0, 1.0, 1.0, reverse)
else:
self.draw_transformed(surftree, clip, 0, 0, 1.0, reverse)
self.draw_transformed(surftree, clip, 0, 0, 1.0, 1.0, reverse)
if flip:
@@ -733,6 +737,7 @@ cdef class GLDraw:
double xo,
double yo,
double alpha,
double over,
render.Matrix2D reverse):
cdef render.Render rend
@@ -751,6 +756,7 @@ cdef class GLDraw:
yo,
reverse,
alpha,
over,
self.environ,
False)
@@ -759,7 +765,7 @@ cdef class GLDraw:
if isinstance(what, pygame.Surface):
tex = self.load_texture(what)
self.draw_transformed(tex, clip, xo, yo, alpha, reverse)
self.draw_transformed(tex, clip, xo, yo, alpha, over, reverse)
return 0
raise Exception("Unknown drawing type. " + repr(what))
@@ -777,10 +783,10 @@ cdef class GLDraw:
# of dissolve on Ren'Py proper.
self.draw_transformed(rend.children[0][0],
clip, xo, yo, alpha, reverse)
clip, xo, yo, alpha, over, reverse)
self.draw_transformed(rend.children[1][0],
clip, xo, yo, alpha * what.operation_complete, reverse)
clip, xo, yo, alpha * what.operation_complete, over, reverse)
else:
@@ -793,6 +799,7 @@ cdef class GLDraw:
yo,
reverse,
alpha,
over,
rend.operation_complete,
self.environ)
@@ -810,6 +817,7 @@ cdef class GLDraw:
yo,
reverse,
alpha,
over,
rend.operation_complete,
rend.operation_parameter,
self.environ)
@@ -835,6 +843,7 @@ cdef class GLDraw:
yo,
reverse,
alpha,
over,
self.environ,
True)
@@ -847,7 +856,7 @@ cdef class GLDraw:
# Non-aligned clipping uses RTT.
if reverse.ydx != 0 or reverse.xdy != 0:
tex = what.render_to_texture(True)
self.draw_transformed(tex, clip, xo, yo, alpha, reverse)
self.draw_transformed(tex, clip, xo, yo, alpha, over, reverse)
return 0
minx, miny, maxx, maxy = clip
@@ -864,7 +873,8 @@ cdef class GLDraw:
clip = (minx, miny, maxx, maxy)
alpha = alpha * rend.alpha
over = over * rend.over
# If our alpha has hit 0, don't do anything.
if alpha <= 0.003: # (1 / 256)
return 0
@@ -878,7 +888,7 @@ cdef class GLDraw:
tcxo = reverse.xdx * cxo + reverse.xdy * cyo
tcyo = reverse.ydx * cxo + reverse.ydy * cyo
self.draw_transformed(child, clip, xo + tcxo, yo + tcyo, alpha, child_reverse)
self.draw_transformed(child, clip, xo + tcxo, yo + tcyo, alpha, over, child_reverse)
return 0
@@ -899,9 +909,10 @@ cdef class GLDraw:
glClear(GL_COLOR_BUFFER_BIT)
clip = (0, 0, what.width, what.height)
self.default_clip = (0, 0, what.width, what.height)
clip = self.default_clip
self.draw_transformed(what, clip, 0, 0, 1.0, reverse)
self.draw_transformed(what, clip, 0, 0, 1.0, 1.0, reverse)
if isinstance(what, render.Render):
what.is_opaque()
@@ -939,7 +950,7 @@ cdef class GLDraw:
clip = (0, 0, 1, 1)
self.draw_transformed(what, clip, 0, 0, 1.0, reverse)
self.draw_transformed(what, clip, 0, 0, 1.0, 1.0, reverse)
cdef unsigned char pixel[4]
@@ -978,7 +989,7 @@ cdef class GLDraw:
clip = (0, 0, width, height)
draw.draw_transformed(what, clip, 0, 0, 1.0, reverse)
draw.draw_transformed(what, clip, 0, 0, 1.0, 1.0, reverse)
if isinstance(what, render.Render):
what.is_opaque()
@@ -1063,6 +1074,7 @@ cdef class GLDraw:
y,
IDENTITY,
1.0,
1.0,
self.environ,
False)
+116 -7
View File
@@ -121,6 +121,27 @@ varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
vec4 color0 = texture2D(tex0, TexCoord0.st);
gl_FragColor = color0 * Color;
}
"""
BLIT_CLIP_SHADER = """
#ifdef GL_ES
precision highp float;
#endif
uniform vec4 Color;
uniform sampler2D tex0;
varying vec2 TexCoord0;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
@@ -149,6 +170,33 @@ varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
vec4 color0 = texture2D(tex0, TexCoord0.st);
vec4 color1 = texture2D(tex1, TexCoord1.st);
gl_FragColor = mix(color0, color1, done) * Color;
}
"""
BLEND_CLIP_SHADER = """
#ifdef GL_ES
precision highp float;
#endif
uniform vec4 Color;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float done;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
@@ -182,6 +230,38 @@ varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
vec4 color0 = texture2D(tex0, TexCoord0.st);
vec4 color1 = texture2D(tex1, TexCoord1.st);
vec4 color2 = texture2D(tex2, TexCoord2.st);
float a = clamp((color0.a + offset) * multiplier, 0.0, 1.0);
gl_FragColor = mix(color1, color2, a) * Color;
}
"""
IMAGEBLEND_CLIP_SHADER = """
#ifdef GL_ES
precision highp float;
#endif
uniform vec4 Color;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float offset;
uniform float multiplier;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 TexCoord2;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
@@ -200,6 +280,7 @@ void main()
def check_status(shader, handle, type):
"""
Checks the status of a shader or program. If it fails, then an
@@ -351,6 +432,11 @@ cdef class ShaderEnviron(Environ):
cdef Program blend_program
cdef Program imageblend_program
cdef Program blit_clip_program
cdef Program blend_clip_program
cdef Program imageblend_clip_program
cdef bint clipping
cdef double clip_x0
cdef double clip_y0
cdef double clip_x1
@@ -361,11 +447,17 @@ cdef class ShaderEnviron(Environ):
cdef int viewport_w
cdef int viewport_h
def init(self):
self.blit_program = Program(VERTEX_SHADER1, BLIT_SHADER)
self.blit_clip_program = Program(VERTEX_SHADER1, BLIT_CLIP_SHADER)
self.blend_program = Program(VERTEX_SHADER2, BLEND_SHADER)
self.blend_clip_program = Program(VERTEX_SHADER2, BLEND_CLIP_SHADER)
self.imageblend_program = Program(VERTEX_SHADER3, IMAGEBLEND_SHADER)
self.imageblend_clip_program = Program(VERTEX_SHADER3, IMAGEBLEND_CLIP_SHADER)
# The current program.
self.program = None
@@ -392,19 +484,27 @@ cdef class ShaderEnviron(Environ):
glUseProgramObjectARB(program.program)
glUniformMatrix4fvARB(program.Projection, 1, GL_FALSE, self.projection)
glUniform2fARB(program.clip0, self.clip_x0, self.clip_y0)
glUniform2fARB(program.clip1, self.clip_x1, self.clip_y1)
if self.clipping:
glUniform2fARB(program.clip0, self.clip_x0, self.clip_y0)
glUniform2fARB(program.clip1, self.clip_x1, self.clip_y1)
cdef void blit(self):
program = self.blit_program
if self.clipping:
program = self.blit_clip_program
else:
program = self.blit_program
if self.program is not program:
self.activate(program)
glUniform1iARB(program.tex0, 0)
cdef void blend(self, double fraction):
program = self.blend_program
if self.clipping:
program = self.blend_clip_program
else:
program = self.blend_program
if self.program is not program:
self.activate(program)
@@ -415,7 +515,10 @@ cdef class ShaderEnviron(Environ):
cdef void imageblend(self, double fraction, int ramp):
program = self.imageblend_program
if self.clipping:
program = self.imageblend_clip_program
else:
program = self.imageblend_program
if self.program is not program:
self.activate(program)
@@ -508,10 +611,15 @@ cdef class ShaderEnviron(Environ):
cdef int cx, cy, cw, ch
cdef int psw, psh
if clip_box == draw.default_clip:
self.unset_clip(draw)
return
minx, miny, maxx, maxy = clip_box
psw, psh = draw.physical_size
# The clipping box.
# The clipping box.
self.clipping = True
self.clip_x0 = minx
self.clip_y0 = miny
self.clip_x1 = maxx
@@ -566,7 +674,8 @@ cdef class ShaderEnviron(Environ):
cdef void unset_clip(self, GLDraw draw):
glDisable(GL_SCISSOR_TEST)
self.clipping = False
self.clip_x0 = 0
self.clip_y0 = 0
self.clip_x1 = 65535
+3
View File
@@ -42,6 +42,7 @@ cpdef blit(
double sy,
render.Matrix2D transform,
double alpha,
double over,
Environ environ,
bint nearest)
@@ -52,6 +53,7 @@ cpdef blend(
double sy,
render.Matrix2D transform,
double alpha,
double over,
double fraction,
Environ environ)
@@ -63,6 +65,7 @@ cpdef imageblend(
double sy,
render.Matrix2D transform,
double alpha,
double over,
double fraction,
int ramp,
Environ environ)
+16 -24
View File
@@ -52,7 +52,7 @@ cdef GLenum rtt_format = GL_RGBA
cdef GLenum rtt_internalformat = GL_RGBA
cdef GLenum rtt_type = GL_UNSIGNED_BYTE
def use_angle():
def use_gles():
global tex_format
global tex_internalformat
global tex_type
@@ -68,22 +68,6 @@ def use_angle():
rtt_internalformat = GL_RGBA
rtt_type = GL_UNSIGNED_BYTE
def use_gles():
global tex_format
global tex_internalformat
global tex_type
global rtt_format
global rtt_internalformat
global rtt_type
tex_format = GL_RGBA
tex_internalformat = GL_RGBA
tex_type = GL_UNSIGNED_BYTE
rtt_format = GL_RGB
rtt_internalformat = GL_RGB
rtt_type = GL_UNSIGNED_BYTE
def use_gl():
global tex_format
global tex_internalformat
@@ -889,7 +873,7 @@ def align_axes(*args):
return rv
cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, double alpha, Environ environ, bint nearest):
cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, double alpha, double over, Environ environ, bint nearest):
"""
This draws texgrid `tg` to the screen. `sx` and `sy` are offsets from
the upper-left corner of the screen.
@@ -898,6 +882,8 @@ cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, doub
texgrid coordinates to screen coordinates.
`alpha` is the alpha multiplier applied, from 0.0 to 1.0.
`over` is the over blending factor.
"""
cdef int x, y
@@ -906,7 +892,7 @@ cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, doub
tg.make_ready(nearest)
environ.blit()
environ.set_color(alpha, alpha, alpha, alpha)
environ.set_color(alpha, alpha, alpha, over * alpha)
y = 0
@@ -932,7 +918,7 @@ cpdef blit(TextureGrid tg, double sx, double sy, render.Matrix2D transform, doub
y += texh
cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matrix2D transform, double alpha, double fraction, Environ environ):
cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matrix2D transform, double alpha, double over, double fraction, Environ environ):
"""
Blends two textures to the screen.
@@ -945,6 +931,8 @@ cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matri
`alpha` is the alpha multiplier applied, from 0.0 to 1.0.
`over` is the over blending factor.
`fraction` is the fraction of the second texture to show.
"""
@@ -952,7 +940,7 @@ cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matri
tg1.make_ready(False)
environ.blend(fraction)
environ.set_color(alpha, alpha, alpha, alpha)
environ.set_color(alpha, alpha, alpha, over * alpha)
y = 0
@@ -985,8 +973,9 @@ cpdef blend(TextureGrid tg0, TextureGrid tg1, double sx, double sy, render.Matri
x += t0w
y += t0h
cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, double sy, render.Matrix2D transform, double alpha, double fraction, int ramp, Environ environ):
cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, double sy, render.Matrix2D transform, double alpha, double over, double fraction, int ramp, Environ environ):
"""
This uses texture 0 to control the blending of tetures 1 and 2 to
the screen.
@@ -998,7 +987,10 @@ cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, d
`transform` is the transform to apply to the texgrid, when going from
texgrid coordinates to screen coordinates.
`alpha` is the alpha multiplier applied, from 0.0 to 1.0.
`over` is the over blending factor.
`additive` is the additive blending factor, which is 1.0 for fully additive,
and 0.0 for fully over blending.
`fraction` is the fraction of the second texture to show.
@@ -1011,7 +1003,7 @@ cpdef imageblend(TextureGrid tg0, TextureGrid tg1, TextureGrid tg2, double sx, d
tg2.make_ready(False)
environ.imageblend(fraction, ramp)
environ.set_color(alpha, alpha, alpha, alpha)
environ.set_color(alpha, alpha, alpha, over * alpha)
y = 0
+21 -4
View File
@@ -26,12 +26,29 @@ from cStringIO import StringIO
import sys
import types
# Ensure the utf-8 codec is loaded, to prevent recursion when we use it
# to look up filenames.
u"".encode("utf-8")
try:
import android.apk
apks = [
android.apk.APK(prefix='assets/x-game/'),
android.apk.APK(prefix='assets/x-common/'),
]
expansion = os.environ.get("ANDROID_EXPANSION", None)
if expansion is not None:
print "Using expansion file", expansion
apks = [
android.apk.APK(apk=expansion, prefix='assets/x-game/'),
android.apk.APK(apk=expansion, prefix='assets/x-common/'),
]
else:
print "Not using expansion file."
apks = [
android.apk.APK(prefix='assets/x-game/'),
android.apk.APK(prefix='assets/x-common/'),
]
except ImportError:
apks = [ ]
+1 -1
View File
@@ -73,7 +73,7 @@ class LogFile(object):
return False
try:
base = os.environ.get("RENPY_LOG_BASE", renpy.config.basedir)
base = os.environ.get("RENPY_LOG_BASE", renpy.config.logdir)
fn = os.path.join(base, self.name + ".txt")
altfn = os.path.join(tempfile.gettempdir(), "renpy-" + self.name + ".txt")
+4
View File
@@ -154,6 +154,10 @@ def main():
renpy.config.commondir = commondir
else:
renpy.config.commondir = None
if renpy.android:
renpy.config.searchpath = [ ]
renpy.config.commondir = None
# Load Ren'Py extensions.
for dir in renpy.config.searchpath: #@ReservedAssignment
+2 -3
View File
@@ -943,9 +943,6 @@ class Lexer(object):
for _fn, ln, text, subblock in block:
if o.line > ln:
assert False
while o.line < ln:
rv.append(indent + '\n')
o.line += 1
@@ -1272,6 +1269,7 @@ def parse_parameters(l):
names.add(name)
if l.match(r'='):
l.skip_whitespace()
default = l.delimited_python("),")
else:
default = None
@@ -1329,6 +1327,7 @@ def parse_arguments(l):
l.revert(state)
name = None
l.skip_whitespace()
arguments.append((name, l.delimited_python("),")))
if l.match(r'\)'):
+17 -3
View File
@@ -107,9 +107,23 @@ def expand_anchor(v):
"""
Turns an anchor into a number.
"""
return anchors.get(v, v)
try:
return anchors.get(v, v)
except:
# This fixes some bugs in very old Ren'Pys.
for n in anchors:
o = getattr(renpy.store, n, None)
if o is None:
continue
if v is o:
return anchors[n]
raise
# A map of properties that we know about. The properties may take a
# function that is called to convert the argument to something more
+1 -1
View File
@@ -314,7 +314,7 @@ cdef class FTFont:
rv.index = index
error = FT_Load_Glyph(face, index, 0)
error = FT_Load_Glyph(face, index, FT_LOAD_FORCE_AUTOHINT)
if error:
raise FreetypeError(error)
+1 -1
View File
@@ -315,7 +315,7 @@ class StringTranslator(object):
new = self.translations.get(notags, None)
if new is not None:
return True
return new
return old
+1 -1
View File
@@ -25,5 +25,5 @@ fi
if [ "$1" = "--build" ] ; then
echo "Ren'Py build complete."
else
exec ./renpy.py "$@"
exec python -OO ./renpy.py "$@"
fi
+26
View File
@@ -447,3 +447,29 @@ And install the packages. Then, try building your game again.
http://lemmasoft.renai.us/forums/viewtopic.php?f=32&t=13987&hilit=rapt
Expansion APKs
--------------
|PGS4A| optionally supports the use of expansion APKs when used on a
device supporting Google Play. Please see:
http://developer.android.com/google/play/expansion-files.html
For information about expansion APKs work. Right now, only the
main expansion APK is supported, giving a 2GB limit.
.. ifconfig:: not is_renpy
When an android APK is created, all assets (from the assets
directory) are placed in the expansion APK. The assets can be
accessed through the :module:`android.assets` interface.
.. ifconfig:: is_renpy
When an APK is created, all game files will be placed in the
expansion APK. Ren'Py will transparently use these files.
|PGS4A| will place the expansion APK on the device when installing
the APK package on the device. In normal operation, Google Play will
place the expansion APK on the device automatically.
-12
View File
@@ -45,20 +45,8 @@ due to the Android software and hardware are:
screen. When the user is not touching the screen, the virtual
pointer will move to the upper-left corner of the screen.
* :func:`ImageDissolve`, :func:`AlphaDissolve`, and :func:`AlphaBlend`
are not supported.
* Functions that render to a texture can only render an opaque
texture. This means that the :func:`Dissolve` and :func:`Pixellate`
transitions will only produce opaque output.
* The :propref:`focus_mask` property is not supported. It will be
treated as if all pixels in the mask are opaque.
* Movie playback is not supported.
* Launching the web browser is not supported.
* Some python modules (including network communication) modules are
not supported.
+31
View File
@@ -751,6 +751,37 @@ both horizontal and vertical positions.
This controls the opacity of the displayable.
The alpha transform is applied to each image comprising the child of
the transform independently. This can lead to unexpected results when
the children overlap, such as as seeing a character through clothing.
The :func:`Flatten` displayable can help with these problems.
.. transform-property:: additive
:type: float
:default: 0.0
This controls how much additive blending Ren'Py performs. When 1.0,
Ren'Py draws using the ADD operator. When 0.0, Ren'Py draws using
the OVER operator.
Additive blending is performed on each child of the transform independently.
Fully additive blending doesn't alter the alpha channel of the destination,
and additive images may not be visible if they're not drawn directly onto
an opaque surface. (Complex operations, like viewport, :func:`Flatten`, :func:`Frame`,
and certain transitions may cause problems with additive blending.)
.. warning::
Additive blending is only supported by hardware-based renderers, such
as the OpenGL and DirectX/ANGLE renderers. The software renderer will
draw additive images incorrectly.
Once the graphics system has started, ``renpy.get_renderer_info()["additive"]``
will be true if additive blending is supported.
.. transform-property:: around
:type: (position, position)
+121 -58
View File
@@ -2,18 +2,82 @@
Full Changelog
==============
Ren'Py 6.15.6
-------------
This release includes improvements for the Android platform:
* Assets are now read exclusively from the APK and expansion file.
* Logs and tracebacks are placed on external storage.
* Saves are placed on external storage, except when saves from
older versions of Ren'Py exist.
The GL2 shaders Ren'Py uses have been simplified in the (usual) case
where no clipping is occuring. This leads to a noticable speed
improvement on Android, and potentially other platforms as well.
An issue with Drag-and-drop has been fixed. Thanks go to Kinsman
for contributing this fixe.
The :func:`Skip` action now triggers the skip indicator. It also
supports a new fast parameter, which causes skipping to the
next menu.
This release includes various minor changes to improve compatibility
with very old Ren'Py games. (It now runs the Ren'Py 5 demo.)
Ren'Py 6.15.5
-------------
This release adds two new features:
* The GL renderer now supports additive blending. This is enabled using the
:tpref:`additive` transform property in an ATL transform or use of the
:func:`Transform` class. Additive blending will not work if the software
renderer is in use, and it's up to creators to deal with that issue.
* The new :func:`Flatten` displayable combines multiple textures into
a single texture. This can be used to prevent incorrect behavior
when a displayable containing multiple overlapping textures (like a
:func:`LiveComposite` is shown with an :tpref:`alpha` between 0 and 1.
It also fixes the following issues:
* Whitespace is now skipped before default arguments, which previously
caused parse errors in some cases.
* Ren'Py now sets the unix mode of files and directories in zip and tar
files to 644 and 755 as appropriate. Prior versions of Ren'Py used
666 and 777 as the permissions, which lead to a security problem
when the file was unpacked by a tool that didn't respect the user's
umask. (Info-zip had this problem.)
* Auto-hinting for fonts is now enabled by default. This restores font
rendering compatibility with prior releases.
* Ren'Py now builds with and requires the current version of libav. It
should also work with current versions of ffmpeg when libav is
available.
* The version of SDL distributed with Ren'Py has been patched to
prevent multiple windows from showing up in the Window menu
when entering and leaving fullscreen mode.
Ren'Py 6.15.4
-------------
This release fixes a compile problem that prevented Ren'Py 6.14.x and
Ren'Py 6.15.0-3 from running on most 64-bit Linux systems.
This release fixes a compile problem that prevented Ren'Py 6.14.x and Ren'Py
6.15.0-3 from running on most 64-bit Linux systems.
Image prediction has become more fine-grained, and can take place
while the screen is animating.
Image prediction has become more fine-grained, and can take place while the
screen is animating.
The new :var:`build.exclude_empty_directories` determines if empty
directories are include or excluded from the distribution. It defaults
to true, previously the default was platform-dependant.
The new :var:`build.exclude_empty_directories` determines if empty directories
are include or excluded from the distribution. It defaults to true,
previously the default was platform-dependant.
@@ -33,21 +97,20 @@ combined at the translator's discretion. As most Ren'Py statements are
allowed inside the new translation blocks, it's possible to use logic (like
conditions) to tailor the translations to your language.
The launcher includes a new "Generate Translations" button, which - as part
of a sanctioned translation where the full script is present - will generate
The launcher includes a new "Generate Translations" button, which - as part of
a sanctioned translation where the full script is present - will generate
empty translation files for a new language.
Improved Japanese Support
-------------------------
Ren'Py 6.15 includes multiple changes to better support the Japanese
language.
Ren'Py 6.15 includes multiple changes to better support the Japanese language.
* The tutorial game has been translated to Japanese, with the language
being selectable from the preferences menu.
* The tutorial game has been translated to Japanese, with the language being
selectable from the preferences menu.
The tutorial was translated by Koichi Akabe.
* Support for vertical writing has been added to Ren'Py. Consisting of the
:propref:`vertical` style property for text, and the new
:propref:`box_reverse` property on hboxes, this support makes it possible
@@ -111,14 +174,13 @@ replay if one is in progress, and is ignored otherwise.
Voice Improvements
------------------
There have been several improvements to the voice playback system. The
new :var:`config.voice_filename_format` variable makes it possible to
use only part of the filename in a voice statement. The new voice_tag
parameter to :func:`Character`, in conjunction with the
:func:`SetVoiceMute` and :func:`ToggleVoiceMute` actions, makes it
possible to selectively mute particular characters' voices. The new
:func:`VoiceReplay` action makes it possible to replay the current
voice.
There have been several improvements to the voice playback system. The new
:var:`config.voice_filename_format` variable makes it possible to use only
part of the filename in a voice statement. The new voice_tag parameter to
:func:`Character`, in conjunction with the :func:`SetVoiceMute` and
:func:`ToggleVoiceMute` actions, makes it possible to selectively mute
particular characters' voices. The new :func:`VoiceReplay` action makes it
possible to replay the current voice.
Launcher Improvements
---------------------
@@ -139,44 +201,44 @@ There were a few launcher improvements in this release.
Macintosh Changes
-----------------
The Macintosh version of Ren'Py now requires a 64-bit capable processor,
and Mac OS X 10.6 or newer.
The Macintosh version of Ren'Py now requires a 64-bit capable processor, and
Mac OS X 10.6 or newer.
Packaging Improvements
----------------------
The file layout of Ren'Py games has been somewhat altered. With the
exception of small launcher programs, all platform-dependent binaries
are under the lib/ directory. Ren'Py itself has now been placed in the
renpy/ directory. The common/ directory has been moved to
renpy/common/, as it's considered an integral part of Ren'Py.
The file layout of Ren'Py games has been somewhat altered. With the exception
of small launcher programs, all platform-dependent binaries are under the
lib/ directory. Ren'Py itself has now been placed in the renpy/ directory.
The common/ directory has been moved to renpy/common/, as it's considered an
integral part of Ren'Py.
Ren'Py now uses renamed but otherwise unmodified python binaries on
all desktop platforms. (Previously, it used platform-specific
binaries.) Portions of the library are shared between the desktop
builds.
Ren'Py now uses renamed but otherwise unmodified python binaries on all
desktop platforms. (Previously, it used platform-specific binaries.) Portions
of the library are shared between the desktop builds.
A running Ren'Py process on Linux will now be named after the game, rather
than having python as a name.
A running Ren'Py process on Linux will now be named after the game,
rather than having python as a name.
Other Changes
-------------
* :ref:`Viewports <sl-viewport>` now support edge scrolling, which
scrolls the viewport when the mouse is within a a configurable
distance of the viewport edge.
* :ref:`Viewports <sl-viewport>` now support edge scrolling, which scrolls
the viewport when the mouse is within a a configurable distance of the
viewport edge.
* Most keyboard keys now automatically repeat. The repeat rate is
controlled by :var:`config.key_repeat`.
* Most keyboard keys now automatically repeat. The repeat rate is controlled
by :var:`config.key_repeat`.
* Side images can now be used with menus.
* The :ref:`config.enter_yesno_transition` and `config.exit_yesno_transition`
variables make it possible to define a transition that is run when
yes/no prompts appear and disappear, respectively.
* The :ref:`config.enter_yesno_transition` and
`config.exit_yesno_transition` variables make it possible to define a
transition that is run when yes/no prompts appear and disappear,
respectively.
* The :ref:`viewport statement <sl-viewport>` now supports edge scrolling -
automatic scrolling when the mouse approaches the sides of the viewport.
@@ -231,20 +293,21 @@ Among others, the following bugs were fixed:
* :ghbug:`51`: The slow_done callback was not called after a rollback.
* :ghbug:`56`, :ghbug:`57`: :func:`renpy.loadable` now works with Android assets.
* :ghbug:`56`, :ghbug:`57`: :func:`renpy.loadable` now works with Android
assets.
* :ghbug:`60`: Fixed a bug that prevented {p} and {w} from working properly when followed
immediately by a text tag.
* :ghbug:`61`: Ren'Py no longer crashes when an end_game_transition is
set and a screen uses a variable that is no longer defined when the
game restarts.
* :ghbug:`60`: Fixed a bug that prevented {p} and {w} from working properly
when followed immediately by a text tag.
* :ghbug:`65`: Multiplying a rollback list by a number now always produces
a rollback list.
* :ghbug:`61`: Ren'Py no longer crashes when an end_game_transition is set
and a screen uses a variable that is no longer defined when the game
restarts.
* :ghbug:`65`: Multiplying a rollback list by a number now always produces a
rollback list.
* Editra should work better on Windows.
* It's now possible to :func:`renpy.call` a label that doesn't take
parameters.
@@ -254,7 +317,7 @@ Among others, the following bugs were fixed:
* Fixed an error handling failure when a python early block contained a
syntax error.
Ren'Py 6.14
===========
@@ -478,7 +541,7 @@ Other Changes
* The :func:`renpy.call` function allows - with major and important caveats
- a call to a Ren'Py label to begin from inside python code. Such a call
immediately terminates the current statement.
immediately terminates the current statement.
* When an action is expected, nested lists of actions can be given. The
lists are flattened and the action executed.
+12
View File
@@ -934,6 +934,18 @@ Rarely or Internally Used
wav files are of a lower rate, changing this to that rate may make
things more efficent.
.. var:: config.start_callbacks = [ ... ]
A list of callbacks functions that are called with no arguments
after the init phase, but before the game (including the
splashscreen) starts. This is intended to be used by frameworks
to initialize variables that will be saved.
The default value of this variable includes callbacks that Ren'Py
uses internally to implement features such as nvl-mode. New
callbacks can be appended to this list, but the existing callbacks
should not be removed.
.. var:: config.start_interact_callbacks = ...
A list of functions that are called (without any arguments) when
+13
View File
@@ -1,5 +1,18 @@
.. Automatically generated file - do not modify.
.. function:: Flatten(child, **properties)
This flattens `child`, which may be made up of multiple textures, into
a single texture.
Certain operations, like the alpha transform property, apply to every
texture making up a displayable, which can yield incorrect results
when the textures overlap on screen. Flatten creates a single texture
from multiple textures, which can prevent this problem.
Flatten is a relatively expensive operation, and so should only be used
when absolutely required.
.. function:: Frame(image, xborder, yborder, tile=False, **properties)
A displayable that resizes an image to fill the available area,
+4 -1
View File
@@ -63,9 +63,12 @@
One of ``"gl"`` or ``"sw"``, corresponding to the OpenGL and
software renderers, respectively.
``"resizable``
``"resizable"``
True if and only if the window is resizable.
``"additive"``
True if and only if the renderer supports additive blending.
Other, renderer-specific, keys may also exist. The dictionary should
be treated as immutable. This should only be called once the display
has been started (that is, after the init code is finished).
+4 -1
View File
@@ -55,11 +55,14 @@
textbutton "Marsopolis":
action [ Jump("mars"), SelectedIf(mars_flag) ]
.. function:: Skip()
.. function:: Skip(fast=False)
Causes the game to begin skipping. If the game is in a menu
context, then this returns to the game. Otherwise, it just
enables skipping.
`fast`
If True, skips directly to the next menu choice.
.. function:: With(transition)
File diff suppressed because one or more lines are too long
+18
View File
@@ -0,0 +1,18 @@
Dealing with Problems
=====================
.. include:: display_problems.rst
64-Bit Linux Problems
----------------------
Ren'Py 6.14.x and 6.15.0-3 were compiled incorrectly, and will often
fail to operate on 64-bit Linux computers. The best way to work around
this is to download Ren'Py 6.15.4 or later, and use it to run the game::
/path/to/renpy-6.15.4/renpy.sh /path/to/game-with-problems
File diff suppressed because one or more lines are too long