Merge branch 'master' of /home/Ancurio/programming/C++/mkxp

Conflicts:
	src/config.h
This commit is contained in:
Jonas Kulla 2015-02-21 02:13:40 +01:00
commit d07309c8f9
85 changed files with 4901 additions and 3428 deletions

View File

@ -124,9 +124,9 @@ set(MAIN_HEADERS
src/glstate.h src/glstate.h
src/quad.h src/quad.h
src/tilemap.h src/tilemap.h
src/flashmap.h src/tilemap-common.h
src/graphics.h src/graphics.h
src/debuglogger.h src/gl-debug.h
src/global-ibo.h src/global-ibo.h
src/exception.h src/exception.h
src/filesystem.h src/filesystem.h
@ -180,7 +180,7 @@ set(MAIN_SOURCE
src/tilemap.cpp src/tilemap.cpp
src/autotiles.cpp src/autotiles.cpp
src/graphics.cpp src/graphics.cpp
src/debuglogger.cpp src/gl-debug.cpp
src/etc.cpp src/etc.cpp
src/config.cpp src/config.cpp
src/settingsmenu.cpp src/settingsmenu.cpp
@ -210,16 +210,21 @@ source_group("MKXP Source" FILES ${MAIN_SOURCE} ${MAIN_HEADERS})
## Setup embedded source ## ## Setup embedded source ##
set(EMBEDDED_INPUT set(EMBEDDED_INPUT
shader/common.h
shader/transSimple.frag shader/transSimple.frag
shader/trans.frag shader/trans.frag
shader/hue.frag shader/hue.frag
shader/sprite.frag shader/sprite.frag
shader/plane.frag shader/plane.frag
shader/gray.frag
shader/bitmapBlit.frag shader/bitmapBlit.frag
shader/flatColor.frag
shader/simple.frag shader/simple.frag
shader/simpleColor.frag shader/simpleColor.frag
shader/simpleAlpha.frag shader/simpleAlpha.frag
shader/simpleAlphaUni.frag
shader/flashMap.frag shader/flashMap.frag
shader/minimal.vert
shader/simple.vert shader/simple.vert
shader/simpleColor.vert shader/simpleColor.vert
shader/sprite.vert shader/sprite.vert
@ -230,6 +235,7 @@ set(EMBEDDED_INPUT
shader/blurV.vert shader/blurV.vert
shader/simpleMatrix.vert shader/simpleMatrix.vert
assets/liberation.ttf assets/liberation.ttf
assets/icon.png
) )
if (RGSS2) if (RGSS2)

View File

@ -4,8 +4,10 @@ mkxp is a project that seeks to provide a fully open source implementation of th
It is licensed under the GNU General Public License v2+. It is licensed under the GNU General Public License v2+.
[**Prebuilt binaries for Linux (32/64)**](http://ancurio.bplaced.net/mkxp/generic/) ## Prebuilt binaries
[**Prebuilt binaries for OSX by Ali**](https://app.box.com/mkxpmacbuilds) [**Linux (32bit/64bit)**](http://ancurio.bplaced.net/mkxp/generic/)
[**OSX**](https://app.box.com/mkxpmacbuilds) by Ali
[**Windows (mingw-w64 32bit)**](http://ancurio.bplaced.net/mkxp/mingw32/)
## Bindings ## Bindings
Bindings provide the glue code for an interpreted language environment to run game scripts in. Currently there are three bindings: Bindings provide the glue code for an interpreted language environment to run game scripts in. Currently there are three bindings:
@ -85,13 +87,11 @@ The syntax is: `--<option>=<value>`
Example: `./mkxp --gameFolder="my game" --vsync=true --fixedFramerate=60` Example: `./mkxp --gameFolder="my game" --vsync=true --fixedFramerate=60`
## Midi music (*ALPHA STATUS*) ## Midi music
mkxp doesn't come with a soundfont by default, so you will have to supply it yourself (set its path in the config). Playback has been tested and should work reasonably well with all RTP assets. mkxp doesn't come with a soundfont by default, so you will have to supply it yourself (set its path in the config). Playback has been tested and should work reasonably well with all RTP assets.
Known issues with midi playback: You can use this public domain soundfont: [GMGSx.sf2](https://www.dropbox.com/s/qxdvoxxcexsvn43/GMGSx.sf2?dl=0)
* Some songs' instruments become mute after looping
## Fonts ## Fonts
@ -101,7 +101,6 @@ If a requested font is not found, no error is generated. Instead, a built-in fon
## What doesn't work (yet) ## What doesn't work (yet)
* Text outline
* Movie playback * Movie playback
* wma audio files * wma audio files
* The Win32API ruby class (for obvious reasons) * The Win32API ruby class (for obvious reasons)

BIN
assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

50
assets/icon.svg Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="100"
height="100"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient3821">
<stop
id="stop3823"
style="stop-color:#00ff88;stop-opacity:1"
offset="0" />
<stop
id="stop3825"
style="stop-color:#00ff86;stop-opacity:1"
offset="1" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-323.76562,-436.67187)"
id="layer1">
<path
d="m 373.76195,439.49229 c -26.05643,0 -47.17591,21.12683 -47.17591,47.18326 0,26.05643 21.11948,47.17591 47.17591,47.17591 26.05643,0 47.18326,-21.11948 47.18326,-47.17591 0,-26.05643 -21.12683,-47.18326 -47.18326,-47.18326 z m 0,26.80867 c 11.25095,0 20.37459,9.12364 20.37459,20.37459 0,11.25094 -9.12364,20.36724 -20.37459,20.36724 -11.25094,0 -20.36724,-9.1163 -20.36724,-20.36724 0,-11.25095 9.1163,-20.37459 20.36724,-20.37459 z"
inkscape:connector-curvature="0"
id="path2985"
style="fill:#00ff87;fill-opacity:1;stroke:#000000;stroke-width:5.64083672;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -25,6 +25,7 @@
#include "eventthread.h" #include "eventthread.h"
#include "filesystem.h" #include "filesystem.h"
#include "util.h" #include "util.h"
#include "sdl-util.h"
#include "debugwriter.h" #include "debugwriter.h"
#include "graphics.h" #include "graphics.h"
#include "audio.h" #include "audio.h"
@ -192,8 +193,11 @@ RB_METHOD(mriP)
RB_METHOD(mkxpDataDirectory) RB_METHOD(mkxpDataDirectory)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
const std::string &path = shState->config().customDataPath;
const char *s = path.empty() ? "." : path.c_str();
return rb_str_new_cstr(shState->config().customDataPath.c_str()); return rb_str_new_cstr(s);
} }
RB_METHOD(mkxpPuts) RB_METHOD(mkxpPuts)
@ -336,7 +340,7 @@ static void runCustomScript(const std::string &filename)
{ {
std::string scriptData; std::string scriptData;
if (!readFile(filename.c_str(), scriptData)) if (!readFileSDL(filename.c_str(), scriptData))
{ {
showMsg(std::string("Unable to open '") + filename + "'"); showMsg(std::string("Unable to open '") + filename + "'");
return; return;
@ -346,7 +350,7 @@ static void runCustomScript(const std::string &filename)
newStringUTF8(filename.c_str(), filename.size()), NULL); newStringUTF8(filename.c_str(), filename.size()), NULL);
} }
VALUE kernelLoadDataInt(const char *filename); VALUE kernelLoadDataInt(const char *filename, bool rubyExc);
struct BacktraceData struct BacktraceData
{ {
@ -373,7 +377,19 @@ static void runRMXPScripts(BacktraceData &btData)
return; return;
} }
VALUE scriptArray = kernelLoadDataInt(scriptPack.c_str()); VALUE scriptArray;
/* We checked if Scripts.rxdata exists, but something might
* still go wrong */
try
{
scriptArray = kernelLoadDataInt(scriptPack.c_str(), false);
}
catch (const Exception &e)
{
showMsg(std::string("Failed to read script data: ") + e.msg);
return;
}
if (!RB_TYPE_P(scriptArray, RUBY_T_ARRAY)) if (!RB_TYPE_P(scriptArray, RUBY_T_ARRAY))
{ {
@ -540,6 +556,13 @@ static void showExc(VALUE exc, const BacktraceData &btData)
static void mriBindingExecute() static void mriBindingExecute()
{ {
/* Normally only a ruby executable would do a sysinit,
* but not doing it will lead to crashes due to closed
* stdio streams on some platforms (eg. Windows) */
int argc = 0;
char **argv = 0;
ruby_sysinit(&argc, &argv);
ruby_setup(); ruby_setup();
rb_enc_set_default_external(rb_enc_from_encoding(rb_utf8_encoding())); rb_enc_set_default_external(rb_enc_from_encoding(rb_utf8_encoding()));

View File

@ -40,7 +40,7 @@ fileIntFreeInstance(void *inst)
DEF_TYPE_CUSTOMFREE(FileInt, fileIntFreeInstance); DEF_TYPE_CUSTOMFREE(FileInt, fileIntFreeInstance);
static VALUE static VALUE
fileIntForPath(const char *path) fileIntForPath(const char *path, bool rubyExc)
{ {
SDL_RWops *ops = SDL_AllocRW(); SDL_RWops *ops = SDL_AllocRW();
@ -51,7 +51,11 @@ fileIntForPath(const char *path)
catch (const Exception &e) catch (const Exception &e)
{ {
SDL_FreeRW(ops); SDL_FreeRW(ops);
raiseRbExc(e);
if (rubyExc)
raiseRbExc(e);
else
throw e;
} }
VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt")); VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));
@ -119,11 +123,11 @@ RB_METHOD(fileIntBinmode)
} }
VALUE VALUE
kernelLoadDataInt(const char *filename) kernelLoadDataInt(const char *filename, bool rubyExc)
{ {
rb_gc_start(); rb_gc_start();
VALUE port = fileIntForPath(filename); VALUE port = fileIntForPath(filename, rubyExc);
VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal")); VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal"));
@ -142,7 +146,7 @@ RB_METHOD(kernelLoadData)
const char *filename; const char *filename;
rb_get_args(argc, argv, "z", &filename RB_ARG_END); rb_get_args(argc, argv, "z", &filename RB_ARG_END);
return kernelLoadDataInt(filename); return kernelLoadDataInt(filename, true);
} }
RB_METHOD(kernelSaveData) RB_METHOD(kernelSaveData)

View File

@ -38,17 +38,22 @@ static int getButtonArg(int argc, VALUE *argv)
{ {
int num; int num;
if (rgssVer >= 3) rb_check_argc(argc, 1);
{
ID sym;
rb_get_args(argc, argv, "n", &sym RB_ARG_END);
if (FIXNUM_P(argv[0]))
{
num = FIX2INT(argv[0]);
}
else if (SYMBOL_P(argv[0]) && rgssVer >= 3)
{
VALUE symHash = getRbData()->buttoncodeHash; VALUE symHash = getRbData()->buttoncodeHash;
num = FIX2INT(rb_hash_lookup2(symHash, ID2SYM(sym), INT2FIX(Input::None))); num = FIX2INT(rb_hash_lookup2(symHash, argv[0], INT2FIX(Input::None)));
} }
else else
{ {
rb_get_args(argc, argv, "i", &num RB_ARG_END); // FIXME: RMXP allows only few more types that
// don't make sense (symbols in pre 3, floats)
num = 0;
} }
return num; return num;

View File

@ -192,7 +192,7 @@ static void
runCustomScript(mrb_state *mrb, mrbc_context *ctx, const char *filename) runCustomScript(mrb_state *mrb, mrbc_context *ctx, const char *filename)
{ {
/* Execute custom script */ /* Execute custom script */
FILE *f = fopen(filename, "r"); FILE *f = fopen(filename, "rb");
if (!f) if (!f)
{ {
@ -217,7 +217,7 @@ static void
runMrbFile(mrb_state *mrb, const char *filename) runMrbFile(mrb_state *mrb, const char *filename)
{ {
/* Execute compiled script */ /* Execute compiled script */
FILE *f = fopen(filename, "r"); FILE *f = fopen(filename, "rb");
if (!f) if (!f)
{ {

View File

@ -40,20 +40,26 @@ MRB_FUNCTION(inputUpdate)
static mrb_int getButtonArg(mrb_state *mrb) static mrb_int getButtonArg(mrb_state *mrb)
{ {
mrb_int num; mrb_int num;
mrb_value arg;
if (rgssVer >= 3) mrb_get_args(mrb, "o", &arg);
if (mrb_fixnum_p(arg))
{
num = mrb_fixnum(arg);
}
else if (mrb_symbol_p(arg) && rgssVer >= 3)
{ {
mrb_sym sym;
mrb_get_args(mrb, "n", &sym);
mrb_value symHash = getMrbData(mrb)->buttoncodeHash; mrb_value symHash = getMrbData(mrb)->buttoncodeHash;
mrb_value numVal = mrb_hash_fetch(mrb, symHash, mrb_symbol_value(sym), mrb_value numVal = mrb_hash_fetch(mrb, symHash, arg,
mrb_fixnum_value(Input::None)); mrb_fixnum_value(Input::None));
num = mrb_fixnum(numVal); num = mrb_fixnum(numVal);
} }
else else
{ {
mrb_get_args(mrb, "i", &num); // FIXME: RMXP allows only few more types that
// don't make sense (symbols in pre 3, floats)
num = 0;
} }
return num; return num;

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,14 @@
# Lines starting with '#' are comments # Lines starting with '#' are comments.
#
# About filesystem paths specified in this config:
# The "gameFolder" path is resolved either relative
# to the directory containing the mkxp executable
# (the default behavior), or relative to the current
# working directory (when compiled with
# -DWORKDIR_CURRENT). All other paths are resolved
# relative to gameFolder and ignoring both RTPs and
# encrypted archives.
# Specify the RGSS version to run under. # Specify the RGSS version to run under.
# Possible values are 0, 1, 2, 3. If set to 0, # Possible values are 0, 1, 2, 3. If set to 0,
@ -17,6 +27,14 @@
# debugMode=false # debugMode=false
# Continuously print average FPS to console.
# This setting does not affect the window title
# FPS display toggled via F2
# (default: disabled)
#
# printFPS=false
# Game window is resizable # Game window is resizable
# (default: disabled) # (default: disabled)
# #
@ -80,12 +98,32 @@
# frameSkip=true # frameSkip=true
# Use a fixed framerate that is approx. equal to the
# native screen refresh rate. This is different from
# "fixedFramerate" because the actual frame rate is
# reported back to the game, ensuring correct timers.
# If the screen refresh rate cannot be determined,
# this option is force-disabled
# (default: disabled)
#
# syncToRefreshrate=false
# Don't use alpha blending when rendering text # Don't use alpha blending when rendering text
# (default: disabled) # (default: disabled)
# #
# solidFonts=false # solidFonts=false
# Work around buggy graphics drivers which don't
# properly synchronize texture access, most
# apparent when text doesn't show up or the map
# tileset doesn't render at all
# (default: disabled)
#
# subImageFix=false
# Set the base path of the game to '/path/to/game' # Set the base path of the game to '/path/to/game'
# (default: executable directory) # (default: executable directory)
# #
@ -218,6 +256,19 @@
# SE.sourceCount=6 # SE.sourceCount=6
# The Windows game executable name minus ".exe". By default
# this is "Game", but some developers manually rename it.
# mkxp needs this name because both the .ini (game
# configuration) and .rgssad (encrypted data archive) must
# carry the same name minus their extension, and we cannot
# guess the executable's name.
# You could just as well rename them both to "Game.ini" and
# "Game.rgssad", but specifying the executable name here
# is a tiny bit less intrusive.
#
# execName=Game
# Give a hint on which language the game title as # Give a hint on which language the game title as
# specified in the Game.ini is, useful if the encoding # specified in the Game.ini is, useful if the encoding
# is being falsely detected. Relevant only if mkxp was # is being falsely detected. Relevant only if mkxp was

View File

@ -103,9 +103,9 @@ HEADERS += \
src/glstate.h \ src/glstate.h \
src/quad.h \ src/quad.h \
src/tilemap.h \ src/tilemap.h \
src/flashmap.h \ src/tilemap-common.h \
src/graphics.h \ src/graphics.h \
src/debuglogger.h \ src/gl-debug.h \
src/global-ibo.h \ src/global-ibo.h \
src/exception.h \ src/exception.h \
src/filesystem.h \ src/filesystem.h \
@ -158,7 +158,7 @@ SOURCES += \
src/tilemap.cpp \ src/tilemap.cpp \
src/autotiles.cpp \ src/autotiles.cpp \
src/graphics.cpp \ src/graphics.cpp \
src/debuglogger.cpp \ src/gl-debug.cpp \
src/etc.cpp \ src/etc.cpp \
src/config.cpp \ src/config.cpp \
src/settingsmenu.cpp \ src/settingsmenu.cpp \
@ -183,16 +183,21 @@ SOURCES += \
src/fluid-fun.cpp src/fluid-fun.cpp
EMBED = \ EMBED = \
shader/common.h \
shader/transSimple.frag \ shader/transSimple.frag \
shader/trans.frag \ shader/trans.frag \
shader/hue.frag \ shader/hue.frag \
shader/sprite.frag \ shader/sprite.frag \
shader/plane.frag \ shader/plane.frag \
shader/gray.frag \
shader/bitmapBlit.frag \ shader/bitmapBlit.frag \
shader/flatColor.frag \
shader/simple.frag \ shader/simple.frag \
shader/simpleColor.frag \ shader/simpleColor.frag \
shader/simpleAlpha.frag \ shader/simpleAlpha.frag \
shader/simpleAlphaUni.frag \
shader/flashMap.frag \ shader/flashMap.frag \
shader/minimal.vert \
shader/simple.vert \ shader/simple.vert \
shader/simpleColor.vert \ shader/simpleColor.vert \
shader/sprite.vert \ shader/sprite.vert \
@ -202,7 +207,8 @@ EMBED = \
shader/blurV.vert \ shader/blurV.vert \
shader/simpleMatrix.vert \ shader/simpleMatrix.vert \
shader/tilemapvx.vert \ shader/tilemapvx.vert \
assets/liberation.ttf assets/liberation.ttf \
assets/icon.png
SHARED_FLUID { SHARED_FLUID {
DEFINES += SHARED_FLUID DEFINES += SHARED_FLUID

View File

@ -0,0 +1,43 @@
--- a/common.mk
+++ b/common.mk
@@ -95,6 +95,7 @@ COMMONOBJS = array.$(OBJEXT) \
vm_trace.$(OBJEXT) \
thread.$(OBJEXT) \
cont.$(OBJEXT) \
+ ext/zlib/zlib.$(OBJEXT) \
$(BUILTIN_ENCOBJS) \
$(BUILTIN_TRANSOBJS) \
$(MISSING)
diff --git a/ruby-2.1.5.orig/configure b/ruby-2.1.5/configure
index d0f1f68..45ab642 100755
--- a/configure
+++ b/configure
@@ -2838,6 +2838,8 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+LIBS="$LIBS -lz"
+
{ # environment section
--- a/configure.in
+++ b/configure.in
@@ -31,6 +31,8 @@ rm() {
}
])])])
+LIBS="$LIBS -lz"
+
{ # environment section
AC_ARG_WITH(baseruby,
--- a/inits.c
+++ b/inits.c
@@ -61,5 +61,6 @@ rb_call_inits(void)
CALL(Complex);
CALL(version);
CALL(vm_trace);
+ CALL(zlib);
}
#undef CALL

View File

@ -6,7 +6,7 @@ uniform sampler2D destination;
uniform vec4 subRect; uniform vec4 subRect;
uniform float opacity; uniform lowp float opacity;
varying vec2 v_texCoord; varying vec2 v_texCoord;

View File

@ -6,7 +6,7 @@ varying vec2 v_blurCoord[2];
void main() void main()
{ {
vec4 frag = vec4(0, 0, 0, 0); lowp vec4 frag = vec4(0, 0, 0, 0);
frag += texture2D(texture, v_texCoord); frag += texture2D(texture, v_texCoord);
frag += texture2D(texture, v_blurCoord[0]); frag += texture2D(texture, v_blurCoord[0]);

15
shader/common.h Normal file
View File

@ -0,0 +1,15 @@
#ifdef GLSLES
#ifdef FRAGMENT_SHADER
/* Only the fragment shader has no default float precision */
precision mediump float;
#endif
#else
/* Desktop GLSL doesn't know about these */
#define highp
#define mediump
#define lowp
#endif

View File

@ -1,7 +1,7 @@
uniform float alpha; uniform lowp float alpha;
varying vec4 v_color; varying lowp vec4 v_color;
void main() void main()
{ {

7
shader/flatColor.frag Normal file
View File

@ -0,0 +1,7 @@
uniform lowp vec4 color;
void main()
{
gl_FragColor = color;
}

19
shader/gray.frag Normal file
View File

@ -0,0 +1,19 @@
uniform sampler2D texture;
uniform lowp float gray;
varying vec2 v_texCoord;
const vec3 lumaF = vec3(.299, .587, .114);
void main()
{
/* Sample source color */
vec4 frag = texture2D(texture, v_texCoord);
/* Apply gray */
float luma = dot(frag.rgb, lumaF);
frag.rgb = mix(frag.rgb, vec3(luma), gray);
gl_FragColor = frag;
}

View File

@ -29,7 +29,11 @@ void main ()
/* Make the user's adjustments */ /* Make the user's adjustments */
hue += hueAdjust; hue += hueAdjust;
// Convert back to YIQ /* Remember old I and color */
float IOriginal = I;
vec4 coOriginal = color;
/* Convert back to YIQ */
Q = chroma * sin (hue); Q = chroma * sin (hue);
I = chroma * cos (hue); I = chroma * cos (hue);
@ -40,5 +44,5 @@ void main ()
color.b = dot (yIQ, kYIQToB); color.b = dot (yIQ, kYIQToB);
/* Save the result */ /* Save the result */
gl_FragColor = color; gl_FragColor = (IOriginal == 0.0) ? coOriginal : color;
} }

8
shader/minimal.vert Normal file
View File

@ -0,0 +1,8 @@
uniform mat4 projMat;
attribute vec2 position;
void main()
{
gl_Position = projMat * vec4(position, 0, 1);
}

View File

@ -1,11 +1,11 @@
uniform sampler2D texture; uniform sampler2D texture;
uniform vec4 tone; uniform lowp vec4 tone;
uniform float opacity; uniform lowp float opacity;
uniform vec4 color; uniform lowp vec4 color;
uniform vec4 flash; uniform lowp vec4 flash;
varying vec2 v_texCoord; varying vec2 v_texCoord;

View File

@ -2,7 +2,7 @@
uniform sampler2D texture; uniform sampler2D texture;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying vec4 v_color; varying lowp vec4 v_color;
void main() void main()
{ {

View File

@ -0,0 +1,11 @@
uniform sampler2D texture;
uniform lowp float alpha;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(texture, v_texCoord);
gl_FragColor.a *= alpha;
}

View File

@ -1,5 +1,5 @@
varying vec4 v_color; varying lowp vec4 v_color;
void main() void main()
{ {

View File

@ -6,10 +6,10 @@ uniform vec2 translation;
attribute vec2 position; attribute vec2 position;
attribute vec2 texCoord; attribute vec2 texCoord;
attribute vec4 color; attribute lowp vec4 color;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying vec4 v_color; varying lowp vec4 v_color;
void main() void main()
{ {

View File

@ -6,10 +6,10 @@ uniform vec2 texSizeInv;
attribute vec2 position; attribute vec2 position;
attribute vec2 texCoord; attribute vec2 texCoord;
attribute vec4 color; attribute lowp vec4 color;
varying vec2 v_texCoord; varying vec2 v_texCoord;
varying vec4 v_color; varying lowp vec4 v_color;
void main() void main()
{ {

View File

@ -1,13 +1,13 @@
uniform sampler2D texture; uniform sampler2D texture;
uniform vec4 tone; uniform lowp vec4 tone;
uniform float opacity; uniform lowp float opacity;
uniform vec4 color; uniform lowp vec4 color;
uniform float bushDepth; uniform float bushDepth;
uniform float bushOpacity; uniform lowp float bushOpacity;
varying vec2 v_texCoord; varying vec2 v_texCoord;
@ -32,7 +32,7 @@ void main()
frag.rgb = mix(frag.rgb, color.rgb, color.a); frag.rgb = mix(frag.rgb, color.rgb, color.a);
/* Apply bush alpha by mathematical if */ /* Apply bush alpha by mathematical if */
float underBush = float(v_texCoord.y < bushDepth); lowp float underBush = float(v_texCoord.y < bushDepth);
frag.a *= clamp(bushOpacity + underBush, 0.0, 1.0); frag.a *= clamp(bushOpacity + underBush, 0.0, 1.0);
gl_FragColor = frag; gl_FragColor = frag;

View File

@ -18,8 +18,9 @@ const float atAniOffset = 32.0*3.0;
void main() void main()
{ {
vec2 tex = texCoord; vec2 tex = texCoord;
if (tex.x <= atAreaW && tex.y <= atAreaH)
tex.x += aniIndex * atAniOffset; lowp float pred = float(tex.x <= atAreaW && tex.y <= atAreaH);
tex.x += aniIndex * atAniOffset * pred;
gl_Position = projMat * vec4(position + translation, 0, 1); gl_Position = projMat * vec4(position + translation, 0, 1);

View File

@ -18,14 +18,15 @@ const float atAreaCW = 4.0*32.0;
void main() void main()
{ {
vec2 tex = texCoord; vec2 tex = texCoord;
lowp float pred;
/* Type A autotiles shift horizontally */ /* Type A autotiles shift horizontally */
if (tex.x <= atAreaA.x && tex.y <= atAreaA.y) pred = float(tex.x <= atAreaA.x && tex.y <= atAreaA.y);
tex.x += aniOffset.x; tex.x += aniOffset.x * pred;
/* Type C autotiles shift vertically */ /* Type C autotiles shift vertically */
if (tex.x >= atAreaCX && tex.x <= (atAreaCX+atAreaCW) && tex.y <= atAreaA.y) pred = float(tex.x >= atAreaCX && tex.x <= (atAreaCX+atAreaCW) && tex.y <= atAreaA.y);
tex.y += aniOffset.y; tex.y += aniOffset.y * pred;
gl_Position = projMat * vec4(position + translation, 0, 1); gl_Position = projMat * vec4(position + translation, 0, 1);

View File

@ -14,7 +14,7 @@ void main()
{ {
float transV = texture2D(transMap, v_texCoord).r; float transV = texture2D(transMap, v_texCoord).r;
float cTransV = clamp(transV, prog, prog+vague); float cTransV = clamp(transV, prog, prog+vague);
float alpha = (cTransV - prog) / vague; lowp float alpha = (cTransV - prog) / vague;
vec4 newFrag = texture2D(currentScene, v_texCoord); vec4 newFrag = texture2D(currentScene, v_texCoord);
vec4 oldFrag = texture2D(frozenScene, v_texCoord); vec4 oldFrag = texture2D(frozenScene, v_texCoord);

View File

@ -238,5 +238,6 @@ inline ALenum chooseALFormat(int sampleSize, int channelCount)
#define AUDIO_SLEEP 10 #define AUDIO_SLEEP 10
#define STREAM_BUF_SIZE 32768 #define STREAM_BUF_SIZE 32768
#define GLOBAL_VOLUME 0.8
#endif // ALUTIL_H #endif // ALUTIL_H

View File

@ -23,10 +23,13 @@
#include "sharedstate.h" #include "sharedstate.h"
#include "sharedmidistate.h" #include "sharedmidistate.h"
#include "eventthread.h"
#include "filesystem.h" #include "filesystem.h"
#include "exception.h"
#include "aldatasource.h" #include "aldatasource.h"
#include "fluid-fun.h" #include "fluid-fun.h"
#include "sdl-util.h" #include "sdl-util.h"
#include "debugwriter.h"
#include <SDL_mutex.h> #include <SDL_mutex.h>
#include <SDL_thread.h> #include <SDL_thread.h>
@ -122,6 +125,9 @@ void ALStream::stop()
void ALStream::play(float offset) void ALStream::play(float offset)
{ {
if (!source)
return;
checkStopped(); checkStopped();
switch (state) switch (state)
@ -195,8 +201,8 @@ void ALStream::closeSource()
void ALStream::openSource(const std::string &filename) void ALStream::openSource(const std::string &filename)
{ {
const char *ext; char ext[8];
shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext); shState->fileSystem().openRead(srcOps, filename.c_str(), false, ext, sizeof(ext));
needsRewind.clear(); needsRewind.clear();
/* Try to read ogg file signature */ /* Try to read ogg file signature */
@ -204,24 +210,36 @@ void ALStream::openSource(const std::string &filename)
SDL_RWread(&srcOps, sig, 1, 4); SDL_RWread(&srcOps, sig, 1, 4);
SDL_RWseek(&srcOps, 0, RW_SEEK_SET); SDL_RWseek(&srcOps, 0, RW_SEEK_SET);
if (!strcmp(sig, "OggS")) try
{ {
source = createVorbisSource(srcOps, looped); if (!strcmp(sig, "OggS"))
return;
}
if (!strcmp(sig, "MThd"))
{
shState->midiState().initIfNeeded(shState->config());
if (HAVE_FLUID)
{ {
source = createMidiSource(srcOps, looped); source = createVorbisSource(srcOps, looped);
return; return;
} }
}
source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped); if (!strcmp(sig, "MThd"))
{
shState->midiState().initIfNeeded(shState->config());
if (HAVE_FLUID)
{
source = createMidiSource(srcOps, looped);
return;
}
}
source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped);
}
catch (const Exception &e)
{
char buf[512];
snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s.%s: %s",
filename.c_str(), ext, e.msg.c_str());
buf[sizeof(buf)-1] = '\0';
Debug() << buf;
}
} }
void ALStream::stopStream() void ALStream::stopStream()
@ -361,6 +379,8 @@ void ALStream::streamData()
* refill and queue them up again */ * refill and queue them up again */
while (true) while (true)
{ {
shState->rtData().syncPoint.passSecondarySync();
ALint procBufs = AL::Source::getProcBufferCount(alSrc); ALint procBufs = AL::Source::getProcBufferCount(alSrc);
while (procBufs--) while (procBufs--)

View File

@ -25,6 +25,7 @@
#include "soundemitter.h" #include "soundemitter.h"
#include "sharedstate.h" #include "sharedstate.h"
#include "sharedmidistate.h" #include "sharedmidistate.h"
#include "eventthread.h"
#include "sdl-util.h" #include "sdl-util.h"
#include <string> #include <string>
@ -40,6 +41,8 @@ struct AudioPrivate
SoundEmitter se; SoundEmitter se;
SyncPoint &syncPoint;
/* The 'MeWatch' is responsible for detecting /* The 'MeWatch' is responsible for detecting
* a playing ME, quickly fading out the BGM and * a playing ME, quickly fading out the BGM and
* keeping it paused/stopped while the ME plays, * keeping it paused/stopped while the ME plays,
@ -60,11 +63,12 @@ struct AudioPrivate
MeWatchState state; MeWatchState state;
} meWatch; } meWatch;
AudioPrivate(const Config &conf) AudioPrivate(RGSSThreadData &rtData)
: bgm(ALStream::Looped, "bgm"), : bgm(ALStream::Looped, "bgm"),
bgs(ALStream::Looped, "bgs"), bgs(ALStream::Looped, "bgs"),
me(ALStream::NotLooped, "me"), me(ALStream::NotLooped, "me"),
se(conf) se(rtData.config),
syncPoint(rtData.syncPoint)
{ {
meWatch.state = MeNotPlaying; meWatch.state = MeNotPlaying;
meWatch.thread = createSDLThread meWatch.thread = createSDLThread
@ -84,6 +88,8 @@ struct AudioPrivate
while (true) while (true)
{ {
syncPoint.passSecondarySync();
if (meWatch.termReq) if (meWatch.termReq)
return; return;
@ -231,8 +237,8 @@ struct AudioPrivate
} }
}; };
Audio::Audio(const Config &conf) Audio::Audio(RGSSThreadData &rtData)
: p(new AudioPrivate(conf)) : p(new AudioPrivate(rtData))
{} {}

View File

@ -33,7 +33,7 @@
* quite make out their meaning yet) */ * quite make out their meaning yet) */
struct AudioPrivate; struct AudioPrivate;
struct Config; struct RGSSThreadData;
class Audio class Audio
{ {
@ -70,7 +70,7 @@ public:
void reset(); void reset();
private: private:
Audio(const Config &conf); Audio(RGSSThreadData &rtData);
~Audio(); ~Audio();
friend struct SharedStatePrivate; friend struct SharedStatePrivate;

View File

@ -252,7 +252,7 @@ float AudioStream::playingOffset()
void AudioStream::updateVolume() void AudioStream::updateVolume()
{ {
float vol = 1.0; float vol = GLOBAL_VOLUME;
for (size_t i = 0; i < VolumeTypeCount; ++i) for (size_t i = 0; i < VolumeTypeCount; ++i)
vol *= volumes[i]; vol *= volumes[i];

View File

@ -4,196 +4,196 @@ extern const StaticRect autotileRects[] =
{ {
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 }, { 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 }, { 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 }, { 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 }, { 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 }, { 16.5, 64.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 }, { 0.5, 80.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 }, { 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 }, { 0.5, 80.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 }, { 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 }, { 16.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 }, { 0.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 }, { 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 }, { 0.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 }, { 80.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 32.5, 48.5, 15, 15 }, { 32.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 48.5, 15, 15 }, { 48.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 }, { 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 }, { 48.5, 32.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 80.5, 16.5, 15, 15 }, { 80.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 64.5, 15, 15 }, { 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 }, { 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 }, { 64.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 64.5, 15, 15 }, { 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 }, { 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 }, { 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 }, { 64.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 }, { 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 32.5, 96.5, 15, 15 }, { 32.5, 96.5, 15, 15 },
{ 48.5, 96.5, 15, 15 }, { 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 }, { 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 48.5, 96.5, 15, 15 }, { 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 }, { 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 96.5, 15, 15 }, { 32.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 }, { 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 }, { 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 0.5, 64.5, 15, 15 }, { 0.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 }, { 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 }, { 0.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 }, { 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 }, { 48.5, 32.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 }, { 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 }, { 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 }, { 16.5, 32.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 16.5, 48.5, 15, 15 }, { 16.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 }, { 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 }, { 16.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 48.5, 15, 15 }, { 0.5, 48.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 32.5, 15, 15 }, { 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 }, { 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 48.5, 15, 15 }, { 64.5, 48.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 32.5, 15, 15 }, { 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 }, { 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 }, { 64.5, 16.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 96.5, 15, 15 }, { 64.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 }, { 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 }, { 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 }, { 64.5, 0.5, 15, 15 },
{ 80.5, 96.5, 15, 15 }, { 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 }, { 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 }, { 0.5, 96.5, 15, 15 },
{ 16.5, 96.5, 15, 15 }, { 16.5, 96.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 }, { 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 }, { 0.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 }, { 80.5, 0.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 }, { 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 }, { 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 }, { 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 }, { 0.5, 48.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 }, { 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 }, { 16.5, 32.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 }, { 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 }, { 0.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 }, { 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 }, { 0.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 32.5, 15, 15 }, { 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 }, { 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 }, { 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 }, { 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 }, { 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 }, { 0.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 0.5, 15, 15 }, { 0.5, 0.5, 15, 15 },
{ 16.5, 0.5, 15, 15 }, { 16.5, 0.5, 15, 15 },
{ 16.5, 16.5, 15, 15 }, { 0.5, 16.5, 15, 15 },
{ 0.5, 16.5, 15, 15 } { 16.5, 16.5, 15, 15 }
}; };
extern const int autotileRectsN = sizeof(autotileRects) / sizeof(autotileRects[0]); extern const int autotileRectsN = sizeof(autotileRects) / sizeof(autotileRects[0]);

View File

@ -52,6 +52,8 @@
"Operation not supported for mega surfaces"); \ "Operation not supported for mega surfaces"); \
} }
#define OUTLINE_SIZE 1
/* Normalize (= ensure width and /* Normalize (= ensure width and
* height are positive) */ * height are positive) */
static IntRect normalizedRect(const IntRect &rect) static IntRect normalizedRect(const IntRect &rect)
@ -248,9 +250,10 @@ struct BitmapPrivate
Bitmap::Bitmap(const char *filename) Bitmap::Bitmap(const char *filename)
{ {
SDL_RWops ops; SDL_RWops ops;
const char *extension; char ext[8];
shState->fileSystem().openRead(ops, filename, FileSystem::Image, false, &extension);
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, extension); shState->fileSystem().openRead(ops, filename, false, ext, sizeof(ext));
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, ext);
if (!imgSurf) if (!imgSurf)
throw Exception(Exception::SDLError, "Error loading image '%s': %s", throw Exception(Exception::SDLError, "Error loading image '%s': %s",
@ -317,6 +320,7 @@ Bitmap::Bitmap(const char *filename)
/* Mega surface */ /* Mega surface */
p = new BitmapPrivate(this); p = new BitmapPrivate(this);
p->megaSurface = imgSurf; p->megaSurface = imgSurf;
SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE);
} }
else if (isCrop) else if (isCrop)
{ {
@ -487,14 +491,46 @@ void Bitmap::stretchBlt(const IntRect &destRect,
if (opacity == 0) if (opacity == 0)
return; return;
if (source.megaSurface()) SDL_Surface *srcSurf = source.megaSurface();
if (srcSurf && shState->config().subImageFix)
{ {
/* Blit from software surface, for broken GL drivers */
Vec2i gpTexSize;
shState->ensureTexSize(sourceRect.w, sourceRect.h, gpTexSize);
shState->bindTex();
GLMeta::subRectImageUpload(srcSurf->w, sourceRect.x, sourceRect.y, 0, 0,
sourceRect.w, sourceRect.h, srcSurf, GL_RGBA);
GLMeta::subRectImageEnd();
SimpleShader &shader = shState->shaders().simple;
shader.bind();
shader.setTranslation(Vec2i());
shader.setTexSize(gpTexSize);
p->pushSetViewport(shader);
p->bindFBO();
Quad &quad = shState->gpQuad();
quad.setTexRect(FloatRect(0, 0, sourceRect.w, sourceRect.h));
quad.setPosRect(destRect);
p->blitQuad(quad);
p->popViewport();
p->addTaintedArea(destRect);
p->onModified();
return;
}
else if (srcSurf)
{
/* Blit from software surface */
/* Don't do transparent blits for now */ /* Don't do transparent blits for now */
if (opacity < 255) if (opacity < 255)
source.ensureNonMega(); source.ensureNonMega();
SDL_Surface *srcSurf = source.megaSurface();
SDL_Rect srcRect = sourceRect; SDL_Rect srcRect = sourceRect;
SDL_Rect dstRect = destRect; SDL_Rect dstRect = destRect;
SDL_Rect btmRect = { 0, 0, width(), height() }; SDL_Rect btmRect = { 0, 0, width(), height() };
@ -510,26 +546,25 @@ void Bitmap::stretchBlt(const IntRect &destRect,
SDL_Surface *blitTemp = SDL_Surface *blitTemp =
SDL_CreateRGBSurface(0, destRect.w, destRect.h, bpp, rMask, gMask, bMask, aMask); SDL_CreateRGBSurface(0, destRect.w, destRect.h, bpp, rMask, gMask, bMask, aMask);
// FXIME: This is supposed to be a scaled blit, put SDL2 for some reason SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0);
// makes the source surface unusable after BlitScaled() is called. Investigate!
SDL_BlitSurface(srcSurf, &srcRect, blitTemp, 0);
TEX::bind(p->gl.tex); TEX::bind(p->gl.tex);
if (bltRect.w == dstRect.w && bltRect.h == dstRect.h) if (bltRect.w == dstRect.w && bltRect.h == dstRect.h)
{ {
/* Dest rectangle lies within bounding box */
TEX::uploadSubImage(destRect.x, destRect.y, TEX::uploadSubImage(destRect.x, destRect.y,
destRect.w, destRect.h, destRect.w, destRect.h,
blitTemp->pixels, GL_RGBA); blitTemp->pixels, GL_RGBA);
} }
else else
{ {
/* Clipped blit */
GLMeta::subRectImageUpload(blitTemp->w, bltRect.x - dstRect.x, bltRect.y - dstRect.y, GLMeta::subRectImageUpload(blitTemp->w, bltRect.x - dstRect.x, bltRect.y - dstRect.y,
bltRect.x, bltRect.y, bltRect.w, bltRect.h, blitTemp, GL_RGBA); bltRect.x, bltRect.y, bltRect.w, bltRect.h, blitTemp, GL_RGBA);
GLMeta::subRectImageEnd(); GLMeta::subRectImageEnd();
} }
SDL_FreeSurface(blitTemp); SDL_FreeSurface(blitTemp);
p->onModified(); p->onModified();
@ -581,7 +616,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
} }
p->addTaintedArea(destRect); p->addTaintedArea(destRect);
p->onModified(); p->onModified();
} }
@ -1057,6 +1091,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
TTF_Font *font = p->font->getSdlFont(); TTF_Font *font = p->font->getSdlFont();
const Color &fontColor = p->font->getColor(); const Color &fontColor = p->font->getColor();
const Color &outColor = p->font->getOutColor();
SDL_Color c = fontColor.toSDLColor(); SDL_Color c = fontColor.toSDLColor();
c.a = 255; c.a = 255;
@ -1072,11 +1107,34 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888); p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888);
// While real outlining is not yet here, use shadow if (p->font->getShadow())
// as a replacement to at least make text legible
if (p->font->getShadow() || p->font->getOutline())
applyShadow(txtSurf, *p->format, c); applyShadow(txtSurf, *p->format, c);
/* outline using TTF_Outline and blending it together with SDL_BlitSurface
* FIXME: outline is forced to have the same opacity as the font color */
if (p->font->getOutline())
{
SDL_Color co = outColor.toSDLColor();
co.a = 255;
SDL_Surface *outline;
/* set the next font render to render the outline */
TTF_SetFontOutline(font, OUTLINE_SIZE);
if (shState->rtData().config.solidFonts)
outline = TTF_RenderUTF8_Solid(font, str, co);
else
outline = TTF_RenderUTF8_Blended(font, str, co);
p->ensureFormat(outline, SDL_PIXELFORMAT_ABGR8888);
SDL_Rect outRect = {OUTLINE_SIZE, OUTLINE_SIZE, txtSurf->w, txtSurf->h};
SDL_SetSurfaceBlendMode(txtSurf, SDL_BLENDMODE_BLEND);
SDL_BlitSurface(txtSurf, NULL, outline, &outRect);
SDL_FreeSurface(txtSurf);
txtSurf = outline;
/* reset outline to 0 */
TTF_SetFontOutline(font, 0);
}
int alignX = rect.x; int alignX = rect.x;
switch (align) switch (align)
@ -1113,7 +1171,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
if (fastBlit) if (fastBlit)
{ {
if (squeeze == 1.0) if (squeeze == 1.0 && !shState->config().subImageFix)
{ {
/* Even faster: upload directly to bitmap texture. /* Even faster: upload directly to bitmap texture.
* We have to make sure the posRect lies within the texture * We have to make sure the posRect lies within the texture

View File

@ -1 +1 @@
#include "../liberation.ttf.xxd" #include "liberation.ttf.xxd"

View File

@ -32,6 +32,7 @@
#include "debugwriter.h" #include "debugwriter.h"
#include "util.h" #include "util.h"
#include "sdl-util.h"
#ifdef INI_ENCODING #ifdef INI_ENCODING
extern "C" { extern "C" {
@ -123,6 +124,10 @@ static bool validUtf8(const char *string)
static std::string prefPath(const char *org, const char *app) static std::string prefPath(const char *org, const char *app)
{ {
char *path = SDL_GetPrefPath(org, app); char *path = SDL_GetPrefPath(org, app);
if (!path)
return std::string();
std::string str(path); std::string str(path);
SDL_free(path); SDL_free(path);
@ -135,65 +140,47 @@ namespace po = boost::program_options;
#define CONF_FILE "mkxp.conf" #define CONF_FILE "mkxp.conf"
Config::Config() Config::Config()
: rgssVersion(0), {}
debugMode(false),
winResizable(false),
fullscreen(false),
fixedAspectRatio(true),
smoothScaling(false),
vsync(false),
defScreenW(0),
defScreenH(0),
fixedFramerate(0),
frameSkip(true),
solidFonts(false),
gameFolder("."),
anyAltToggleFS(false),
enableReset(true),
allowSymlinks(false),
pathCache(true),
useScriptNames(false)
{
midi.chorus = false;
midi.reverb = false;
SE.sourceCount = 6;
}
void Config::read(int argc, char *argv[]) void Config::read(int argc, char *argv[])
{ {
#define PO_DESC_ALL \ #define PO_DESC_ALL \
PO_DESC(rgssVersion, int) \ PO_DESC(rgssVersion, int, 0) \
PO_DESC(debugMode, bool) \ PO_DESC(debugMode, bool, false) \
PO_DESC(winResizable, bool) \ PO_DESC(printFPS, bool, false) \
PO_DESC(fullscreen, bool) \ PO_DESC(winResizable, bool, false) \
PO_DESC(fixedAspectRatio, bool) \ PO_DESC(fullscreen, bool, false) \
PO_DESC(smoothScaling, bool) \ PO_DESC(fixedAspectRatio, bool, true) \
PO_DESC(vsync, bool) \ PO_DESC(smoothScaling, bool, false) \
PO_DESC(defScreenW, int) \ PO_DESC(vsync, bool, false) \
PO_DESC(defScreenH, int) \ PO_DESC(defScreenW, int, 0) \
PO_DESC(fixedFramerate, int) \ PO_DESC(defScreenH, int, 0) \
PO_DESC(frameSkip, bool) \ PO_DESC(fixedFramerate, int, 0) \
PO_DESC(solidFonts, bool) \ PO_DESC(frameSkip, bool, true) \
PO_DESC(gameFolder, std::string) \ PO_DESC(syncToRefreshrate, bool, false) \
PO_DESC(anyAltToggleFS, bool) \ PO_DESC(solidFonts, bool, false) \
PO_DESC(enableReset, bool) \ PO_DESC(subImageFix, bool, false) \
PO_DESC(allowSymlinks, bool) \ PO_DESC(gameFolder, std::string, ".") \
PO_DESC(dataPathOrg, std::string) \ PO_DESC(anyAltToggleFS, bool, false) \
PO_DESC(dataPathApp, std::string) \ PO_DESC(enableReset, bool, true) \
PO_DESC(iconPath, std::string) \ PO_DESC(allowSymlinks, bool, false) \
PO_DESC(titleLanguage, std::string) \ PO_DESC(dataPathOrg, std::string, "") \
PO_DESC(midi.soundFont, std::string) \ PO_DESC(dataPathApp, std::string, "") \
PO_DESC(midi.chorus, bool) \ PO_DESC(iconPath, std::string, "") \
PO_DESC(midi.reverb, bool) \ PO_DESC(execName, std::string, "Game") \
PO_DESC(SE.sourceCount, int) \ PO_DESC(titleLanguage, std::string, "") \
PO_DESC(customScript, std::string) \ PO_DESC(midi.soundFont, std::string, "") \
PO_DESC(pathCache, bool) \ PO_DESC(midi.chorus, bool, false) \
PO_DESC(useScriptNames, bool) PO_DESC(midi.reverb, bool, false) \
PO_DESC(SE.sourceCount, int, 6) \
PO_DESC(customScript, std::string, "") \
PO_DESC(pathCache, bool, true) \
PO_DESC(useScriptNames, bool, false)
// Not gonna take your shit boost // Not gonna take your shit boost
#define GUARD_ALL( exp ) try { exp } catch(...) {} #define GUARD_ALL( exp ) try { exp } catch(...) {}
#define PO_DESC(key, type) (#key, po::value< type >()->default_value(key)) #define PO_DESC(key, type, def) (#key, po::value< type >()->default_value(def))
po::options_description podesc; po::options_description podesc;
podesc.add_options() podesc.add_options()
@ -219,26 +206,23 @@ void Config::read(int argc, char *argv[])
} }
/* Parse configuration file */ /* Parse configuration file */
std::ifstream confFile; SDLRWStream confFile(CONF_FILE, "r");
confFile.open(CONF_FILE);
if (confFile) if (confFile)
{ {
try try
{ {
po::store(po::parse_config_file(confFile, podesc, true), vm); po::store(po::parse_config_file(confFile.stream(), podesc, true), vm);
po::notify(vm); po::notify(vm);
} }
catch (po::error &error) catch (po::error &error)
{ {
Debug() << CONF_FILE":" << error.what(); Debug() << CONF_FILE":" << error.what();
} }
confFile.close();
} }
#undef PO_DESC #undef PO_DESC
#define PO_DESC(key, type) GUARD_ALL( key = vm[#key].as< type >(); ) #define PO_DESC(key, type, def) GUARD_ALL( key = vm[#key].as< type >(); )
PO_DESC_ALL; PO_DESC_ALL;
@ -349,16 +333,26 @@ void Config::readGameINI()
("Game.Scripts", po::value<std::string>()) ("Game.Scripts", po::value<std::string>())
; ;
std::string iniPath = gameFolder + "/Game.ini";
std::ifstream iniFile;
iniFile.open((iniPath).c_str());
po::variables_map vm; po::variables_map vm;
po::store(po::parse_config_file(iniFile, podesc, true), vm); std::string iniFilename = execName + ".ini";
po::notify(vm); SDLRWStream iniFile(iniFilename.c_str(), "r");
iniFile.close(); if (iniFile)
{
try
{
po::store(po::parse_config_file(iniFile.stream(), podesc, true), vm);
po::notify(vm);
}
catch (po::error &error)
{
Debug() << iniFilename + ":" << error.what();
}
}
else
{
Debug() << "FAILED to open" << iniFilename;
}
GUARD_ALL( game.title = vm["Game.Title"].as<std::string>(); ); GUARD_ALL( game.title = vm["Game.Title"].as<std::string>(); );
GUARD_ALL( game.scripts = vm["Game.Scripts"].as<std::string>(); ); GUARD_ALL( game.scripts = vm["Game.Scripts"].as<std::string>(); );

View File

@ -29,6 +29,49 @@ struct CropTexture
{ {
std::string filename; std::string filename;
int w, h; int w, h;
}
struct TouchOverlay
{
std::string image;
struct Button
{
enum Shape
{
Rectangle,
Circle,
Triangle
};
std::string id;
std::string target;
Shape shape;
int x;
int y;
union
{
struct
{
int width;
int height;
} r;
struct
{
int radius;
} c;
struct
{
int x1, y1;
int x2, y2;
} t;
} u;
};
std::vector<Button> buttons;
}; };
struct Config struct Config
@ -36,6 +79,7 @@ struct Config
int rgssVersion; int rgssVersion;
bool debugMode; bool debugMode;
bool printFPS;
bool winResizable; bool winResizable;
bool fullscreen; bool fullscreen;
@ -48,9 +92,12 @@ struct Config
int fixedFramerate; int fixedFramerate;
bool frameSkip; bool frameSkip;
bool syncToRefreshrate;
bool solidFonts; bool solidFonts;
bool subImageFix;
std::string gameFolder; std::string gameFolder;
bool anyAltToggleFS; bool anyAltToggleFS;
bool enableReset; bool enableReset;
@ -61,6 +108,7 @@ struct Config
std::string dataPathApp; std::string dataPathApp;
std::string iconPath; std::string iconPath;
std::string execName;
std::string titleLanguage; std::string titleLanguage;
struct struct

View File

@ -26,6 +26,11 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#ifdef __ANDROID__
#include <android/log.h>
#endif
/* A cheap replacement for qDebug() */ /* A cheap replacement for qDebug() */
class Debug class Debug
@ -56,7 +61,11 @@ public:
~Debug() ~Debug()
{ {
std::clog << buf.str() << std::endl; #ifdef __ANDROID__
__android_log_write(ANDROID_LOG_DEBUG, "mkxp", buf.str().c_str());
#else
std::cerr << buf.str() << std::endl;
#endif
} }
private: private:

View File

@ -60,6 +60,11 @@ struct Vec4
{ {
return (x == other.x && y == other.y && z == other.z && w == other.w); return (x == other.x && y == other.y && z == other.z && w == other.w);
} }
bool xyzHasEffect() const
{
return (x != 0.0 || y != 0.0 || z != 0.0);
}
}; };
struct Vec2i struct Vec2i
@ -74,19 +79,68 @@ struct Vec2i
: x(x), y(y) : x(x), y(y)
{} {}
explicit Vec2i(int xy)
: x(xy), y(xy)
{}
bool operator==(const Vec2i &other) const bool operator==(const Vec2i &other) const
{ {
return x == other.x && y == other.y; return x == other.x && y == other.y;
} }
Vec2i &operator+=(const Vec2i &other) Vec2i &operator+=(const Vec2i &value)
{ {
x += other.x; x += value.x;
y += other.y; y += value.y;
return *this; return *this;
} }
Vec2i &operator-=(const Vec2i &value)
{
x -= value.x;
y -= value.y;
return *this;
}
Vec2i operator+(const Vec2i &value) const
{
return Vec2i(x + value.x, y + value.y);
}
Vec2i operator-(const Vec2i &value) const
{
return Vec2i(x - value.x, y - value.y);
}
template<typename T>
Vec2i operator*(T value) const
{
return Vec2i(x * value, y * value);
}
template<typename T>
Vec2i operator/(T value) const
{
return Vec2i(x / value, y / value);
}
Vec2i operator%(int value) const
{
return Vec2i(x % value, y % value);
}
Vec2i operator-() const
{
return Vec2i(-x, -y);
}
Vec2i operator!() const
{
return Vec2i(!x, !y);
}
operator Vec2() const operator Vec2() const
{ {
return Vec2(x, y); return Vec2(x, y);
@ -108,6 +162,14 @@ struct IntRect : SDL_Rect
this->h = h; this->h = h;
} }
IntRect(const Vec2i &pos, const Vec2i &size)
{
x = pos.x;
y = pos.y;
w = size.x;
h = size.y;
}
bool operator==(const IntRect &other) const bool operator==(const IntRect &other) const
{ {
return (x == other.x && y == other.y && return (x == other.x && y == other.y &&
@ -124,10 +186,24 @@ struct IntRect : SDL_Rect
return Vec2i(w, h); return Vec2i(w, h);
} }
operator SDL_Rect() const void setPos(const Vec2i &value)
{ {
SDL_Rect r = { x, y, w, h }; x = value.x;
return r; y = value.y;
}
void setSize(const Vec2i &value)
{
w = value.x;
h = value.y;
}
bool encloses(const IntRect &o) const
{
return (x <= o.x &&
y <= o.y &&
x+w >= o.x+o.w &&
y+h >= o.y+o.h);
} }
}; };
@ -163,35 +239,10 @@ struct FloatRect
Vec2 topRight() const { return Vec2(x+w, y); } Vec2 topRight() const { return Vec2(x+w, y); }
Vec2 bottomRight() const { return Vec2(x+w, y+h); } Vec2 bottomRight() const { return Vec2(x+w, y+h); }
void shrinkHalf()
{
x += 0.5;
y += 0.5;
w -= 1.0;
h -= 1.0;
}
FloatRect vFlipped() const
{
return FloatRect(x, y+h, w, -h);
}
FloatRect hFlipped() const FloatRect hFlipped() const
{ {
return FloatRect(x+w, y, -w, h); return FloatRect(x+w, y, -w, h);
} }
Vec2 corner(int i) const
{
switch (i)
{
case 0 : return topLeft();
case 1 : return topRight();
case 2 : return bottomRight();
case 3 : return bottomLeft();
default : return Vec2();
}
}
}; };
/* Value between 0 and 255 with internal /* Value between 0 and 255 with internal

View File

@ -105,12 +105,10 @@ int Color::serialSize() const
void Color::serialize(char *buffer) const void Color::serialize(char *buffer) const
{ {
char *buf = buffer; writeDouble(&buffer, red);
writeDouble(&buffer, green);
write_double(&buf, red); writeDouble(&buffer, blue);
write_double(&buf, green); writeDouble(&buffer, alpha);
write_double(&buf, blue);
write_double(&buf, alpha);
} }
Color *Color::deserialize(const char *data, int len) Color *Color::deserialize(const char *data, int len)
@ -119,12 +117,11 @@ Color *Color::deserialize(const char *data, int len)
throw Exception(Exception::ArgumentError, "Color: Serialized data invalid"); throw Exception(Exception::ArgumentError, "Color: Serialized data invalid");
Color *c = new Color(); Color *c = new Color();
uint i = 0;
c->red = read_double(data, i); c->red = readDouble(&data);
c->green = read_double(data, i); c->green = readDouble(&data);
c->blue = read_double(data, i); c->blue = readDouble(&data);
c->alpha = read_double(data, i); c->alpha = readDouble(&data);
c->updateInternal(); c->updateInternal();
return c; return c;
@ -241,12 +238,10 @@ int Tone::serialSize() const
void Tone::serialize(char *buffer) const void Tone::serialize(char *buffer) const
{ {
char *buf = buffer; writeDouble(&buffer, red);
writeDouble(&buffer, green);
write_double(&buf, red); writeDouble(&buffer, blue);
write_double(&buf, green); writeDouble(&buffer, gray);
write_double(&buf, blue);
write_double(&buf, gray);
} }
Tone *Tone::deserialize(const char *data, int len) Tone *Tone::deserialize(const char *data, int len)
@ -255,12 +250,11 @@ Tone *Tone::deserialize(const char *data, int len)
throw Exception(Exception::ArgumentError, "Tone: Serialized data invalid"); throw Exception(Exception::ArgumentError, "Tone: Serialized data invalid");
Tone *t = new Tone(); Tone *t = new Tone();
uint i = 0;
t->red = read_double(data, i); t->red = readDouble(&data);
t->green = read_double(data, i); t->green = readDouble(&data);
t->blue = read_double(data, i); t->blue = readDouble(&data);
t->gray = read_double(data, i); t->gray = readDouble(&data);
t->updateInternal(); t->updateInternal();
return t; return t;
@ -390,12 +384,10 @@ int Rect::serialSize() const
void Rect::serialize(char *buffer) const void Rect::serialize(char *buffer) const
{ {
char *buf = buffer; writeInt32(&buffer, x);
writeInt32(&buffer, y);
write_int32(&buf, x); writeInt32(&buffer, width);
write_int32(&buf, y); writeInt32(&buffer, height);
write_int32(&buf, width);
write_int32(&buf, height);
} }
Rect *Rect::deserialize(const char *data, int len) Rect *Rect::deserialize(const char *data, int len)
@ -404,12 +396,11 @@ Rect *Rect::deserialize(const char *data, int len)
throw Exception(Exception::ArgumentError, "Rect: Serialized data invalid"); throw Exception(Exception::ArgumentError, "Rect: Serialized data invalid");
Rect *r = new Rect(); Rect *r = new Rect();
uint i = 0;
r->x = read_int32(data, i); r->x = readInt32(&data);
r->y = read_int32(data, i); r->y = readInt32(&data);
r->width = read_int32(data, i); r->width = readInt32(&data);
r->height = read_int32(data, i); r->height = readInt32(&data);
return r; return r;
} }

View File

@ -26,25 +26,51 @@
#include <SDL_messagebox.h> #include <SDL_messagebox.h>
#include <SDL_timer.h> #include <SDL_timer.h>
#include <SDL_thread.h> #include <SDL_thread.h>
#include <SDL_touch.h>
#include <alext.h>
#include "sharedstate.h" #include "sharedstate.h"
#include "graphics.h" #include "graphics.h"
#include "settingsmenu.h" #include "settingsmenu.h"
#include "al-util.h"
#include "debugwriter.h" #include "debugwriter.h"
#include <string.h> #include <string.h>
uint8_t EventThread::keyStates[] = { false }; typedef void (ALC_APIENTRY *LPALCDEVICEPAUSESOFT) (ALCdevice *device);
typedef void (ALC_APIENTRY *LPALCDEVICERESUMESOFT) (ALCdevice *device);
EventThread::JoyState EventThread::joyState = #define AL_DEVICE_PAUSE_FUN \
{ AL_FUN(DevicePause, LPALCDEVICEPAUSESOFT) \
{ 0 }, { false } AL_FUN(DeviceResume, LPALCDEVICERESUMESOFT)
};
EventThread::MouseState EventThread::mouseState = struct ALCFunctions
{ {
0, 0, false, { false } #define AL_FUN(name, type) type name;
}; AL_DEVICE_PAUSE_FUN
#undef AL_FUN
} static alc;
static void
initALCFunctions(ALCdevice *alcDev)
{
if (!strstr(alcGetString(alcDev, ALC_EXTENSIONS), "ALC_SOFT_pause_device"))
return;
Debug() << "ALC_SOFT_pause_device present";
#define AL_FUN(name, type) alc. name = (type) alcGetProcAddress(alcDev, "alc" #name "SOFT");
AL_DEVICE_PAUSE_FUN;
#undef AL_FUN
}
#define HAVE_ALC_DEVICE_PAUSE alc.DevicePause
uint8_t EventThread::keyStates[];
EventThread::JoyState EventThread::joyState;
EventThread::MouseState EventThread::mouseState;
EventThread::TouchState EventThread::touchState;
/* User event codes */ /* User event codes */
enum enum
@ -80,19 +106,24 @@ void EventThread::process(RGSSThreadData &rtData)
{ {
SDL_Event event; SDL_Event event;
SDL_Window *win = rtData.window; SDL_Window *win = rtData.window;
WindowSizeNotify &windowSizeMsg = rtData.windowSizeMsg; UnidirMessage<Vec2i> &windowSizeMsg = rtData.windowSizeMsg;
initALCFunctions(rtData.alcDev);
SDL_SetEventFilter(eventFilter, &rtData);
fullscreen = rtData.config.fullscreen; fullscreen = rtData.config.fullscreen;
int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT; int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT;
fps.lastFrame = SDL_GetPerformanceCounter(); fps.lastFrame = SDL_GetPerformanceCounter();
fps.displayCounter = 0; fps.displayCounter = 0;
fps.displaying = false;
fps.immInitFlag = false;
fps.immFiniFlag = false;
fps.acc = 0; fps.acc = 0;
fps.accDiv = 0; fps.accDiv = 0;
if (rtData.config.printFPS)
fps.sendUpdates.set();
bool displayingFPS = false;
bool cursorInWindow = false; bool cursorInWindow = false;
bool windowFocused = false; bool windowFocused = false;
@ -109,6 +140,11 @@ void EventThread::process(RGSSThreadData &rtData)
bool resetting = false; bool resetting = false;
int winW, winH;
int i;
SDL_GetWindowSize(win, &winW, &winH);
SettingsMenu *sMenu = 0; SettingsMenu *sMenu = 0;
while (true) while (true)
@ -132,14 +168,36 @@ void EventThread::process(RGSSThreadData &rtData)
continue; continue;
} }
/* Preselect and discard unwanted events here */
switch (event.type)
{
case SDL_MOUSEBUTTONDOWN :
case SDL_MOUSEBUTTONUP :
case SDL_MOUSEMOTION :
if (event.button.which == SDL_TOUCH_MOUSEID)
continue;
break;
case SDL_FINGERDOWN :
case SDL_FINGERUP :
case SDL_FINGERMOTION :
if (event.tfinger.fingerId >= MAX_FINGERS)
continue;
break;
}
/* Now process the rest */
switch (event.type) switch (event.type)
{ {
case SDL_WINDOWEVENT : case SDL_WINDOWEVENT :
switch (event.window.event) switch (event.window.event)
{ {
case SDL_WINDOWEVENT_SIZE_CHANGED : case SDL_WINDOWEVENT_SIZE_CHANGED :
windowSizeMsg.notifyChange(event.window.data1, winW = event.window.data1;
event.window.data2); winH = event.window.data2;
windowSizeMsg.post(Vec2i(winW, winH));
resetInputStates();
break; break;
case SDL_WINDOWEVENT_ENTER : case SDL_WINDOWEVENT_ENTER :
@ -210,14 +268,18 @@ void EventThread::process(RGSSThreadData &rtData)
if (event.key.keysym.scancode == SDL_SCANCODE_F2) if (event.key.keysym.scancode == SDL_SCANCODE_F2)
{ {
if (!fps.displaying) if (!displayingFPS)
{ {
fps.immInitFlag = true; fps.immInitFlag.set();
fps.displaying = true; fps.sendUpdates.set();
displayingFPS = true;
} }
else else
{ {
fps.displaying = false; displayingFPS = false;
if (!rtData.config.printFPS)
fps.sendUpdates.clear();
if (fullscreen) if (fullscreen)
{ {
@ -274,8 +336,12 @@ void EventThread::process(RGSSThreadData &rtData)
joyState.buttons[event.jbutton.button] = false; joyState.buttons[event.jbutton.button] = false;
break; break;
case SDL_JOYHATMOTION :
joyState.hats[event.jhat.hat] = event.jhat.value;
break;
case SDL_JOYAXISMOTION : case SDL_JOYAXISMOTION :
joyState.axis[event.jaxis.axis] = event.jaxis.value; joyState.axes[event.jaxis.axis] = event.jaxis.value;
break; break;
case SDL_JOYDEVICEADDED : case SDL_JOYDEVICEADDED :
@ -300,7 +366,21 @@ void EventThread::process(RGSSThreadData &rtData)
case SDL_MOUSEMOTION : case SDL_MOUSEMOTION :
mouseState.x = event.motion.x; mouseState.x = event.motion.x;
mouseState.y = event.motion.y; mouseState.y = event.motion.y;
break;
case SDL_FINGERDOWN :
i = event.tfinger.fingerId;
touchState.fingers[i].down = true;
case SDL_FINGERMOTION :
i = event.tfinger.fingerId;
touchState.fingers[i].x = event.tfinger.x * winW;
touchState.fingers[i].y = event.tfinger.y * winH;
break;
case SDL_FINGERUP :
i = event.tfinger.fingerId;
memset(&touchState.fingers[i], 0, sizeof(touchState.fingers[0]));
break; break;
default : default :
@ -329,7 +409,10 @@ void EventThread::process(RGSSThreadData &rtData)
break; break;
case UPDATE_FPS : case UPDATE_FPS :
if (!fps.displaying) if (rtData.config.printFPS)
Debug() << "FPS:" << event.user.code;
if (!fps.sendUpdates)
break; break;
snprintf(buffer, sizeof(buffer), "%s - %d FPS", snprintf(buffer, sizeof(buffer), "%s - %d FPS",
@ -354,12 +437,69 @@ void EventThread::process(RGSSThreadData &rtData)
break; break;
} }
/* Just in case */
rtData.syncPoint.resumeThreads();
if (SDL_JoystickGetAttached(js)) if (SDL_JoystickGetAttached(js))
SDL_JoystickClose(js); SDL_JoystickClose(js);
delete sMenu; delete sMenu;
} }
int EventThread::eventFilter(void *data, SDL_Event *event)
{
RGSSThreadData &rtData = *static_cast<RGSSThreadData*>(data);
switch (event->type)
{
case SDL_APP_WILLENTERBACKGROUND :
Debug() << "SDL_APP_WILLENTERBACKGROUND";
if (HAVE_ALC_DEVICE_PAUSE)
alc.DevicePause(rtData.alcDev);
rtData.syncPoint.haltThreads();
return 0;
case SDL_APP_DIDENTERBACKGROUND :
Debug() << "SDL_APP_DIDENTERBACKGROUND";
return 0;
case SDL_APP_WILLENTERFOREGROUND :
Debug() << "SDL_APP_WILLENTERFOREGROUND";
return 0;
case SDL_APP_DIDENTERFOREGROUND :
Debug() << "SDL_APP_DIDENTERFOREGROUND";
if (HAVE_ALC_DEVICE_PAUSE)
alc.DeviceResume(rtData.alcDev);
rtData.syncPoint.resumeThreads();
return 0;
case SDL_APP_TERMINATING :
Debug() << "SDL_APP_TERMINATING";
return 0;
case SDL_APP_LOWMEMORY :
Debug() << "SDL_APP_LOWMEMORY";
return 0;
case SDL_RENDER_TARGETS_RESET :
Debug() << "****** SDL_RENDER_TARGETS_RESET";
return 0;
case SDL_RENDER_DEVICE_RESET :
Debug() << "****** SDL_RENDER_DEVICE_RESET";
return 0;
}
return 1;
}
void EventThread::cleanup() void EventThread::cleanup()
{ {
SDL_Event event; SDL_Event event;
@ -374,6 +514,7 @@ void EventThread::resetInputStates()
memset(&keyStates, 0, sizeof(keyStates)); memset(&keyStates, 0, sizeof(keyStates));
memset(&joyState, 0, sizeof(joyState)); memset(&joyState, 0, sizeof(joyState));
memset(&mouseState.buttons, 0, sizeof(mouseState.buttons)); memset(&mouseState.buttons, 0, sizeof(mouseState.buttons));
memset(&touchState, 0, sizeof(touchState));
} }
void EventThread::setFullscreen(SDL_Window *win, bool mode) void EventThread::setFullscreen(SDL_Window *win, bool mode)
@ -454,7 +595,7 @@ bool EventThread::getShowCursor() const
void EventThread::notifyFrame() void EventThread::notifyFrame()
{ {
if (!fps.displaying) if (!fps.sendUpdates)
return; return;
uint64_t current = SDL_GetPerformanceCounter(); uint64_t current = SDL_GetPerformanceCounter();
@ -463,8 +604,8 @@ void EventThread::notifyFrame()
if (fps.immInitFlag) if (fps.immInitFlag)
{ {
fps.immInitFlag = false; fps.immInitFlag.clear();
fps.immFiniFlag = true; fps.immFiniFlag.set();
return; return;
} }
@ -480,7 +621,7 @@ void EventThread::notifyFrame()
return; return;
fps.displayCounter = 0; fps.displayCounter = 0;
fps.immFiniFlag = false; fps.immFiniFlag.clear();
int32_t avgFPS = fps.acc / fps.accDiv; int32_t avgFPS = fps.acc / fps.accDiv;
fps.acc = fps.accDiv = 0; fps.acc = fps.accDiv = 0;
@ -490,3 +631,87 @@ void EventThread::notifyFrame()
event.user.type = usrIdStart + UPDATE_FPS; event.user.type = usrIdStart + UPDATE_FPS;
SDL_PushEvent(&event); SDL_PushEvent(&event);
} }
void SyncPoint::haltThreads()
{
if (mainSync.locked)
return;
/* Lock the reply sync first to avoid races */
reply.lock();
/* Lock main sync and sleep until RGSS thread
* reports back */
mainSync.lock();
reply.waitForUnlock();
/* Now that the RGSS thread is asleep, we can
* safely put the other threads to sleep as well
* without causing deadlocks */
secondSync.lock();
}
void SyncPoint::resumeThreads()
{
if (!mainSync.locked)
return;
mainSync.unlock(false);
secondSync.unlock(true);
}
bool SyncPoint::mainSyncLocked()
{
return mainSync.locked;
}
void SyncPoint::waitMainSync()
{
reply.unlock(false);
mainSync.waitForUnlock();
}
void SyncPoint::passSecondarySync()
{
if (!secondSync.locked)
return;
secondSync.waitForUnlock();
}
SyncPoint::Util::Util()
{
mut = SDL_CreateMutex();
cond = SDL_CreateCond();
}
SyncPoint::Util::~Util()
{
SDL_DestroyCond(cond);
SDL_DestroyMutex(mut);
}
void SyncPoint::Util::lock()
{
locked.set();
}
void SyncPoint::Util::unlock(bool multi)
{
locked.clear();
if (multi)
SDL_CondBroadcast(cond);
else
SDL_CondSignal(cond);
}
void SyncPoint::Util::waitForUnlock()
{
SDL_LockMutex(mut);
while (locked)
SDL_CondWait(cond, mut);
SDL_UnlockMutex(mut);
}

View File

@ -37,21 +37,22 @@
#include <stdint.h> #include <stdint.h>
struct RGSSThreadData; struct RGSSThreadData;
typedef struct ALCdevice_struct ALCdevice;
struct SDL_Window; struct SDL_Window;
union SDL_Event;
#define MAX_FINGERS 4
class EventThread class EventThread
{ {
public: public:
static uint8_t keyStates[SDL_NUM_SCANCODES];
struct JoyState struct JoyState
{ {
int axis[256]; int axes[256];
uint8_t hats[256];
bool buttons[256]; bool buttons[256];
}; };
static JoyState joyState;
struct MouseState struct MouseState
{ {
int x, y; int x, y;
@ -59,7 +60,21 @@ public:
bool buttons[32]; bool buttons[32];
}; };
struct FingerState
{
bool down;
int x, y;
};
struct TouchState
{
FingerState fingers[MAX_FINGERS];
};
static uint8_t keyStates[SDL_NUM_SCANCODES];
static JoyState joyState;
static MouseState mouseState; static MouseState mouseState;
static TouchState touchState;
static bool allocUserEvents(); static bool allocUserEvents();
@ -84,6 +99,8 @@ public:
void notifyFrame(); void notifyFrame();
private: private:
static int eventFilter(void *, SDL_Event*);
void resetInputStates(); void resetInputStates();
void setFullscreen(SDL_Window *, bool mode); void setFullscreen(SDL_Window *, bool mode);
void updateCursorState(bool inWindow); void updateCursorState(bool inWindow);
@ -96,111 +113,101 @@ private:
{ {
uint64_t lastFrame; uint64_t lastFrame;
uint64_t displayCounter; uint64_t displayCounter;
bool displaying; AtomicFlag sendUpdates;
bool immInitFlag; AtomicFlag immInitFlag;
bool immFiniFlag; AtomicFlag immFiniFlag;
double acc; double acc;
uint32_t accDiv; uint32_t accDiv;
} fps; } fps;
}; };
/* Used to asynchronously inform the RGSS thread /* Used to asynchronously inform the RGSS thread
* about window size changes */ * about certain value changes */
struct WindowSizeNotify template<typename T>
struct UnidirMessage
{ {
SDL_mutex *mutex; UnidirMessage()
: mutex(SDL_CreateMutex()),
current(T())
{}
AtomicFlag changed; ~UnidirMessage()
int w, h;
WindowSizeNotify()
{
mutex = SDL_CreateMutex();
w = h = 0;
}
~WindowSizeNotify()
{ {
SDL_DestroyMutex(mutex); SDL_DestroyMutex(mutex);
} }
/* Done from the sending side */ /* Done from the sending side */
void notifyChange(int w, int h) void post(const T &value)
{ {
SDL_LockMutex(mutex); SDL_LockMutex(mutex);
this->w = w;
this->h = h;
changed.set(); changed.set();
current = value;
SDL_UnlockMutex(mutex); SDL_UnlockMutex(mutex);
} }
/* Done from the receiving side */ /* Done from the receiving side */
bool pollChange(int *w, int *h) bool poll(T &out) const
{ {
if (!changed) if (!changed)
return false; return false;
SDL_LockMutex(mutex); SDL_LockMutex(mutex);
*w = this->w; out = current;
*h = this->h;
changed.clear(); changed.clear();
SDL_UnlockMutex(mutex); SDL_UnlockMutex(mutex);
return true; return true;
} }
};
struct BindingNotify /* Done from either */
{ void get(T &out) const
BindingNotify()
{ {
mut = SDL_CreateMutex(); SDL_LockMutex(mutex);
} out = current;
~BindingNotify() SDL_UnlockMutex(mutex);
{
SDL_DestroyMutex(mut);
}
bool poll(BDescVec &out) const
{
if (!changed)
return false;
SDL_LockMutex(mut);
out = data;
changed.clear();
SDL_UnlockMutex(mut);
return true;
}
void get(BDescVec &out) const
{
SDL_LockMutex(mut);
out = data;
SDL_UnlockMutex(mut);
}
void post(const BDescVec &d)
{
SDL_LockMutex(mut);
changed.set();
data = d;
SDL_UnlockMutex(mut);
} }
private: private:
SDL_mutex *mut; SDL_mutex *mutex;
BDescVec data;
mutable AtomicFlag changed; mutable AtomicFlag changed;
T current;
};
struct SyncPoint
{
/* Used by eventFilter to control sleep/wakeup */
void haltThreads();
void resumeThreads();
/* Used by RGSS thread */
bool mainSyncLocked();
void waitMainSync();
/* Used by secondary (audio) threads */
void passSecondarySync();
private:
struct Util
{
Util();
~Util();
void lock();
void unlock(bool multi);
void waitForUnlock();
AtomicFlag locked;
SDL_mutex *mut;
SDL_cond *cond;
};
Util mainSync;
Util reply;
Util secondSync;
}; };
struct RGSSThreadData struct RGSSThreadData
@ -218,15 +225,18 @@ struct RGSSThreadData
AtomicFlag rqResetFinish; AtomicFlag rqResetFinish;
EventThread *ethread; EventThread *ethread;
WindowSizeNotify windowSizeMsg; UnidirMessage<Vec2i> windowSizeMsg;
BindingNotify bindingUpdateMsg; UnidirMessage<BDescVec> bindingUpdateMsg;
SyncPoint syncPoint;
const char *argv0; const char *argv0;
SDL_Window *window; SDL_Window *window;
ALCdevice *alcDev;
Vec2 sizeResoRatio; Vec2 sizeResoRatio;
Vec2i screenOffset; Vec2i screenOffset;
const int refreshRate;
Config config; Config config;
@ -235,11 +245,15 @@ struct RGSSThreadData
RGSSThreadData(EventThread *ethread, RGSSThreadData(EventThread *ethread,
const char *argv0, const char *argv0,
SDL_Window *window, SDL_Window *window,
ALCdevice *alcDev,
int refreshRate,
const Config& newconf) const Config& newconf)
: ethread(ethread), : ethread(ethread),
argv0(argv0), argv0(argv0),
window(window), window(window),
alcDev(alcDev),
sizeResoRatio(1, 1), sizeResoRatio(1, 1),
refreshRate(refreshRate),
config(newconf) config(newconf)
{} {}
}; };

View File

@ -42,6 +42,105 @@
#include <iconv.h> #include <iconv.h>
#endif #endif
struct SDLRWIoContext
{
SDL_RWops *ops;
std::string filename;
SDLRWIoContext(const char *filename)
: ops(SDL_RWFromFile(filename, "r")),
filename(filename)
{
if (!ops)
throw Exception(Exception::SDLError,
"Failed to open file: %s", SDL_GetError());
}
~SDLRWIoContext()
{
SDL_RWclose(ops);
}
};
static PHYSFS_Io *createSDLRWIo(const char *filename);
static SDL_RWops *getSDLRWops(PHYSFS_Io *io)
{
return static_cast<SDLRWIoContext*>(io->opaque)->ops;
}
static PHYSFS_sint64 SDLRWIoRead(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len)
{
return SDL_RWread(getSDLRWops(io), buf, 1, len);
}
static int SDLRWIoSeek(struct PHYSFS_Io *io, PHYSFS_uint64 offset)
{
return (SDL_RWseek(getSDLRWops(io), offset, RW_SEEK_SET) != -1);
}
static PHYSFS_sint64 SDLRWIoTell(struct PHYSFS_Io *io)
{
return SDL_RWseek(getSDLRWops(io), 0, RW_SEEK_CUR);
}
static PHYSFS_sint64 SDLRWIoLength(struct PHYSFS_Io *io)
{
return SDL_RWsize(getSDLRWops(io));
}
static struct PHYSFS_Io *SDLRWIoDuplicate(struct PHYSFS_Io *io)
{
SDLRWIoContext *ctx = static_cast<SDLRWIoContext*>(io->opaque);
int64_t offset = io->tell(io);
PHYSFS_Io *dup = createSDLRWIo(ctx->filename.c_str());
if (dup)
SDLRWIoSeek(dup, offset);
return dup;
}
static void SDLRWIoDestroy(struct PHYSFS_Io *io)
{
delete static_cast<SDLRWIoContext*>(io->opaque);
delete io;
}
static PHYSFS_Io SDLRWIoTemplate =
{
0, 0, /* version, opaque */
SDLRWIoRead,
0, /* write */
SDLRWIoSeek,
SDLRWIoTell,
SDLRWIoLength,
SDLRWIoDuplicate,
0, /* flush */
SDLRWIoDestroy
};
static PHYSFS_Io *createSDLRWIo(const char *filename)
{
SDLRWIoContext *ctx;
try
{
ctx = new SDLRWIoContext(filename);
}
catch (const Exception &e)
{
Debug() << "Failed mounting" << filename;
return 0;
}
PHYSFS_Io *io = new PHYSFS_Io;
*io = SDLRWIoTemplate;
io->opaque = ctx;
return io;
}
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops) static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
{ {
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1); return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
@ -131,18 +230,36 @@ static int SDL_RWopsCloseFree(SDL_RWops *ops)
return result; return result;
} }
/* Copies the first srcN characters from src into dst,
* or the full string if srcN == -1. Never writes more
* than dstMax, and guarantees dst to be null terminated.
* Returns copied bytes (minus terminating null) */
static size_t
strcpySafe(char *dst, const char *src,
size_t dstMax, int srcN)
{
if (srcN < 0)
srcN = strlen(src);
size_t cpyMax = std::min<size_t>(dstMax-1, srcN);
memcpy(dst, src, cpyMax);
dst[cpyMax] = '\0';
return cpyMax;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10; const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
struct FileSystemPrivate struct FileSystemPrivate
{ {
/* Maps: lower case filename, To: actual (mixed case) filename. /* Maps: lower case filepath without extension,
* To: mixed case full filepath
* This is for compatibility with games that take Windows' * This is for compatibility with games that take Windows'
* case insensitivity for granted */ * case insensitivity for granted */
BoostHash<std::string, std::string> pathCache; BoostHash<std::string, std::string> pathCache;
bool havePathCache; bool havePathCache;
std::vector<std::string> extensions[FileSystem::Undefined+1];
/* Attempt to locate an extension string in a filename. /* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the * Either a pointer into the input string pointing at the
* extension, or null is returned */ * extension, or null is returned */
@ -162,120 +279,129 @@ struct FileSystemPrivate
return 0; return 0;
} }
/* Complete filename via regular physfs lookup */ struct CompleteFilenameData
bool completeFilenameReg(const char *filename, {
FileSystem::FileType type, bool found;
/* Contains the incomplete filename we're looking for;
* when found, we write the complete filename into this
* same buffer */
char *outBuf;
/* Length of incomplete file name */
size_t filenameLen;
/* Maximum we can write into outBuf */
size_t outBufN;
};
static void completeFilenameRegCB(void *data, const char *,
const char *fname)
{
CompleteFilenameData &d = *static_cast<CompleteFilenameData*>(data);
if (d.found)
return;
if (strncmp(d.outBuf, fname, d.filenameLen) != 0)
return;
/* If fname matches up to a following '.' (meaning the rest is part
* of the extension), or up to a following '\0' (full match), we've
* found our file */
switch (fname[d.filenameLen])
{
case '.' :
/* Overwrite the incomplete file name we looked for with
* the full version containing any extensions */
strcpySafe(d.outBuf, fname, d.outBufN, -1);
case '\0' :
d.found = true;
}
}
bool completeFilenameReg(const char *filepath,
char *outBuffer, char *outBuffer,
size_t outN, size_t outN)
const char **foundExt)
{ {
/* Try supplementing extensions to find an existing path */ strcpySafe(outBuffer, filepath, outN, -1);
const std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i) size_t len = strlen(outBuffer);
char *delim;
/* Find the deliminator separating directory and file name */
for (delim = outBuffer + len; delim > outBuffer; --delim)
if (*delim == '/')
break;
bool root = (delim == outBuffer);
CompleteFilenameData d;
if (!root)
{ {
const char *ext = extList[i].c_str(); /* If we have such a deliminator, we set it to '\0' so we
* can pass the first half to PhysFS as the directory name,
* and compare all filenames against the second half */
d.outBuf = delim+1;
d.filenameLen = len - (delim - outBuffer + 1);
snprintf(outBuffer, outN, "%s.%s", filename, ext); *delim = '\0';
}
if (PHYSFS_exists(outBuffer)) else
{ {
if (foundExt) /* Otherwise the file is in the root directory */
*foundExt = ext; d.outBuf = outBuffer;
d.filenameLen = len - (delim - outBuffer);
return true;
}
} }
/* Doing the check without supplemented extension d.found = false;
* fits the usage pattern of RMXP games */ d.outBufN = outN - (d.outBuf - outBuffer);
if (PHYSFS_exists(filename))
{
strncpy(outBuffer, filename, outN);
if (foundExt) PHYSFS_enumerateFilesCallback(root ? "" : outBuffer, completeFilenameRegCB, &d);
*foundExt = findExt(filename);
return true; if (!d.found)
} return false;
return false; /* Now we put the deliminator back in to form the completed
* file path (if required) */
if (delim != outBuffer)
*delim = '/';
return true;
} }
/* Complete filename via path cache */ bool completeFilenamePC(const char *filepath,
bool completeFilenamePC(const char *filename,
FileSystem::FileType type,
char *outBuffer, char *outBuffer,
size_t outN, size_t outN)
const char **foundExt)
{ {
size_t i; std::string lowCase(filepath);
char lowCase[512];
for (i = 0; i < sizeof(lowCase)-1 && filename[i]; ++i) for (size_t i = 0; i < lowCase.size(); ++i)
lowCase[i] = tolower(filename[i]); lowCase[i] = tolower(lowCase[i]);
lowCase[i] = '\0'; if (!pathCache.contains(lowCase))
return false;
std::string key; const std::string &fullPath = pathCache[lowCase];
strcpySafe(outBuffer, fullPath.c_str(), outN, fullPath.size());
const std::vector<std::string> &extList = extensions[type]; return true;
for (size_t i = 0; i < extList.size(); ++i)
{
const char *ext = extList[i].c_str();
snprintf(outBuffer, outN, "%s.%s", lowCase, ext);
key = outBuffer;
if (pathCache.contains(key))
{
strncpy(outBuffer, pathCache[key].c_str(), outN);
if (foundExt)
*foundExt = ext;
return true;
}
}
key = lowCase;
if (pathCache.contains(key))
{
strncpy(outBuffer, pathCache[key].c_str(), outN);
if (foundExt)
*foundExt = findExt(filename);
return true;
}
return false;
} }
/* Try to complete 'filename' with file extensions bool completeFilename(const char *filepath,
* based on 'type'. If no combination could be found,
* returns false, and 'foundExt' is untouched */
bool completeFileName(const char *filename,
FileSystem::FileType type,
char *outBuffer, char *outBuffer,
size_t outN, size_t outN)
const char **foundExt)
{ {
if (havePathCache) if (havePathCache)
return completeFilenamePC(filename, type, outBuffer, outN, foundExt); return completeFilenamePC(filepath, outBuffer, outN);
else else
return completeFilenameReg(filename, type, outBuffer, outN, foundExt); return completeFilenameReg(filepath, outBuffer, outN);
} }
PHYSFS_File *openReadHandle(const char *filename, PHYSFS_File *openReadHandle(const char *filename,
FileSystem::FileType type, char *extBuf,
const char **foundExt) size_t extBufN)
{ {
char found[512]; char found[512];
if (!completeFileName(filename, type, found, sizeof(found), foundExt)) if (!completeFilename(filename, found, sizeof(found)))
throw Exception(Exception::NoFileError, "%s", filename); throw Exception(Exception::NoFileError, "%s", filename);
PHYSFS_File *handle = PHYSFS_openRead(found); PHYSFS_File *handle = PHYSFS_openRead(found);
@ -283,6 +409,21 @@ struct FileSystemPrivate
if (!handle) if (!handle)
throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError()); throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError());
if (!extBuf)
return handle;
for (char *q = found+strlen(found); q > found; --q)
{
if (*q == '/')
break;
if (*q != '.')
continue;
strcpySafe(extBuf, q+1, extBufN, -1);
break;
}
return handle; return handle;
} }
@ -309,45 +450,8 @@ FileSystem::FileSystem(const char *argv0,
bool allowSymlinks) bool allowSymlinks)
{ {
p = new FileSystemPrivate; p = new FileSystemPrivate;
p->havePathCache = false; p->havePathCache = false;
/* Image extensions */
p->extensions[Image].push_back("jpg");
p->extensions[Image].push_back("png");
/* Audio extensions */
const Sound_DecoderInfo **di;
for (di = Sound_AvailableDecoders(); *di; ++di)
{
const char **ext;
for (ext = (*di)->extensions; *ext; ++ext)
{
/* All reported extensions are uppercase,
* so we need to hammer them down first */
char buf[16];
for (size_t i = 0; i < sizeof(buf); ++i)
{
buf[i] = tolower((*ext)[i]);
if (!buf[i])
break;
}
p->extensions[Audio].push_back(buf);
}
}
if (rgssVer >= 2 && !contains(p->extensions[Audio], std::string("ogg")))
p->extensions[Audio].push_back("ogg");
p->extensions[Audio].push_back("mid");
p->extensions[Audio].push_back("midi");
/* Font extensions */
p->extensions[Font].push_back("ttf");
p->extensions[Font].push_back("otf");
PHYSFS_init(argv0); PHYSFS_init(argv0);
PHYSFS_registerArchiver(&RGSS1_Archiver); PHYSFS_registerArchiver(&RGSS1_Archiver);
@ -368,7 +472,16 @@ FileSystem::~FileSystem()
void FileSystem::addPath(const char *path) void FileSystem::addPath(const char *path)
{ {
PHYSFS_mount(path, 0, 1); /* Try the normal mount first */
if (!PHYSFS_mount(path, 0, 1))
{
/* If it didn't work, try mounting via a wrapped
* SDL_RWops */
PHYSFS_Io *io = createSDLRWIo(path);
if (io)
PHYSFS_mountIo(io, path, 0, 1);
}
} }
#ifdef __APPLE__ #ifdef __APPLE__
@ -436,12 +549,22 @@ static void cacheEnumCB(void *d, const char *origdir,
std::string mixedCase(ptr); std::string mixedCase(ptr);
for (char *p = bufNfc; *p; ++p) for (char *q = bufNfc; *q; ++q)
*p = tolower(*p); *q = tolower(*q);
std::string lowerCase(ptr); p->pathCache.insert(std::string(ptr), mixedCase);
p->pathCache.insert(lowerCase, mixedCase); for (char *q = ptr+strlen(ptr); q > ptr; --q)
{
if (*q == '/')
break;
if (*q != '.')
continue;
*q = '\0';
p->pathCache.insert(std::string(ptr), mixedCase);
}
PHYSFS_enumerateFilesCallback(mixedCase.c_str(), cacheEnumCB, d); PHYSFS_enumerateFilesCallback(mixedCase.c_str(), cacheEnumCB, d);
} }
@ -450,7 +573,7 @@ void FileSystem::createPathCache()
{ {
#ifdef __APPLE__ #ifdef __APPLE__
CacheEnumCBData data(p); CacheEnumCBData data(p);
PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data); PHYSFS_enumerateFilesCallback("", cacheEnumCB2, &data);
#else #else
PHYSFS_enumerateFilesCallback("", cacheEnumCB, p); PHYSFS_enumerateFilesCallback("", cacheEnumCB, p);
#endif #endif
@ -458,12 +581,6 @@ void FileSystem::createPathCache()
p->havePathCache = true; p->havePathCache = true;
} }
static void strToLower(std::string &str)
{
for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
}
struct FontSetsCBData struct FontSetsCBData
{ {
FileSystemPrivate *p; FileSystemPrivate *p;
@ -482,16 +599,21 @@ static void fontSetEnumCB(void *data, const char *,
if (!ext) if (!ext)
return; return;
std::string lower(ext); char lowExt[8];
strToLower(lower); size_t i;
if (!contains(p->extensions[FileSystem::Font], lower)) for (i = 0; i < sizeof(lowExt)-1 && ext[i]; ++i)
lowExt[i] = tolower(ext[i]);
lowExt[i] = '\0';
if (strcmp(lowExt, "ttf") && strcmp(lowExt, "otf"))
return; return;
std::string filename("Fonts/"); char filename[512];
filename += fname; snprintf(filename, sizeof(filename), "Fonts/%s", fname);
filename[sizeof(filename)-1] = '\0';
PHYSFS_File *handle = PHYSFS_openRead(filename.c_str()); PHYSFS_File *handle = PHYSFS_openRead(filename);
if (!handle) if (!handle)
return; return;
@ -513,11 +635,11 @@ void FileSystem::initFontSets(SharedFontState &sfs)
void FileSystem::openRead(SDL_RWops &ops, void FileSystem::openRead(SDL_RWops &ops,
const char *filename, const char *filename,
FileType type,
bool freeOnClose, bool freeOnClose,
const char **foundExt) char *extBuf,
size_t extBufN)
{ {
PHYSFS_File *handle = p->openReadHandle(filename, type, foundExt); PHYSFS_File *handle = p->openReadHandle(filename, extBuf, extBufN);
p->initReadOps(handle, ops, freeOnClose); p->initReadOps(handle, ops, freeOnClose);
} }
@ -532,9 +654,9 @@ void FileSystem::openReadRaw(SDL_RWops &ops,
p->initReadOps(handle, ops, freeOnClose); p->initReadOps(handle, ops, freeOnClose);
} }
bool FileSystem::exists(const char *filename, FileType type) bool FileSystem::exists(const char *filename)
{ {
char found[512]; char found[512];
return p->completeFileName(filename, type, found, sizeof(found), 0); return p->completeFilename(filename, found, sizeof(found));
} }

View File

@ -43,28 +43,18 @@ public:
* available font assets */ * available font assets */
void initFontSets(SharedFontState &sfs); void initFontSets(SharedFontState &sfs);
/* For extension supplementing */
enum FileType
{
Image = 0,
Audio,
Font,
Undefined
};
void openRead(SDL_RWops &ops, void openRead(SDL_RWops &ops,
const char *filename, const char *filename,
FileType type = Undefined,
bool freeOnClose = false, bool freeOnClose = false,
const char **foundExt = 0); char *extBuf = 0,
size_t extBufN = 0);
/* Circumvents extension supplementing */ /* Circumvents extension supplementing */
void openReadRaw(SDL_RWops &ops, void openReadRaw(SDL_RWops &ops,
const char *filename, const char *filename,
bool freeOnClose = false); bool freeOnClose = false);
bool exists(const char *filename, bool exists(const char *filename);
FileType type = Undefined);
private: private:
FileSystemPrivate *p; FileSystemPrivate *p;

View File

@ -10,7 +10,7 @@
#include <fluidsynth.h> #include <fluidsynth.h>
#endif #endif
#ifdef __LINUX__ #if __LINUX__ || __ANDROID__
#define FLUID_LIB "libfluidsynth.so.1" #define FLUID_LIB "libfluidsynth.so.1"
#elif __MACOSX__ #elif __MACOSX__
#define FLUID_LIB "libfluidsynth.1.dylib" #define FLUID_LIB "libfluidsynth.1.dylib"

View File

@ -86,16 +86,14 @@ public:
const Font &operator=(const Font &o); const Font &operator=(const Font &o);
const char *getName() const; DECL_ATTR( Name, const char * )
void setName(const char *value); DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Size, int ) DECL_ATTR( Italic, bool )
DECL_ATTR( Bold, bool ) DECL_ATTR( Color, Color& )
DECL_ATTR( Italic, bool ) DECL_ATTR( Shadow, bool )
DECL_ATTR( Color, Color& ) DECL_ATTR( Outline, bool )
DECL_ATTR( Shadow, bool ) DECL_ATTR( OutColor, Color& )
DECL_ATTR( Outline, bool )
DECL_ATTR( OutColor, Color& )
DECL_ATTR_STATIC( DefaultName, const char* ) DECL_ATTR_STATIC( DefaultName, const char* )
DECL_ATTR_STATIC( DefaultSize, int ) DECL_ATTR_STATIC( DefaultSize, int )
@ -108,7 +106,7 @@ public:
/* Assigns heap allocated objects to object properties; /* Assigns heap allocated objects to object properties;
* using this in pure C++ will cause memory leaks * using this in pure C++ will cause memory leaks
* (ie. only to be used in GCed language bindings */ * (ie. only to be used in GCed language bindings) */
void initDynAttribs(); void initDynAttribs();
static void initDefaultDynAttribs(); static void initDefaultDynAttribs();

View File

@ -1,5 +1,5 @@
/* /*
** debuglogger.cpp ** gl-debug.cpp
** **
** This file is part of mkxp. ** This file is part of mkxp.
** **
@ -19,25 +19,25 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>. ** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "debuglogger.h" #include "gl-debug.h"
#include "debugwriter.h" #include "debugwriter.h"
#include <iostream> #include <iostream>
#include "gl-fun.h" #include "gl-fun.h"
struct DebugLoggerPrivate struct GLDebugLoggerPrivate
{ {
std::ostream *stream; std::ostream *stream;
DebugLoggerPrivate(const char *logFilename) GLDebugLoggerPrivate(const char *logFilename)
{ {
(void) logFilename; (void) logFilename;
stream = &std::clog; stream = &std::clog;
} }
~DebugLoggerPrivate() ~GLDebugLoggerPrivate()
{ {
} }
@ -62,8 +62,8 @@ static void APIENTRY arbDebugFunc(GLenum source,
const GLchar* message, const GLchar* message,
const void* userParam) const void* userParam)
{ {
DebugLoggerPrivate *p = GLDebugLoggerPrivate *p =
static_cast<DebugLoggerPrivate*>(const_cast<void*>(userParam)); static_cast<GLDebugLoggerPrivate*>(const_cast<void*>(userParam));
(void) source; (void) source;
(void) type; (void) type;
@ -75,9 +75,9 @@ static void APIENTRY arbDebugFunc(GLenum source,
p->writeLine(message); p->writeLine(message);
} }
DebugLogger::DebugLogger(const char *filename) GLDebugLogger::GLDebugLogger(const char *filename)
{ {
p = new DebugLoggerPrivate(filename); p = new GLDebugLoggerPrivate(filename);
if (gl.DebugMessageCallback) if (gl.DebugMessageCallback)
gl.DebugMessageCallback(arbDebugFunc, p); gl.DebugMessageCallback(arbDebugFunc, p);
@ -85,7 +85,7 @@ DebugLogger::DebugLogger(const char *filename)
Debug() << "DebugLogger: no debug extensions found"; Debug() << "DebugLogger: no debug extensions found";
} }
DebugLogger::~DebugLogger() GLDebugLogger::~GLDebugLogger()
{ {
delete p; delete p;
} }

View File

@ -1,5 +1,5 @@
/* /*
** debuglogger.h ** gl-debug.h
** **
** This file is part of mkxp. ** This file is part of mkxp.
** **
@ -22,16 +22,30 @@
#ifndef DEBUGLOGGER_H #ifndef DEBUGLOGGER_H
#define DEBUGLOGGER_H #define DEBUGLOGGER_H
struct DebugLoggerPrivate; #include "gl-fun.h"
class DebugLogger #include <stdio.h>
#include <algorithm>
struct GLDebugLoggerPrivate;
class GLDebugLogger
{ {
public: public:
DebugLogger(const char *filename = 0); GLDebugLogger(const char *filename = 0);
~DebugLogger(); ~GLDebugLogger();
private: private:
DebugLoggerPrivate *p; GLDebugLoggerPrivate *p;
}; };
#define GL_MARKER(format, ...) \
if (gl.StringMarker) \
{ \
char buf[128]; \
int len = snprintf(buf, sizeof(buf), format, ##__VA_ARGS__); \
gl.StringMarker(std::min<size_t>(len, sizeof(buf)), buf); \
}
#endif // DEBUGLOGGER_H #endif // DEBUGLOGGER_H

View File

@ -29,12 +29,12 @@
GLFunctions gl; GLFunctions gl;
typedef const GLubyte* (APIENTRYP PFNGLGETSTRINGIPROC) (GLenum, GLuint); typedef const GLubyte* (APIENTRYP _PFNGLGETSTRINGIPROC) (GLenum, GLuint);
static void parseExtensionsCore(PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::string> &out) static void parseExtensionsCore(_PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::string> &out)
{ {
PFNGLGETSTRINGIPROC GetStringi = _PFNGLGETSTRINGIPROC GetStringi =
(PFNGLGETSTRINGIPROC) SDL_GL_GetProcAddress("glGetStringi"); (_PFNGLGETSTRINGIPROC) SDL_GL_GetProcAddress("glGetStringi");
GLint extCount = 0; GLint extCount = 0;
GetIntegerv(GL_NUM_EXTENSIONS, &extCount); GetIntegerv(GL_NUM_EXTENSIONS, &extCount);
@ -43,7 +43,7 @@ static void parseExtensionsCore(PFNGLGETINTEGERVPROC GetIntegerv, BoostSet<std::
out.insert((const char*) GetStringi(GL_EXTENSIONS, i)); out.insert((const char*) GetStringi(GL_EXTENSIONS, i));
} }
static void parseExtensionsCompat(PFNGLGETSTRINGPROC GetString, BoostSet<std::string> &out) static void parseExtensionsCompat(_PFNGLGETSTRINGPROC GetString, BoostSet<std::string> &out)
{ {
const char *ext = (const char*) GetString(GL_EXTENSIONS); const char *ext = (const char*) GetString(GL_EXTENSIONS);
@ -82,8 +82,8 @@ void initGLFunctions()
/* Determine GL version */ /* Determine GL version */
const char *ver = (const char*) gl.GetString(GL_VERSION); const char *ver = (const char*) gl.GetString(GL_VERSION);
const char *glesPrefix = "OpenGL ES "; const char glesPrefix[] = "OpenGL ES ";
size_t glesPrefixN = strlen(glesPrefix); const size_t glesPrefixN = sizeof(glesPrefix)-1;
bool gles = false; bool gles = false;
@ -101,6 +101,11 @@ void initGLFunctions()
if (glMajor < 2) if (glMajor < 2)
throw EXC("At least OpenGL (ES) 2.0 is required"); throw EXC("At least OpenGL (ES) 2.0 is required");
if (gles)
{
GL_ES_FUN;
}
BoostSet<std::string> ext; BoostSet<std::string> ext;
if (glMajor >= 3) if (glMajor >= 3)
@ -172,6 +177,13 @@ void initGLFunctions()
GL_DEBUG_KHR_FUN; GL_DEBUG_KHR_FUN;
} }
if (HAVE_EXT(GREMEDY_string_marker))
{
#undef EXT_SUFFIX
#define EXT_SUFFIX "GREMEDY"
GL_GREMEMDY_FUN;
}
/* Misc caps */ /* Misc caps */
if (!gles || glMajor >= 3 || HAVE_EXT(EXT_unpack_subimage)) if (!gles || glMajor >= 3 || HAVE_EXT(EXT_unpack_subimage))
gl.unpack_subimage = true; gl.unpack_subimage = true;

View File

@ -30,179 +30,194 @@
#endif #endif
/* Etc */ /* Etc */
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void); typedef GLenum (APIENTRYP _PFNGLGETERRORPROC) (void);
typedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); typedef void (APIENTRYP _PFNGLCLEARCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
typedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask); typedef void (APIENTRYP _PFNGLCLEARPROC) (GLbitfield mask);
typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); typedef const GLubyte * (APIENTRYP _PFNGLGETSTRINGPROC) (GLenum name);
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params); typedef void (APIENTRYP _PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); typedef void (APIENTRYP _PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); typedef void (APIENTRYP _PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap); typedef void (APIENTRYP _PFNGLENABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap); typedef void (APIENTRYP _PFNGLDISABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP _PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP _PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); typedef void (APIENTRYP _PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor);
typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (APIENTRYP _PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (APIENTRYP _PFNGLBLENDEQUATIONPROC) (GLenum mode);
typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); typedef void (APIENTRYP _PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
/* Texture */ /* Texture */
typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); typedef void (APIENTRYP _PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); typedef void (APIENTRYP _PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);
typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); typedef void (APIENTRYP _PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP _PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP _PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP _PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP _PFNGLACTIVETEXTUREPROC) (GLenum texture);
/* Debug callback */ /* Debugging */
typedef void (APIENTRY * _GLDEBUGPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void *userParam); typedef void (APIENTRY * _GLDEBUGPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void *userParam);
typedef void (APIENTRYP _PFNGLDEBUGMESSAGECALLBACKPROC) (_GLDEBUGPROC callback, const void *userParam); typedef void (APIENTRYP _PFNGLDEBUGMESSAGECALLBACKPROC) (_GLDEBUGPROC callback, const void *userParam);
typedef void (APIENTRYP _PFNGLSTRINGMARKERPROC) (GLsizei len, const GLvoid *string);
/* Buffer object */ /* Buffer object */
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers); typedef void (APIENTRYP _PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers); typedef void (APIENTRYP _PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP _PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage); typedef void (APIENTRYP _PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); typedef void (APIENTRYP _PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
/* Shader */ /* Shader */
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef GLuint (APIENTRYP _PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP _PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths); typedef void (APIENTRYP _PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths);
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (APIENTRYP _PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP _PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param); typedef void (APIENTRYP _PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param);
typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); typedef void (APIENTRYP _PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
/* Program */ /* Program */
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (APIENTRYP _PFNGLCREATEPROGRAMPROC) (void);
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP _PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP _PFNGLUSEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP _PFNGLLINKPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* param); typedef void (APIENTRYP _PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint* param);
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); typedef void (APIENTRYP _PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
/* Uniform */ /* Uniform */
typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar* name); typedef GLint (APIENTRYP _PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar* name);
typedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP _PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
typedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP _PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);
typedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (APIENTRYP _PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
typedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0); typedef void (APIENTRYP _PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); typedef void (APIENTRYP _PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
/* Vertex attribute */ /* Vertex attribute */
typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name); typedef void (APIENTRYP _PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint); typedef void (APIENTRYP _PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint);
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint); typedef void (APIENTRYP _PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint);
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer); typedef void (APIENTRYP _PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
/* Framebuffer object */ /* Framebuffer object */
typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers); typedef void (APIENTRYP _PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers);
typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint* framebuffers); typedef void (APIENTRYP _PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint* framebuffers);
typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void (APIENTRYP _PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (APIENTRYP _PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (APIENTRYP _PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
/* Vertex array object */ /* Vertex array object */
typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays); typedef void (APIENTRYP _PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays); typedef void (APIENTRYP _PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays);
typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); typedef void (APIENTRYP _PFNGLBINDVERTEXARRAYPROC) (GLuint array);
/* GLES only */
typedef void (APIENTRYP _PFNGLRELEASESHADERCOMPILERPROC) (void);
#ifdef GLES2_HEADER #ifdef GLES2_HEADER
#define GL_NUM_EXTENSIONS 0x821D #define GL_NUM_EXTENSIONS 0x821D
#define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
#define GL_UNPACK_SKIP_ROWS 0x0CF3
#endif #endif
#define GL_20_FUN \ #define GL_20_FUN \
/* Etc */ \ /* Etc */ \
GL_FUN(GetError, PFNGLGETERRORPROC) \ GL_FUN(GetError, _PFNGLGETERRORPROC) \
GL_FUN(ClearColor, PFNGLCLEARCOLORPROC) \ GL_FUN(ClearColor, _PFNGLCLEARCOLORPROC) \
GL_FUN(Clear, PFNGLCLEARPROC) \ GL_FUN(Clear, _PFNGLCLEARPROC) \
GL_FUN(GetString, PFNGLGETSTRINGPROC) \ GL_FUN(GetString, _PFNGLGETSTRINGPROC) \
GL_FUN(GetIntegerv, PFNGLGETINTEGERVPROC) \ GL_FUN(GetIntegerv, _PFNGLGETINTEGERVPROC) \
GL_FUN(PixelStorei, PFNGLPIXELSTOREIPROC) \ GL_FUN(PixelStorei, _PFNGLPIXELSTOREIPROC) \
GL_FUN(ReadPixels, PFNGLREADPIXELSPROC) \ GL_FUN(ReadPixels, _PFNGLREADPIXELSPROC) \
GL_FUN(Enable, PFNGLENABLEPROC) \ GL_FUN(Enable, _PFNGLENABLEPROC) \
GL_FUN(Disable, PFNGLDISABLEPROC) \ GL_FUN(Disable, _PFNGLDISABLEPROC) \
GL_FUN(Scissor, PFNGLSCISSORPROC) \ GL_FUN(Scissor, _PFNGLSCISSORPROC) \
GL_FUN(Viewport, PFNGLVIEWPORTPROC) \ GL_FUN(Viewport, _PFNGLVIEWPORTPROC) \
GL_FUN(BlendFunc, PFNGLBLENDFUNCPROC) \ GL_FUN(BlendFunc, _PFNGLBLENDFUNCPROC) \
GL_FUN(BlendFuncSeparate, PFNGLBLENDFUNCSEPARATEPROC) \ GL_FUN(BlendFuncSeparate, _PFNGLBLENDFUNCSEPARATEPROC) \
GL_FUN(BlendEquation, PFNGLBLENDEQUATIONPROC) \ GL_FUN(BlendEquation, _PFNGLBLENDEQUATIONPROC) \
GL_FUN(DrawElements, PFNGLDRAWELEMENTSPROC) \ GL_FUN(DrawElements, _PFNGLDRAWELEMENTSPROC) \
/* Texture */ \ /* Texture */ \
GL_FUN(GenTextures, PFNGLGENTEXTURESPROC) \ GL_FUN(GenTextures, _PFNGLGENTEXTURESPROC) \
GL_FUN(DeleteTextures, PFNGLDELETETEXTURESPROC) \ GL_FUN(DeleteTextures, _PFNGLDELETETEXTURESPROC) \
GL_FUN(BindTexture, PFNGLBINDTEXTUREPROC) \ GL_FUN(BindTexture, _PFNGLBINDTEXTUREPROC) \
GL_FUN(TexImage2D, PFNGLTEXIMAGE2DPROC) \ GL_FUN(TexImage2D, _PFNGLTEXIMAGE2DPROC) \
GL_FUN(TexSubImage2D, PFNGLTEXSUBIMAGE2DPROC) \ GL_FUN(TexSubImage2D, _PFNGLTEXSUBIMAGE2DPROC) \
GL_FUN(TexParameteri, PFNGLTEXPARAMETERIPROC) \ GL_FUN(TexParameteri, _PFNGLTEXPARAMETERIPROC) \
GL_FUN(ActiveTexture, PFNGLACTIVETEXTUREPROC) \ GL_FUN(ActiveTexture, _PFNGLACTIVETEXTUREPROC) \
/* Buffer object */ \ /* Buffer object */ \
GL_FUN(GenBuffers, PFNGLGENBUFFERSPROC) \ GL_FUN(GenBuffers, _PFNGLGENBUFFERSPROC) \
GL_FUN(DeleteBuffers, PFNGLDELETEBUFFERSPROC) \ GL_FUN(DeleteBuffers, _PFNGLDELETEBUFFERSPROC) \
GL_FUN(BindBuffer, PFNGLBINDBUFFERPROC) \ GL_FUN(BindBuffer, _PFNGLBINDBUFFERPROC) \
GL_FUN(BufferData, PFNGLBUFFERDATAPROC) \ GL_FUN(BufferData, _PFNGLBUFFERDATAPROC) \
GL_FUN(BufferSubData, PFNGLBUFFERSUBDATAPROC) \ GL_FUN(BufferSubData, _PFNGLBUFFERSUBDATAPROC) \
/* Shader */ \ /* Shader */ \
GL_FUN(CreateShader, PFNGLCREATESHADERPROC) \ GL_FUN(CreateShader, _PFNGLCREATESHADERPROC) \
GL_FUN(DeleteShader, PFNGLDELETESHADERPROC) \ GL_FUN(DeleteShader, _PFNGLDELETESHADERPROC) \
GL_FUN(ShaderSource, PFNGLSHADERSOURCEPROC) \ GL_FUN(ShaderSource, _PFNGLSHADERSOURCEPROC) \
GL_FUN(CompileShader, PFNGLCOMPILESHADERPROC) \ GL_FUN(CompileShader, _PFNGLCOMPILESHADERPROC) \
GL_FUN(AttachShader, PFNGLATTACHSHADERPROC) \ GL_FUN(AttachShader, _PFNGLATTACHSHADERPROC) \
GL_FUN(GetShaderiv, PFNGLGETSHADERIVPROC) \ GL_FUN(GetShaderiv, _PFNGLGETSHADERIVPROC) \
GL_FUN(GetShaderInfoLog, PFNGLGETSHADERINFOLOGPROC) \ GL_FUN(GetShaderInfoLog, _PFNGLGETSHADERINFOLOGPROC) \
/* Program */ \ /* Program */ \
GL_FUN(CreateProgram, PFNGLCREATEPROGRAMPROC) \ GL_FUN(CreateProgram, _PFNGLCREATEPROGRAMPROC) \
GL_FUN(DeleteProgram, PFNGLDELETEPROGRAMPROC) \ GL_FUN(DeleteProgram, _PFNGLDELETEPROGRAMPROC) \
GL_FUN(UseProgram, PFNGLUSEPROGRAMPROC) \ GL_FUN(UseProgram, _PFNGLUSEPROGRAMPROC) \
GL_FUN(LinkProgram, PFNGLLINKPROGRAMPROC) \ GL_FUN(LinkProgram, _PFNGLLINKPROGRAMPROC) \
GL_FUN(GetProgramiv, PFNGLGETPROGRAMIVPROC) \ GL_FUN(GetProgramiv, _PFNGLGETPROGRAMIVPROC) \
GL_FUN(GetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \ GL_FUN(GetProgramInfoLog, _PFNGLGETPROGRAMINFOLOGPROC) \
/* Uniform */ \ /* Uniform */ \
GL_FUN(GetUniformLocation, PFNGLGETUNIFORMLOCATIONPROC) \ GL_FUN(GetUniformLocation, _PFNGLGETUNIFORMLOCATIONPROC) \
GL_FUN(Uniform1f, PFNGLUNIFORM1FPROC) \ GL_FUN(Uniform1f, _PFNGLUNIFORM1FPROC) \
GL_FUN(Uniform2f, PFNGLUNIFORM2FPROC) \ GL_FUN(Uniform2f, _PFNGLUNIFORM2FPROC) \
GL_FUN(Uniform4f, PFNGLUNIFORM4FPROC) \ GL_FUN(Uniform4f, _PFNGLUNIFORM4FPROC) \
GL_FUN(Uniform1i, PFNGLUNIFORM1IPROC) \ GL_FUN(Uniform1i, _PFNGLUNIFORM1IPROC) \
GL_FUN(UniformMatrix4fv, PFNGLUNIFORMMATRIX4FVPROC) \ GL_FUN(UniformMatrix4fv, _PFNGLUNIFORMMATRIX4FVPROC) \
/* Vertex attribute */ \ /* Vertex attribute */ \
GL_FUN(BindAttribLocation, PFNGLBINDATTRIBLOCATIONPROC) \ GL_FUN(BindAttribLocation, _PFNGLBINDATTRIBLOCATIONPROC) \
GL_FUN(EnableVertexAttribArray, PFNGLENABLEVERTEXATTRIBARRAYPROC) \ GL_FUN(EnableVertexAttribArray, _PFNGLENABLEVERTEXATTRIBARRAYPROC) \
GL_FUN(DisableVertexAttribArray, PFNGLDISABLEVERTEXATTRIBARRAYPROC) \ GL_FUN(DisableVertexAttribArray, _PFNGLDISABLEVERTEXATTRIBARRAYPROC) \
GL_FUN(VertexAttribPointer, PFNGLVERTEXATTRIBPOINTERPROC) GL_FUN(VertexAttribPointer, _PFNGLVERTEXATTRIBPOINTERPROC)
#define GL_ES_FUN \
GL_FUN(ReleaseShaderCompiler, _PFNGLRELEASESHADERCOMPILERPROC)
#define GL_FBO_FUN \ #define GL_FBO_FUN \
/* Framebuffer object */ \ /* Framebuffer object */ \
GL_FUN(GenFramebuffers, PFNGLGENFRAMEBUFFERSPROC) \ GL_FUN(GenFramebuffers, _PFNGLGENFRAMEBUFFERSPROC) \
GL_FUN(DeleteFramebuffers, PFNGLDELETEFRAMEBUFFERSPROC) \ GL_FUN(DeleteFramebuffers, _PFNGLDELETEFRAMEBUFFERSPROC) \
GL_FUN(BindFramebuffer, PFNGLBINDFRAMEBUFFERPROC) \ GL_FUN(BindFramebuffer, _PFNGLBINDFRAMEBUFFERPROC) \
GL_FUN(FramebufferTexture2D, PFNGLFRAMEBUFFERTEXTURE2DPROC) GL_FUN(FramebufferTexture2D, _PFNGLFRAMEBUFFERTEXTURE2DPROC)
#define GL_FBO_BLIT_FUN \ #define GL_FBO_BLIT_FUN \
GL_FUN(BlitFramebuffer, PFNGLBLITFRAMEBUFFERPROC) GL_FUN(BlitFramebuffer, _PFNGLBLITFRAMEBUFFERPROC)
#define GL_VAO_FUN \ #define GL_VAO_FUN \
/* Vertex array object */ \ /* Vertex array object */ \
GL_FUN(GenVertexArrays, PFNGLGENVERTEXARRAYSPROC) \ GL_FUN(GenVertexArrays, _PFNGLGENVERTEXARRAYSPROC) \
GL_FUN(DeleteVertexArrays, PFNGLDELETEVERTEXARRAYSPROC) \ GL_FUN(DeleteVertexArrays, _PFNGLDELETEVERTEXARRAYSPROC) \
GL_FUN(BindVertexArray, PFNGLBINDVERTEXARRAYPROC) GL_FUN(BindVertexArray, _PFNGLBINDVERTEXARRAYPROC)
#define GL_DEBUG_KHR_FUN \ #define GL_DEBUG_KHR_FUN \
GL_FUN(DebugMessageCallback, _PFNGLDEBUGMESSAGECALLBACKPROC) GL_FUN(DebugMessageCallback, _PFNGLDEBUGMESSAGECALLBACKPROC)
#define GL_GREMEMDY_FUN \
GL_FUN(StringMarker, _PFNGLSTRINGMARKERPROC)
struct GLFunctions struct GLFunctions
{ {
#define GL_FUN(name, type) type name; #define GL_FUN(name, type) type name;
GL_20_FUN GL_20_FUN
GL_ES_FUN
GL_FBO_FUN GL_FBO_FUN
GL_FBO_BLIT_FUN GL_FBO_BLIT_FUN
GL_VAO_FUN GL_VAO_FUN
GL_DEBUG_KHR_FUN GL_DEBUG_KHR_FUN
GL_GREMEMDY_FUN
bool glsles; bool glsles;
bool unpack_subimage; bool unpack_subimage;

View File

@ -61,43 +61,43 @@ namespace TEX
return id; return id;
} }
inline void del(ID id) static inline void del(ID id)
{ {
gl.DeleteTextures(1, &id.gl); gl.DeleteTextures(1, &id.gl);
} }
inline void bind(ID id) static inline void bind(ID id)
{ {
gl.BindTexture(GL_TEXTURE_2D, id.gl); gl.BindTexture(GL_TEXTURE_2D, id.gl);
} }
inline void unbind() static inline void unbind()
{ {
bind(ID(0)); bind(ID(0));
} }
inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format) static inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format)
{ {
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, data); gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, data);
} }
inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format) static inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format)
{ {
gl.TexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, format, GL_UNSIGNED_BYTE, data); gl.TexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, format, GL_UNSIGNED_BYTE, data);
} }
inline void allocEmpty(GLsizei width, GLsizei height) static inline void allocEmpty(GLsizei width, GLsizei height)
{ {
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
} }
inline void setRepeat(bool mode) static inline void setRepeat(bool mode)
{ {
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
} }
inline void setSmooth(bool mode) static inline void setSmooth(bool mode)
{ {
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode ? GL_LINEAR : GL_NEAREST); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode ? GL_LINEAR : GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST);
@ -117,27 +117,27 @@ namespace FBO
return id; return id;
} }
inline void del(ID id) static inline void del(ID id)
{ {
gl.DeleteFramebuffers(1, &id.gl); gl.DeleteFramebuffers(1, &id.gl);
} }
inline void bind(ID id) static inline void bind(ID id)
{ {
gl.BindFramebuffer(GL_FRAMEBUFFER, id.gl); gl.BindFramebuffer(GL_FRAMEBUFFER, id.gl);
} }
inline void unbind() static inline void unbind()
{ {
bind(ID(0)); bind(ID(0));
} }
inline void setTarget(TEX::ID target, unsigned colorAttach = 0) static inline void setTarget(TEX::ID target, unsigned colorAttach = 0)
{ {
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, target.gl, 0); gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, target.gl, 0);
} }
inline void clear() static inline void clear()
{ {
gl.Clear(GL_COLOR_BUFFER_BIT); gl.Clear(GL_COLOR_BUFFER_BIT);
} }
@ -148,7 +148,7 @@ struct GenericBO
{ {
DEF_GL_ID DEF_GL_ID
inline static ID gen() static inline ID gen()
{ {
ID id; ID id;
gl.GenBuffers(1, &id.gl); gl.GenBuffers(1, &id.gl);
@ -156,32 +156,32 @@ struct GenericBO
return id; return id;
} }
inline static void del(ID id) static inline void del(ID id)
{ {
gl.DeleteBuffers(1, &id.gl); gl.DeleteBuffers(1, &id.gl);
} }
inline static void bind(ID id) static inline void bind(ID id)
{ {
gl.BindBuffer(target, id.gl); gl.BindBuffer(target, id.gl);
} }
inline static void unbind() static inline void unbind()
{ {
bind(ID(0)); bind(ID(0));
} }
inline static void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW) static inline void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW)
{ {
gl.BufferData(target, size, data, usage); gl.BufferData(target, size, data, usage);
} }
inline static void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data) static inline void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data)
{ {
gl.BufferSubData(target, offset, size, data); gl.BufferSubData(target, offset, size, data);
} }
inline static void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW) static inline void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW)
{ {
uploadData(size, 0, usage); uploadData(size, 0, usage);
} }

View File

@ -43,7 +43,7 @@ void GLScissorBox::apply(const IntRect &value)
void GLScissorBox::setIntersect(const IntRect &value) void GLScissorBox::setIntersect(const IntRect &value)
{ {
IntRect &current = get(); const IntRect &current = get();
SDL_Rect r1 = { current.x, current.y, current.w, current.h }; SDL_Rect r1 = { current.x, current.y, current.w, current.h };
SDL_Rect r2 = { value.x, value.y, value.w, value.h }; SDL_Rect r2 = { value.x, value.y, value.w, value.h };

View File

@ -43,7 +43,7 @@ struct GLProperty
void push() { stack.push(current); } void push() { stack.push(current); }
void pop() { set(stack.top()); stack.pop(); } void pop() { set(stack.top()); stack.pop(); }
T &get() { return current; } const T &get() { return current; }
void set(const T &value) void set(const T &value)
{ {
if (value == current) if (value == current)

View File

@ -171,36 +171,112 @@ public:
void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t) void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t)
{ {
pp.swapRender(); const IntRect &viewpRect = glState.scissorBox.get();
const IntRect &screenRect = geometry.rect;
/* Scissor test _does_ affect FBO blit operations, if (t.w != 0.0)
* and since we're inside the draw cycle, it will {
* be turned on, so turn it off temporarily */ pp.swapRender();
glState.scissorTest.pushSet(false);
GLMeta::blitBegin(pp.frontBuffer()); if (!viewpRect.encloses(screenRect))
GLMeta::blitSource(pp.backBuffer()); {
GLMeta::blitRectangle(geometry.rect, Vec2i()); /* Scissor test _does_ affect FBO blit operations,
GLMeta::blitEnd(); * and since we're inside the draw cycle, it will
* be turned on, so turn it off temporarily */
glState.scissorTest.pushSet(false);
glState.scissorTest.pop(); GLMeta::blitBegin(pp.frontBuffer());
GLMeta::blitSource(pp.backBuffer());
GLMeta::blitRectangle(geometry.rect, Vec2i());
GLMeta::blitEnd();
PlaneShader &shader = shState->shaders().plane; glState.scissorTest.pop();
}
GrayShader &shader = shState->shaders().gray;
shader.bind();
shader.setGray(t.w);
shader.applyViewportProj();
shader.setTexSize(screenRect.size());
TEX::bind(pp.backBuffer().tex);
glState.blend.pushSet(false);
screenQuad.draw();
glState.blend.pop();
}
bool toneEffect = t.xyzHasEffect();
bool colorEffect = c.xyzHasEffect();
bool flashEffect = f.xyzHasEffect();
if (!toneEffect && !colorEffect && !flashEffect)
return;
FlatColorShader &shader = shState->shaders().flatColor;
shader.bind(); shader.bind();
shader.setColor(c);
shader.setFlash(f);
shader.setTone(t);
shader.setOpacity(1.0);
shader.applyViewportProj(); shader.applyViewportProj();
shader.setTexSize(geometry.rect.size());
TEX::bind(pp.backBuffer().tex); /* Apply tone */
if (toneEffect)
{
/* First split up additive / substractive components */
Vec4 add, sub;
glState.blend.pushSet(false); if (t.x > 0)
add.x = t.x;
if (t.y > 0)
add.y = t.y;
if (t.z > 0)
add.z = t.z;
screenQuad.draw(); if (t.x < 0)
sub.x = -t.x;
if (t.y < 0)
sub.y = -t.y;
if (t.z < 0)
sub.z = -t.z;
glState.blend.pop(); /* Then apply them using hardware blending */
gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE);
if (add.xyzHasEffect())
{
gl.BlendEquation(GL_FUNC_ADD);
shader.setColor(add);
screenQuad.draw();
}
if (sub.xyzHasEffect())
{
gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
shader.setColor(sub);
screenQuad.draw();
}
}
if (colorEffect || flashEffect)
{
gl.BlendEquation(GL_FUNC_ADD);
gl.BlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ZERO, GL_ONE);
}
if (colorEffect)
{
shader.setColor(c);
screenQuad.draw();
}
if (flashEffect)
{
shader.setColor(f);
screenQuad.draw();
}
glState.blendMode.refresh();
} }
void setBrightness(float norm) void setBrightness(float norm)
@ -390,6 +466,7 @@ struct GraphicsPrivate
ScreenScene screen; ScreenScene screen;
RGSSThreadData *threadData; RGSSThreadData *threadData;
SDL_GLContext glCtx;
int frameRate; int frameRate;
int frameCount; int frameCount;
@ -413,6 +490,7 @@ struct GraphicsPrivate
winSize(rtData->config.defScreenW, rtData->config.defScreenH), winSize(rtData->config.defScreenW, rtData->config.defScreenH),
screen(scRes.x, scRes.y), screen(scRes.x, scRes.y),
threadData(rtData), threadData(rtData),
glCtx(SDL_GL_GetCurrentContext()),
frameRate(DEF_FRAMERATE), frameRate(DEF_FRAMERATE),
frameCount(0), frameCount(0),
brightness(255), brightness(255),
@ -482,7 +560,7 @@ struct GraphicsPrivate
void checkResize() void checkResize()
{ {
if (threadData->windowSizeMsg.pollChange(&winSize.x, &winSize.y)) if (threadData->windowSizeMsg.poll(winSize))
{ {
/* some GL drivers change the viewport on window resize */ /* some GL drivers change the viewport on window resize */
glState.viewport.refresh(); glState.viewport.refresh();
@ -552,16 +630,40 @@ struct GraphicsPrivate
swapGLBuffer(); swapGLBuffer();
} }
void checkSyncLock()
{
if (!threadData->syncPoint.mainSyncLocked())
return;
/* Releasing the GL context before sleeping and making it
* current again on wakeup seems to avoid the context loss
* when the app moves into the background on Android */
SDL_GL_MakeCurrent(threadData->window, 0);
threadData->syncPoint.waitMainSync();
SDL_GL_MakeCurrent(threadData->window, glCtx);
fpsLimiter.resetFrameAdjust();
}
}; };
Graphics::Graphics(RGSSThreadData *data) Graphics::Graphics(RGSSThreadData *data)
{ {
p = new GraphicsPrivate(data); p = new GraphicsPrivate(data);
if (data->config.fixedFramerate > 0) if (data->config.syncToRefreshrate)
p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate); {
else if (data->config.fixedFramerate < 0) p->frameRate = data->refreshRate;
p->fpsLimiter.disabled = true; p->fpsLimiter.disabled = true;
}
else if (data->config.fixedFramerate > 0)
{
p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate);
}
else if (data->config.fixedFramerate < 0)
{
p->fpsLimiter.disabled = true;
}
} }
Graphics::~Graphics() Graphics::~Graphics()
@ -572,6 +674,7 @@ Graphics::~Graphics()
void Graphics::update() void Graphics::update()
{ {
p->checkShutDownReset(); p->checkShutDownReset();
p->checkSyncLock();
if (p->frozen) if (p->frozen)
return; return;
@ -613,10 +716,12 @@ void Graphics::transition(int duration,
const char *filename, const char *filename,
int vague) int vague)
{ {
p->checkSyncLock();
if (!p->frozen) if (!p->frozen)
return; return;
vague = clamp(vague, 0, 512); vague = clamp(vague, 1, 256);
Bitmap *transMap = filename ? new Bitmap(filename) : 0; Bitmap *transMap = filename ? new Bitmap(filename) : 0;
setBrightness(255); setBrightness(255);
@ -637,7 +742,7 @@ void Graphics::transition(int duration,
shader.setFrozenScene(p->frozenScene.tex); shader.setFrozenScene(p->frozenScene.tex);
shader.setCurrentScene(p->currentScene.tex); shader.setCurrentScene(p->currentScene.tex);
shader.setTransMap(transMap->getGLTypes().tex); shader.setTransMap(transMap->getGLTypes().tex);
shader.setVague(vague / 512.0f); shader.setVague(vague / 256.0);
shader.setTexSize(p->scRes); shader.setTexSize(p->scRes);
} }
else else
@ -673,6 +778,8 @@ void Graphics::transition(int duration,
return; return;
} }
p->checkSyncLock();
const float prog = i * (1.0 / duration); const float prog = i * (1.0 / duration);
if (transMap) if (transMap)
@ -728,6 +835,9 @@ void Graphics::setFrameRate(int value)
{ {
p->frameRate = clamp(value, 10, 120); p->frameRate = clamp(value, 10, 120);
if (p->threadData->config.syncToRefreshrate)
return;
if (p->threadData->config.fixedFramerate > 0) if (p->threadData->config.fixedFramerate > 0)
return; return;

View File

@ -133,7 +133,7 @@ struct JsAxisBinding : public Binding
bool sourceActive() const bool sourceActive() const
{ {
int val = EventThread::joyState.axis[source]; int val = EventThread::joyState.axes[source];
if (dir == Negative) if (dir == Negative)
return val < -JAXIS_THRESHOLD; return val < -JAXIS_THRESHOLD;
@ -150,6 +150,34 @@ struct JsAxisBinding : public Binding
AxisDir dir; AxisDir dir;
}; };
/* Joystick hat binding */
struct JsHatBinding : public Binding
{
JsHatBinding() {}
JsHatBinding(uint8_t source,
uint8_t pos,
Input::ButtonCode target)
: Binding(target),
source(source),
pos(pos)
{}
bool sourceActive() const
{
/* For a diagonal input accept it as an input for both the axes */
return (pos & EventThread::joyState.hats[source]) != 0;
}
bool sourceRepeatable() const
{
return true;
}
uint8_t source;
uint8_t pos;
};
/* Mouse button binding */ /* Mouse button binding */
struct MsBinding : public Binding struct MsBinding : public Binding
{ {
@ -241,6 +269,7 @@ struct InputPrivate
std::vector<KbBinding> kbStatBindings; std::vector<KbBinding> kbStatBindings;
std::vector<KbBinding> kbBindings; std::vector<KbBinding> kbBindings;
std::vector<JsAxisBinding> jsABindings; std::vector<JsAxisBinding> jsABindings;
std::vector<JsHatBinding> jsHBindings;
std::vector<JsButtonBinding> jsBBindings; std::vector<JsButtonBinding> jsBBindings;
std::vector<MsBinding> msBindings; std::vector<MsBinding> msBindings;
@ -348,6 +377,7 @@ struct InputPrivate
{ {
kbBindings.clear(); kbBindings.clear();
jsABindings.clear(); jsABindings.clear();
jsHBindings.clear();
jsBBindings.clear(); jsBBindings.clear();
for (size_t i = 0; i < d.size(); ++i) for (size_t i = 0; i < d.size(); ++i)
@ -381,6 +411,16 @@ struct InputPrivate
break; break;
} }
case JHat :
{
JsHatBinding bind;
bind.source = src.d.jh.hat;
bind.pos = src.d.jh.pos;
bind.target = desc.target;
jsHBindings.push_back(bind);
break;
}
case JButton : case JButton :
{ {
JsButtonBinding bind; JsButtonBinding bind;
@ -402,6 +442,7 @@ struct InputPrivate
appendBindings(kbBindings); appendBindings(kbBindings);
appendBindings(jsABindings); appendBindings(jsABindings);
appendBindings(jsHBindings);
appendBindings(jsBBindings); appendBindings(jsBBindings);
} }

View File

@ -129,6 +129,20 @@ static void addAxisBinding(BDescVec &d, uint8_t axis, AxisDir dir, Input::Button
d.push_back(desc); d.push_back(desc);
} }
static void addHatBinding(BDescVec &d, uint8_t hat, uint8_t pos, Input::ButtonCode target)
{
SourceDesc src;
src.type = JHat;
src.d.jh.hat = hat;
src.d.jh.pos = pos;
BindingDesc desc;
desc.src = src;
desc.target = target;
d.push_back(desc);
}
BDescVec genDefaultBindings(const Config &conf) BDescVec genDefaultBindings(const Config &conf)
{ {
BDescVec d; BDescVec d;
@ -150,11 +164,16 @@ BDescVec genDefaultBindings(const Config &conf)
addAxisBinding(d, 0, Positive, Input::Right); addAxisBinding(d, 0, Positive, Input::Right);
addAxisBinding(d, 1, Negative, Input::Up ); addAxisBinding(d, 1, Negative, Input::Up );
addAxisBinding(d, 1, Positive, Input::Down ); addAxisBinding(d, 1, Positive, Input::Down );
addHatBinding(d, 0, SDL_HAT_LEFT, Input::Left );
addHatBinding(d, 0, SDL_HAT_RIGHT, Input::Right);
addHatBinding(d, 0, SDL_HAT_UP, Input::Up );
addHatBinding(d, 0, SDL_HAT_DOWN, Input::Down );
return d; return d;
} }
#define FORMAT_VER 1 #define FORMAT_VER 2
struct Header struct Header
{ {
@ -166,7 +185,7 @@ struct Header
static void buildPath(const std::string &dir, uint32_t rgssVersion, static void buildPath(const std::string &dir, uint32_t rgssVersion,
char *out, size_t outSize) char *out, size_t outSize)
{ {
snprintf(out, outSize, "%s/keybindings.mkxp%u", dir.c_str(), rgssVersion); snprintf(out, outSize, "%skeybindings.mkxp%u", dir.c_str(), rgssVersion);
} }
static bool writeBindings(const BDescVec &d, const std::string &dir, static bool writeBindings(const BDescVec &d, const std::string &dir,
@ -178,7 +197,7 @@ static bool writeBindings(const BDescVec &d, const std::string &dir,
char path[1024]; char path[1024];
buildPath(dir, rgssVersion, path, sizeof(path)); buildPath(dir, rgssVersion, path, sizeof(path));
FILE *f = fopen(path, "w"); FILE *f = fopen(path, "wb");
if (!f) if (!f)
return false; return false;
@ -247,6 +266,10 @@ static bool verifyDesc(const BindingDesc &desc)
return src.d.scan < SDL_NUM_SCANCODES; return src.d.scan < SDL_NUM_SCANCODES;
case JButton: case JButton:
return true; return true;
case JHat:
/* Only accept single directional binds */
return src.d.jh.pos == SDL_HAT_LEFT || src.d.jh.pos == SDL_HAT_RIGHT ||
src.d.jh.pos == SDL_HAT_UP || src.d.jh.pos == SDL_HAT_DOWN;
case JAxis: case JAxis:
return src.d.ja.dir == Negative || src.d.ja.dir == Positive; return src.d.ja.dir == Negative || src.d.ja.dir == Positive;
default: default:
@ -263,7 +286,7 @@ static bool readBindings(BDescVec &out, const std::string &dir,
char path[1024]; char path[1024];
buildPath(dir, rgssVersion, path, sizeof(path)); buildPath(dir, rgssVersion, path, sizeof(path));
FILE *f = fopen(path, "r"); FILE *f = fopen(path, "rb");
if (!f) if (!f)
return false; return false;

View File

@ -25,6 +25,7 @@
#include "input.h" #include "input.h"
#include <SDL_scancode.h> #include <SDL_scancode.h>
#include <SDL_joystick.h>
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <vector> #include <vector>
@ -40,7 +41,8 @@ enum SourceType
Invalid, Invalid,
Key, Key,
JButton, JButton,
JAxis JAxis,
JHat
}; };
struct SourceDesc struct SourceDesc
@ -60,6 +62,13 @@ struct SourceDesc
/* Joystick axis direction */ /* Joystick axis direction */
AxisDir dir; AxisDir dir;
} ja; } ja;
struct
{
/* Joystick axis index */
uint8_t hat;
/* Joystick axis direction */
uint8_t pos;
} jh;
} d; } d;
bool operator==(const SourceDesc &o) const bool operator==(const SourceDesc &o) const
@ -77,6 +86,8 @@ struct SourceDesc
return d.jb == o.d.jb; return d.jb == o.d.jb;
case JAxis: case JAxis:
return (d.ja.axis == o.d.ja.axis) && (d.ja.dir == o.d.ja.dir); return (d.ja.axis == o.d.ja.axis) && (d.ja.dir == o.d.ja.dir);
case JHat:
return (d.jh.hat == o.d.jh.hat) && (d.jh.pos == o.d.jh.pos);
default: default:
assert(!"unreachable"); assert(!"unreachable");
return false; return false;

View File

@ -26,20 +26,21 @@
#include <SDL_ttf.h> #include <SDL_ttf.h>
#include <SDL_sound.h> #include <SDL_sound.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <string> #include <string>
#include "sharedstate.h" #include "sharedstate.h"
#include "eventthread.h" #include "eventthread.h"
#include "debuglogger.h" #include "gl-debug.h"
#include "debugwriter.h" #include "debugwriter.h"
#include "exception.h" #include "exception.h"
#include "gl-fun.h" #include "gl-fun.h"
#include "binding.h" #include "binding.h"
#include <unistd.h> #include "icon.png.xxd"
#include <string.h>
#include <assert.h>
static void static void
rgssThreadError(RGSSThreadData *rtData, const std::string &msg) rgssThreadError(RGSSThreadData *rtData, const std::string &msg)
@ -67,13 +68,14 @@ printGLInfo()
int rgssThreadFun(void *userdata) int rgssThreadFun(void *userdata)
{ {
RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata); RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata);
const Config &conf = threadData->config;
SDL_Window *win = threadData->window; SDL_Window *win = threadData->window;
SDL_GLContext glCtx; SDL_GLContext glCtx;
/* Setup GL context */ /* Setup GL context */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if (threadData->config.debugMode) if (conf.debugMode)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
glCtx = SDL_GL_CreateContext(win); glCtx = SDL_GL_CreateContext(win);
@ -102,27 +104,17 @@ int rgssThreadFun(void *userdata)
printGLInfo(); printGLInfo();
SDL_GL_SetSwapInterval(threadData->config.vsync ? 1 : 0); bool vsync = conf.vsync || conf.syncToRefreshrate;
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
DebugLogger dLogger; GLDebugLogger dLogger;
/* Setup AL context */ /* Setup AL context */
ALCdevice *alcDev = alcOpenDevice(0); ALCcontext *alcCtx = alcCreateContext(threadData->alcDev, 0);
if (!alcDev)
{
rgssThreadError(threadData, "Error opening OpenAL device");
SDL_GL_DeleteContext(glCtx);
return 0;
}
ALCcontext *alcCtx = alcCreateContext(alcDev, 0);
if (!alcCtx) if (!alcCtx)
{ {
rgssThreadError(threadData, "Error creating OpenAL context"); rgssThreadError(threadData, "Error creating OpenAL context");
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx); SDL_GL_DeleteContext(glCtx);
return 0; return 0;
@ -138,7 +130,6 @@ int rgssThreadFun(void *userdata)
{ {
rgssThreadError(threadData, exc.msg); rgssThreadError(threadData, exc.msg);
alcDestroyContext(alcCtx); alcDestroyContext(alcCtx);
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx); SDL_GL_DeleteContext(glCtx);
return 0; return 0;
@ -153,8 +144,6 @@ int rgssThreadFun(void *userdata)
SharedState::finiInstance(); SharedState::finiInstance();
alcDestroyContext(alcCtx); alcDestroyContext(alcCtx);
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx); SDL_GL_DeleteContext(glCtx);
return 0; return 0;
@ -171,20 +160,27 @@ static void printRgssVersion(int ver)
Debug() << buf; Debug() << buf;
} }
static void showInitError(const std::string &msg)
{
Debug() << msg;
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "mkxp", msg.c_str(), 0);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
/* initialize SDL first */ /* initialize SDL first */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0)
{ {
Debug() << "Error initializing SDL:" << SDL_GetError(); showInitError(std::string("Error initializing SDL: ") + SDL_GetError());
return 0; return 0;
} }
if (!EventThread::allocUserEvents()) if (!EventThread::allocUserEvents())
{ {
Debug() << "Error allocating SDL user events"; showInitError("Error allocating SDL user events");
return 0; return 0;
} }
@ -201,8 +197,15 @@ int main(int argc, char *argv[])
/* now we load the config */ /* now we load the config */
Config conf; Config conf;
conf.read(argc, argv); conf.read(argc, argv);
if (!conf.gameFolder.empty())
if (chdir(conf.gameFolder.c_str()) != 0)
{
showInitError(std::string("Unable to switch into gameFolder ") + conf.gameFolder);
return 0;
}
conf.readGameINI(); conf.readGameINI();
assert(conf.rgssVersion >= 1 && conf.rgssVersion <= 3); assert(conf.rgssVersion >= 1 && conf.rgssVersion <= 3);
@ -211,7 +214,7 @@ int main(int argc, char *argv[])
int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG; int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
if (IMG_Init(imgFlags) != imgFlags) if (IMG_Init(imgFlags) != imgFlags)
{ {
Debug() << "Error initializing SDL_image:" << SDL_GetError(); showInitError(std::string("Error initializing SDL_image: ") + SDL_GetError());
SDL_Quit(); SDL_Quit();
return 0; return 0;
@ -219,7 +222,7 @@ int main(int argc, char *argv[])
if (TTF_Init() < 0) if (TTF_Init() < 0)
{ {
Debug() << "Error initializing SDL_ttf:" << SDL_GetError(); showInitError(std::string("Error initializing SDL_ttf: ") + SDL_GetError());
IMG_Quit(); IMG_Quit();
SDL_Quit(); SDL_Quit();
@ -228,7 +231,7 @@ int main(int argc, char *argv[])
if (Sound_Init() == 0) if (Sound_Init() == 0)
{ {
Debug() << "Error initializing SDL_sound:" << Sound_GetError(); showInitError(std::string("Error initializing SDL_sound: ") + Sound_GetError());
TTF_Quit(); TTF_Quit();
IMG_Quit(); IMG_Quit();
SDL_Quit(); SDL_Quit();
@ -236,7 +239,15 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0"); /* Setup application icon */
SDL_RWops *iconSrc;
if (conf.iconPath.empty())
iconSrc = SDL_RWFromConstMem(assets_icon_png, assets_icon_png_len);
else
iconSrc = SDL_RWFromFile(conf.iconPath.c_str(), "rb");
SDL_Surface *iconImg = IMG_Load_RW(iconSrc, SDL_TRUE);
SDL_Window *win; SDL_Window *win;
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS; Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS;
@ -252,22 +263,43 @@ int main(int argc, char *argv[])
if (!win) if (!win)
{ {
Debug() << "Error creating window:" << SDL_GetError(); showInitError(std::string("Error creating window: ") + SDL_GetError());
return 0; return 0;
} }
if (!conf.iconPath.empty()) if (iconImg)
{ {
SDL_Surface *iconImg = IMG_Load(conf.iconPath.c_str()); SDL_SetWindowIcon(win, iconImg);
if (iconImg) SDL_FreeSurface(iconImg);
{
SDL_SetWindowIcon(win, iconImg);
SDL_FreeSurface(iconImg);
}
} }
ALCdevice *alcDev = alcOpenDevice(0);
if (!alcDev)
{
showInitError("Error opening OpenAL device");
SDL_DestroyWindow(win);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}
SDL_DisplayMode mode;
SDL_GetDisplayMode(0, 0, &mode);
/* Can't sync to display refresh rate if its value is unknown */
if (!mode.refresh_rate)
conf.syncToRefreshrate = false;
EventThread eventThread; EventThread eventThread;
RGSSThreadData rtData(&eventThread, argv[0], win, conf); RGSSThreadData rtData(&eventThread, argv[0], win,
alcDev, mode.refresh_rate, conf);
int winW, winH;
SDL_GetWindowSize(win, &winW, &winH);
rtData.windowSizeMsg.post(Vec2i(winW, winH));
/* Load and post key bindings */ /* Load and post key bindings */
rtData.bindingUpdateMsg.post(loadBindings(conf)); rtData.bindingUpdateMsg.post(loadBindings(conf));
@ -314,13 +346,9 @@ int main(int argc, char *argv[])
/* Clean up any remainin events */ /* Clean up any remainin events */
eventThread.cleanup(); eventThread.cleanup();
/* Store key bindings */
BDescVec keyBinds;
rtData.bindingUpdateMsg.get(keyBinds);
storeBindings(keyBinds, rtData.config);
Debug() << "Shutting down."; Debug() << "Shutting down.";
alcCloseDevice(alcDev);
SDL_DestroyWindow(win); SDL_DestroyWindow(win);
Sound_Quit(); Sound_Quit();

View File

@ -55,7 +55,13 @@
#define TICK_FRAMES 32 #define TICK_FRAMES 32
#define BUF_TICKS (STREAM_BUF_SIZE / TICK_FRAMES) #define BUF_TICKS (STREAM_BUF_SIZE / TICK_FRAMES)
#define DEFAULT_BPM 120 #define DEFAULT_BPM 120
#define LOOP_MARKER 111 #define MAX_CHANNELS 16
#define CC_CTRL_VOLUME 7
#define CC_CTRL_EXPRESSION 11
#define CC_CTRL_LOOP 111
#define CC_VAL_DEFAULT 127
enum MidiEventType enum MidiEventType
{ {
@ -522,6 +528,59 @@ struct Track
} }
}; };
/* Some songs use CC events for effects like fade-out,
* slowly decreasing a channel's volume to 0. The problem is that
* for looped songs, events are continuously fed into the synth
* without restoring those controls back to their default value.
* We can't reset them at the very beginning of tracks because it
* might cause audible interactions with notes which are still decaying
* past the end of the song. Therefore, we insert a fake CC event right
* after the first NoteOn event for each channel which resets the
* control to its default state while avoiding audible glitches.
* If there is already a CC event for this control before the first
* NoteOn event, we don't clobber it by not inserting our fake event. */
template<uint8_t ctrl>
struct CCResetter
{
bool chanHandled[MAX_CHANNELS];
CCResetter()
{
memset(&chanHandled, 0, sizeof(chanHandled));
}
void handleEvent(const MidiEvent &e, Track &track)
{
if (e.type != NoteOn && e.type != CC)
return;
uint8_t chan = e.e.chan.chan;
if (chanHandled[chan])
return;
if (e.type == CC && e.e.cc.ctrl == ctrl)
{
/* Don't clobber the existing CC value */
chanHandled[chan] = true;
return;
}
else if (e.type == NoteOn)
{
chanHandled[chan] = true;
MidiEvent re;
re.delta = 0;
re.type = CC;
re.e.cc.chan = chan;
re.e.cc.ctrl = ctrl;
re.e.cc.val = CC_VAL_DEFAULT;
track.appendEvent(re);
}
}
};
struct MidiSource : ALDataSource, MidiReadHandler struct MidiSource : ALDataSource, MidiReadHandler
{ {
const uint16_t freq; const uint16_t freq;
@ -530,6 +589,8 @@ struct MidiSource : ALDataSource, MidiReadHandler
int16_t synthBuf[BUF_TICKS*TICK_FRAMES*2]; int16_t synthBuf[BUF_TICKS*TICK_FRAMES*2];
std::vector<Track> tracks; std::vector<Track> tracks;
CCResetter<CC_CTRL_VOLUME> volReset;
CCResetter<CC_CTRL_EXPRESSION> expReset;
/* Index of longest track */ /* Index of longest track */
uint8_t longestI; uint8_t longestI;
@ -631,7 +692,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
playbackSpeed = TICK_FRAMES / (deltaLength * freq); playbackSpeed = TICK_FRAMES / (deltaLength * freq);
} }
void activateEvent(MidiEvent &e) void activateEvent(const MidiEvent &e)
{ {
int16_t key = e.e.note.key; int16_t key = e.e.note.key;
@ -705,9 +766,14 @@ struct MidiSource : ALDataSource, MidiReadHandler
void onMidiEvent(const MidiEvent &e, uint32_t absDelta) void onMidiEvent(const MidiEvent &e, uint32_t absDelta)
{ {
assert(curTrack >= 0 && curTrack < (int16_t) tracks.size()); assert(curTrack >= 0 && curTrack < (int16_t) tracks.size());
tracks[curTrack].appendEvent(e);
if (e.type == CC && e.e.cc.ctrl == LOOP_MARKER) Track &track = tracks[curTrack];
track.appendEvent(e);
volReset.handleEvent(e, track);
expReset.handleEvent(e, track);
if (e.type == CC && e.e.cc.ctrl == CC_CTRL_LOOP)
loopDelta = absDelta; loopDelta = absDelta;
} }

View File

@ -90,8 +90,8 @@ struct PlanePrivate
if (gl.npot_repeat) if (gl.npot_repeat)
{ {
FloatRect srcRect; FloatRect srcRect;
srcRect.x = (sceneGeo.xOrigin + ox) / zoomX; srcRect.x = (sceneGeo.orig.x + ox) / zoomX;
srcRect.y = (sceneGeo.yOrigin + oy) / zoomY; srcRect.y = (sceneGeo.orig.y + oy) / zoomY;
srcRect.w = sceneGeo.rect.w / zoomX; srcRect.w = sceneGeo.rect.w / zoomX;
srcRect.h = sceneGeo.rect.h / zoomY; srcRect.h = sceneGeo.rect.h / zoomY;

View File

@ -23,10 +23,7 @@
#include "sharedstate.h" #include "sharedstate.h"
Scene::Scene() Scene::Scene()
{ {}
geometry.xOrigin = geometry.yOrigin = 0;
geometry.rect = IntRect();
}
Scene::~Scene() Scene::~Scene()
{ {

View File

@ -39,8 +39,16 @@ class Scene
public: public:
struct Geometry struct Geometry
{ {
int xOrigin, yOrigin; /* Position and size relative to parent */
IntRect rect; IntRect rect;
/* Origin of contents */
Vec2i orig;
Vec2i offset() const
{
return rect.pos() - orig;
}
}; };
Scene(); Scene();

View File

@ -3,8 +3,10 @@
#include <SDL_atomic.h> #include <SDL_atomic.h>
#include <SDL_thread.h> #include <SDL_thread.h>
#include <SDL_rwops.h>
#include <string> #include <string>
#include <iostream>
struct AtomicFlag struct AtomicFlag
{ {
@ -45,4 +47,115 @@ SDL_Thread *createSDLThread(C *obj, const std::string &name = std::string())
return SDL_CreateThread(__sdlThreadFun<C, func>, name.c_str(), obj); return SDL_CreateThread(__sdlThreadFun<C, func>, name.c_str(), obj);
} }
/* On Android, SDL_RWFromFile always opens files from inside
* the apk asset folder even when a file with same name exists
* on the physical filesystem. This wrapper attempts to open a
* real file first before falling back to the assets folder */
static inline
SDL_RWops *RWFromFile(const char *filename,
const char *mode)
{
FILE *f = fopen(filename, mode);
if (!f)
return SDL_RWFromFile(filename, mode);
return SDL_RWFromFP(f, SDL_TRUE);
}
inline bool readFileSDL(const char *path,
std::string &out)
{
SDL_RWops *f = RWFromFile(path, "rb");
if (!f)
return false;
long size = SDL_RWsize(f);
size_t back = out.size();
out.resize(back+size);
size_t read = SDL_RWread(f, &out[back], 1, size);
SDL_RWclose(f);
if (read != (size_t) size)
out.resize(back+read);
return true;
}
template<size_t bufSize = 248, size_t pbSize = 8>
class SDLRWBuf : public std::streambuf
{
public:
SDLRWBuf(SDL_RWops *ops)
: ops(ops)
{
char *end = buf + bufSize + pbSize;
setg(end, end, end);
}
private:
int_type underflow()
{
if (!ops)
return traits_type::eof();
if (gptr() < egptr())
return traits_type::to_int_type(*gptr());
char *base = buf;
char *start = base;
if (eback() == base)
{
memmove(base, egptr() - pbSize, pbSize);
start += pbSize;
}
size_t n = SDL_RWread(ops, start, 1, bufSize - (start - base));
if (n == 0)
return traits_type::eof();
setg(base, start, start + n);
return underflow();
}
SDL_RWops *ops;
char buf[bufSize+pbSize];
};
class SDLRWStream
{
public:
SDLRWStream(const char *filename,
const char *mode)
: ops(RWFromFile(filename, mode)),
buf(ops),
s(&buf)
{}
~SDLRWStream()
{
if (ops)
SDL_RWclose(ops);
}
operator bool() const
{
return ops != 0;
}
std::istream &stream()
{
return s;
}
private:
SDL_RWops *ops;
SDLRWBuf<> buf;
std::istream s;
};
#endif // SDLUTIL_H #endif // SDLUTIL_H

View File

@ -27,67 +27,44 @@
#include <SDL_endian.h> #include <SDL_endian.h>
typedef unsigned uint;
#if SDL_BYTEORDER != SDL_LIL_ENDIAN #if SDL_BYTEORDER != SDL_LIL_ENDIAN
#error "Non little endian systems not supported" #error "Non little endian systems not supported"
#endif #endif
static inline int16_t
read_int16(const char *data, uint &i)
{
int16_t result;
memcpy(&result, &data[i], 2);
i += 2;
return result;
}
static inline int32_t static inline int32_t
read_int32(const char *data, uint &i) readInt32(const char **dataP)
{ {
int32_t result; int32_t result;
memcpy(&result, &data[i], 4); memcpy(&result, *dataP, 4);
i += 4; *dataP += 4;
return result; return result;
} }
static inline double static inline double
read_double(const char *data, uint &i) readDouble(const char **dataP)
{ {
double result; double result;
memcpy(&result, &data[i], 8); memcpy(&result, *dataP, 8);
i += 8; *dataP += 8;
return result; return result;
} }
static inline void static inline void
write_int16(char **data, int16_t value) writeInt32(char **dataP, int32_t value)
{ {
memcpy(*data, &value, 2); memcpy(*dataP, &value, 4);
*dataP += 4;
*data += 2;
} }
static inline void static inline void
write_int32(char **data, int32_t value) writeDouble(char **dataP, double value)
{ {
memcpy(*data, &value, 4); memcpy(*dataP, &value, 8);
*dataP += 8;
*data += 4;
}
static inline void
write_double(char **data, double value)
{
memcpy(*data, &value, 8);
*data += 8;
} }
#endif // SERIALUTIL_H #endif // SERIALUTIL_H

View File

@ -81,6 +81,7 @@ static elementsN(vButtons);
std::string sourceDescString(const SourceDesc &src) std::string sourceDescString(const SourceDesc &src)
{ {
char buf[128]; char buf[128];
char pos;
switch (src.type) switch (src.type)
{ {
@ -104,6 +105,32 @@ std::string sourceDescString(const SourceDesc &src)
snprintf(buf, sizeof(buf), "JS %d", src.d.jb); snprintf(buf, sizeof(buf), "JS %d", src.d.jb);
return buf; return buf;
case JHat:
switch(src.d.jh.pos)
{
case SDL_HAT_UP:
pos = 'U';
break;
case SDL_HAT_DOWN:
pos = 'D';
break;
case SDL_HAT_LEFT:
pos = 'L';
break;
case SDL_HAT_RIGHT:
pos = 'R';
break;
default:
pos = '-';
}
snprintf(buf, sizeof(buf), "Hat %d:%c",
src.d.jh.hat, pos);
return buf;
case JAxis: case JAxis:
snprintf(buf, sizeof(buf), "Axis %d%c", snprintf(buf, sizeof(buf), "Axis %d%c",
src.d.ja.axis, src.d.ja.dir == Negative ? '-' : '+'); src.d.ja.axis, src.d.ja.dir == Negative ? '-' : '+');
@ -204,7 +231,8 @@ struct Label : Widget
Label(SMP *p, const IntRect &rect, Label(SMP *p, const IntRect &rect,
const char *str, uint8_t r, uint8_t g, uint8_t b) const char *str, uint8_t r, uint8_t g, uint8_t b)
: Widget(p, rect), : Widget(p, rect),
str(str) str(str),
visible(true)
{ {
c.r = r; c.r = r;
c.g = g; c.g = g;
@ -615,6 +643,21 @@ struct SettingsMenuPrivate
desc.d.jb = event.jbutton.button; desc.d.jb = event.jbutton.button;
break; break;
case SDL_JOYHATMOTION:
{
int v = event.jhat.value;
/* Only register if single directional input */
if (v != SDL_HAT_LEFT && v != SDL_HAT_RIGHT &&
v != SDL_HAT_UP && v != SDL_HAT_DOWN)
return true;
desc.type = JHat;
desc.d.jh.hat = event.jhat.hat;
desc.d.jh.pos = v;
break;
}
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
{ {
int v = event.jaxis.value; int v = event.jaxis.value;
@ -677,6 +720,9 @@ struct SettingsMenuPrivate
rtData.bindingUpdateMsg.post(binds); rtData.bindingUpdateMsg.post(binds);
/* Store the key bindings to disk as well to prevent config loss */
storeBindings(binds, rtData.config);
destroyReq = true; destroyReq = true;
} }
@ -1007,6 +1053,7 @@ bool SettingsMenu::onEvent(const SDL_Event &event)
case SDL_JOYBUTTONDOWN : case SDL_JOYBUTTONDOWN :
case SDL_JOYBUTTONUP : case SDL_JOYBUTTONUP :
case SDL_JOYHATMOTION :
case SDL_JOYAXISMOTION : case SDL_JOYAXISMOTION :
if (!p->hasFocus) if (!p->hasFocus)
return false; return false;
@ -1083,6 +1130,7 @@ bool SettingsMenu::onEvent(const SDL_Event &event)
} }
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
case SDL_JOYHATMOTION:
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
if (p->state != AwaitingInput) if (p->state != AwaitingInput)
return true; return true;

View File

@ -28,25 +28,30 @@
#include <string.h> #include <string.h>
#include <iostream> #include <iostream>
#include "../sprite.frag.xxd" #include "common.h.xxd"
#include "../hue.frag.xxd" #include "sprite.frag.xxd"
#include "../trans.frag.xxd" #include "hue.frag.xxd"
#include "../transSimple.frag.xxd" #include "trans.frag.xxd"
#include "../bitmapBlit.frag.xxd" #include "transSimple.frag.xxd"
#include "../plane.frag.xxd" #include "bitmapBlit.frag.xxd"
#include "../simple.frag.xxd" #include "plane.frag.xxd"
#include "../simpleColor.frag.xxd" #include "gray.frag.xxd"
#include "../simpleAlpha.frag.xxd" #include "flatColor.frag.xxd"
#include "../flashMap.frag.xxd" #include "simple.frag.xxd"
#include "../simple.vert.xxd" #include "simpleColor.frag.xxd"
#include "../simpleColor.vert.xxd" #include "simpleAlpha.frag.xxd"
#include "../sprite.vert.xxd" #include "simpleAlphaUni.frag.xxd"
#include "../tilemap.vert.xxd" #include "flashMap.frag.xxd"
#include "../blur.frag.xxd" #include "minimal.vert.xxd"
#include "../simpleMatrix.vert.xxd" #include "simple.vert.xxd"
#include "../blurH.vert.xxd" #include "simpleColor.vert.xxd"
#include "../blurV.vert.xxd" #include "sprite.vert.xxd"
#include "../tilemapvx.vert.xxd" #include "tilemap.vert.xxd"
#include "blur.frag.xxd"
#include "simpleMatrix.vert.xxd"
#include "blurH.vert.xxd"
#include "blurV.vert.xxd"
#include "tilemapvx.vert.xxd"
#define INIT_SHADER(vert, frag, name) \ #define INIT_SHADER(vert, frag, name) \
@ -106,32 +111,39 @@ void Shader::unbind()
glState.program.set(0); glState.program.set(0);
} }
static const char *glesHeader = "precision mediump float;\n"; static void setupShaderSource(GLuint shader, GLenum type,
static const size_t glesHeaderSize = strlen(glesHeader); const unsigned char *body, int bodySize)
static void setupShaderSource(GLuint shader,
const unsigned char *src, int srcSize)
{ {
GLuint shaderSrcN; static const char glesDefine[] = "#define GLSLES\n";
const GLchar *shaderSrc[2]; static const char fragDefine[] = "#define FRAGMENT_SHADER\n";
GLint shaderSrcSize[2];
const GLchar *shaderSrc[4];
GLint shaderSrcSize[4];
size_t i = 0;
if (gl.glsles) if (gl.glsles)
{ {
shaderSrcN = 2; shaderSrc[i] = glesDefine;
shaderSrc[0] = glesHeader; shaderSrcSize[i] = sizeof(glesDefine)-1;
shaderSrc[1] = (const GLchar*) src; ++i;
shaderSrcSize[0] = glesHeaderSize;
shaderSrcSize[1] = srcSize;
}
else
{
shaderSrcN = 1;
shaderSrc[0] = (const GLchar*) src;
shaderSrcSize[0] = srcSize;
} }
gl.ShaderSource(shader, shaderSrcN, shaderSrc, shaderSrcSize); if (type == GL_FRAGMENT_SHADER)
{
shaderSrc[i] = fragDefine;
shaderSrcSize[i] = sizeof(fragDefine)-1;
++i;
}
shaderSrc[i] = (const GLchar*) shader_common_h;
shaderSrcSize[i] = shader_common_h_len;
++i;
shaderSrc[i] = (const GLchar*) body;
shaderSrcSize[i] = bodySize;
++i;
gl.ShaderSource(shader, i, shaderSrc, shaderSrcSize);
} }
void Shader::init(const unsigned char *vert, int vertSize, void Shader::init(const unsigned char *vert, int vertSize,
@ -142,7 +154,7 @@ void Shader::init(const unsigned char *vert, int vertSize,
GLint success; GLint success;
/* Compile vertex shader */ /* Compile vertex shader */
setupShaderSource(vertShader, vert, vertSize); setupShaderSource(vertShader, GL_VERTEX_SHADER, vert, vertSize);
gl.CompileShader(vertShader); gl.CompileShader(vertShader);
gl.GetShaderiv(vertShader, GL_COMPILE_STATUS, &success); gl.GetShaderiv(vertShader, GL_COMPILE_STATUS, &success);
@ -156,7 +168,7 @@ void Shader::init(const unsigned char *vert, int vertSize,
} }
/* Compile fragment shader */ /* Compile fragment shader */
setupShaderSource(fragShader, frag, fragSize); setupShaderSource(fragShader, GL_FRAGMENT_SHADER, frag, fragSize);
gl.CompileShader(fragShader); gl.CompileShader(fragShader);
gl.GetShaderiv(fragShader, GL_COMPILE_STATUS, &success); gl.GetShaderiv(fragShader, GL_COMPILE_STATUS, &success);
@ -260,6 +272,21 @@ void ShaderBase::setTranslation(const Vec2i &value)
} }
FlatColorShader::FlatColorShader()
{
INIT_SHADER(minimal, flatColor, FlatColorShader);
ShaderBase::init();
GET_U(color);
}
void FlatColorShader::setColor(const Vec4 &value)
{
setVec4Uniform(u_color, value);
}
SimpleShader::SimpleShader() SimpleShader::SimpleShader()
{ {
INIT_SHADER(simple, simple, SimpleShader); INIT_SHADER(simple, simple, SimpleShader);
@ -306,6 +333,27 @@ void SimpleSpriteShader::setSpriteMat(const float value[16])
} }
AlphaSpriteShader::AlphaSpriteShader()
{
INIT_SHADER(sprite, simpleAlphaUni, AlphaSpriteShader);
ShaderBase::init();
GET_U(spriteMat);
GET_U(alpha);
}
void AlphaSpriteShader::setSpriteMat(const float value[16])
{
gl.UniformMatrix4fv(u_spriteMat, 1, GL_FALSE, value);
}
void AlphaSpriteShader::setAlpha(float value)
{
gl.Uniform1f(u_alpha, value);
}
TransShader::TransShader() TransShader::TransShader()
{ {
INIT_SHADER(simple, trans, TransShader); INIT_SHADER(simple, trans, TransShader);
@ -450,6 +498,21 @@ void PlaneShader::setOpacity(float value)
} }
GrayShader::GrayShader()
{
INIT_SHADER(simple, gray, GrayShader);
ShaderBase::init();
GET_U(gray);
}
void GrayShader::setGray(float value)
{
gl.Uniform1f(u_gray, value);
}
TilemapShader::TilemapShader() TilemapShader::TilemapShader()
{ {
INIT_SHADER(tilemap, simple, TilemapShader); INIT_SHADER(tilemap, simple, TilemapShader);

View File

@ -87,6 +87,17 @@ protected:
GLint u_texSizeInv, u_translation; GLint u_texSizeInv, u_translation;
}; };
class FlatColorShader : public ShaderBase
{
public:
FlatColorShader();
void setColor(const Vec4 &value);
private:
GLint u_color;
};
class SimpleShader : public ShaderBase class SimpleShader : public ShaderBase
{ {
public: public:
@ -121,6 +132,18 @@ private:
GLint u_spriteMat; GLint u_spriteMat;
}; };
class AlphaSpriteShader : public ShaderBase
{
public:
AlphaSpriteShader();
void setSpriteMat(const float value[16]);
void setAlpha(float value);
private:
GLint u_spriteMat, u_alpha;
};
class TransShader : public ShaderBase class TransShader : public ShaderBase
{ {
public: public:
@ -179,6 +202,17 @@ private:
GLint u_tone, u_color, u_flash, u_opacity; GLint u_tone, u_color, u_flash, u_opacity;
}; };
class GrayShader : public ShaderBase
{
public:
GrayShader();
void setGray(float value);
private:
GLint u_gray;
};
class TilemapShader : public ShaderBase class TilemapShader : public ShaderBase
{ {
public: public:
@ -273,12 +307,15 @@ private:
/* Global object containing all available shaders */ /* Global object containing all available shaders */
struct ShaderSet struct ShaderSet
{ {
FlatColorShader flatColor;
SimpleShader simple; SimpleShader simple;
SimpleColorShader simpleColor; SimpleColorShader simpleColor;
SimpleAlphaShader simpleAlpha; SimpleAlphaShader simpleAlpha;
SimpleSpriteShader simpleSprite; SimpleSpriteShader simpleSprite;
AlphaSpriteShader alphaSprite;
SpriteShader sprite; SpriteShader sprite;
PlaneShader plane; PlaneShader plane;
GrayShader gray;
TilemapShader tilemap; TilemapShader tilemap;
FlashMapShader flashMap; FlashMapShader flashMap;
TransShader trans; TransShader trans;

View File

@ -46,14 +46,14 @@ SharedState *SharedState::instance = 0;
int SharedState::rgssVersion = 0; int SharedState::rgssVersion = 0;
static GlobalIBO *_globalIBO = 0; static GlobalIBO *_globalIBO = 0;
static const char *defGameArchive() static const char *gameArchExt()
{ {
if (rgssVer == 1) if (rgssVer == 1)
return "Game.rgssad"; return ".rgssad";
else if (rgssVer == 2) else if (rgssVer == 2)
return "Game.rgss2a"; return ".rgss2a";
else if (rgssVer == 3) else if (rgssVer == 3)
return "Game.rgss3a"; return ".rgss3a";
assert(!"unreachable"); assert(!"unreachable");
return 0; return 0;
@ -88,6 +88,7 @@ struct SharedStatePrivate
TEX::ID globalTex; TEX::ID globalTex;
int globalTexW, globalTexH; int globalTexW, globalTexH;
bool globalTexDirty;
TEXFBO gpTexFBO; TEXFBO gpTexFBO;
@ -107,25 +108,18 @@ struct SharedStatePrivate
midiState(threadData->config), midiState(threadData->config),
graphics(threadData), graphics(threadData),
input(*threadData), input(*threadData),
audio(threadData->config), audio(*threadData),
fontState(threadData->config), fontState(threadData->config),
stampCounter(0) stampCounter(0)
{ {
if (!config.gameFolder.empty()) /* Shaders have been compiled in ShaderSet's constructor */
{ if (gl.ReleaseShaderCompiler)
int result = chdir(config.gameFolder.c_str()); gl.ReleaseShaderCompiler();
if (result != 0) std::string archPath = config.execName + gameArchExt();
throw Exception(Exception::MKXPError,
"Unable to switch into gameFolder '%s'",
config.gameFolder.c_str());
}
// FIXME find out correct archive filename
std::string archPath = defGameArchive();
/* Check if a game archive exists */ /* Check if a game archive exists */
FILE *tmp = fopen(archPath.c_str(), "r"); FILE *tmp = fopen(archPath.c_str(), "rb");
if (tmp) if (tmp)
{ {
fileSystem.addPath(archPath.c_str()); fileSystem.addPath(archPath.c_str());
@ -150,6 +144,7 @@ struct SharedStatePrivate
TEX::setRepeat(false); TEX::setRepeat(false);
TEX::setSmooth(false); TEX::setSmooth(false);
TEX::allocEmpty(globalTexW, globalTexH); TEX::allocEmpty(globalTexW, globalTexH);
globalTexDirty = false;
TEXFBO::init(gpTexFBO); TEXFBO::init(gpTexFBO);
/* Reuse starting values */ /* Reuse starting values */
@ -257,16 +252,27 @@ GlobalIBO &SharedState::globalIBO()
void SharedState::bindTex() void SharedState::bindTex()
{ {
TEX::bind(p->globalTex); TEX::bind(p->globalTex);
TEX::allocEmpty(p->globalTexW, p->globalTexH);
if (p->globalTexDirty)
{
TEX::allocEmpty(p->globalTexW, p->globalTexH);
p->globalTexDirty = false;
}
} }
void SharedState::ensureTexSize(int minW, int minH, Vec2i &currentSizeOut) void SharedState::ensureTexSize(int minW, int minH, Vec2i &currentSizeOut)
{ {
if (minW > p->globalTexW) if (minW > p->globalTexW)
{
p->globalTexDirty = true;
p->globalTexW = findNextPow2(minW); p->globalTexW = findNextPow2(minW);
}
if (minH > p->globalTexH) if (minH > p->globalTexH)
{
p->globalTexDirty = true;
p->globalTexH = findNextPow2(minH); p->globalTexH = findNextPow2(minH);
}
currentSizeOut = Vec2i(p->globalTexW, p->globalTexH); currentSizeOut = Vec2i(p->globalTexW, p->globalTexH);
} }

View File

@ -26,6 +26,7 @@
#include "exception.h" #include "exception.h"
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
#include "debugwriter.h"
#include <SDL_sound.h> #include <SDL_sound.h>
@ -120,13 +121,16 @@ SoundEmitter::~SoundEmitter()
void SoundEmitter::play(const std::string &filename, void SoundEmitter::play(const std::string &filename,
int volume, int volume,
int pitch) int pitch)
{ {
float _volume = clamp<int>(volume, 0, 100) / 100.f; float _volume = clamp<int>(volume, 0, 100) / 100.f;
float _pitch = clamp<int>(pitch, 50, 150) / 100.f; float _pitch = clamp<int>(pitch, 50, 150) / 100.f;
SoundBuffer *buffer = allocateBuffer(filename); SoundBuffer *buffer = allocateBuffer(filename);
if (!buffer)
return;
/* Try to find first free source */ /* Try to find first free source */
size_t i; size_t i;
for (i = 0; i < srcCount; ++i) for (i = 0; i < srcCount; ++i)
@ -168,7 +172,7 @@ void SoundEmitter::play(const std::string &filename,
if (switchBuffer) if (switchBuffer)
AL::Source::attachBuffer(src, buffer->alBuffer); AL::Source::attachBuffer(src, buffer->alBuffer);
AL::Source::setVolume(src, _volume); AL::Source::setVolume(src, _volume * GLOBAL_VOLUME);
AL::Source::setPitch(src, _pitch); AL::Source::setPitch(src, _pitch);
AL::Source::play(src); AL::Source::play(src);
@ -197,18 +201,22 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
{ {
/* Buffer not in cashe, needs to be loaded */ /* Buffer not in cashe, needs to be loaded */
SDL_RWops dataSource; SDL_RWops dataSource;
const char *extension; char ext[8];
shState->fileSystem().openRead(dataSource, filename.c_str(), shState->fileSystem().openRead(dataSource, filename.c_str(),
FileSystem::Audio, false, &extension); false, ext, sizeof(ext));
Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, extension, 0, STREAM_BUF_SIZE); Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, ext, 0, STREAM_BUF_SIZE);
if (!sampleHandle) if (!sampleHandle)
{ {
SDL_RWclose(&dataSource); char buf[512];
throw Exception(Exception::SDLError, "%s.%s: %s", snprintf(buf, sizeof(buf), "Unable to decode sound: %s.%s: %s",
filename.c_str(), extension, Sound_GetError()); filename.c_str(), ext, Sound_GetError());
buf[sizeof(buf)-1] = '\0';
Debug() << buf;
return 0;
} }
uint32_t decBytes = Sound_DecodeAll(sampleHandle); uint32_t decBytes = Sound_DecodeAll(sampleHandle);

View File

@ -57,7 +57,8 @@ struct SpritePrivate
NormValue opacity; NormValue opacity;
BlendType blendType; BlendType blendType;
SDL_Rect sceneRect; IntRect sceneRect;
Vec2i sceneOrig;
/* Would this sprite be visible on /* Would this sprite be visible on
* the screen if drawn? */ * the screen if drawn? */
@ -182,9 +183,8 @@ struct SpritePrivate
return; return;
} }
SDL_Rect self; IntRect self;
self.x = trans.getPosition().x - trans.getOrigin().x; self.setPos(trans.getPositionI() - (trans.getOriginI() + sceneOrig));
self.y = trans.getPosition().y - trans.getOrigin().y;
self.w = bitmap->width(); self.w = bitmap->width();
self.h = bitmap->height(); self.h = bitmap->height();
@ -332,7 +332,7 @@ void Sprite::setBitmap(Bitmap *bitmap)
p->bitmap = bitmap; p->bitmap = bitmap;
if (!bitmap) if (nullOrDisposed(bitmap))
return; return;
bitmap->ensureNonMega(); bitmap->ensureNonMega();
@ -515,7 +515,6 @@ void Sprite::draw()
bool renderEffect = p->color->hasEffect() || bool renderEffect = p->color->hasEffect() ||
p->tone->hasEffect() || p->tone->hasEffect() ||
p->opacity != 255 ||
flashing || flashing ||
p->bushDepth != 0; p->bushDepth != 0;
@ -541,6 +540,16 @@ void Sprite::draw()
base = &shader; base = &shader;
} }
else if (p->opacity != 255)
{
AlphaSpriteShader &shader = shState->shaders().alphaSprite;
shader.bind();
shader.setSpriteMat(p->trans.getMatrix());
shader.setAlpha(p->opacity.norm);
shader.applyViewportProj();
base = &shader;
}
else else
{ {
SimpleSpriteShader &shader = shState->shaders().simpleSprite; SimpleSpriteShader &shader = shState->shaders().simpleSprite;
@ -567,13 +576,10 @@ void Sprite::onGeometryChange(const Scene::Geometry &geo)
{ {
/* Offset at which the sprite will be drawn /* Offset at which the sprite will be drawn
* relative to screen origin */ * relative to screen origin */
int xOffset = geo.rect.x - geo.xOrigin; p->trans.setGlobalOffset(geo.offset());
int yOffset = geo.rect.y - geo.yOrigin;
p->trans.setGlobalOffset(xOffset, yOffset); p->sceneRect.setSize(geo.rect.size());
p->sceneOrig = geo.orig;
p->sceneRect.w = geo.rect.w;
p->sceneRect.h = geo.rect.h;
} }
void Sprite::releaseResources() void Sprite::releaseResources()

View File

@ -30,94 +30,92 @@
/* Init normally */ /* Init normally */
Table::Table(int x, int y /*= 1*/, int z /*= 1*/) Table::Table(int x, int y /*= 1*/, int z /*= 1*/)
: m_x(x), m_y(y), m_z(z), : xs(x), ys(y), zs(z),
data(x*y*z) data(x*y*z)
{} {}
Table::Table(const Table &other) Table::Table(const Table &other)
: m_x(other.m_x), m_y(other.m_y), m_z(other.m_z), : xs(other.xs), ys(other.ys), zs(other.zs),
data(other.data) data(other.data)
{} {}
int16_t Table::get(int x, int y, int z) const int16_t Table::get(int x, int y, int z) const
{ {
return data[m_x*m_y*z + m_x*y + x]; return data[xs*ys*z + xs*y + x];
} }
void Table::set(int16_t value, int x, int y, int z) void Table::set(int16_t value, int x, int y, int z)
{ {
if (x < 0 || x >= m_x if (x < 0 || x >= xs
|| y < 0 || y >= m_y || y < 0 || y >= ys
|| z < 0 || z >= m_z) || z < 0 || z >= zs)
{ {
return; return;
} }
data[m_x*m_y*z + m_x*y + x] = value; data[xs*ys*z + xs*y + x] = value;
modified(); modified();
} }
void Table::resize(int x, int y, int z) void Table::resize(int x, int y, int z)
{ {
if (x == m_x && y == m_y && z == m_z) if (x == xs && y == ys && z == zs)
return; return;
std::vector<int16_t> newData(x*y*z); std::vector<int16_t> newData(x*y*z);
for (int k = 0; k < std::min(z, m_z); ++k) for (int k = 0; k < std::min(z, zs); ++k)
for (int j = 0; j < std::min(y, m_y); ++j) for (int j = 0; j < std::min(y, ys); ++j)
for (int i = 0; i < std::min(x, m_x); ++i) for (int i = 0; i < std::min(x, xs); ++i)
newData[x*y*k + x*j + i] = at(i, j, k); newData[x*y*k + x*j + i] = at(i, j, k);
data.swap(newData); data.swap(newData);
m_x = x; xs = x;
m_y = y; ys = y;
m_z = z; zs = z;
return; return;
} }
void Table::resize(int x, int y) void Table::resize(int x, int y)
{ {
resize(x, y, m_z); resize(x, y, zs);
} }
void Table::resize(int x) void Table::resize(int x)
{ {
resize(x, m_y, m_z); resize(x, ys, zs);
} }
/* Serializable */ /* Serializable */
int Table::serialSize() const int Table::serialSize() const
{ {
/* header + data */ /* header + data */
return 20 + (m_x * m_y * m_z) * 2; return 20 + (xs * ys * zs) * 2;
} }
void Table::serialize(char *buffer) const void Table::serialize(char *buffer) const
{ {
char *buff_p = buffer;
/* Table dimensions: we don't care /* Table dimensions: we don't care
* about them but RMXP needs them */ * about them but RMXP needs them */
int dim = 1; int dim = 1;
int size = m_x * m_y * m_z; int size = xs * ys * zs;
if (m_y > 1) if (ys > 1)
dim = 2; dim = 2;
if (m_z > 1) if (zs > 1)
dim = 3; dim = 3;
write_int32(&buff_p, dim); writeInt32(&buffer, dim);
write_int32(&buff_p, m_x); writeInt32(&buffer, xs);
write_int32(&buff_p, m_y); writeInt32(&buffer, ys);
write_int32(&buff_p, m_z); writeInt32(&buffer, zs);
write_int32(&buff_p, size); writeInt32(&buffer, size);
memcpy(buff_p, dataPtr(data), sizeof(int16_t)*size); memcpy(buffer, dataPtr(data), sizeof(int16_t)*size);
} }
@ -126,13 +124,11 @@ Table *Table::deserialize(const char *data, int len)
if (len < 20) if (len < 20)
throw Exception(Exception::RGSSError, "Marshal: Table: bad file format"); throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
uint idx = 0; readInt32(&data);
int x = readInt32(&data);
read_int32(data, idx); int y = readInt32(&data);
int x = read_int32(data, idx); int z = readInt32(&data);
int y = read_int32(data, idx); int size = readInt32(&data);
int z = read_int32(data, idx);
int size = read_int32(data, idx);
if (size != x*y*z) if (size != x*y*z)
throw Exception(Exception::RGSSError, "Marshal: Table: bad file format"); throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
@ -141,7 +137,7 @@ Table *Table::deserialize(const char *data, int len)
throw Exception(Exception::RGSSError, "Marshal: Table: bad file format"); throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
Table *t = new Table(x, y, z); Table *t = new Table(x, y, z);
memcpy(dataPtr(t->data), &data[idx], sizeof(int16_t)*size); memcpy(dataPtr(t->data), data, sizeof(int16_t)*size);
return t; return t;
} }

View File

@ -36,9 +36,9 @@ public:
Table(const Table &other); Table(const Table &other);
virtual ~Table() {} virtual ~Table() {}
int xSize() const { return m_x; } int xSize() const { return xs; }
int ySize() const { return m_y; } int ySize() const { return ys; }
int zSize() const { return m_z; } int zSize() const { return zs; }
int16_t get(int x, int y = 0, int z = 0) const; int16_t get(int x, int y = 0, int z = 0) const;
void set(int16_t value, int x, int y = 0, int z = 0); void set(int16_t value, int x, int y = 0, int z = 0);
@ -54,18 +54,18 @@ public:
/* <internal */ /* <internal */
inline int16_t &at(int x, int y = 0, int z = 0) inline int16_t &at(int x, int y = 0, int z = 0)
{ {
return data[m_x*m_y*z + m_x*y + x]; return data[xs*ys*z + xs*y + x];
} }
inline const int16_t &at(int x, int y = 0, int z = 0) const inline const int16_t &at(int x, int y = 0, int z = 0) const
{ {
return data[m_x*m_y*z + m_x*y + x]; return data[xs*ys*z + xs*y + x];
} }
sigc::signal<void> modified; sigc::signal<void> modified;
private: private:
int m_x, m_y, m_z; int xs, ys, zs;
std::vector<int16_t> data; std::vector<int16_t> data;
}; };

View File

@ -21,6 +21,7 @@
#include "tileatlasvx.h" #include "tileatlasvx.h"
#include "tilemap-common.h"
#include "bitmap.h" #include "bitmap.h"
#include "table.h" #include "table.h"
#include "etc-internal.h" #include "etc-internal.h"
@ -65,21 +66,6 @@ static elementsN(autotileVXRectsC);
namespace TileAtlasVX namespace TileAtlasVX
{ {
static int
wrap(int value, int range)
{
int res = value % range;
return res < 0 ? res + range : res;
}
static int16_t
tableGetWrapped(const Table &t, int x, int y, int z = 0)
{
return t.at(wrap(x, t.xSize()),
wrap(y, t.ySize()),
z);
}
static int16_t static int16_t
tableGetSafe(const Table *t, int x) tableGetSafe(const Table *t, int x)
{ {
@ -333,35 +319,6 @@ void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT])
#define OVER_PLAYER_FLAG (1 << 4) #define OVER_PLAYER_FLAG (1 << 4)
#define TABLE_FLAG (1 << 7) #define TABLE_FLAG (1 << 7)
static void
atSelectSubPos(FloatRect &pos, int i)
{
switch (i)
{
case 0:
return;
case 1:
pos.x += 16;
return;
case 2:
pos.y += 16;
return;
case 3:
pos.x += 16;
pos.y += 16;
return;
case 4:
pos.y += 24;
return;
case 5:
pos.x += 16;
pos.y += 24;
return;
default:
assert(!"Unreachable");
}
}
/* Reference: http://www.tktkgame.com/tkool/memo/vx/tile_id.html */ /* Reference: http://www.tktkgame.com/tkool/memo/vx/tile_id.html */
static void static void

View File

@ -1,5 +1,5 @@
/* /*
** flashmap.h ** tilemap-common.h
** **
** This file is part of mkxp. ** This file is part of mkxp.
** **
@ -19,8 +19,8 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>. ** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef FLASHMAP_H #ifndef TILEMAPCOMMON_H
#define FLASHMAP_H #define TILEMAPCOMMON_H
#include "table.h" #include "table.h"
#include "gl-util.h" #include "gl-util.h"
@ -30,8 +30,11 @@
#include "glstate.h" #include "glstate.h"
#include "shader.h" #include "shader.h"
#include "vertex.h" #include "vertex.h"
#include "quad.h"
#include "etc-internal.h"
#include <stdint.h> #include <stdint.h>
#include <assert.h>
#include <vector> #include <vector>
#include <sigc++/connection.h> #include <sigc++/connection.h>
@ -44,11 +47,50 @@ wrap(int value, int range)
} }
static inline int16_t static inline int16_t
tableGetWrapped(const Table *t, int x, int y, int z = 0) tableGetWrapped(const Table &t, int x, int y, int z = 0)
{ {
return t->get(wrap(x, t->xSize()), return t.get(wrap(x, t.xSize()),
wrap(y, t->ySize()), wrap(y, t.ySize()),
z); z);
}
enum AtSubPos
{
TopLeft = 0,
TopRight = 1,
BottomLeft = 2,
BottomRight = 3,
BottomLeftTable = 4,
BottomRightTable = 5
};
static inline void
atSelectSubPos(FloatRect &pos, int i)
{
switch (i)
{
case TopLeft:
return;
case TopRight:
pos.x += 16;
return;
case BottomLeft:
pos.y += 16;
return;
case BottomRight:
pos.x += 16;
pos.y += 16;
return;
case BottomLeftTable:
pos.y += 24;
return;
case BottomRightTable:
pos.x += 16;
pos.y += 24;
return;
default:
assert(!"Unreachable");
}
} }
struct FlashMap struct FlashMap
@ -144,7 +186,7 @@ private:
bool sampleFlashColor(Vec4 &out, int x, int y) const bool sampleFlashColor(Vec4 &out, int x, int y) const
{ {
int16_t packed = tableGetWrapped(data, x, y); int16_t packed = tableGetWrapped(*data, x, y);
if (packed == 0) if (packed == 0)
return false; return false;
@ -216,4 +258,4 @@ private:
std::vector<CVertex> vertices; std::vector<CVertex> vertices;
}; };
#endif // FLASHMAP_H #endif // TILEMAPCOMMON_H

View File

@ -26,6 +26,7 @@
#include "table.h" #include "table.h"
#include "sharedstate.h" #include "sharedstate.h"
#include "config.h"
#include "glstate.h" #include "glstate.h"
#include "gl-util.h" #include "gl-util.h"
#include "gl-meta.h" #include "gl-meta.h"
@ -36,7 +37,7 @@
#include "quad.h" #include "quad.h"
#include "vertex.h" #include "vertex.h"
#include "tileatlas.h" #include "tileatlas.h"
#include "flashmap.h" #include "tilemap-common.h"
#include <sigc++/connection.h> #include <sigc++/connection.h>
@ -441,15 +442,13 @@ struct TilemapPrivate
void updateSceneGeometry(const Scene::Geometry &geo) void updateSceneGeometry(const Scene::Geometry &geo)
{ {
elem.sceneOffset.x = geo.rect.x - geo.xOrigin; elem.sceneOffset = geo.offset();
elem.sceneOffset.y = geo.rect.y - geo.yOrigin;
elem.sceneGeo = geo; elem.sceneGeo = geo;
} }
void updatePosition() void updatePosition()
{ {
dispPos.x = -(offset.x - viewpPos.x * 32) + elem.sceneOffset.x; dispPos = -(offset - viewpPos * 32) + elem.sceneOffset;
dispPos.y = -(offset.y - viewpPos.y * 32) + elem.sceneOffset.y;
} }
void invalidateAtlasSize() void invalidateAtlasSize()
@ -542,19 +541,59 @@ struct TilemapPrivate
if (tileset->megaSurface()) if (tileset->megaSurface())
{ {
/* Mega surface tileset */ /* Mega surface tileset */
TEX::bind(atlas.gl.tex);
SDL_Surface *tsSurf = tileset->megaSurface(); SDL_Surface *tsSurf = tileset->megaSurface();
for (size_t i = 0; i < blits.size(); ++i) if (shState->config().subImageFix)
{ {
const TileAtlas::Blit &blitOp = blits[i]; /* Implementation for broken GL drivers */
FBO::bind(atlas.gl.fbo);
glState.blend.pushSet(false);
glState.viewport.pushSet(IntRect(0, 0, atlas.size.x, atlas.size.y));
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y, SimpleShader &shader = shState->shaders().simple;
blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA); shader.bind();
shader.applyViewportProj();
shader.setTranslation(Vec2i());
Quad &quad = shState->gpQuad();
for (size_t i = 0; i < blits.size(); ++i)
{
const TileAtlas::Blit &blitOp = blits[i];
Vec2i texSize;
shState->ensureTexSize(tsLaneW, blitOp.h, texSize);
shState->bindTex();
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
0, 0, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
shader.setTexSize(texSize);
quad.setTexRect(FloatRect(0, 0, tsLaneW, blitOp.h));
quad.setPosRect(FloatRect(blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h));
quad.draw();
}
GLMeta::subRectImageEnd();
glState.viewport.pop();
glState.blend.pop();
}
else
{
/* Clean implementation */
TEX::bind(atlas.gl.tex);
for (size_t i = 0; i < blits.size(); ++i)
{
const TileAtlas::Blit &blitOp = blits[i];
GLMeta::subRectImageUpload(tsSurf->w, blitOp.src.x, blitOp.src.y,
blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
}
GLMeta::subRectImageEnd();
} }
GLMeta::subRectImageEnd();
} }
else else
{ {
@ -590,21 +629,6 @@ struct TilemapPrivate
return value; return value;
} }
FloatRect getAutotilePieceRect(int x, int y, /* in pixel coords */
int corner)
{
switch (corner)
{
case 0 : break;
case 1 : x += 16; break;
case 2 : x += 16; y += 16; break;
case 3 : y += 16; break;
default: abort();
}
return FloatRect(x, y, 16, 16);
}
void handleAutotile(int x, int y, int tileInd, SVVector *array) void handleAutotile(int x, int y, int tileInd, SVVector *array)
{ {
/* Which autotile [0-7] */ /* Which autotile [0-7] */
@ -617,7 +641,9 @@ struct TilemapPrivate
/* Iterate over the 4 tile pieces */ /* Iterate over the 4 tile pieces */
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
FloatRect posRect = getAutotilePieceRect(x*32, y*32, i); FloatRect posRect(x*32, y*32, 16, 16);
atSelectSubPos(posRect, i);
FloatRect texRect = pieceRect[i]; FloatRect texRect = pieceRect[i];
/* Adjust to atlas coordinates */ /* Adjust to atlas coordinates */
@ -635,7 +661,7 @@ struct TilemapPrivate
void handleTile(int x, int y, int z) void handleTile(int x, int y, int z)
{ {
int tileInd = int tileInd =
tableGetWrapped(mapData, x + viewpPos.x, y + viewpPos.y, z); tableGetWrapped(*mapData, x + viewpPos.x, y + viewpPos.y, z);
/* Check for empty space */ /* Check for empty space */
if (tileInd < 48) if (tileInd < 48)
@ -972,6 +998,9 @@ void GroundLayer::updateVboCount()
void GroundLayer::draw() void GroundLayer::draw()
{ {
if (p->groundVert.size() == 0)
return;
ShaderBase *shader; ShaderBase *shader;
p->bindShader(shader); p->bindShader(shader);

View File

@ -33,7 +33,7 @@
#include "quad.h" #include "quad.h"
#include "quadarray.h" #include "quadarray.h"
#include "shader.h" #include "shader.h"
#include "flashmap.h" #include "tilemap-common.h"
#include <vector> #include <vector>
#include <sigc++/connection.h> #include <sigc++/connection.h>
@ -366,11 +366,10 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
void onGeometryChange(const Scene::Geometry &geo) void onGeometryChange(const Scene::Geometry &geo)
{ {
mapViewp.w = (geo.rect.w / 32) + !!(geo.rect.w % 32) + 1; const Vec2i geoSize = geo.rect.size();
mapViewp.h = (geo.rect.h / 32) + !!(geo.rect.h % 32) + 1; mapViewp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1));
sceneOffset.x = geo.rect.x - geo.xOrigin; sceneOffset = geo.offset();
sceneOffset.y = geo.rect.y - geo.yOrigin;
sceneGeo = geo; sceneGeo = geo;
buffersDirty = true; buffersDirty = true;

View File

@ -58,7 +58,6 @@ public:
Transform() Transform()
: scale(1, 1), : scale(1, 1),
rotation(0), rotation(0),
xOffset(0), yOffset(0),
dirty(true) dirty(true)
{ {
memset(matrix, 0, sizeof(matrix)); memset(matrix, 0, sizeof(matrix));
@ -68,38 +67,47 @@ public:
} }
Vec2 &getPosition() { return position; } Vec2 &getPosition() { return position; }
Vec2 &getScale() { return scale; }
Vec2 &getOrigin() { return origin; } Vec2 &getOrigin() { return origin; }
Vec2 &getScale() { return scale; }
float getRotation() { return rotation; } float getRotation() { return rotation; }
Vec2i getPositionI() const
{
return Vec2i(position.x, position.y);
}
Vec2i getOriginI() const
{
return Vec2i(origin.x, origin.y);
}
void setPosition(const Vec2 &value) void setPosition(const Vec2 &value)
{ {
position = value; position = value;
dirty = true; dirty = true;
} }
void setScale(const Vec2 &value)
{
scale = value;
dirty = true;
}
void setOrigin(const Vec2 &value) void setOrigin(const Vec2 &value)
{ {
origin = value; origin = value;
dirty = true; dirty = true;
} }
void setScale(const Vec2 &value)
{
scale = value;
dirty = true;
}
void setRotation(float value) void setRotation(float value)
{ {
rotation = value; rotation = value;
dirty = true; dirty = true;
} }
void setGlobalOffset(int x, int y) void setGlobalOffset(const Vec2i &value)
{ {
xOffset = x; offset = value;
yOffset = y;
dirty = true; dirty = true;
} }
@ -129,8 +137,8 @@ private:
float syc = scale.y * cosine; float syc = scale.y * cosine;
float sxs = scale.x * sine; float sxs = scale.x * sine;
float sys = scale.y * sine; float sys = scale.y * sine;
float tx = -origin.x * sxc - origin.y * sys + position.x + xOffset; float tx = -origin.x * sxc - origin.y * sys + position.x + offset.x;
float ty = origin.x * sxs - origin.y * syc + position.y + yOffset; float ty = origin.x * sxs - origin.y * syc + position.y + offset.y;
matrix[0] = sxc; matrix[0] = sxc;
matrix[1] = -sxs; matrix[1] = -sxs;
@ -146,7 +154,7 @@ private:
float rotation; float rotation;
/* Silently added to position */ /* Silently added to position */
int xOffset, yOffset; Vec2i offset;
float matrix[16]; float matrix[16];

View File

@ -66,7 +66,7 @@ findNextPow2(int start)
inline bool readFile(const char *path, inline bool readFile(const char *path,
std::string &out) std::string &out)
{ {
FILE *f = fopen(path, "r"); FILE *f = fopen(path, "rb");
if (!f) if (!f)
return false; return false;

View File

@ -144,8 +144,8 @@ void Viewport::update()
Flashable::update(); Flashable::update();
} }
DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.xOrigin) DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.orig.x)
DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.yOrigin) DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.orig.y)
DEF_ATTR_SIMPLE(Viewport, Rect, Rect&, *p->rect) DEF_ATTR_SIMPLE(Viewport, Rect, Rect&, *p->rect)
DEF_ATTR_SIMPLE(Viewport, Color, Color&, *p->color) DEF_ATTR_SIMPLE(Viewport, Color, Color&, *p->color)
@ -155,10 +155,10 @@ void Viewport::setOX(int value)
{ {
guardDisposed(); guardDisposed();
if (geometry.xOrigin == value) if (geometry.orig.x == value)
return; return;
geometry.xOrigin = value; geometry.orig.x = value;
notifyGeometryChange(); notifyGeometryChange();
} }
@ -166,10 +166,10 @@ void Viewport::setOY(int value)
{ {
guardDisposed(); guardDisposed();
if (geometry.yOrigin == value) if (geometry.orig.y == value)
return; return;
geometry.yOrigin = value; geometry.orig.y = value;
notifyGeometryChange(); notifyGeometryChange();
} }

View File

@ -471,16 +471,15 @@ struct WindowPrivate
i += TileQuads::buildFrame(effectRect, cursorVert.vert); i += TileQuads::buildFrame(effectRect, cursorVert.vert);
} }
/* Scroll arrows */ /* Scroll arrow position: Top Bottom X, Left Right Y */
int scrollLRY = (size.y - 16) / 2; const Vec2i scroll = (size - Vec2i(16)) / 2;
int scrollTBX = (size.x - 16) / 2;
Sides<IntRect> scrollArrows; Sides<IntRect> scrollArrows;
scrollArrows.l = IntRect(4, scrollLRY, 8, 16); scrollArrows.l = IntRect(4, scroll.y, 8, 16);
scrollArrows.r = IntRect(size.x - 12, scrollLRY, 8, 16); scrollArrows.r = IntRect(size.x - 12, scroll.y, 8, 16);
scrollArrows.t = IntRect(scrollTBX, 4, 16, 8); scrollArrows.t = IntRect(scroll.x, 4, 16, 8);
scrollArrows.b = IntRect(scrollTBX, size.y - 12, 16, 8); scrollArrows.b = IntRect(scroll.x, size.y - 12, 16, 8);
if (contents) if (contents)
{ {
@ -557,13 +556,10 @@ struct WindowPrivate
if (size == Vec2i(0, 0)) if (size == Vec2i(0, 0))
return; return;
Vec2i trans(position.x + sceneOffset.x,
position.y + sceneOffset.y);
SimpleAlphaShader &shader = shState->shaders().simpleAlpha; SimpleAlphaShader &shader = shState->shaders().simpleAlpha;
shader.bind(); shader.bind();
shader.applyViewportProj(); shader.applyViewportProj();
shader.setTranslation(trans); shader.setTranslation(position + sceneOffset);
if (useBaseTex) if (useBaseTex)
{ {
@ -598,12 +594,11 @@ struct WindowPrivate
controlsVertDirty = false; controlsVertDirty = false;
} }
/* Actual on screen coordinates */ /* Effective on screen coordinates */
int effectX = position.x + sceneOffset.x; const Vec2i efPos = position + sceneOffset;
int effectY = position.y + sceneOffset.y;
IntRect windowRect(effectX, effectY, size.x, size.y); const IntRect windowRect(efPos, size);
IntRect contentsRect(effectX+16, effectY+16, size.x-32, size.y-32); const IntRect contentsRect(efPos + Vec2i(16), size - Vec2i(32));
glState.scissorTest.pushSet(true); glState.scissorTest.pushSet(true);
glState.scissorBox.push(); glState.scissorBox.push();
@ -615,7 +610,7 @@ struct WindowPrivate
if (!nullOrDisposed(windowskin)) if (!nullOrDisposed(windowskin))
{ {
shader.setTranslation(Vec2i(effectX, effectY)); shader.setTranslation(efPos);
/* Draw arrows / cursors */ /* Draw arrows / cursors */
windowskin->bindTex(shader); windowskin->bindTex(shader);
@ -631,9 +626,7 @@ struct WindowPrivate
/* Draw contents bitmap */ /* Draw contents bitmap */
glState.scissorBox.setIntersect(contentsRect); glState.scissorBox.setIntersect(contentsRect);
effectX += 16-contentsOffset.x; shader.setTranslation(efPos + (Vec2i(16) - contentsOffset));
effectY += 16-contentsOffset.y;
shader.setTranslation(Vec2i(effectX, effectY));
contents->bindTex(shader); contents->bindTex(shader);
contentsQuad.draw(); contentsQuad.draw();
@ -727,7 +720,7 @@ void Window::setWindowskin(Bitmap *value)
p->windowskin = value; p->windowskin = value;
if (!value) if (nullOrDisposed(value))
return; return;
value->ensureNonMega(); value->ensureNonMega();
@ -743,7 +736,7 @@ void Window::setContents(Bitmap *value)
p->contents = value; p->contents = value;
p->controlsVertDirty = true; p->controlsVertDirty = true;
if (!value) if (nullOrDisposed(value))
return; return;
value->ensureNonMega(); value->ensureNonMega();
@ -876,8 +869,7 @@ void Window::draw()
void Window::onGeometryChange(const Scene::Geometry &geo) void Window::onGeometryChange(const Scene::Geometry &geo)
{ {
p->sceneOffset.x = geo.rect.x - geo.xOrigin; p->sceneOffset = geo.offset();
p->sceneOffset.y = geo.rect.y - geo.yOrigin;
} }
void Window::setZ(int value) void Window::setZ(int value)

View File

@ -506,15 +506,15 @@ struct WindowVXPrivate
void rebuildCtrlVert() void rebuildCtrlVert()
{ {
const int arrowTBX = (geo.w - 16) / 2; /* Scroll arrow position: Top Bottom X, Left Right Y */
const int arrowLRY = (geo.h - 16) / 2; const Vec2i arrow = (geo.size() - Vec2i(16)) / 2;
const Sides<FloatRect> arrowPos = const Sides<FloatRect> arrowPos =
{ {
FloatRect( 4, arrowLRY, 8, 16 ), /* Left */ FloatRect( 4, arrow.y, 8, 16 ), /* Left */
FloatRect( geo.w - 12, arrowLRY, 8, 16 ), /* Right */ FloatRect( geo.w - 12, arrow.y, 8, 16 ), /* Right */
FloatRect( arrowTBX, 4, 16, 8 ), /* Top */ FloatRect( arrow.x, 4, 16, 8 ), /* Top */
FloatRect( arrowTBX, geo.h - 12, 16, 8 ) /* Bottom */ FloatRect( arrow.x, geo.h - 12, 16, 8 ) /* Bottom */
}; };
size_t i = 0; size_t i = 0;
@ -538,7 +538,7 @@ struct WindowVXPrivate
if (pause) if (pause)
{ {
const FloatRect pausePos(arrowTBX, geo.h - 16, 16, 16); const FloatRect pausePos(arrow.x, geo.h - 16, 16, 16);
pauseVert = &vert[i*4]; pauseVert = &vert[i*4];
i += Quad::setTexPosRect(&vert[i*4], pauseSrc[0], pausePos); i += Quad::setTexPosRect(&vert[i*4], pauseSrc[0], pausePos);
@ -730,8 +730,7 @@ struct WindowVXPrivate
bool windowskinValid = !nullOrDisposed(windowskin); bool windowskinValid = !nullOrDisposed(windowskin);
bool contentsValid = !nullOrDisposed(contents); bool contentsValid = !nullOrDisposed(contents);
Vec2i trans(geo.x + sceneOffset.x, Vec2i trans = geo.pos() + sceneOffset;
geo.y + sceneOffset.y);
SimpleAlphaShader &shader = shState->shaders().simpleAlpha; SimpleAlphaShader &shader = shState->shaders().simpleAlpha;
shader.bind(); shader.bind();
@ -764,8 +763,7 @@ struct WindowVXPrivate
{ {
/* Translate cliprect from local into screen space */ /* Translate cliprect from local into screen space */
IntRect clip = clipRect; IntRect clip = clipRect;
clip.x += trans.x; clip.setPos(clip.pos() + trans);
clip.y += trans.y;
glState.scissorBox.push(); glState.scissorBox.push();
glState.scissorTest.pushSet(true); glState.scissorTest.pushSet(true);
@ -773,11 +771,10 @@ struct WindowVXPrivate
if (rgssVer >= 3) if (rgssVer >= 3)
glState.scissorBox.setIntersect(clip); glState.scissorBox.setIntersect(clip);
else else
glState.scissorBox.setIntersect(IntRect(trans.x, trans.y, geo.w, geo.h)); glState.scissorBox.setIntersect(IntRect(trans, geo.size()));
IntRect pad = padRect; IntRect pad = padRect;
pad.x += trans.x; pad.setPos(pad.pos() + trans);
pad.y += trans.y;
if (drawCursor) if (drawCursor)
{ {
@ -786,10 +783,7 @@ struct WindowVXPrivate
contTrans.y += cursorRect->y; contTrans.y += cursorRect->y;
if (rgssVer >= 3) if (rgssVer >= 3)
{ contTrans -= contentsOff;
contTrans.x -= contentsOff.x;
contTrans.y -= contentsOff.y;
}
shader.setTranslation(contTrans); shader.setTranslation(contTrans);
@ -804,8 +798,7 @@ struct WindowVXPrivate
glState.scissorBox.setIntersect(clip); glState.scissorBox.setIntersect(clip);
Vec2i contTrans = pad.pos(); Vec2i contTrans = pad.pos();
contTrans.x -= contentsOff.x; contTrans -= contentsOff;
contTrans.y -= contentsOff.y;
shader.setTranslation(contTrans); shader.setTranslation(contTrans);
TEX::setSmooth(false); // XXX TEX::setSmooth(false); // XXX
@ -921,6 +914,9 @@ void WindowVX::setContents(Bitmap *value)
p->contents = value; p->contents = value;
if (nullOrDisposed(value))
return;
FloatRect rect = p->contents->rect(); FloatRect rect = p->contents->rect();
p->contentsQuad.setTexPosRect(rect, rect); p->contentsQuad.setTexPosRect(rect, rect);
p->ctrlVertDirty = true; p->ctrlVertDirty = true;
@ -1102,8 +1098,7 @@ void WindowVX::draw()
void WindowVX::onGeometryChange(const Scene::Geometry &geo) void WindowVX::onGeometryChange(const Scene::Geometry &geo)
{ {
p->sceneOffset.x = geo.rect.x - geo.xOrigin; p->sceneOffset = geo.offset();
p->sceneOffset.y = geo.rect.y - geo.yOrigin;
} }
void WindowVX::releaseResources() void WindowVX::releaseResources()