Implement F12 game reset (MRI only)
Can be disabled with "enableReset=false". While at it, also replace the flakey volatile bool flags with proper atomics.
This commit is contained in:
parent
3a2e560139
commit
d223d83cbf
|
@ -15,7 +15,6 @@ Missing RGSS3 functionality:
|
||||||
|
|
||||||
* Text outline
|
* Text outline
|
||||||
* Movie playback
|
* Movie playback
|
||||||
* F12 reset
|
|
||||||
* Audio fade-in
|
* Audio fade-in
|
||||||
|
|
||||||
Some other things might be implemented, but simply not bound yet.
|
Some other things might be implemented, but simply not bound yet.
|
||||||
|
@ -116,7 +115,6 @@ If a requested font is not found, no error is generated. Instead, a built-in fon
|
||||||
|
|
||||||
* wma audio files
|
* wma audio files
|
||||||
* The Win32API ruby class (for obvious reasons)
|
* The Win32API ruby class (for obvious reasons)
|
||||||
* Restarting the game with F12
|
|
||||||
* Creating Bitmaps with sizes greater than the OpenGL texture size limit (around 8192 on modern cards)*
|
* Creating Bitmaps with sizes greater than the OpenGL texture size limit (around 8192 on modern cards)*
|
||||||
|
|
||||||
\* There is an exception to this, called *mega surface*. When a Bitmap bigger than the texture limit is created from a file, it is not stored in VRAM, but regular RAM. Its sole purpose is to be used as a tileset bitmap. Any other operation to it (besides blitting to a regular Bitmap) will result in an error.
|
\* There is an exception to this, called *mega surface*. When a Bitmap bigger than the texture limit is created from a file, it is not stored in VRAM, but regular RAM. Its sole purpose is to be used as a tileset bitmap. Any other operation to it (besides blitting to a regular Bitmap) will result in an error.
|
||||||
|
|
|
@ -97,6 +97,15 @@ DEF_FADE( me )
|
||||||
|
|
||||||
DEF_PLAY_STOP( se )
|
DEF_PLAY_STOP( se )
|
||||||
|
|
||||||
|
RB_METHOD(audioReset)
|
||||||
|
{
|
||||||
|
RB_UNUSED_PARAM;
|
||||||
|
|
||||||
|
shState->audio().reset();
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define BIND_PLAY_STOP(entity) \
|
#define BIND_PLAY_STOP(entity) \
|
||||||
_rb_define_module_function(module, #entity "_play", audio_##entity##Play); \
|
_rb_define_module_function(module, #entity "_play", audio_##entity##Play); \
|
||||||
|
@ -129,4 +138,6 @@ audioBindingInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
BIND_PLAY_STOP( se )
|
BIND_PLAY_STOP( se )
|
||||||
|
|
||||||
|
_rb_define_module_function(module, "__reset__", audioReset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "debugwriter.h"
|
#include "debugwriter.h"
|
||||||
#include "graphics.h"
|
#include "graphics.h"
|
||||||
|
#include "audio.h"
|
||||||
#include "boost-hash.h"
|
#include "boost-hash.h"
|
||||||
|
|
||||||
#include <ruby.h>
|
#include <ruby.h>
|
||||||
|
@ -44,11 +45,13 @@ extern const char module_rpg3[];
|
||||||
|
|
||||||
static void mriBindingExecute();
|
static void mriBindingExecute();
|
||||||
static void mriBindingTerminate();
|
static void mriBindingTerminate();
|
||||||
|
static void mriBindingReset();
|
||||||
|
|
||||||
ScriptBinding scriptBindingImpl =
|
ScriptBinding scriptBindingImpl =
|
||||||
{
|
{
|
||||||
mriBindingExecute,
|
mriBindingExecute,
|
||||||
mriBindingTerminate
|
mriBindingTerminate,
|
||||||
|
mriBindingReset
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptBinding *scriptBinding = &scriptBindingImpl;
|
ScriptBinding *scriptBinding = &scriptBindingImpl;
|
||||||
|
@ -213,12 +216,51 @@ RB_METHOD(mriDataDirectory)
|
||||||
return pathStr;
|
return pathStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE rgssMainCb(VALUE block)
|
||||||
|
{
|
||||||
|
rb_funcall2(block, rb_intern("call"), 0, 0);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE rgssMainRescue(VALUE arg, VALUE exc)
|
||||||
|
{
|
||||||
|
VALUE *excRet = (VALUE*) arg;
|
||||||
|
|
||||||
|
*excRet = exc;
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void processReset()
|
||||||
|
{
|
||||||
|
shState->graphics().reset();
|
||||||
|
shState->audio().reset();
|
||||||
|
|
||||||
|
shState->rtData().rqReset.clear();
|
||||||
|
shState->graphics().repaintWait(shState->rtData().rqResetFinish,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
RB_METHOD(mriRgssMain)
|
RB_METHOD(mriRgssMain)
|
||||||
{
|
{
|
||||||
RB_UNUSED_PARAM;
|
RB_UNUSED_PARAM;
|
||||||
|
|
||||||
// TODO: Implement F12 reset
|
while (true)
|
||||||
rb_yield(Qnil);
|
{
|
||||||
|
VALUE exc = Qnil;
|
||||||
|
|
||||||
|
rb_rescue2((VALUE(*)(ANYARGS)) rgssMainCb, rb_block_proc(),
|
||||||
|
(VALUE(*)(ANYARGS)) rgssMainRescue, (VALUE) &exc,
|
||||||
|
rb_eException, (VALUE) 0);
|
||||||
|
|
||||||
|
if (NIL_P(exc))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (rb_obj_class(exc) == getRbData()->exc[Reset])
|
||||||
|
processReset();
|
||||||
|
else
|
||||||
|
rb_exc_raise(exc);
|
||||||
|
}
|
||||||
|
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
@ -395,30 +437,39 @@ static void runRMXPScripts(BacktraceData &btData)
|
||||||
for (size_t i = 0; i < conf.preloadScripts.size(); ++i)
|
for (size_t i = 0; i < conf.preloadScripts.size(); ++i)
|
||||||
runCustomScript(conf.preloadScripts[i]);
|
runCustomScript(conf.preloadScripts[i]);
|
||||||
|
|
||||||
for (long i = 0; i < scriptCount; ++i)
|
while (true)
|
||||||
{
|
{
|
||||||
VALUE script = rb_ary_entry(scriptArray, i);
|
for (long i = 0; i < scriptCount; ++i)
|
||||||
VALUE scriptDecoded = rb_ary_entry(script, 3);
|
{
|
||||||
VALUE string = newStringUTF8(RSTRING_PTR(scriptDecoded),
|
VALUE script = rb_ary_entry(scriptArray, i);
|
||||||
RSTRING_LEN(scriptDecoded));
|
VALUE scriptDecoded = rb_ary_entry(script, 3);
|
||||||
|
VALUE string = newStringUTF8(RSTRING_PTR(scriptDecoded),
|
||||||
|
RSTRING_LEN(scriptDecoded));
|
||||||
|
|
||||||
VALUE fname;
|
VALUE fname;
|
||||||
const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1));
|
const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1));
|
||||||
char buf[512];
|
char buf[512];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (conf.useScriptNames)
|
if (conf.useScriptNames)
|
||||||
len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName);
|
len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName);
|
||||||
else
|
else
|
||||||
len = snprintf(buf, sizeof(buf), SCRIPT_SECTION_FMT, i);
|
len = snprintf(buf, sizeof(buf), SCRIPT_SECTION_FMT, i);
|
||||||
|
|
||||||
fname = newStringUTF8(buf, len);
|
fname = newStringUTF8(buf, len);
|
||||||
btData.scriptNames.insert(buf, scriptName);
|
btData.scriptNames.insert(buf, scriptName);
|
||||||
|
|
||||||
int state;
|
int state;
|
||||||
evalString(string, fname, &state);
|
evalString(string, fname, &state);
|
||||||
if (state)
|
if (state)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE exc = rb_gv_get("$!");
|
||||||
|
if (rb_obj_class(exc) != getRbData()->exc[Reset])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
processReset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,10 +571,15 @@ static void mriBindingExecute()
|
||||||
|
|
||||||
ruby_cleanup(0);
|
ruby_cleanup(0);
|
||||||
|
|
||||||
shState->rtData().rqTermAck = true;
|
shState->rtData().rqTermAck.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mriBindingTerminate()
|
static void mriBindingTerminate()
|
||||||
{
|
{
|
||||||
rb_raise(rb_eSystemExit, " ");
|
rb_raise(rb_eSystemExit, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mriBindingReset()
|
||||||
|
{
|
||||||
|
rb_raise(getRbData()->exc[Reset], " ");
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ RbData::RbData()
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(customExc); ++i)
|
for (size_t i = 0; i < ARRAY_SIZE(customExc); ++i)
|
||||||
exc[customExc[i].id] = rb_define_class(customExc[i].name, rb_eException);
|
exc[customExc[i].id] = rb_define_class(customExc[i].name, rb_eException);
|
||||||
|
|
||||||
|
exc[Reset] = rb_define_class(rgssVer >= 3 ? "RGSSReset" : "Reset", rb_eException);
|
||||||
|
|
||||||
exc[ErrnoENOENT] = rb_const_get(rb_const_get(rb_cObject, rb_intern("Errno")), rb_intern("ENOENT"));
|
exc[ErrnoENOENT] = rb_const_get(rb_const_get(rb_cObject, rb_intern("Errno")), rb_intern("ENOENT"));
|
||||||
exc[IOError] = rb_eIOError;
|
exc[IOError] = rb_eIOError;
|
||||||
exc[TypeError] = rb_eTypeError;
|
exc[TypeError] = rb_eTypeError;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
enum RbException
|
enum RbException
|
||||||
{
|
{
|
||||||
RGSS = 0,
|
RGSS = 0,
|
||||||
|
Reset,
|
||||||
PHYSFS,
|
PHYSFS,
|
||||||
SDL,
|
SDL,
|
||||||
MKXP,
|
MKXP,
|
||||||
|
|
|
@ -174,6 +174,15 @@ RB_METHOD(graphicsResizeScreen)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RB_METHOD(graphicsReset)
|
||||||
|
{
|
||||||
|
RB_UNUSED_PARAM;
|
||||||
|
|
||||||
|
shState->graphics().reset();
|
||||||
|
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
DEF_GRA_PROP_I(FrameRate)
|
DEF_GRA_PROP_I(FrameRate)
|
||||||
DEF_GRA_PROP_I(FrameCount)
|
DEF_GRA_PROP_I(FrameCount)
|
||||||
DEF_GRA_PROP_I(Brightness)
|
DEF_GRA_PROP_I(Brightness)
|
||||||
|
@ -196,6 +205,8 @@ void graphicsBindingInit()
|
||||||
_rb_define_module_function(module, "transition", graphicsTransition);
|
_rb_define_module_function(module, "transition", graphicsTransition);
|
||||||
_rb_define_module_function(module, "frame_reset", graphicsFrameReset);
|
_rb_define_module_function(module, "frame_reset", graphicsFrameReset);
|
||||||
|
|
||||||
|
_rb_define_module_function(module, "__reset__", graphicsReset);
|
||||||
|
|
||||||
INIT_GRA_PROP_BIND( FrameRate, "frame_rate" );
|
INIT_GRA_PROP_BIND( FrameRate, "frame_rate" );
|
||||||
INIT_GRA_PROP_BIND( FrameCount, "frame_count" );
|
INIT_GRA_PROP_BIND( FrameCount, "frame_count" );
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,13 @@
|
||||||
|
|
||||||
static void mrbBindingExecute();
|
static void mrbBindingExecute();
|
||||||
static void mrbBindingTerminate();
|
static void mrbBindingTerminate();
|
||||||
|
static void mrbBindingReset();
|
||||||
|
|
||||||
ScriptBinding scriptBindingImpl =
|
ScriptBinding scriptBindingImpl =
|
||||||
{
|
{
|
||||||
mrbBindingExecute,
|
mrbBindingExecute,
|
||||||
mrbBindingTerminate
|
mrbBindingTerminate,
|
||||||
|
mrbBindingReset
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptBinding *scriptBinding = &scriptBindingImpl;
|
ScriptBinding *scriptBinding = &scriptBindingImpl;
|
||||||
|
@ -384,7 +386,7 @@ static void mrbBindingExecute()
|
||||||
|
|
||||||
checkException(mrb);
|
checkException(mrb);
|
||||||
|
|
||||||
shState->rtData().rqTermAck = true;
|
shState->rtData().rqTermAck.set();
|
||||||
shState->texPool().disable();
|
shState->texPool().disable();
|
||||||
|
|
||||||
mrbc_context_free(mrb, ctx);
|
mrbc_context_free(mrb, ctx);
|
||||||
|
@ -398,3 +400,8 @@ static void mrbBindingTerminate()
|
||||||
|
|
||||||
mrb_raise(mrb, data->exc[Shutdown], "");
|
mrb_raise(mrb, data->exc[Shutdown], "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mrbBindingReset()
|
||||||
|
{
|
||||||
|
// No idea how to do this with mruby yet
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
static void nullBindingExecute()
|
static void nullBindingExecute()
|
||||||
{
|
{
|
||||||
Debug() << "The null binding doesn't do anything, so we're done!";
|
Debug() << "The null binding doesn't do anything, so we're done!";
|
||||||
shState->rtData().rqTermAck = true;
|
shState->rtData().rqTermAck.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nullBindingTerminate()
|
static void nullBindingTerminate()
|
||||||
|
@ -35,10 +35,16 @@ static void nullBindingTerminate()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nullBindingReset()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ScriptBinding scriptBindingImpl =
|
ScriptBinding scriptBindingImpl =
|
||||||
{
|
{
|
||||||
nullBindingExecute,
|
nullBindingExecute,
|
||||||
nullBindingTerminate
|
nullBindingTerminate,
|
||||||
|
nullBindingReset
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptBinding *scriptBinding = &scriptBindingImpl;
|
ScriptBinding *scriptBinding = &scriptBindingImpl;
|
||||||
|
|
|
@ -99,6 +99,12 @@
|
||||||
# anyAltToggleFS=false
|
# anyAltToggleFS=false
|
||||||
|
|
||||||
|
|
||||||
|
# Enable F12 game reset
|
||||||
|
# (default: enabled)
|
||||||
|
#
|
||||||
|
# enableReset=true
|
||||||
|
|
||||||
|
|
||||||
# Allow symlinks for game assets to be followed
|
# Allow symlinks for game assets to be followed
|
||||||
# (default: disabled)
|
# (default: disabled)
|
||||||
#
|
#
|
||||||
|
|
|
@ -327,4 +327,12 @@ float Audio::bgsPos()
|
||||||
return p->bgs.playingOffset();
|
return p->bgs.playingOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Audio::reset()
|
||||||
|
{
|
||||||
|
p->bgm.stop();
|
||||||
|
p->bgs.stop();
|
||||||
|
p->me.stop();
|
||||||
|
p->se.stop();
|
||||||
|
}
|
||||||
|
|
||||||
Audio::~Audio() { delete p; }
|
Audio::~Audio() { delete p; }
|
||||||
|
|
|
@ -67,6 +67,8 @@ public:
|
||||||
float bgmPos();
|
float bgmPos();
|
||||||
float bgsPos();
|
float bgsPos();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Audio(const Config &conf);
|
Audio(const Config &conf);
|
||||||
~Audio();
|
~Audio();
|
||||||
|
|
|
@ -35,6 +35,10 @@ struct ScriptBinding
|
||||||
* function will perform a longjmp instead of returning,
|
* function will perform a longjmp instead of returning,
|
||||||
* so be careful about any variables with local storage */
|
* so be careful about any variables with local storage */
|
||||||
void (*terminate) (void);
|
void (*terminate) (void);
|
||||||
|
|
||||||
|
/* Instructs the binding to issue a game reset.
|
||||||
|
* Same conditions as for terminate apply */
|
||||||
|
void (*reset) (void);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* VTable defined in the binding source */
|
/* VTable defined in the binding source */
|
||||||
|
|
|
@ -138,6 +138,7 @@ Config::Config()
|
||||||
solidFonts(false),
|
solidFonts(false),
|
||||||
gameFolder("."),
|
gameFolder("."),
|
||||||
anyAltToggleFS(false),
|
anyAltToggleFS(false),
|
||||||
|
enableReset(true),
|
||||||
allowSymlinks(false),
|
allowSymlinks(false),
|
||||||
pathCache(true),
|
pathCache(true),
|
||||||
useScriptNames(false)
|
useScriptNames(false)
|
||||||
|
@ -164,6 +165,7 @@ void Config::read(int argc, char *argv[])
|
||||||
PO_DESC(solidFonts, bool) \
|
PO_DESC(solidFonts, bool) \
|
||||||
PO_DESC(gameFolder, std::string) \
|
PO_DESC(gameFolder, std::string) \
|
||||||
PO_DESC(anyAltToggleFS, bool) \
|
PO_DESC(anyAltToggleFS, bool) \
|
||||||
|
PO_DESC(enableReset, bool) \
|
||||||
PO_DESC(allowSymlinks, bool) \
|
PO_DESC(allowSymlinks, bool) \
|
||||||
PO_DESC(iconPath, std::string) \
|
PO_DESC(iconPath, std::string) \
|
||||||
PO_DESC(titleLanguage, std::string) \
|
PO_DESC(titleLanguage, std::string) \
|
||||||
|
|
|
@ -47,6 +47,7 @@ struct Config
|
||||||
|
|
||||||
std::string gameFolder;
|
std::string gameFolder;
|
||||||
bool anyAltToggleFS;
|
bool anyAltToggleFS;
|
||||||
|
bool enableReset;
|
||||||
bool allowSymlinks;
|
bool allowSymlinks;
|
||||||
bool pathCache;
|
bool pathCache;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,10 @@
|
||||||
#ifndef DISPOSABLE_H
|
#ifndef DISPOSABLE_H
|
||||||
#define DISPOSABLE_H
|
#define DISPOSABLE_H
|
||||||
|
|
||||||
|
#include "intrulist.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
#include "sharedstate.h"
|
||||||
|
#include "graphics.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sigc++/signal.h>
|
#include <sigc++/signal.h>
|
||||||
|
@ -32,12 +35,15 @@ class Disposable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Disposable()
|
Disposable()
|
||||||
: disposed(false)
|
: disposed(false),
|
||||||
{}
|
link(this)
|
||||||
|
{
|
||||||
|
shState->graphics().addDisposable(this);
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~Disposable()
|
virtual ~Disposable()
|
||||||
{
|
{
|
||||||
assert(disposed);
|
shState->graphics().remDisposable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose()
|
void dispose()
|
||||||
|
@ -69,7 +75,10 @@ private:
|
||||||
virtual void releaseResources() = 0;
|
virtual void releaseResources() = 0;
|
||||||
virtual const char *klassName() const = 0;
|
virtual const char *klassName() const = 0;
|
||||||
|
|
||||||
|
friend class Graphics;
|
||||||
|
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
IntruListLink<Disposable> link;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class C>
|
template<class C>
|
||||||
|
|
|
@ -106,6 +106,8 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
char pendingTitle[128];
|
char pendingTitle[128];
|
||||||
bool havePendingTitle = false;
|
bool havePendingTitle = false;
|
||||||
|
|
||||||
|
bool resetting = false;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!SDL_WaitEvent(&event))
|
if (!SDL_WaitEvent(&event))
|
||||||
|
@ -206,10 +208,34 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_F12)
|
||||||
|
{
|
||||||
|
if (!rtData.config.enableReset)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (resetting)
|
||||||
|
break;
|
||||||
|
|
||||||
|
resetting = true;
|
||||||
|
rtData.rqResetFinish.clear();
|
||||||
|
rtData.rqReset.set();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
keyStates[event.key.keysym.scancode] = true;
|
keyStates[event.key.keysym.scancode] = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_KEYUP :
|
case SDL_KEYUP :
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_F12)
|
||||||
|
{
|
||||||
|
if (!rtData.config.enableReset)
|
||||||
|
break;
|
||||||
|
|
||||||
|
resetting = false;
|
||||||
|
rtData.rqResetFinish.set();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
keyStates[event.key.keysym.scancode] = false;
|
keyStates[event.key.keysym.scancode] = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -271,7 +297,7 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
rtData.config.game.title.c_str(),
|
rtData.config.game.title.c_str(),
|
||||||
(const char*) event.user.data1, win);
|
(const char*) event.user.data1, win);
|
||||||
free(event.user.data1);
|
free(event.user.data1);
|
||||||
msgBoxDone = true;
|
msgBoxDone.set();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REQUEST_SETCURSORVISIBLE :
|
case REQUEST_SETCURSORVISIBLE :
|
||||||
|
@ -377,7 +403,7 @@ void EventThread::requestShowCursor(bool mode)
|
||||||
|
|
||||||
void EventThread::showMessageBox(const char *body, int flags)
|
void EventThread::showMessageBox(const char *body, int flags)
|
||||||
{
|
{
|
||||||
msgBoxDone = false;
|
msgBoxDone.clear();
|
||||||
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
event.user.code = flags;
|
event.user.code = flags;
|
||||||
|
@ -386,7 +412,7 @@ void EventThread::showMessageBox(const char *body, int flags)
|
||||||
SDL_PushEvent(&event);
|
SDL_PushEvent(&event);
|
||||||
|
|
||||||
/* Keep repainting screen while box is open */
|
/* Keep repainting screen while box is open */
|
||||||
shState->graphics().repaintWait(&msgBoxDone);
|
shState->graphics().repaintWait(msgBoxDone);
|
||||||
/* Prevent endless loops */
|
/* Prevent endless loops */
|
||||||
resetInputStates();
|
resetInputStates();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <SDL_joystick.h>
|
#include <SDL_joystick.h>
|
||||||
#include <SDL_mouse.h>
|
#include <SDL_mouse.h>
|
||||||
#include <SDL_mutex.h>
|
#include <SDL_mutex.h>
|
||||||
|
#include <SDL_atomic.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -38,6 +39,32 @@ struct RGSSThreadData;
|
||||||
struct SDL_Thread;
|
struct SDL_Thread;
|
||||||
struct SDL_Window;
|
struct SDL_Window;
|
||||||
|
|
||||||
|
struct AtomicFlag
|
||||||
|
{
|
||||||
|
AtomicFlag()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set()
|
||||||
|
{
|
||||||
|
SDL_AtomicSet(&atom, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
SDL_AtomicSet(&atom, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return SDL_AtomicGet(&atom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable SDL_atomic_t atom;
|
||||||
|
};
|
||||||
|
|
||||||
class EventThread
|
class EventThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -91,7 +118,7 @@ private:
|
||||||
|
|
||||||
bool fullscreen;
|
bool fullscreen;
|
||||||
bool showCursor;
|
bool showCursor;
|
||||||
volatile bool msgBoxDone;
|
AtomicFlag msgBoxDone;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -111,13 +138,12 @@ struct WindowSizeNotify
|
||||||
{
|
{
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
|
|
||||||
volatile bool changedFlag;
|
AtomicFlag changed;
|
||||||
volatile int w, h;
|
int w, h;
|
||||||
|
|
||||||
WindowSizeNotify()
|
WindowSizeNotify()
|
||||||
{
|
{
|
||||||
mutex = SDL_CreateMutex();
|
mutex = SDL_CreateMutex();
|
||||||
changedFlag = false;
|
|
||||||
w = h = 0;
|
w = h = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +159,7 @@ struct WindowSizeNotify
|
||||||
|
|
||||||
this->w = w;
|
this->w = w;
|
||||||
this->h = h;
|
this->h = h;
|
||||||
changedFlag = true;
|
changed.set();
|
||||||
|
|
||||||
SDL_UnlockMutex(mutex);
|
SDL_UnlockMutex(mutex);
|
||||||
}
|
}
|
||||||
|
@ -141,14 +167,14 @@ struct WindowSizeNotify
|
||||||
/* Done from the receiving side */
|
/* Done from the receiving side */
|
||||||
bool pollChange(int *w, int *h)
|
bool pollChange(int *w, int *h)
|
||||||
{
|
{
|
||||||
if (!changedFlag)
|
if (!changed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SDL_LockMutex(mutex);
|
SDL_LockMutex(mutex);
|
||||||
|
|
||||||
*w = this->w;
|
*w = this->w;
|
||||||
*h = this->h;
|
*h = this->h;
|
||||||
changedFlag = false;
|
changed.clear();
|
||||||
|
|
||||||
SDL_UnlockMutex(mutex);
|
SDL_UnlockMutex(mutex);
|
||||||
|
|
||||||
|
@ -159,10 +185,16 @@ struct WindowSizeNotify
|
||||||
struct RGSSThreadData
|
struct RGSSThreadData
|
||||||
{
|
{
|
||||||
/* Main thread sets this to request RGSS thread to terminate */
|
/* Main thread sets this to request RGSS thread to terminate */
|
||||||
volatile bool rqTerm;
|
AtomicFlag rqTerm;
|
||||||
/* In response, RGSS thread sets this to confirm
|
/* In response, RGSS thread sets this to confirm
|
||||||
* that it received the request and isn't stuck */
|
* that it received the request and isn't stuck */
|
||||||
volatile bool rqTermAck;
|
AtomicFlag rqTermAck;
|
||||||
|
|
||||||
|
/* Set when F12 is pressed */
|
||||||
|
AtomicFlag rqReset;
|
||||||
|
|
||||||
|
/* Set when F12 is released */
|
||||||
|
AtomicFlag rqResetFinish;
|
||||||
|
|
||||||
EventThread *ethread;
|
EventThread *ethread;
|
||||||
WindowSizeNotify windowSizeMsg;
|
WindowSizeNotify windowSizeMsg;
|
||||||
|
@ -182,9 +214,7 @@ struct RGSSThreadData
|
||||||
const char *argv0,
|
const char *argv0,
|
||||||
SDL_Window *window,
|
SDL_Window *window,
|
||||||
const Config& newconf)
|
const Config& newconf)
|
||||||
: rqTerm(false),
|
: ethread(ethread),
|
||||||
rqTermAck(false),
|
|
||||||
ethread(ethread),
|
|
||||||
argv0(argv0),
|
argv0(argv0),
|
||||||
window(window),
|
window(window),
|
||||||
sizeResoRatio(1, 1),
|
sizeResoRatio(1, 1),
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include "texpool.h"
|
#include "texpool.h"
|
||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "etc-internal.h"
|
#include "etc-internal.h"
|
||||||
|
#include "disposable.h"
|
||||||
|
#include "intrulist.h"
|
||||||
#include "binding.h"
|
#include "binding.h"
|
||||||
#include "debugwriter.h"
|
#include "debugwriter.h"
|
||||||
|
|
||||||
|
@ -109,6 +111,19 @@ struct PingPong
|
||||||
bind();
|
bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearBuffers()
|
||||||
|
{
|
||||||
|
glState.clearColor.pushSet(Vec4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
FBO::bind(rt[i].fbo);
|
||||||
|
FBO::clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
glState.clearColor.pop();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void bind()
|
void bind()
|
||||||
{
|
{
|
||||||
|
@ -388,6 +403,10 @@ struct GraphicsPrivate
|
||||||
Quad screenQuad;
|
Quad screenQuad;
|
||||||
TEXFBO transBuffer;
|
TEXFBO transBuffer;
|
||||||
|
|
||||||
|
/* Global list of all live Disposables
|
||||||
|
* (disposed on reset) */
|
||||||
|
IntruList<Disposable> dispList;
|
||||||
|
|
||||||
GraphicsPrivate(RGSSThreadData *rtData)
|
GraphicsPrivate(RGSSThreadData *rtData)
|
||||||
: scRes(DEF_SCREEN_W, DEF_SCREEN_H),
|
: scRes(DEF_SCREEN_W, DEF_SCREEN_H),
|
||||||
scSize(scRes),
|
scSize(scRes),
|
||||||
|
@ -472,9 +491,15 @@ struct GraphicsPrivate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkShutDownReset()
|
||||||
|
{
|
||||||
|
shState->checkShutdown();
|
||||||
|
shState->checkReset();
|
||||||
|
}
|
||||||
|
|
||||||
void shutdown()
|
void shutdown()
|
||||||
{
|
{
|
||||||
threadData->rqTermAck = true;
|
threadData->rqTermAck.set();
|
||||||
shState->texPool().disable();
|
shState->texPool().disable();
|
||||||
|
|
||||||
scriptBinding->terminate();
|
scriptBinding->terminate();
|
||||||
|
@ -540,7 +565,7 @@ Graphics::~Graphics()
|
||||||
|
|
||||||
void Graphics::update()
|
void Graphics::update()
|
||||||
{
|
{
|
||||||
shState->checkShutdown();
|
p->checkShutDownReset();
|
||||||
|
|
||||||
if (p->frozen)
|
if (p->frozen)
|
||||||
return;
|
return;
|
||||||
|
@ -571,7 +596,7 @@ void Graphics::freeze()
|
||||||
{
|
{
|
||||||
p->frozen = true;
|
p->frozen = true;
|
||||||
|
|
||||||
shState->checkShutdown();
|
p->checkShutDownReset();
|
||||||
p->checkResize();
|
p->checkResize();
|
||||||
|
|
||||||
/* Capture scene into frozen buffer */
|
/* Capture scene into frozen buffer */
|
||||||
|
@ -623,10 +648,23 @@ void Graphics::transition(int duration,
|
||||||
|
|
||||||
for (int i = 0; i < duration; ++i)
|
for (int i = 0; i < duration; ++i)
|
||||||
{
|
{
|
||||||
|
/* We need to clean up transMap properly before
|
||||||
|
* a possible longjmp, so we manually test for
|
||||||
|
* shutdown/reset here */
|
||||||
if (p->threadData->rqTerm)
|
if (p->threadData->rqTerm)
|
||||||
{
|
{
|
||||||
|
glState.blend.pop();
|
||||||
delete transMap;
|
delete transMap;
|
||||||
p->shutdown();
|
p->shutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->threadData->rqReset)
|
||||||
|
{
|
||||||
|
glState.blend.pop();
|
||||||
|
delete transMap;
|
||||||
|
scriptBinding->reset();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float prog = i * (1.0 / duration);
|
const float prog = i * (1.0 / duration);
|
||||||
|
@ -694,8 +732,7 @@ void Graphics::wait(int duration)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < duration; ++i)
|
for (int i = 0; i < duration; ++i)
|
||||||
{
|
{
|
||||||
shState->checkShutdown();
|
p->checkShutDownReset();
|
||||||
p->checkResize();
|
|
||||||
p->redrawScreen();
|
p->redrawScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -823,6 +860,29 @@ void Graphics::setBrightness(int value)
|
||||||
p->screen.setBrightness(value / 255.0);
|
p->screen.setBrightness(value / 255.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Graphics::reset()
|
||||||
|
{
|
||||||
|
/* Dispose all live Disposables */
|
||||||
|
IntruListLink<Disposable> *iter;
|
||||||
|
|
||||||
|
for (iter = p->dispList.begin();
|
||||||
|
iter != p->dispList.end();
|
||||||
|
iter = iter->next)
|
||||||
|
{
|
||||||
|
iter->data->dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
p->dispList.clear();
|
||||||
|
|
||||||
|
/* Reset attributes (frame count not included) */
|
||||||
|
p->fpsLimiter.resetFrameAdjust();
|
||||||
|
p->frozen = false;
|
||||||
|
p->screen.getPP().clearBuffers();
|
||||||
|
|
||||||
|
setFrameRate(DEF_FRAMERATE);
|
||||||
|
setBrightness(255);
|
||||||
|
}
|
||||||
|
|
||||||
bool Graphics::getFullscreen() const
|
bool Graphics::getFullscreen() const
|
||||||
{
|
{
|
||||||
return p->threadData->ethread->getFullscreen();
|
return p->threadData->ethread->getFullscreen();
|
||||||
|
@ -848,9 +908,9 @@ Scene *Graphics::getScreen() const
|
||||||
return &p->screen;
|
return &p->screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::repaintWait(volatile bool *exitCond)
|
void Graphics::repaintWait(const AtomicFlag &exitCond, bool checkReset)
|
||||||
{
|
{
|
||||||
if (*exitCond)
|
if (exitCond)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Repaint the screen with the last good frame we drew */
|
/* Repaint the screen with the last good frame we drew */
|
||||||
|
@ -858,10 +918,13 @@ void Graphics::repaintWait(volatile bool *exitCond)
|
||||||
GLMeta::blitBeginScreen(p->winSize);
|
GLMeta::blitBeginScreen(p->winSize);
|
||||||
GLMeta::blitSource(lastFrame);
|
GLMeta::blitSource(lastFrame);
|
||||||
|
|
||||||
while (!*exitCond)
|
while (!exitCond)
|
||||||
{
|
{
|
||||||
shState->checkShutdown();
|
shState->checkShutdown();
|
||||||
|
|
||||||
|
if (checkReset)
|
||||||
|
shState->checkReset();
|
||||||
|
|
||||||
FBO::clear();
|
FBO::clear();
|
||||||
p->metaBlitBufferFlippedScaled();
|
p->metaBlitBufferFlippedScaled();
|
||||||
SDL_GL_SwapWindow(p->threadData->window);
|
SDL_GL_SwapWindow(p->threadData->window);
|
||||||
|
@ -872,3 +935,13 @@ void Graphics::repaintWait(volatile bool *exitCond)
|
||||||
|
|
||||||
GLMeta::blitEnd();
|
GLMeta::blitEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Graphics::addDisposable(Disposable *d)
|
||||||
|
{
|
||||||
|
p->dispList.append(d->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::remDisposable(Disposable *d)
|
||||||
|
{
|
||||||
|
p->dispList.remove(d->link);
|
||||||
|
}
|
||||||
|
|
|
@ -26,8 +26,10 @@
|
||||||
|
|
||||||
class Scene;
|
class Scene;
|
||||||
class Bitmap;
|
class Bitmap;
|
||||||
|
class Disposable;
|
||||||
struct RGSSThreadData;
|
struct RGSSThreadData;
|
||||||
struct GraphicsPrivate;
|
struct GraphicsPrivate;
|
||||||
|
struct AtomicFlag;
|
||||||
|
|
||||||
class Graphics
|
class Graphics
|
||||||
{
|
{
|
||||||
|
@ -53,6 +55,8 @@ public:
|
||||||
int height() const;
|
int height() const;
|
||||||
void resizeScreen(int width, int height);
|
void resizeScreen(int width, int height);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
/* Non-standard extension */
|
/* Non-standard extension */
|
||||||
DECL_ATTR( Fullscreen, bool )
|
DECL_ATTR( Fullscreen, bool )
|
||||||
DECL_ATTR( ShowCursor, bool )
|
DECL_ATTR( ShowCursor, bool )
|
||||||
|
@ -60,14 +64,20 @@ public:
|
||||||
/* <internal> */
|
/* <internal> */
|
||||||
Scene *getScreen() const;
|
Scene *getScreen() const;
|
||||||
/* Repaint screen with static image until exitCond
|
/* Repaint screen with static image until exitCond
|
||||||
* turns true. Used in EThread::showMessageBox() */
|
* is set. Observes reset flag on top of shutdown
|
||||||
void repaintWait(volatile bool *exitCond);
|
* if "checkReset" */
|
||||||
|
void repaintWait(const AtomicFlag &exitCond,
|
||||||
|
bool checkReset = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Graphics(RGSSThreadData *data);
|
Graphics(RGSSThreadData *data);
|
||||||
~Graphics();
|
~Graphics();
|
||||||
|
|
||||||
|
void addDisposable(Disposable *);
|
||||||
|
void remDisposable(Disposable *);
|
||||||
|
|
||||||
friend struct SharedStatePrivate;
|
friend struct SharedStatePrivate;
|
||||||
|
friend class Disposable;
|
||||||
|
|
||||||
GraphicsPrivate *p;
|
GraphicsPrivate *p;
|
||||||
};
|
};
|
||||||
|
|
|
@ -105,6 +105,15 @@ public:
|
||||||
size--;
|
size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
remove(root);
|
||||||
|
root.prev = &root;
|
||||||
|
root.next = &root;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
T *tail() const
|
T *tail() const
|
||||||
{
|
{
|
||||||
IntruListLink<T> *node = root.prev;
|
IntruListLink<T> *node = root.prev;
|
||||||
|
|
|
@ -46,7 +46,7 @@ rgssThreadError(RGSSThreadData *rtData, const std::string &msg)
|
||||||
{
|
{
|
||||||
rtData->rgssErrorMsg = msg;
|
rtData->rgssErrorMsg = msg;
|
||||||
rtData->ethread->requestTerminate();
|
rtData->ethread->requestTerminate();
|
||||||
rtData->rqTermAck = true;
|
rtData->rqTermAck.set();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char*
|
static inline const char*
|
||||||
|
@ -147,7 +147,7 @@ int rgssThreadFun(void *userdata)
|
||||||
/* Start script execution */
|
/* Start script execution */
|
||||||
scriptBinding->execute();
|
scriptBinding->execute();
|
||||||
|
|
||||||
threadData->rqTermAck = true;
|
threadData->rqTermAck.set();
|
||||||
threadData->ethread->requestTerminate();
|
threadData->ethread->requestTerminate();
|
||||||
|
|
||||||
SharedState::finiInstance();
|
SharedState::finiInstance();
|
||||||
|
@ -276,7 +276,7 @@ int main(int argc, char *argv[])
|
||||||
eventThread.process(rtData);
|
eventThread.process(rtData);
|
||||||
|
|
||||||
/* Request RGSS thread to stop */
|
/* Request RGSS thread to stop */
|
||||||
rtData.rqTerm = true;
|
rtData.rqTerm.set();
|
||||||
|
|
||||||
/* Wait for RGSS thread response */
|
/* Wait for RGSS thread response */
|
||||||
for (int i = 0; i < 1000; ++i)
|
for (int i = 0; i < 1000; ++i)
|
||||||
|
|
|
@ -330,11 +330,20 @@ void SharedState::checkShutdown()
|
||||||
if (!p->rtData.rqTerm)
|
if (!p->rtData.rqTerm)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p->rtData.rqTermAck = true;
|
p->rtData.rqTermAck.set();
|
||||||
p->texPool.disable();
|
p->texPool.disable();
|
||||||
scriptBinding->terminate();
|
scriptBinding->terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SharedState::checkReset()
|
||||||
|
{
|
||||||
|
if (!p->rtData.rqReset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p->rtData.rqReset.clear();
|
||||||
|
scriptBinding->reset();
|
||||||
|
}
|
||||||
|
|
||||||
Font &SharedState::defaultFont() const
|
Font &SharedState::defaultFont() const
|
||||||
{
|
{
|
||||||
return *p->defaultFont;
|
return *p->defaultFont;
|
||||||
|
|
|
@ -109,6 +109,8 @@ struct SharedState
|
||||||
* function will most likely not return */
|
* function will most likely not return */
|
||||||
void checkShutdown();
|
void checkShutdown();
|
||||||
|
|
||||||
|
void checkReset();
|
||||||
|
|
||||||
static SharedState *instance;
|
static SharedState *instance;
|
||||||
static int rgssVersion;
|
static int rgssVersion;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue