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/quad.h
src/tilemap.h
src/flashmap.h
src/tilemap-common.h
src/graphics.h
src/debuglogger.h
src/gl-debug.h
src/global-ibo.h
src/exception.h
src/filesystem.h
@ -180,7 +180,7 @@ set(MAIN_SOURCE
src/tilemap.cpp
src/autotiles.cpp
src/graphics.cpp
src/debuglogger.cpp
src/gl-debug.cpp
src/etc.cpp
src/config.cpp
src/settingsmenu.cpp
@ -210,16 +210,21 @@ source_group("MKXP Source" FILES ${MAIN_SOURCE} ${MAIN_HEADERS})
## Setup embedded source ##
set(EMBEDDED_INPUT
shader/common.h
shader/transSimple.frag
shader/trans.frag
shader/hue.frag
shader/sprite.frag
shader/plane.frag
shader/gray.frag
shader/bitmapBlit.frag
shader/flatColor.frag
shader/simple.frag
shader/simpleColor.frag
shader/simpleAlpha.frag
shader/simpleAlphaUni.frag
shader/flashMap.frag
shader/minimal.vert
shader/simple.vert
shader/simpleColor.vert
shader/sprite.vert
@ -230,6 +235,7 @@ set(EMBEDDED_INPUT
shader/blurV.vert
shader/simpleMatrix.vert
assets/liberation.ttf
assets/icon.png
)
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+.
[**Prebuilt binaries for Linux (32/64)**](http://ancurio.bplaced.net/mkxp/generic/)
[**Prebuilt binaries for OSX by Ali**](https://app.box.com/mkxpmacbuilds)
## Prebuilt binaries
[**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 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`
## 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.
Known issues with midi playback:
* Some songs' instruments become mute after looping
You can use this public domain soundfont: [GMGSx.sf2](https://www.dropbox.com/s/qxdvoxxcexsvn43/GMGSx.sf2?dl=0)
## 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)
* Text outline
* Movie playback
* wma audio files
* 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 "filesystem.h"
#include "util.h"
#include "sdl-util.h"
#include "debugwriter.h"
#include "graphics.h"
#include "audio.h"
@ -192,8 +193,11 @@ RB_METHOD(mriP)
RB_METHOD(mkxpDataDirectory)
{
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)
@ -336,7 +340,7 @@ static void runCustomScript(const std::string &filename)
{
std::string scriptData;
if (!readFile(filename.c_str(), scriptData))
if (!readFileSDL(filename.c_str(), scriptData))
{
showMsg(std::string("Unable to open '") + filename + "'");
return;
@ -346,7 +350,7 @@ static void runCustomScript(const std::string &filename)
newStringUTF8(filename.c_str(), filename.size()), NULL);
}
VALUE kernelLoadDataInt(const char *filename);
VALUE kernelLoadDataInt(const char *filename, bool rubyExc);
struct BacktraceData
{
@ -373,7 +377,19 @@ static void runRMXPScripts(BacktraceData &btData)
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))
{
@ -540,6 +556,13 @@ static void showExc(VALUE exc, const BacktraceData &btData)
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();
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);
static VALUE
fileIntForPath(const char *path)
fileIntForPath(const char *path, bool rubyExc)
{
SDL_RWops *ops = SDL_AllocRW();
@ -51,7 +51,11 @@ fileIntForPath(const char *path)
catch (const Exception &e)
{
SDL_FreeRW(ops);
raiseRbExc(e);
if (rubyExc)
raiseRbExc(e);
else
throw e;
}
VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));
@ -119,11 +123,11 @@ RB_METHOD(fileIntBinmode)
}
VALUE
kernelLoadDataInt(const char *filename)
kernelLoadDataInt(const char *filename, bool rubyExc)
{
rb_gc_start();
VALUE port = fileIntForPath(filename);
VALUE port = fileIntForPath(filename, rubyExc);
VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal"));
@ -142,7 +146,7 @@ RB_METHOD(kernelLoadData)
const char *filename;
rb_get_args(argc, argv, "z", &filename RB_ARG_END);
return kernelLoadDataInt(filename);
return kernelLoadDataInt(filename, true);
}
RB_METHOD(kernelSaveData)

View File

@ -38,17 +38,22 @@ static int getButtonArg(int argc, VALUE *argv)
{
int num;
if (rgssVer >= 3)
{
ID sym;
rb_get_args(argc, argv, "n", &sym RB_ARG_END);
rb_check_argc(argc, 1);
if (FIXNUM_P(argv[0]))
{
num = FIX2INT(argv[0]);
}
else if (SYMBOL_P(argv[0]) && rgssVer >= 3)
{
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
{
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;

View File

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

View File

@ -40,20 +40,26 @@ MRB_FUNCTION(inputUpdate)
static mrb_int getButtonArg(mrb_state *mrb)
{
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 numVal = mrb_hash_fetch(mrb, symHash, mrb_symbol_value(sym),
mrb_value numVal = mrb_hash_fetch(mrb, symHash, arg,
mrb_fixnum_value(Input::None));
num = mrb_fixnum(numVal);
}
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;

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.
# Possible values are 0, 1, 2, 3. If set to 0,
@ -17,6 +27,14 @@
# 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
# (default: disabled)
#
@ -80,12 +98,32 @@
# 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
# (default: disabled)
#
# 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'
# (default: executable directory)
#
@ -218,6 +256,19 @@
# 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
# specified in the Game.ini is, useful if the encoding
# is being falsely detected. Relevant only if mkxp was

View File

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

View File

@ -6,7 +6,7 @@ varying vec2 v_blurCoord[2];
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_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()
{

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 */
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);
I = chroma * cos (hue);
@ -40,5 +44,5 @@ void main ()
color.b = dot (yIQ, kYIQToB);
/* 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 vec4 tone;
uniform lowp vec4 tone;
uniform float opacity;
uniform vec4 color;
uniform vec4 flash;
uniform lowp float opacity;
uniform lowp vec4 color;
uniform lowp vec4 flash;
varying vec2 v_texCoord;

View File

@ -2,7 +2,7 @@
uniform sampler2D texture;
varying vec2 v_texCoord;
varying vec4 v_color;
varying lowp vec4 v_color;
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()
{

View File

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

View File

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

View File

@ -1,13 +1,13 @@
uniform sampler2D texture;
uniform vec4 tone;
uniform lowp vec4 tone;
uniform float opacity;
uniform vec4 color;
uniform lowp float opacity;
uniform lowp vec4 color;
uniform float bushDepth;
uniform float bushOpacity;
uniform lowp float bushOpacity;
varying vec2 v_texCoord;
@ -32,7 +32,7 @@ void main()
frag.rgb = mix(frag.rgb, color.rgb, color.a);
/* 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);
gl_FragColor = frag;

View File

@ -18,8 +18,9 @@ const float atAniOffset = 32.0*3.0;
void main()
{
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);

View File

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

View File

@ -14,7 +14,7 @@ void main()
{
float transV = texture2D(transMap, v_texCoord).r;
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 oldFrag = texture2D(frozenScene, v_texCoord);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,196 +4,196 @@ extern const StaticRect autotileRects[] =
{
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.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 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.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 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 32.5, 48.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 },
{ 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 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 32.5, 96.5, 15, 15 },
{ 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 16.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 48.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 16.5, 96.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.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]);

View File

@ -52,6 +52,8 @@
"Operation not supported for mega surfaces"); \
}
#define OUTLINE_SIZE 1
/* Normalize (= ensure width and
* height are positive) */
static IntRect normalizedRect(const IntRect &rect)
@ -248,9 +250,10 @@ struct BitmapPrivate
Bitmap::Bitmap(const char *filename)
{
SDL_RWops ops;
const char *extension;
shState->fileSystem().openRead(ops, filename, FileSystem::Image, false, &extension);
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, extension);
char ext[8];
shState->fileSystem().openRead(ops, filename, false, ext, sizeof(ext));
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, ext);
if (!imgSurf)
throw Exception(Exception::SDLError, "Error loading image '%s': %s",
@ -317,6 +320,7 @@ Bitmap::Bitmap(const char *filename)
/* Mega surface */
p = new BitmapPrivate(this);
p->megaSurface = imgSurf;
SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE);
}
else if (isCrop)
{
@ -487,14 +491,46 @@ void Bitmap::stretchBlt(const IntRect &destRect,
if (opacity == 0)
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 */
if (opacity < 255)
source.ensureNonMega();
SDL_Surface *srcSurf = source.megaSurface();
SDL_Rect srcRect = sourceRect;
SDL_Rect dstRect = destRect;
SDL_Rect btmRect = { 0, 0, width(), height() };
@ -510,26 +546,25 @@ void Bitmap::stretchBlt(const IntRect &destRect,
SDL_Surface *blitTemp =
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
// makes the source surface unusable after BlitScaled() is called. Investigate!
SDL_BlitSurface(srcSurf, &srcRect, blitTemp, 0);
SDL_BlitScaled(srcSurf, &srcRect, blitTemp, 0);
TEX::bind(p->gl.tex);
if (bltRect.w == dstRect.w && bltRect.h == dstRect.h)
{
/* Dest rectangle lies within bounding box */
TEX::uploadSubImage(destRect.x, destRect.y,
destRect.w, destRect.h,
blitTemp->pixels, GL_RGBA);
}
else
{
/* Clipped blit */
GLMeta::subRectImageUpload(blitTemp->w, bltRect.x - dstRect.x, bltRect.y - dstRect.y,
bltRect.x, bltRect.y, bltRect.w, bltRect.h, blitTemp, GL_RGBA);
GLMeta::subRectImageEnd();
}
SDL_FreeSurface(blitTemp);
p->onModified();
@ -581,7 +616,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
}
p->addTaintedArea(destRect);
p->onModified();
}
@ -1057,6 +1091,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
TTF_Font *font = p->font->getSdlFont();
const Color &fontColor = p->font->getColor();
const Color &outColor = p->font->getOutColor();
SDL_Color c = fontColor.toSDLColor();
c.a = 255;
@ -1072,11 +1107,34 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888);
// While real outlining is not yet here, use shadow
// as a replacement to at least make text legible
if (p->font->getShadow() || p->font->getOutline())
if (p->font->getShadow())
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;
switch (align)
@ -1113,7 +1171,7 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
if (fastBlit)
{
if (squeeze == 1.0)
if (squeeze == 1.0 && !shState->config().subImageFix)
{
/* Even faster: upload directly to bitmap 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 "util.h"
#include "sdl-util.h"
#ifdef INI_ENCODING
extern "C" {
@ -123,6 +124,10 @@ static bool validUtf8(const char *string)
static std::string prefPath(const char *org, const char *app)
{
char *path = SDL_GetPrefPath(org, app);
if (!path)
return std::string();
std::string str(path);
SDL_free(path);
@ -135,65 +140,47 @@ namespace po = boost::program_options;
#define CONF_FILE "mkxp.conf"
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[])
{
#define PO_DESC_ALL \
PO_DESC(rgssVersion, int) \
PO_DESC(debugMode, bool) \
PO_DESC(winResizable, bool) \
PO_DESC(fullscreen, bool) \
PO_DESC(fixedAspectRatio, bool) \
PO_DESC(smoothScaling, bool) \
PO_DESC(vsync, bool) \
PO_DESC(defScreenW, int) \
PO_DESC(defScreenH, int) \
PO_DESC(fixedFramerate, int) \
PO_DESC(frameSkip, bool) \
PO_DESC(solidFonts, bool) \
PO_DESC(gameFolder, std::string) \
PO_DESC(anyAltToggleFS, bool) \
PO_DESC(enableReset, bool) \
PO_DESC(allowSymlinks, bool) \
PO_DESC(dataPathOrg, std::string) \
PO_DESC(dataPathApp, std::string) \
PO_DESC(iconPath, std::string) \
PO_DESC(titleLanguage, std::string) \
PO_DESC(midi.soundFont, std::string) \
PO_DESC(midi.chorus, bool) \
PO_DESC(midi.reverb, bool) \
PO_DESC(SE.sourceCount, int) \
PO_DESC(customScript, std::string) \
PO_DESC(pathCache, bool) \
PO_DESC(useScriptNames, bool)
PO_DESC(rgssVersion, int, 0) \
PO_DESC(debugMode, bool, false) \
PO_DESC(printFPS, bool, false) \
PO_DESC(winResizable, bool, false) \
PO_DESC(fullscreen, bool, false) \
PO_DESC(fixedAspectRatio, bool, true) \
PO_DESC(smoothScaling, bool, false) \
PO_DESC(vsync, bool, false) \
PO_DESC(defScreenW, int, 0) \
PO_DESC(defScreenH, int, 0) \
PO_DESC(fixedFramerate, int, 0) \
PO_DESC(frameSkip, bool, true) \
PO_DESC(syncToRefreshrate, bool, false) \
PO_DESC(solidFonts, bool, false) \
PO_DESC(subImageFix, bool, false) \
PO_DESC(gameFolder, std::string, ".") \
PO_DESC(anyAltToggleFS, bool, false) \
PO_DESC(enableReset, bool, true) \
PO_DESC(allowSymlinks, bool, false) \
PO_DESC(dataPathOrg, std::string, "") \
PO_DESC(dataPathApp, std::string, "") \
PO_DESC(iconPath, std::string, "") \
PO_DESC(execName, std::string, "Game") \
PO_DESC(titleLanguage, std::string, "") \
PO_DESC(midi.soundFont, std::string, "") \
PO_DESC(midi.chorus, bool, false) \
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
#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;
podesc.add_options()
@ -219,26 +206,23 @@ void Config::read(int argc, char *argv[])
}
/* Parse configuration file */
std::ifstream confFile;
confFile.open(CONF_FILE);
SDLRWStream confFile(CONF_FILE, "r");
if (confFile)
{
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);
}
catch (po::error &error)
{
Debug() << CONF_FILE":" << error.what();
}
confFile.close();
}
#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;
@ -349,16 +333,26 @@ void Config::readGameINI()
("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::store(po::parse_config_file(iniFile, podesc, true), vm);
po::notify(vm);
std::string iniFilename = execName + ".ini";
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.scripts = vm["Game.Scripts"].as<std::string>(); );

View File

@ -29,6 +29,49 @@ struct CropTexture
{
std::string filename;
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
@ -36,6 +79,7 @@ struct Config
int rgssVersion;
bool debugMode;
bool printFPS;
bool winResizable;
bool fullscreen;
@ -48,9 +92,12 @@ struct Config
int fixedFramerate;
bool frameSkip;
bool syncToRefreshrate;
bool solidFonts;
bool subImageFix;
std::string gameFolder;
bool anyAltToggleFS;
bool enableReset;
@ -61,6 +108,7 @@ struct Config
std::string dataPathApp;
std::string iconPath;
std::string execName;
std::string titleLanguage;
struct

View File

@ -26,6 +26,11 @@
#include <sstream>
#include <vector>
#ifdef __ANDROID__
#include <android/log.h>
#endif
/* A cheap replacement for qDebug() */
class Debug
@ -56,7 +61,11 @@ public:
~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:

View File

@ -60,6 +60,11 @@ struct Vec4
{
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
@ -74,19 +79,68 @@ struct Vec2i
: x(x), y(y)
{}
explicit Vec2i(int xy)
: x(xy), y(xy)
{}
bool operator==(const Vec2i &other) const
{
return x == other.x && y == other.y;
}
Vec2i &operator+=(const Vec2i &other)
Vec2i &operator+=(const Vec2i &value)
{
x += other.x;
y += other.y;
x += value.x;
y += value.y;
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
{
return Vec2(x, y);
@ -108,6 +162,14 @@ struct IntRect : SDL_Rect
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
{
return (x == other.x && y == other.y &&
@ -124,10 +186,24 @@ struct IntRect : SDL_Rect
return Vec2i(w, h);
}
operator SDL_Rect() const
void setPos(const Vec2i &value)
{
SDL_Rect r = { x, y, w, h };
return r;
x = value.x;
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 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
{
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

View File

@ -105,12 +105,10 @@ int Color::serialSize() const
void Color::serialize(char *buffer) const
{
char *buf = buffer;
write_double(&buf, red);
write_double(&buf, green);
write_double(&buf, blue);
write_double(&buf, alpha);
writeDouble(&buffer, red);
writeDouble(&buffer, green);
writeDouble(&buffer, blue);
writeDouble(&buffer, alpha);
}
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");
Color *c = new Color();
uint i = 0;
c->red = read_double(data, i);
c->green = read_double(data, i);
c->blue = read_double(data, i);
c->alpha = read_double(data, i);
c->red = readDouble(&data);
c->green = readDouble(&data);
c->blue = readDouble(&data);
c->alpha = readDouble(&data);
c->updateInternal();
return c;
@ -241,12 +238,10 @@ int Tone::serialSize() const
void Tone::serialize(char *buffer) const
{
char *buf = buffer;
write_double(&buf, red);
write_double(&buf, green);
write_double(&buf, blue);
write_double(&buf, gray);
writeDouble(&buffer, red);
writeDouble(&buffer, green);
writeDouble(&buffer, blue);
writeDouble(&buffer, gray);
}
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");
Tone *t = new Tone();
uint i = 0;
t->red = read_double(data, i);
t->green = read_double(data, i);
t->blue = read_double(data, i);
t->gray = read_double(data, i);
t->red = readDouble(&data);
t->green = readDouble(&data);
t->blue = readDouble(&data);
t->gray = readDouble(&data);
t->updateInternal();
return t;
@ -390,12 +384,10 @@ int Rect::serialSize() const
void Rect::serialize(char *buffer) const
{
char *buf = buffer;
write_int32(&buf, x);
write_int32(&buf, y);
write_int32(&buf, width);
write_int32(&buf, height);
writeInt32(&buffer, x);
writeInt32(&buffer, y);
writeInt32(&buffer, width);
writeInt32(&buffer, height);
}
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");
Rect *r = new Rect();
uint i = 0;
r->x = read_int32(data, i);
r->y = read_int32(data, i);
r->width = read_int32(data, i);
r->height = read_int32(data, i);
r->x = readInt32(&data);
r->y = readInt32(&data);
r->width = readInt32(&data);
r->height = readInt32(&data);
return r;
}

View File

@ -26,25 +26,51 @@
#include <SDL_messagebox.h>
#include <SDL_timer.h>
#include <SDL_thread.h>
#include <SDL_touch.h>
#include <alext.h>
#include "sharedstate.h"
#include "graphics.h"
#include "settingsmenu.h"
#include "al-util.h"
#include "debugwriter.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 =
{
{ 0 }, { false }
};
#define AL_DEVICE_PAUSE_FUN \
AL_FUN(DevicePause, LPALCDEVICEPAUSESOFT) \
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 */
enum
@ -80,19 +106,24 @@ void EventThread::process(RGSSThreadData &rtData)
{
SDL_Event event;
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;
int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT;
fps.lastFrame = SDL_GetPerformanceCounter();
fps.displayCounter = 0;
fps.displaying = false;
fps.immInitFlag = false;
fps.immFiniFlag = false;
fps.acc = 0;
fps.accDiv = 0;
if (rtData.config.printFPS)
fps.sendUpdates.set();
bool displayingFPS = false;
bool cursorInWindow = false;
bool windowFocused = false;
@ -109,6 +140,11 @@ void EventThread::process(RGSSThreadData &rtData)
bool resetting = false;
int winW, winH;
int i;
SDL_GetWindowSize(win, &winW, &winH);
SettingsMenu *sMenu = 0;
while (true)
@ -132,14 +168,36 @@ void EventThread::process(RGSSThreadData &rtData)
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)
{
case SDL_WINDOWEVENT :
switch (event.window.event)
{
case SDL_WINDOWEVENT_SIZE_CHANGED :
windowSizeMsg.notifyChange(event.window.data1,
event.window.data2);
winW = event.window.data1;
winH = event.window.data2;
windowSizeMsg.post(Vec2i(winW, winH));
resetInputStates();
break;
case SDL_WINDOWEVENT_ENTER :
@ -210,14 +268,18 @@ void EventThread::process(RGSSThreadData &rtData)
if (event.key.keysym.scancode == SDL_SCANCODE_F2)
{
if (!fps.displaying)
if (!displayingFPS)
{
fps.immInitFlag = true;
fps.displaying = true;
fps.immInitFlag.set();
fps.sendUpdates.set();
displayingFPS = true;
}
else
{
fps.displaying = false;
displayingFPS = false;
if (!rtData.config.printFPS)
fps.sendUpdates.clear();
if (fullscreen)
{
@ -274,8 +336,12 @@ void EventThread::process(RGSSThreadData &rtData)
joyState.buttons[event.jbutton.button] = false;
break;
case SDL_JOYHATMOTION :
joyState.hats[event.jhat.hat] = event.jhat.value;
break;
case SDL_JOYAXISMOTION :
joyState.axis[event.jaxis.axis] = event.jaxis.value;
joyState.axes[event.jaxis.axis] = event.jaxis.value;
break;
case SDL_JOYDEVICEADDED :
@ -300,7 +366,21 @@ void EventThread::process(RGSSThreadData &rtData)
case SDL_MOUSEMOTION :
mouseState.x = event.motion.x;
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;
default :
@ -329,7 +409,10 @@ void EventThread::process(RGSSThreadData &rtData)
break;
case UPDATE_FPS :
if (!fps.displaying)
if (rtData.config.printFPS)
Debug() << "FPS:" << event.user.code;
if (!fps.sendUpdates)
break;
snprintf(buffer, sizeof(buffer), "%s - %d FPS",
@ -354,12 +437,69 @@ void EventThread::process(RGSSThreadData &rtData)
break;
}
/* Just in case */
rtData.syncPoint.resumeThreads();
if (SDL_JoystickGetAttached(js))
SDL_JoystickClose(js);
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()
{
SDL_Event event;
@ -374,6 +514,7 @@ void EventThread::resetInputStates()
memset(&keyStates, 0, sizeof(keyStates));
memset(&joyState, 0, sizeof(joyState));
memset(&mouseState.buttons, 0, sizeof(mouseState.buttons));
memset(&touchState, 0, sizeof(touchState));
}
void EventThread::setFullscreen(SDL_Window *win, bool mode)
@ -454,7 +595,7 @@ bool EventThread::getShowCursor() const
void EventThread::notifyFrame()
{
if (!fps.displaying)
if (!fps.sendUpdates)
return;
uint64_t current = SDL_GetPerformanceCounter();
@ -463,8 +604,8 @@ void EventThread::notifyFrame()
if (fps.immInitFlag)
{
fps.immInitFlag = false;
fps.immFiniFlag = true;
fps.immInitFlag.clear();
fps.immFiniFlag.set();
return;
}
@ -480,7 +621,7 @@ void EventThread::notifyFrame()
return;
fps.displayCounter = 0;
fps.immFiniFlag = false;
fps.immFiniFlag.clear();
int32_t avgFPS = fps.acc / fps.accDiv;
fps.acc = fps.accDiv = 0;
@ -490,3 +631,87 @@ void EventThread::notifyFrame()
event.user.type = usrIdStart + UPDATE_FPS;
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>
struct RGSSThreadData;
typedef struct ALCdevice_struct ALCdevice;
struct SDL_Window;
union SDL_Event;
#define MAX_FINGERS 4
class EventThread
{
public:
static uint8_t keyStates[SDL_NUM_SCANCODES];
struct JoyState
{
int axis[256];
int axes[256];
uint8_t hats[256];
bool buttons[256];
};
static JoyState joyState;
struct MouseState
{
int x, y;
@ -59,7 +60,21 @@ public:
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 TouchState touchState;
static bool allocUserEvents();
@ -84,6 +99,8 @@ public:
void notifyFrame();
private:
static int eventFilter(void *, SDL_Event*);
void resetInputStates();
void setFullscreen(SDL_Window *, bool mode);
void updateCursorState(bool inWindow);
@ -96,111 +113,101 @@ private:
{
uint64_t lastFrame;
uint64_t displayCounter;
bool displaying;
bool immInitFlag;
bool immFiniFlag;
AtomicFlag sendUpdates;
AtomicFlag immInitFlag;
AtomicFlag immFiniFlag;
double acc;
uint32_t accDiv;
} fps;
};
/* Used to asynchronously inform the RGSS thread
* about window size changes */
struct WindowSizeNotify
* about certain value changes */
template<typename T>
struct UnidirMessage
{
SDL_mutex *mutex;
UnidirMessage()
: mutex(SDL_CreateMutex()),
current(T())
{}
AtomicFlag changed;
int w, h;
WindowSizeNotify()
{
mutex = SDL_CreateMutex();
w = h = 0;
}
~WindowSizeNotify()
~UnidirMessage()
{
SDL_DestroyMutex(mutex);
}
/* Done from the sending side */
void notifyChange(int w, int h)
void post(const T &value)
{
SDL_LockMutex(mutex);
this->w = w;
this->h = h;
changed.set();
current = value;
SDL_UnlockMutex(mutex);
}
/* Done from the receiving side */
bool pollChange(int *w, int *h)
bool poll(T &out) const
{
if (!changed)
return false;
SDL_LockMutex(mutex);
*w = this->w;
*h = this->h;
out = current;
changed.clear();
SDL_UnlockMutex(mutex);
return true;
}
};
struct BindingNotify
{
BindingNotify()
/* Done from either */
void get(T &out) const
{
mut = SDL_CreateMutex();
}
~BindingNotify()
{
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);
SDL_LockMutex(mutex);
out = current;
SDL_UnlockMutex(mutex);
}
private:
SDL_mutex *mut;
BDescVec data;
SDL_mutex *mutex;
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
@ -218,15 +225,18 @@ struct RGSSThreadData
AtomicFlag rqResetFinish;
EventThread *ethread;
WindowSizeNotify windowSizeMsg;
BindingNotify bindingUpdateMsg;
UnidirMessage<Vec2i> windowSizeMsg;
UnidirMessage<BDescVec> bindingUpdateMsg;
SyncPoint syncPoint;
const char *argv0;
SDL_Window *window;
ALCdevice *alcDev;
Vec2 sizeResoRatio;
Vec2i screenOffset;
const int refreshRate;
Config config;
@ -235,11 +245,15 @@ struct RGSSThreadData
RGSSThreadData(EventThread *ethread,
const char *argv0,
SDL_Window *window,
ALCdevice *alcDev,
int refreshRate,
const Config& newconf)
: ethread(ethread),
argv0(argv0),
window(window),
alcDev(alcDev),
sizeResoRatio(1, 1),
refreshRate(refreshRate),
config(newconf)
{}
};

View File

@ -42,6 +42,105 @@
#include <iconv.h>
#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)
{
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
@ -131,18 +230,36 @@ static int SDL_RWopsCloseFree(SDL_RWops *ops)
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;
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'
* case insensitivity for granted */
BoostHash<std::string, std::string> pathCache;
bool havePathCache;
std::vector<std::string> extensions[FileSystem::Undefined+1];
/* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the
* extension, or null is returned */
@ -162,120 +279,129 @@ struct FileSystemPrivate
return 0;
}
/* Complete filename via regular physfs lookup */
bool completeFilenameReg(const char *filename,
FileSystem::FileType type,
struct CompleteFilenameData
{
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,
size_t outN,
const char **foundExt)
size_t outN)
{
/* Try supplementing extensions to find an existing path */
const std::vector<std::string> &extList = extensions[type];
strcpySafe(outBuffer, filepath, outN, -1);
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);
if (PHYSFS_exists(outBuffer))
{
if (foundExt)
*foundExt = ext;
return true;
}
*delim = '\0';
}
else
{
/* Otherwise the file is in the root directory */
d.outBuf = outBuffer;
d.filenameLen = len - (delim - outBuffer);
}
/* Doing the check without supplemented extension
* fits the usage pattern of RMXP games */
if (PHYSFS_exists(filename))
{
strncpy(outBuffer, filename, outN);
d.found = false;
d.outBufN = outN - (d.outBuf - outBuffer);
if (foundExt)
*foundExt = findExt(filename);
PHYSFS_enumerateFilesCallback(root ? "" : outBuffer, completeFilenameRegCB, &d);
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 *filename,
FileSystem::FileType type,
bool completeFilenamePC(const char *filepath,
char *outBuffer,
size_t outN,
const char **foundExt)
size_t outN)
{
size_t i;
char lowCase[512];
std::string lowCase(filepath);
for (i = 0; i < sizeof(lowCase)-1 && filename[i]; ++i)
lowCase[i] = tolower(filename[i]);
for (size_t i = 0; i < lowCase.size(); ++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];
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;
return true;
}
/* Try to complete 'filename' with file extensions
* based on 'type'. If no combination could be found,
* returns false, and 'foundExt' is untouched */
bool completeFileName(const char *filename,
FileSystem::FileType type,
bool completeFilename(const char *filepath,
char *outBuffer,
size_t outN,
const char **foundExt)
size_t outN)
{
if (havePathCache)
return completeFilenamePC(filename, type, outBuffer, outN, foundExt);
return completeFilenamePC(filepath, outBuffer, outN);
else
return completeFilenameReg(filename, type, outBuffer, outN, foundExt);
return completeFilenameReg(filepath, outBuffer, outN);
}
PHYSFS_File *openReadHandle(const char *filename,
FileSystem::FileType type,
const char **foundExt)
char *extBuf,
size_t extBufN)
{
char found[512];
if (!completeFileName(filename, type, found, sizeof(found), foundExt))
if (!completeFilename(filename, found, sizeof(found)))
throw Exception(Exception::NoFileError, "%s", filename);
PHYSFS_File *handle = PHYSFS_openRead(found);
@ -283,6 +409,21 @@ struct FileSystemPrivate
if (!handle)
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;
}
@ -309,45 +450,8 @@ FileSystem::FileSystem(const char *argv0,
bool allowSymlinks)
{
p = new FileSystemPrivate;
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_registerArchiver(&RGSS1_Archiver);
@ -368,7 +472,16 @@ FileSystem::~FileSystem()
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__
@ -436,12 +549,22 @@ static void cacheEnumCB(void *d, const char *origdir,
std::string mixedCase(ptr);
for (char *p = bufNfc; *p; ++p)
*p = tolower(*p);
for (char *q = bufNfc; *q; ++q)
*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);
}
@ -450,7 +573,7 @@ void FileSystem::createPathCache()
{
#ifdef __APPLE__
CacheEnumCBData data(p);
PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data);
PHYSFS_enumerateFilesCallback("", cacheEnumCB2, &data);
#else
PHYSFS_enumerateFilesCallback("", cacheEnumCB, p);
#endif
@ -458,12 +581,6 @@ void FileSystem::createPathCache()
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
{
FileSystemPrivate *p;
@ -482,16 +599,21 @@ static void fontSetEnumCB(void *data, const char *,
if (!ext)
return;
std::string lower(ext);
strToLower(lower);
char lowExt[8];
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;
std::string filename("Fonts/");
filename += fname;
char filename[512];
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)
return;
@ -513,11 +635,11 @@ void FileSystem::initFontSets(SharedFontState &sfs)
void FileSystem::openRead(SDL_RWops &ops,
const char *filename,
FileType type,
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);
}
@ -532,9 +654,9 @@ void FileSystem::openReadRaw(SDL_RWops &ops,
p->initReadOps(handle, ops, freeOnClose);
}
bool FileSystem::exists(const char *filename, FileType type)
bool FileSystem::exists(const char *filename)
{
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 */
void initFontSets(SharedFontState &sfs);
/* For extension supplementing */
enum FileType
{
Image = 0,
Audio,
Font,
Undefined
};
void openRead(SDL_RWops &ops,
const char *filename,
FileType type = Undefined,
bool freeOnClose = false,
const char **foundExt = 0);
char *extBuf = 0,
size_t extBufN = 0);
/* Circumvents extension supplementing */
void openReadRaw(SDL_RWops &ops,
const char *filename,
bool freeOnClose = false);
bool exists(const char *filename,
FileType type = Undefined);
bool exists(const char *filename);
private:
FileSystemPrivate *p;

View File

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

View File

@ -86,16 +86,14 @@ public:
const Font &operator=(const Font &o);
const char *getName() const;
void setName(const char *value);
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Color, Color& )
DECL_ATTR( Shadow, bool )
DECL_ATTR( Outline, bool )
DECL_ATTR( OutColor, Color& )
DECL_ATTR( Name, const char * )
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Color, Color& )
DECL_ATTR( Shadow, bool )
DECL_ATTR( Outline, bool )
DECL_ATTR( OutColor, Color& )
DECL_ATTR_STATIC( DefaultName, const char* )
DECL_ATTR_STATIC( DefaultSize, int )
@ -108,7 +106,7 @@ public:
/* Assigns heap allocated objects to object properties;
* 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();
static void initDefaultDynAttribs();

View File

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

View File

@ -1,5 +1,5 @@
/*
** debuglogger.h
** gl-debug.h
**
** This file is part of mkxp.
**
@ -22,16 +22,30 @@
#ifndef DEBUGLOGGER_H
#define DEBUGLOGGER_H
struct DebugLoggerPrivate;
#include "gl-fun.h"
class DebugLogger
#include <stdio.h>
#include <algorithm>
struct GLDebugLoggerPrivate;
class GLDebugLogger
{
public:
DebugLogger(const char *filename = 0);
~DebugLogger();
GLDebugLogger(const char *filename = 0);
~GLDebugLogger();
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

View File

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

View File

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

View File

@ -61,43 +61,43 @@ namespace TEX
return id;
}
inline void del(ID id)
static inline void del(ID id)
{
gl.DeleteTextures(1, &id.gl);
}
inline void bind(ID id)
static inline void bind(ID id)
{
gl.BindTexture(GL_TEXTURE_2D, id.gl);
}
inline void unbind()
static inline void unbind()
{
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);
}
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);
}
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);
}
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_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_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST);
@ -117,27 +117,27 @@ namespace FBO
return id;
}
inline void del(ID id)
static inline void del(ID id)
{
gl.DeleteFramebuffers(1, &id.gl);
}
inline void bind(ID id)
static inline void bind(ID id)
{
gl.BindFramebuffer(GL_FRAMEBUFFER, id.gl);
}
inline void unbind()
static inline void unbind()
{
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);
}
inline void clear()
static inline void clear()
{
gl.Clear(GL_COLOR_BUFFER_BIT);
}
@ -148,7 +148,7 @@ struct GenericBO
{
DEF_GL_ID
inline static ID gen()
static inline ID gen()
{
ID id;
gl.GenBuffers(1, &id.gl);
@ -156,32 +156,32 @@ struct GenericBO
return id;
}
inline static void del(ID id)
static inline void del(ID id)
{
gl.DeleteBuffers(1, &id.gl);
}
inline static void bind(ID id)
static inline void bind(ID id)
{
gl.BindBuffer(target, id.gl);
}
inline static void unbind()
static inline void unbind()
{
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);
}
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);
}
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);
}

View File

@ -43,7 +43,7 @@ void GLScissorBox::apply(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 r2 = { value.x, value.y, value.w, value.h };

View File

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

View File

@ -171,36 +171,112 @@ public:
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,
* and since we're inside the draw cycle, it will
* be turned on, so turn it off temporarily */
glState.scissorTest.pushSet(false);
if (t.w != 0.0)
{
pp.swapRender();
GLMeta::blitBegin(pp.frontBuffer());
GLMeta::blitSource(pp.backBuffer());
GLMeta::blitRectangle(geometry.rect, Vec2i());
GLMeta::blitEnd();
if (!viewpRect.encloses(screenRect))
{
/* Scissor test _does_ affect FBO blit operations,
* 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.setColor(c);
shader.setFlash(f);
shader.setTone(t);
shader.setOpacity(1.0);
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)
@ -390,6 +466,7 @@ struct GraphicsPrivate
ScreenScene screen;
RGSSThreadData *threadData;
SDL_GLContext glCtx;
int frameRate;
int frameCount;
@ -413,6 +490,7 @@ struct GraphicsPrivate
winSize(rtData->config.defScreenW, rtData->config.defScreenH),
screen(scRes.x, scRes.y),
threadData(rtData),
glCtx(SDL_GL_GetCurrentContext()),
frameRate(DEF_FRAMERATE),
frameCount(0),
brightness(255),
@ -482,7 +560,7 @@ struct GraphicsPrivate
void checkResize()
{
if (threadData->windowSizeMsg.pollChange(&winSize.x, &winSize.y))
if (threadData->windowSizeMsg.poll(winSize))
{
/* some GL drivers change the viewport on window resize */
glState.viewport.refresh();
@ -552,16 +630,40 @@ struct GraphicsPrivate
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)
{
p = new GraphicsPrivate(data);
if (data->config.fixedFramerate > 0)
p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate);
else if (data->config.fixedFramerate < 0)
if (data->config.syncToRefreshrate)
{
p->frameRate = data->refreshRate;
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()
@ -572,6 +674,7 @@ Graphics::~Graphics()
void Graphics::update()
{
p->checkShutDownReset();
p->checkSyncLock();
if (p->frozen)
return;
@ -613,10 +716,12 @@ void Graphics::transition(int duration,
const char *filename,
int vague)
{
p->checkSyncLock();
if (!p->frozen)
return;
vague = clamp(vague, 0, 512);
vague = clamp(vague, 1, 256);
Bitmap *transMap = filename ? new Bitmap(filename) : 0;
setBrightness(255);
@ -637,7 +742,7 @@ void Graphics::transition(int duration,
shader.setFrozenScene(p->frozenScene.tex);
shader.setCurrentScene(p->currentScene.tex);
shader.setTransMap(transMap->getGLTypes().tex);
shader.setVague(vague / 512.0f);
shader.setVague(vague / 256.0);
shader.setTexSize(p->scRes);
}
else
@ -673,6 +778,8 @@ void Graphics::transition(int duration,
return;
}
p->checkSyncLock();
const float prog = i * (1.0 / duration);
if (transMap)
@ -728,6 +835,9 @@ void Graphics::setFrameRate(int value)
{
p->frameRate = clamp(value, 10, 120);
if (p->threadData->config.syncToRefreshrate)
return;
if (p->threadData->config.fixedFramerate > 0)
return;

View File

@ -133,7 +133,7 @@ struct JsAxisBinding : public Binding
bool sourceActive() const
{
int val = EventThread::joyState.axis[source];
int val = EventThread::joyState.axes[source];
if (dir == Negative)
return val < -JAXIS_THRESHOLD;
@ -150,6 +150,34 @@ struct JsAxisBinding : public Binding
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 */
struct MsBinding : public Binding
{
@ -241,6 +269,7 @@ struct InputPrivate
std::vector<KbBinding> kbStatBindings;
std::vector<KbBinding> kbBindings;
std::vector<JsAxisBinding> jsABindings;
std::vector<JsHatBinding> jsHBindings;
std::vector<JsButtonBinding> jsBBindings;
std::vector<MsBinding> msBindings;
@ -348,6 +377,7 @@ struct InputPrivate
{
kbBindings.clear();
jsABindings.clear();
jsHBindings.clear();
jsBBindings.clear();
for (size_t i = 0; i < d.size(); ++i)
@ -381,6 +411,16 @@ struct InputPrivate
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 :
{
JsButtonBinding bind;
@ -402,6 +442,7 @@ struct InputPrivate
appendBindings(kbBindings);
appendBindings(jsABindings);
appendBindings(jsHBindings);
appendBindings(jsBBindings);
}

View File

@ -129,6 +129,20 @@ static void addAxisBinding(BDescVec &d, uint8_t axis, AxisDir dir, Input::Button
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 d;
@ -150,11 +164,16 @@ BDescVec genDefaultBindings(const Config &conf)
addAxisBinding(d, 0, Positive, Input::Right);
addAxisBinding(d, 1, Negative, Input::Up );
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;
}
#define FORMAT_VER 1
#define FORMAT_VER 2
struct Header
{
@ -166,7 +185,7 @@ struct Header
static void buildPath(const std::string &dir, uint32_t rgssVersion,
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,
@ -178,7 +197,7 @@ static bool writeBindings(const BDescVec &d, const std::string &dir,
char path[1024];
buildPath(dir, rgssVersion, path, sizeof(path));
FILE *f = fopen(path, "w");
FILE *f = fopen(path, "wb");
if (!f)
return false;
@ -247,6 +266,10 @@ static bool verifyDesc(const BindingDesc &desc)
return src.d.scan < SDL_NUM_SCANCODES;
case JButton:
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:
return src.d.ja.dir == Negative || src.d.ja.dir == Positive;
default:
@ -263,7 +286,7 @@ static bool readBindings(BDescVec &out, const std::string &dir,
char path[1024];
buildPath(dir, rgssVersion, path, sizeof(path));
FILE *f = fopen(path, "r");
FILE *f = fopen(path, "rb");
if (!f)
return false;

View File

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

View File

@ -26,20 +26,21 @@
#include <SDL_ttf.h>
#include <SDL_sound.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <string>
#include "sharedstate.h"
#include "eventthread.h"
#include "debuglogger.h"
#include "gl-debug.h"
#include "debugwriter.h"
#include "exception.h"
#include "gl-fun.h"
#include "binding.h"
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include "icon.png.xxd"
static void
rgssThreadError(RGSSThreadData *rtData, const std::string &msg)
@ -67,13 +68,14 @@ printGLInfo()
int rgssThreadFun(void *userdata)
{
RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata);
const Config &conf = threadData->config;
SDL_Window *win = threadData->window;
SDL_GLContext glCtx;
/* Setup GL context */
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);
glCtx = SDL_GL_CreateContext(win);
@ -102,27 +104,17 @@ int rgssThreadFun(void *userdata)
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 */
ALCdevice *alcDev = alcOpenDevice(0);
if (!alcDev)
{
rgssThreadError(threadData, "Error opening OpenAL device");
SDL_GL_DeleteContext(glCtx);
return 0;
}
ALCcontext *alcCtx = alcCreateContext(alcDev, 0);
ALCcontext *alcCtx = alcCreateContext(threadData->alcDev, 0);
if (!alcCtx)
{
rgssThreadError(threadData, "Error creating OpenAL context");
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx);
return 0;
@ -138,7 +130,6 @@ int rgssThreadFun(void *userdata)
{
rgssThreadError(threadData, exc.msg);
alcDestroyContext(alcCtx);
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx);
return 0;
@ -153,8 +144,6 @@ int rgssThreadFun(void *userdata)
SharedState::finiInstance();
alcDestroyContext(alcCtx);
alcCloseDevice(alcDev);
SDL_GL_DeleteContext(glCtx);
return 0;
@ -171,20 +160,27 @@ static void printRgssVersion(int ver)
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[])
{
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
/* initialize SDL first */
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;
}
if (!EventThread::allocUserEvents())
{
Debug() << "Error allocating SDL user events";
showInitError("Error allocating SDL user events");
return 0;
}
@ -201,8 +197,15 @@ int main(int argc, char *argv[])
/* now we load the config */
Config conf;
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();
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;
if (IMG_Init(imgFlags) != imgFlags)
{
Debug() << "Error initializing SDL_image:" << SDL_GetError();
showInitError(std::string("Error initializing SDL_image: ") + SDL_GetError());
SDL_Quit();
return 0;
@ -219,7 +222,7 @@ int main(int argc, char *argv[])
if (TTF_Init() < 0)
{
Debug() << "Error initializing SDL_ttf:" << SDL_GetError();
showInitError(std::string("Error initializing SDL_ttf: ") + SDL_GetError());
IMG_Quit();
SDL_Quit();
@ -228,7 +231,7 @@ int main(int argc, char *argv[])
if (Sound_Init() == 0)
{
Debug() << "Error initializing SDL_sound:" << Sound_GetError();
showInitError(std::string("Error initializing SDL_sound: ") + Sound_GetError());
TTF_Quit();
IMG_Quit();
SDL_Quit();
@ -236,7 +239,15 @@ int main(int argc, char *argv[])
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;
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS;
@ -252,22 +263,43 @@ int main(int argc, char *argv[])
if (!win)
{
Debug() << "Error creating window:" << SDL_GetError();
showInitError(std::string("Error creating window: ") + SDL_GetError());
return 0;
}
if (!conf.iconPath.empty())
if (iconImg)
{
SDL_Surface *iconImg = IMG_Load(conf.iconPath.c_str());
if (iconImg)
{
SDL_SetWindowIcon(win, 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;
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 */
rtData.bindingUpdateMsg.post(loadBindings(conf));
@ -314,13 +346,9 @@ int main(int argc, char *argv[])
/* Clean up any remainin events */
eventThread.cleanup();
/* Store key bindings */
BDescVec keyBinds;
rtData.bindingUpdateMsg.get(keyBinds);
storeBindings(keyBinds, rtData.config);
Debug() << "Shutting down.";
alcCloseDevice(alcDev);
SDL_DestroyWindow(win);
Sound_Quit();

View File

@ -55,7 +55,13 @@
#define TICK_FRAMES 32
#define BUF_TICKS (STREAM_BUF_SIZE / TICK_FRAMES)
#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
{
@ -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
{
const uint16_t freq;
@ -530,6 +589,8 @@ struct MidiSource : ALDataSource, MidiReadHandler
int16_t synthBuf[BUF_TICKS*TICK_FRAMES*2];
std::vector<Track> tracks;
CCResetter<CC_CTRL_VOLUME> volReset;
CCResetter<CC_CTRL_EXPRESSION> expReset;
/* Index of longest track */
uint8_t longestI;
@ -631,7 +692,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
playbackSpeed = TICK_FRAMES / (deltaLength * freq);
}
void activateEvent(MidiEvent &e)
void activateEvent(const MidiEvent &e)
{
int16_t key = e.e.note.key;
@ -705,9 +766,14 @@ struct MidiSource : ALDataSource, MidiReadHandler
void onMidiEvent(const MidiEvent &e, uint32_t absDelta)
{
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;
}

View File

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

View File

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

View File

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

View File

@ -3,8 +3,10 @@
#include <SDL_atomic.h>
#include <SDL_thread.h>
#include <SDL_rwops.h>
#include <string>
#include <iostream>
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);
}
/* 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

View File

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

View File

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

View File

@ -28,25 +28,30 @@
#include <string.h>
#include <iostream>
#include "../sprite.frag.xxd"
#include "../hue.frag.xxd"
#include "../trans.frag.xxd"
#include "../transSimple.frag.xxd"
#include "../bitmapBlit.frag.xxd"
#include "../plane.frag.xxd"
#include "../simple.frag.xxd"
#include "../simpleColor.frag.xxd"
#include "../simpleAlpha.frag.xxd"
#include "../flashMap.frag.xxd"
#include "../simple.vert.xxd"
#include "../simpleColor.vert.xxd"
#include "../sprite.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"
#include "common.h.xxd"
#include "sprite.frag.xxd"
#include "hue.frag.xxd"
#include "trans.frag.xxd"
#include "transSimple.frag.xxd"
#include "bitmapBlit.frag.xxd"
#include "plane.frag.xxd"
#include "gray.frag.xxd"
#include "flatColor.frag.xxd"
#include "simple.frag.xxd"
#include "simpleColor.frag.xxd"
#include "simpleAlpha.frag.xxd"
#include "simpleAlphaUni.frag.xxd"
#include "flashMap.frag.xxd"
#include "minimal.vert.xxd"
#include "simple.vert.xxd"
#include "simpleColor.vert.xxd"
#include "sprite.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) \
@ -106,32 +111,39 @@ void Shader::unbind()
glState.program.set(0);
}
static const char *glesHeader = "precision mediump float;\n";
static const size_t glesHeaderSize = strlen(glesHeader);
static void setupShaderSource(GLuint shader,
const unsigned char *src, int srcSize)
static void setupShaderSource(GLuint shader, GLenum type,
const unsigned char *body, int bodySize)
{
GLuint shaderSrcN;
const GLchar *shaderSrc[2];
GLint shaderSrcSize[2];
static const char glesDefine[] = "#define GLSLES\n";
static const char fragDefine[] = "#define FRAGMENT_SHADER\n";
const GLchar *shaderSrc[4];
GLint shaderSrcSize[4];
size_t i = 0;
if (gl.glsles)
{
shaderSrcN = 2;
shaderSrc[0] = glesHeader;
shaderSrc[1] = (const GLchar*) src;
shaderSrcSize[0] = glesHeaderSize;
shaderSrcSize[1] = srcSize;
}
else
{
shaderSrcN = 1;
shaderSrc[0] = (const GLchar*) src;
shaderSrcSize[0] = srcSize;
shaderSrc[i] = glesDefine;
shaderSrcSize[i] = sizeof(glesDefine)-1;
++i;
}
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,
@ -142,7 +154,7 @@ void Shader::init(const unsigned char *vert, int vertSize,
GLint success;
/* Compile vertex shader */
setupShaderSource(vertShader, vert, vertSize);
setupShaderSource(vertShader, GL_VERTEX_SHADER, vert, vertSize);
gl.CompileShader(vertShader);
gl.GetShaderiv(vertShader, GL_COMPILE_STATUS, &success);
@ -156,7 +168,7 @@ void Shader::init(const unsigned char *vert, int vertSize,
}
/* Compile fragment shader */
setupShaderSource(fragShader, frag, fragSize);
setupShaderSource(fragShader, GL_FRAGMENT_SHADER, frag, fragSize);
gl.CompileShader(fragShader);
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()
{
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()
{
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()
{
INIT_SHADER(tilemap, simple, TilemapShader);

View File

@ -87,6 +87,17 @@ protected:
GLint u_texSizeInv, u_translation;
};
class FlatColorShader : public ShaderBase
{
public:
FlatColorShader();
void setColor(const Vec4 &value);
private:
GLint u_color;
};
class SimpleShader : public ShaderBase
{
public:
@ -121,6 +132,18 @@ private:
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
{
public:
@ -179,6 +202,17 @@ private:
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
{
public:
@ -273,12 +307,15 @@ private:
/* Global object containing all available shaders */
struct ShaderSet
{
FlatColorShader flatColor;
SimpleShader simple;
SimpleColorShader simpleColor;
SimpleAlphaShader simpleAlpha;
SimpleSpriteShader simpleSprite;
AlphaSpriteShader alphaSprite;
SpriteShader sprite;
PlaneShader plane;
GrayShader gray;
TilemapShader tilemap;
FlashMapShader flashMap;
TransShader trans;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@
#include "tileatlasvx.h"
#include "tilemap-common.h"
#include "bitmap.h"
#include "table.h"
#include "etc-internal.h"
@ -65,21 +66,6 @@ static elementsN(autotileVXRectsC);
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
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 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 */
static void

View File

@ -1,5 +1,5 @@
/*
** flashmap.h
** tilemap-common.h
**
** This file is part of mkxp.
**
@ -19,8 +19,8 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FLASHMAP_H
#define FLASHMAP_H
#ifndef TILEMAPCOMMON_H
#define TILEMAPCOMMON_H
#include "table.h"
#include "gl-util.h"
@ -30,8 +30,11 @@
#include "glstate.h"
#include "shader.h"
#include "vertex.h"
#include "quad.h"
#include "etc-internal.h"
#include <stdint.h>
#include <assert.h>
#include <vector>
#include <sigc++/connection.h>
@ -44,11 +47,50 @@ wrap(int value, int range)
}
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()),
wrap(y, t->ySize()),
z);
return t.get(wrap(x, t.xSize()),
wrap(y, t.ySize()),
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
@ -144,7 +186,7 @@ private:
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)
return false;
@ -216,4 +258,4 @@ private:
std::vector<CVertex> vertices;
};
#endif // FLASHMAP_H
#endif // TILEMAPCOMMON_H

View File

@ -26,6 +26,7 @@
#include "table.h"
#include "sharedstate.h"
#include "config.h"
#include "glstate.h"
#include "gl-util.h"
#include "gl-meta.h"
@ -36,7 +37,7 @@
#include "quad.h"
#include "vertex.h"
#include "tileatlas.h"
#include "flashmap.h"
#include "tilemap-common.h"
#include <sigc++/connection.h>
@ -441,15 +442,13 @@ struct TilemapPrivate
void updateSceneGeometry(const Scene::Geometry &geo)
{
elem.sceneOffset.x = geo.rect.x - geo.xOrigin;
elem.sceneOffset.y = geo.rect.y - geo.yOrigin;
elem.sceneOffset = geo.offset();
elem.sceneGeo = geo;
}
void updatePosition()
{
dispPos.x = -(offset.x - viewpPos.x * 32) + elem.sceneOffset.x;
dispPos.y = -(offset.y - viewpPos.y * 32) + elem.sceneOffset.y;
dispPos = -(offset - viewpPos * 32) + elem.sceneOffset;
}
void invalidateAtlasSize()
@ -542,19 +541,59 @@ struct TilemapPrivate
if (tileset->megaSurface())
{
/* Mega surface tileset */
TEX::bind(atlas.gl.tex);
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,
blitOp.dst.x, blitOp.dst.y, tsLaneW, blitOp.h, tsSurf, GL_RGBA);
SimpleShader &shader = shState->shaders().simple;
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
{
@ -590,21 +629,6 @@ struct TilemapPrivate
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)
{
/* Which autotile [0-7] */
@ -617,7 +641,9 @@ struct TilemapPrivate
/* Iterate over the 4 tile pieces */
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];
/* Adjust to atlas coordinates */
@ -635,7 +661,7 @@ struct TilemapPrivate
void handleTile(int x, int y, int z)
{
int tileInd =
tableGetWrapped(mapData, x + viewpPos.x, y + viewpPos.y, z);
tableGetWrapped(*mapData, x + viewpPos.x, y + viewpPos.y, z);
/* Check for empty space */
if (tileInd < 48)
@ -972,6 +998,9 @@ void GroundLayer::updateVboCount()
void GroundLayer::draw()
{
if (p->groundVert.size() == 0)
return;
ShaderBase *shader;
p->bindShader(shader);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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