Merge branch 'master' of /home/Ancurio/programming/C++/mkxp
This commit is contained in:
commit
d9f13c39e9
|
@ -20,6 +20,8 @@ Matz's Ruby Interpreter, also called CRuby, is the most widely deployed version
|
||||||
For a list of differences, see:
|
For a list of differences, see:
|
||||||
http://stackoverflow.com/questions/21574/what-is-the-difference-between-ruby-1-8-and-ruby-1-9
|
http://stackoverflow.com/questions/21574/what-is-the-difference-between-ruby-1-8-and-ruby-1-9
|
||||||
|
|
||||||
|
This binding supports RGSS1, RGSS2 and RGSS3.
|
||||||
|
|
||||||
### mruby (Lightweight Ruby)
|
### mruby (Lightweight Ruby)
|
||||||
Website: https://github.com/mruby/mruby
|
Website: https://github.com/mruby/mruby
|
||||||
|
|
||||||
|
@ -29,6 +31,8 @@ Due to heavy differences between mruby and MRI as well as lacking modules, runni
|
||||||
|
|
||||||
Some extensions to the standard classes/modules are provided, taking the RPG Maker XP helpfile as a quasi "reference". These include Marshal, File, FileTest and Time.
|
Some extensions to the standard classes/modules are provided, taking the RPG Maker XP helpfile as a quasi "reference". These include Marshal, File, FileTest and Time.
|
||||||
|
|
||||||
|
This binding only supports RGSS1.
|
||||||
|
|
||||||
**Important:** If you decide to use [mattn's oniguruma regexp gem](https://github.com/mattn/mruby-onig-regexp), don't forget to add `-lonig` to the linker flags to avoid ugly symbol overlaps with libc.
|
**Important:** If you decide to use [mattn's oniguruma regexp gem](https://github.com/mattn/mruby-onig-regexp), don't forget to add `-lonig` to the linker flags to avoid ugly symbol overlaps with libc.
|
||||||
|
|
||||||
### null
|
### null
|
||||||
|
|
|
@ -46,7 +46,7 @@ fileIntForPath(const char *path, bool rubyExc)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
shState->fileSystem().openRead(*ops, path);
|
shState->fileSystem().openReadRaw(*ops, path);
|
||||||
}
|
}
|
||||||
catch (const Exception &e)
|
catch (const Exception &e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,29 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
collectStrings(VALUE obj, std::vector<std::string> &out)
|
||||||
|
{
|
||||||
|
if (RB_TYPE_P(obj, RUBY_T_STRING))
|
||||||
|
{
|
||||||
|
out.push_back(RSTRING_PTR(obj));
|
||||||
|
}
|
||||||
|
else if (RB_TYPE_P(obj, RUBY_T_ARRAY))
|
||||||
|
{
|
||||||
|
for (long i = 0; i < RARRAY_LEN(obj); ++i)
|
||||||
|
{
|
||||||
|
VALUE str = rb_ary_entry(obj, i);
|
||||||
|
|
||||||
|
/* Non-string objects are tolerated (ignored) */
|
||||||
|
if (!RB_TYPE_P(str, RUBY_T_STRING))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out.push_back(RSTRING_PTR(str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEF_TYPE(Font);
|
DEF_TYPE(Font);
|
||||||
|
|
||||||
RB_METHOD(fontDoesExist)
|
RB_METHOD(fontDoesExist)
|
||||||
|
@ -48,12 +71,30 @@ RB_METHOD(FontSetName);
|
||||||
|
|
||||||
RB_METHOD(fontInitialize)
|
RB_METHOD(fontInitialize)
|
||||||
{
|
{
|
||||||
VALUE name = Qnil;
|
VALUE namesObj = Qnil;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
|
||||||
rb_get_args(argc, argv, "|oi", &name, &size RB_ARG_END);
|
rb_get_args(argc, argv, "|oi", &namesObj, &size RB_ARG_END);
|
||||||
|
|
||||||
Font *f = new Font(0, size);
|
Font *f;
|
||||||
|
|
||||||
|
if (NIL_P(namesObj))
|
||||||
|
{
|
||||||
|
namesObj = rb_iv_get(rb_obj_class(self), "default_name");
|
||||||
|
f = new Font(0, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<std::string> names;
|
||||||
|
collectStrings(namesObj, names);
|
||||||
|
|
||||||
|
f = new Font(&names, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is semantically wrong; the new Font object should take
|
||||||
|
* a dup'ed object here in case of an array. Ditto for the setters.
|
||||||
|
* However the same bug/behavior exists in all RM versions. */
|
||||||
|
rb_iv_set(self, "name", namesObj);
|
||||||
|
|
||||||
setPrivateData(self, f);
|
setPrivateData(self, f);
|
||||||
|
|
||||||
|
@ -65,13 +106,6 @@ RB_METHOD(fontInitialize)
|
||||||
if (rgssVer >= 3)
|
if (rgssVer >= 3)
|
||||||
wrapProperty(self, &f->getOutColor(), "out_color", ColorType);
|
wrapProperty(self, &f->getOutColor(), "out_color", ColorType);
|
||||||
|
|
||||||
if (NIL_P(name))
|
|
||||||
name = rb_iv_get(rb_obj_class(self), "default_name");
|
|
||||||
|
|
||||||
/* Going over the 'name=' function automatically causes
|
|
||||||
* a possbile name array to be re-verified for existing fonts */
|
|
||||||
FontSetName(1, &name, self);
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,57 +139,17 @@ RB_METHOD(FontGetName)
|
||||||
return rb_iv_get(self, "name");
|
return rb_iv_get(self, "name");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
fontSetNameHelper(VALUE self, int argc, VALUE *argv,
|
|
||||||
const char *nameIv, char *outBuf, size_t outLen)
|
|
||||||
{
|
|
||||||
rb_check_argc(argc, 1);
|
|
||||||
|
|
||||||
VALUE arg = argv[0];
|
|
||||||
|
|
||||||
// Fixme: in RGSS3, specifying "" (and only that) as font name results in
|
|
||||||
// no text being drawn (everything else is substituted with Arial I think)
|
|
||||||
strncpy(outBuf, "", outLen);
|
|
||||||
|
|
||||||
if (RB_TYPE_P(arg, RUBY_T_STRING))
|
|
||||||
{
|
|
||||||
strncpy(outBuf, RSTRING_PTR(arg), outLen);
|
|
||||||
}
|
|
||||||
else if (RB_TYPE_P(arg, RUBY_T_ARRAY))
|
|
||||||
{
|
|
||||||
for (long i = 0; i < RARRAY_LEN(arg); ++i)
|
|
||||||
{
|
|
||||||
VALUE str = rb_ary_entry(arg, i);
|
|
||||||
|
|
||||||
/* Non-string objects are tolerated (ignored) */
|
|
||||||
if (!RB_TYPE_P(str, RUBY_T_STRING))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const char *family = RSTRING_PTR(str);
|
|
||||||
|
|
||||||
/* We only set the core Font object's name attribute
|
|
||||||
* to the actually existing font name */
|
|
||||||
if (!shState->fontState().fontPresent(family))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
strncpy(outBuf, family, outLen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RMXP doesn't even care if the argument type is
|
|
||||||
* something other than string/array. Whatever... */
|
|
||||||
rb_iv_set(self, nameIv, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
RB_METHOD(FontSetName)
|
RB_METHOD(FontSetName)
|
||||||
{
|
{
|
||||||
Font *f = getPrivateData<Font>(self);
|
Font *f = getPrivateData<Font>(self);
|
||||||
|
|
||||||
char result[256];
|
rb_check_argc(argc, 1);
|
||||||
fontSetNameHelper(self, argc, argv, "name",
|
|
||||||
result, sizeof(result));
|
|
||||||
|
|
||||||
f->setName(result);
|
std::vector<std::string> namesObj;
|
||||||
|
collectStrings(argv[0], namesObj);
|
||||||
|
|
||||||
|
f->setName(namesObj);
|
||||||
|
rb_iv_set(self, "name", argv[0]);
|
||||||
|
|
||||||
return argv[0];
|
return argv[0];
|
||||||
}
|
}
|
||||||
|
@ -223,11 +217,15 @@ RB_METHOD(FontGetDefaultName)
|
||||||
|
|
||||||
RB_METHOD(FontSetDefaultName)
|
RB_METHOD(FontSetDefaultName)
|
||||||
{
|
{
|
||||||
char result[256];
|
RB_UNUSED_PARAM;
|
||||||
fontSetNameHelper(self, argc, argv, "default_name",
|
|
||||||
result, sizeof(result));
|
|
||||||
|
|
||||||
Font::setDefaultName(result);
|
rb_check_argc(argc, 1);
|
||||||
|
|
||||||
|
std::vector<std::string> namesObj;
|
||||||
|
collectStrings(argv[0], namesObj);
|
||||||
|
|
||||||
|
Font::setDefaultName(namesObj, shState->fontState());
|
||||||
|
rb_iv_set(self, "default_name", argv[0]);
|
||||||
|
|
||||||
return argv[0];
|
return argv[0];
|
||||||
}
|
}
|
||||||
|
@ -267,7 +265,24 @@ fontBindingInit()
|
||||||
|
|
||||||
Font::initDefaultDynAttribs();
|
Font::initDefaultDynAttribs();
|
||||||
wrapProperty(klass, &Font::getDefaultColor(), "default_color", ColorType);
|
wrapProperty(klass, &Font::getDefaultColor(), "default_color", ColorType);
|
||||||
rb_iv_set(klass, "default_name", rb_str_new_cstr(Font::getDefaultName()));
|
|
||||||
|
/* Initialize default names */
|
||||||
|
const std::vector<std::string> &defNames = Font::getInitialDefaultNames();
|
||||||
|
VALUE defNamesObj;
|
||||||
|
|
||||||
|
if (defNames.size() == 1)
|
||||||
|
{
|
||||||
|
defNamesObj = rb_str_new_cstr(defNames[0].c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defNamesObj = rb_ary_new2(defNames.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < defNames.size(); ++i)
|
||||||
|
rb_ary_push(defNamesObj, rb_str_new_cstr(defNames[i].c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_iv_set(klass, "default_name", defNamesObj);
|
||||||
|
|
||||||
if (rgssVer >= 3)
|
if (rgssVer >= 3)
|
||||||
wrapProperty(klass, &Font::getDefaultOutColor(), "default_out_color", ColorType);
|
wrapProperty(klass, &Font::getDefaultOutColor(), "default_out_color", ColorType);
|
||||||
|
@ -310,14 +325,4 @@ fontBindingInit()
|
||||||
INIT_PROP_BIND(Font, Outline, "outline");
|
INIT_PROP_BIND(Font, Outline, "outline");
|
||||||
INIT_PROP_BIND(Font, OutColor, "out_color");
|
INIT_PROP_BIND(Font, OutColor, "out_color");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rgssVer >= 2)
|
|
||||||
{
|
|
||||||
VALUE defNames = rb_ary_new2(3);
|
|
||||||
rb_ary_push(defNames, rb_str_new2("Verdana"));
|
|
||||||
rb_ary_push(defNames, rb_str_new2("Arial"));
|
|
||||||
rb_ary_push(defNames, rb_str_new2("Courier New"));
|
|
||||||
|
|
||||||
FontSetDefaultName(1, &defNames, klass);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,18 @@ RB_METHOD(graphicsReset)
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RB_METHOD(graphicsPlayMovie)
|
||||||
|
{
|
||||||
|
RB_UNUSED_PARAM;
|
||||||
|
|
||||||
|
const char *filename;
|
||||||
|
rb_get_args(argc, argv, "z", &filename RB_ARG_END);
|
||||||
|
|
||||||
|
shState->graphics().playMovie(filename);
|
||||||
|
|
||||||
|
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)
|
||||||
|
@ -223,6 +235,11 @@ void graphicsBindingInit()
|
||||||
INIT_GRA_PROP_BIND( Brightness, "brightness" );
|
INIT_GRA_PROP_BIND( Brightness, "brightness" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rgssVer >= 3)
|
||||||
|
{
|
||||||
|
_rb_define_module_function(module, "play_movie", graphicsPlayMovie);
|
||||||
|
}
|
||||||
|
|
||||||
INIT_GRA_PROP_BIND( Fullscreen, "fullscreen" );
|
INIT_GRA_PROP_BIND( Fullscreen, "fullscreen" );
|
||||||
INIT_GRA_PROP_BIND( ShowCursor, "show_cursor" );
|
INIT_GRA_PROP_BIND( ShowCursor, "show_cursor" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ DEF_PROP_I(Sprite, Y)
|
||||||
DEF_PROP_I(Sprite, OX)
|
DEF_PROP_I(Sprite, OX)
|
||||||
DEF_PROP_I(Sprite, OY)
|
DEF_PROP_I(Sprite, OY)
|
||||||
DEF_PROP_I(Sprite, BushDepth)
|
DEF_PROP_I(Sprite, BushDepth)
|
||||||
|
DEF_PROP_I(Sprite, BushOpacity)
|
||||||
DEF_PROP_I(Sprite, Opacity)
|
DEF_PROP_I(Sprite, Opacity)
|
||||||
DEF_PROP_I(Sprite, BlendType)
|
DEF_PROP_I(Sprite, BlendType)
|
||||||
DEF_PROP_I(Sprite, WaveAmp)
|
DEF_PROP_I(Sprite, WaveAmp)
|
||||||
|
@ -126,6 +127,8 @@ spriteBindingInit()
|
||||||
_rb_define_method(klass, "width", spriteWidth);
|
_rb_define_method(klass, "width", spriteWidth);
|
||||||
_rb_define_method(klass, "height", spriteHeight);
|
_rb_define_method(klass, "height", spriteHeight);
|
||||||
|
|
||||||
|
INIT_PROP_BIND( Sprite, BushOpacity, "bush_opacity" );
|
||||||
|
|
||||||
INIT_PROP_BIND( Sprite, WaveAmp, "wave_amp" );
|
INIT_PROP_BIND( Sprite, WaveAmp, "wave_amp" );
|
||||||
INIT_PROP_BIND( Sprite, WaveLength, "wave_length" );
|
INIT_PROP_BIND( Sprite, WaveLength, "wave_length" );
|
||||||
INIT_PROP_BIND( Sprite, WaveSpeed, "wave_speed" );
|
INIT_PROP_BIND( Sprite, WaveSpeed, "wave_speed" );
|
||||||
|
|
|
@ -266,7 +266,7 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
|
||||||
mrb_state *scriptMrb = mrb_open();
|
mrb_state *scriptMrb = mrb_open();
|
||||||
SDL_RWops ops;
|
SDL_RWops ops;
|
||||||
|
|
||||||
shState->fileSystem().openRead(ops, scriptPack.c_str());
|
shState->fileSystem().openReadRaw(ops, scriptPack.c_str());
|
||||||
|
|
||||||
mrb_value scriptArray = mrb_nil_value();
|
mrb_value scriptArray = mrb_nil_value();
|
||||||
std::string readError;
|
std::string readError;
|
||||||
|
|
|
@ -57,9 +57,9 @@
|
||||||
|
|
||||||
# Apply linear interpolation when game screen
|
# Apply linear interpolation when game screen
|
||||||
# is upscaled
|
# is upscaled
|
||||||
# (default: disabled)
|
# (default: enabled)
|
||||||
#
|
#
|
||||||
# smoothScaling=false
|
# smoothScaling=true
|
||||||
|
|
||||||
|
|
||||||
# Sync screen redraws to the monitor refresh rate
|
# Sync screen redraws to the monitor refresh rate
|
||||||
|
|
|
@ -238,6 +238,6 @@ inline ALenum chooseALFormat(int sampleSize, int channelCount)
|
||||||
|
|
||||||
#define AUDIO_SLEEP 10
|
#define AUDIO_SLEEP 10
|
||||||
#define STREAM_BUF_SIZE 32768
|
#define STREAM_BUF_SIZE 32768
|
||||||
#define GLOBAL_VOLUME 0.8
|
#define GLOBAL_VOLUME 0.8f
|
||||||
|
|
||||||
#endif // ALUTIL_H
|
#endif // ALUTIL_H
|
||||||
|
|
100
src/alstream.cpp
100
src/alstream.cpp
|
@ -42,12 +42,12 @@ ALStream::ALStream(LoopMode loopMode,
|
||||||
source(0),
|
source(0),
|
||||||
thread(0),
|
thread(0),
|
||||||
preemptPause(false),
|
preemptPause(false),
|
||||||
pitch(1.0)
|
pitch(1.0f)
|
||||||
{
|
{
|
||||||
alSrc = AL::Source::gen();
|
alSrc = AL::Source::gen();
|
||||||
|
|
||||||
AL::Source::setVolume(alSrc, 1.0);
|
AL::Source::setVolume(alSrc, 1.0f);
|
||||||
AL::Source::setPitch(alSrc, 1.0);
|
AL::Source::setPitch(alSrc, 1.0f);
|
||||||
AL::Source::detachBuffer(alSrc);
|
AL::Source::detachBuffer(alSrc);
|
||||||
|
|
||||||
for (int i = 0; i < STREAM_BUFS; ++i)
|
for (int i = 0; i < STREAM_BUFS; ++i)
|
||||||
|
@ -172,7 +172,7 @@ void ALStream::setPitch(float value)
|
||||||
/* If the source supports setting pitch natively,
|
/* If the source supports setting pitch natively,
|
||||||
* we don't have to do it via OpenAL */
|
* we don't have to do it via OpenAL */
|
||||||
if (source && source->setPitch(value))
|
if (source && source->setPitch(value))
|
||||||
AL::Source::setPitch(alSrc, 1.0);
|
AL::Source::setPitch(alSrc, 1.0f);
|
||||||
else
|
else
|
||||||
AL::Source::setPitch(alSrc, value);
|
AL::Source::setPitch(alSrc, value);
|
||||||
}
|
}
|
||||||
|
@ -199,43 +199,73 @@ void ALStream::closeSource()
|
||||||
delete source;
|
delete source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ALStreamOpenHandler : FileSystem::OpenHandler
|
||||||
|
{
|
||||||
|
SDL_RWops *srcOps;
|
||||||
|
bool looped;
|
||||||
|
ALDataSource *source;
|
||||||
|
std::string errorMsg;
|
||||||
|
|
||||||
|
ALStreamOpenHandler(SDL_RWops &srcOps, bool looped)
|
||||||
|
: srcOps(&srcOps), looped(looped), source(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool tryRead(SDL_RWops &ops, const char *ext)
|
||||||
|
{
|
||||||
|
/* Copy this because we need to keep it around,
|
||||||
|
* as we will continue reading data from it later */
|
||||||
|
*srcOps = ops;
|
||||||
|
|
||||||
|
/* Try to read ogg file signature */
|
||||||
|
char sig[5] = { 0 };
|
||||||
|
SDL_RWread(srcOps, sig, 1, 4);
|
||||||
|
SDL_RWseek(srcOps, 0, RW_SEEK_SET);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!strcmp(sig, "OggS"))
|
||||||
|
{
|
||||||
|
source = createVorbisSource(*srcOps, looped);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(sig, "MThd"))
|
||||||
|
{
|
||||||
|
shState->midiState().initIfNeeded(shState->config());
|
||||||
|
|
||||||
|
if (HAVE_FLUID)
|
||||||
|
{
|
||||||
|
source = createMidiSource(*srcOps, looped);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source = createSDLSource(*srcOps, ext, STREAM_BUF_SIZE, looped);
|
||||||
|
}
|
||||||
|
catch (const Exception &e)
|
||||||
|
{
|
||||||
|
/* All source constructors will close the passed ops
|
||||||
|
* before throwing errors */
|
||||||
|
errorMsg = e.msg;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void ALStream::openSource(const std::string &filename)
|
void ALStream::openSource(const std::string &filename)
|
||||||
{
|
{
|
||||||
char ext[8];
|
ALStreamOpenHandler handler(srcOps, looped);
|
||||||
shState->fileSystem().openRead(srcOps, filename.c_str(), false, ext, sizeof(ext));
|
shState->fileSystem().openRead(handler, filename.c_str());
|
||||||
|
source = handler.source;
|
||||||
needsRewind.clear();
|
needsRewind.clear();
|
||||||
|
|
||||||
/* Try to read ogg file signature */
|
if (!source)
|
||||||
char sig[5] = { 0 };
|
|
||||||
SDL_RWread(&srcOps, sig, 1, 4);
|
|
||||||
SDL_RWseek(&srcOps, 0, RW_SEEK_SET);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!strcmp(sig, "OggS"))
|
|
||||||
{
|
|
||||||
source = createVorbisSource(srcOps, looped);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
char buf[512];
|
||||||
snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s.%s: %s",
|
snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s: %s",
|
||||||
filename.c_str(), ext, e.msg.c_str());
|
filename.c_str(), handler.errorMsg.c_str());
|
||||||
|
|
||||||
Debug() << buf;
|
Debug() << buf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ struct AudioPrivate
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* BGM is stopped. -> MeNotPlaying */
|
/* BGM is stopped. -> MeNotPlaying */
|
||||||
bgm.setVolume(AudioStream::External, 1.0);
|
bgm.setVolume(AudioStream::External, 1.0f);
|
||||||
|
|
||||||
if (!bgm.noResumeStop)
|
if (!bgm.noResumeStop)
|
||||||
bgm.stream.play();
|
bgm.stream.play();
|
||||||
|
@ -193,7 +193,7 @@ struct AudioPrivate
|
||||||
if (bgm.stream.queryState() == ALStream::Stopped)
|
if (bgm.stream.queryState() == ALStream::Stopped)
|
||||||
{
|
{
|
||||||
/* BGM stopped midway fade in. -> MeNotPlaying */
|
/* BGM stopped midway fade in. -> MeNotPlaying */
|
||||||
bgm.setVolume(AudioStream::External, 1.0);
|
bgm.setVolume(AudioStream::External, 1.0f);
|
||||||
meWatch.state = MeNotPlaying;
|
meWatch.state = MeNotPlaying;
|
||||||
bgm.unlockStream();
|
bgm.unlockStream();
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ struct AudioPrivate
|
||||||
if (vol >= 1)
|
if (vol >= 1)
|
||||||
{
|
{
|
||||||
/* BGM fully faded in. -> MeNotPlaying */
|
/* BGM fully faded in. -> MeNotPlaying */
|
||||||
vol = 1.0;
|
vol = 1.0f;
|
||||||
meWatch.state = MeNotPlaying;
|
meWatch.state = MeNotPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ AudioStream::AudioStream(ALStream::LoopMode loopMode,
|
||||||
noResumeStop(false),
|
noResumeStop(false),
|
||||||
stream(loopMode, threadId)
|
stream(loopMode, threadId)
|
||||||
{
|
{
|
||||||
current.volume = 1.0;
|
current.volume = 1.0f;
|
||||||
current.pitch = 1.0;
|
current.pitch = 1.0f;
|
||||||
|
|
||||||
for (size_t i = 0; i < VolumeTypeCount; ++i)
|
for (size_t i = 0; i < VolumeTypeCount; ++i)
|
||||||
volumes[i] = 1.0;
|
volumes[i] = 1.0f;
|
||||||
|
|
||||||
fade.thread = 0;
|
fade.thread = 0;
|
||||||
fade.threadName = std::string("audio_fadeout (") + threadId + ")";
|
fade.threadName = std::string("audio_fadeout (") + threadId + ")";
|
||||||
|
@ -82,8 +82,8 @@ void AudioStream::play(const std::string &filename,
|
||||||
|
|
||||||
lockStream();
|
lockStream();
|
||||||
|
|
||||||
float _volume = clamp<int>(volume, 0, 100) / 100.f;
|
float _volume = clamp<int>(volume, 0, 100) / 100.0f;
|
||||||
float _pitch = clamp<int>(pitch, 50, 150) / 100.f;
|
float _pitch = clamp<int>(pitch, 50, 150) / 100.0f;
|
||||||
|
|
||||||
ALStream::State sState = stream.queryState();
|
ALStream::State sState = stream.queryState();
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ void AudioStream::fadeOut(int duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
fade.active.set();
|
fade.active.set();
|
||||||
fade.msStep = (1.0) / duration;
|
fade.msStep = 1.0f / duration;
|
||||||
fade.reqFini.clear();
|
fade.reqFini.clear();
|
||||||
fade.reqTerm.clear();
|
fade.reqTerm.clear();
|
||||||
fade.startTicks = SDL_GetTicks();
|
fade.startTicks = SDL_GetTicks();
|
||||||
|
@ -302,7 +302,7 @@ void AudioStream::fadeOutThread()
|
||||||
lockStream();
|
lockStream();
|
||||||
|
|
||||||
uint32_t curDur = SDL_GetTicks() - fade.startTicks;
|
uint32_t curDur = SDL_GetTicks() - fade.startTicks;
|
||||||
float resVol = 1.0 - (curDur*fade.msStep);
|
float resVol = 1.0f - (curDur*fade.msStep);
|
||||||
|
|
||||||
ALStream::State state = stream.queryState();
|
ALStream::State state = stream.queryState();
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ void AudioStream::fadeOutThread()
|
||||||
if (state != ALStream::Paused)
|
if (state != ALStream::Paused)
|
||||||
stream.stop();
|
stream.stop();
|
||||||
|
|
||||||
setVolume(FadeOut, 1.0);
|
setVolume(FadeOut, 1.0f);
|
||||||
unlockStream();
|
unlockStream();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -340,15 +340,15 @@ void AudioStream::fadeInThread()
|
||||||
|
|
||||||
/* Fade in duration is always 1 second */
|
/* Fade in duration is always 1 second */
|
||||||
uint32_t cur = SDL_GetTicks() - fadeIn.startTicks;
|
uint32_t cur = SDL_GetTicks() - fadeIn.startTicks;
|
||||||
float prog = cur / 1000.0;
|
float prog = cur / 1000.0f;
|
||||||
|
|
||||||
ALStream::State state = stream.queryState();
|
ALStream::State state = stream.queryState();
|
||||||
|
|
||||||
if (state != ALStream::Playing
|
if (state != ALStream::Playing
|
||||||
|| prog >= 1.0
|
|| prog >= 1.0f
|
||||||
|| fadeIn.rqFini)
|
|| fadeIn.rqFini)
|
||||||
{
|
{
|
||||||
setVolume(FadeIn, 1.0);
|
setVolume(FadeIn, 1.0f);
|
||||||
unlockStream();
|
unlockStream();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -247,13 +247,26 @@ struct BitmapPrivate
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BitmapOpenHandler : FileSystem::OpenHandler
|
||||||
|
{
|
||||||
|
SDL_Surface *surf;
|
||||||
|
|
||||||
|
BitmapOpenHandler()
|
||||||
|
: surf(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool tryRead(SDL_RWops &ops, const char *ext)
|
||||||
|
{
|
||||||
|
surf = IMG_LoadTyped_RW(&ops, 1, ext);
|
||||||
|
return surf != 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Bitmap::Bitmap(const char *filename)
|
Bitmap::Bitmap(const char *filename)
|
||||||
{
|
{
|
||||||
SDL_RWops ops;
|
BitmapOpenHandler handler;
|
||||||
char ext[8];
|
shState->fileSystem().openRead(handler, filename);
|
||||||
|
SDL_Surface *imgSurf = handler.surf;
|
||||||
shState->fileSystem().openRead(ops, filename, false, ext, sizeof(ext));
|
|
||||||
SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, ext);
|
|
||||||
|
|
||||||
if (!imgSurf)
|
if (!imgSurf)
|
||||||
throw Exception(Exception::SDLError, "Error loading image '%s': %s",
|
throw Exception(Exception::SDLError, "Error loading image '%s': %s",
|
||||||
|
@ -992,9 +1005,9 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C
|
||||||
SDL_Surface *out = SDL_CreateRGBSurface
|
SDL_Surface *out = SDL_CreateRGBSurface
|
||||||
(0, in->w+1, in->h+1, fm.BitsPerPixel, fm.Rmask, fm.Gmask, fm.Bmask, fm.Amask);
|
(0, in->w+1, in->h+1, fm.BitsPerPixel, fm.Rmask, fm.Gmask, fm.Bmask, fm.Amask);
|
||||||
|
|
||||||
float fr = c.r / 255.0;
|
float fr = c.r / 255.0f;
|
||||||
float fg = c.g / 255.0;
|
float fg = c.g / 255.0f;
|
||||||
float fb = c.b / 255.0;
|
float fb = c.b / 255.0f;
|
||||||
|
|
||||||
/* We allocate an output surface one pixel wider and higher than the input,
|
/* We allocate an output surface one pixel wider and higher than the input,
|
||||||
* (implicitly) blit a copy of the input with RGB values set to black into
|
* (implicitly) blit a copy of the input with RGB values set to black into
|
||||||
|
@ -1048,11 +1061,11 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float fSrcA = srcA / 255.0;
|
float fSrcA = srcA / 255.0f;
|
||||||
float fShdA = shdA / 255.0;
|
float fShdA = shdA / 255.0f;
|
||||||
|
|
||||||
/* Because opacity == 1, co1 == fSrcA */
|
/* Because opacity == 1, co1 == fSrcA */
|
||||||
float co2 = fShdA * (1.0 - fSrcA);
|
float co2 = fShdA * (1.0f - fSrcA);
|
||||||
/* Result alpha */
|
/* Result alpha */
|
||||||
float fa = fSrcA + co2;
|
float fa = fSrcA + co2;
|
||||||
/* Temp value to simplify arithmetic below */
|
/* Temp value to simplify arithmetic below */
|
||||||
|
@ -1061,10 +1074,10 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C
|
||||||
/* Result colors */
|
/* Result colors */
|
||||||
uint8_t r, g, b, a;
|
uint8_t r, g, b, a;
|
||||||
|
|
||||||
r = clamp<float>(fr * co3, 0, 1) * 255;
|
r = clamp<float>(fr * co3, 0, 1) * 255.0f;
|
||||||
g = clamp<float>(fg * co3, 0, 1) * 255;
|
g = clamp<float>(fg * co3, 0, 1) * 255.0f;
|
||||||
b = clamp<float>(fb * co3, 0, 1) * 255;
|
b = clamp<float>(fb * co3, 0, 1) * 255.0f;
|
||||||
a = clamp<float>(fa, 0, 1) * 255;
|
a = clamp<float>(fa, 0, 1) * 255.0f;
|
||||||
|
|
||||||
*outP = SDL_MapRGBA(&fm, r, g, b, a);
|
*outP = SDL_MapRGBA(&fm, r, g, b, a);
|
||||||
}
|
}
|
||||||
|
@ -1169,11 +1182,11 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
|
||||||
Vec2i gpTexSize;
|
Vec2i gpTexSize;
|
||||||
shState->ensureTexSize(txtSurf->w, txtSurf->h, gpTexSize);
|
shState->ensureTexSize(txtSurf->w, txtSurf->h, gpTexSize);
|
||||||
|
|
||||||
bool fastBlit = !p->touchesTaintedArea(posRect) && txtAlpha == 1.0;
|
bool fastBlit = !p->touchesTaintedArea(posRect) && txtAlpha == 1.0f;
|
||||||
|
|
||||||
if (fastBlit)
|
if (fastBlit)
|
||||||
{
|
{
|
||||||
if (squeeze == 1.0 && !shState->config().subImageFix)
|
if (squeeze == 1.0f && !shState->config().subImageFix)
|
||||||
{
|
{
|
||||||
/* Even faster: upload directly to bitmap texture.
|
/* Even faster: upload directly to bitmap texture.
|
||||||
* We have to make sure the posRect lies within the texture
|
* We have to make sure the posRect lies within the texture
|
||||||
|
|
|
@ -151,7 +151,7 @@ void Config::read(int argc, char *argv[])
|
||||||
PO_DESC(winResizable, bool, false) \
|
PO_DESC(winResizable, bool, false) \
|
||||||
PO_DESC(fullscreen, bool, false) \
|
PO_DESC(fullscreen, bool, false) \
|
||||||
PO_DESC(fixedAspectRatio, bool, true) \
|
PO_DESC(fixedAspectRatio, bool, true) \
|
||||||
PO_DESC(smoothScaling, bool, false) \
|
PO_DESC(smoothScaling, bool, true) \
|
||||||
PO_DESC(vsync, bool, false) \
|
PO_DESC(vsync, bool, false) \
|
||||||
PO_DESC(defScreenW, int, 0) \
|
PO_DESC(defScreenW, int, 0) \
|
||||||
PO_DESC(defScreenH, int, 0) \
|
PO_DESC(defScreenH, int, 0) \
|
||||||
|
|
43
src/config.h
43
src/config.h
|
@ -31,49 +31,6 @@ struct CropTexture
|
||||||
int w, h;
|
int w, h;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TouchOverlay
|
|
||||||
{
|
|
||||||
std::string image;
|
|
||||||
|
|
||||||
struct Button
|
|
||||||
{
|
|
||||||
enum Shape
|
|
||||||
{
|
|
||||||
Rectangle,
|
|
||||||
Circle,
|
|
||||||
Triangle
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string id;
|
|
||||||
std::string target;
|
|
||||||
Shape shape;
|
|
||||||
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
} r;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int radius;
|
|
||||||
} c;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
int x1, y1;
|
|
||||||
int x2, y2;
|
|
||||||
} t;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Button> buttons;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Config
|
struct Config
|
||||||
{
|
{
|
||||||
int rgssVersion;
|
int rgssVersion;
|
||||||
|
|
|
@ -61,9 +61,9 @@ struct Vec4
|
||||||
return (x == other.x && y == other.y && z == other.z && w == other.w);
|
return (x == other.x && y == other.y && z == other.z && w == other.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xyzHasEffect() const
|
bool xyzNotNull() const
|
||||||
{
|
{
|
||||||
return (x != 0.0 || y != 0.0 || z != 0.0);
|
return (x != 0.0f || y != 0.0f || z != 0.0f);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,6 +88,11 @@ struct Vec2i
|
||||||
return x == other.x && y == other.y;
|
return x == other.x && y == other.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Vec2i &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
Vec2i &operator+=(const Vec2i &value)
|
Vec2i &operator+=(const Vec2i &value)
|
||||||
{
|
{
|
||||||
x += value.x;
|
x += value.x;
|
||||||
|
@ -131,6 +136,11 @@ struct Vec2i
|
||||||
return Vec2i(x % value, y % value);
|
return Vec2i(x % value, y % value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec2i operator&(unsigned value) const
|
||||||
|
{
|
||||||
|
return Vec2i(x & value, y & value);
|
||||||
|
}
|
||||||
|
|
||||||
Vec2i operator-() const
|
Vec2i operator-() const
|
||||||
{
|
{
|
||||||
return Vec2i(-x, -y);
|
return Vec2i(-x, -y);
|
||||||
|
@ -176,6 +186,11 @@ struct IntRect : SDL_Rect
|
||||||
w == other.w && h == other.h);
|
w == other.w && h == other.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator!=(const IntRect &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
Vec2i pos() const
|
Vec2i pos() const
|
||||||
{
|
{
|
||||||
return Vec2i(x, y);
|
return Vec2i(x, y);
|
||||||
|
@ -259,13 +274,13 @@ struct NormValue
|
||||||
|
|
||||||
NormValue(int unNorm)
|
NormValue(int unNorm)
|
||||||
: unNorm(unNorm),
|
: unNorm(unNorm),
|
||||||
norm(unNorm / 255.0)
|
norm(unNorm / 255.0f)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void operator =(int value)
|
void operator =(int value)
|
||||||
{
|
{
|
||||||
unNorm = clamp(value, 0, 255);
|
unNorm = clamp(value, 0, 255);
|
||||||
norm = unNorm / 255.0;
|
norm = unNorm / 255.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator ==(int value) const
|
bool operator ==(int value) const
|
||||||
|
|
|
@ -111,7 +111,11 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
UnidirMessage<Vec2i> &windowSizeMsg = rtData.windowSizeMsg;
|
UnidirMessage<Vec2i> &windowSizeMsg = rtData.windowSizeMsg;
|
||||||
|
|
||||||
initALCFunctions(rtData.alcDev);
|
initALCFunctions(rtData.alcDev);
|
||||||
|
|
||||||
|
// XXX this function breaks input focus on OSX
|
||||||
|
#ifndef __MACOSX__
|
||||||
SDL_SetEventFilter(eventFilter, &rtData);
|
SDL_SetEventFilter(eventFilter, &rtData);
|
||||||
|
#endif
|
||||||
|
|
||||||
fullscreen = rtData.config.fullscreen;
|
fullscreen = rtData.config.fullscreen;
|
||||||
int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT;
|
int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT;
|
||||||
|
@ -127,7 +131,9 @@ void EventThread::process(RGSSThreadData &rtData)
|
||||||
bool displayingFPS = false;
|
bool displayingFPS = false;
|
||||||
|
|
||||||
bool cursorInWindow = false;
|
bool cursorInWindow = false;
|
||||||
bool windowFocused = false;
|
|
||||||
|
/* SDL doesn't send an initial FOCUS_GAINED event */
|
||||||
|
bool windowFocused = true;
|
||||||
|
|
||||||
bool terminate = false;
|
bool terminate = false;
|
||||||
|
|
||||||
|
@ -490,9 +496,9 @@ int EventThread::eventFilter(void *data, SDL_Event *event)
|
||||||
Debug() << "SDL_APP_LOWMEMORY";
|
Debug() << "SDL_APP_LOWMEMORY";
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case SDL_RENDER_TARGETS_RESET :
|
// case SDL_RENDER_TARGETS_RESET :
|
||||||
Debug() << "****** SDL_RENDER_TARGETS_RESET";
|
// Debug() << "****** SDL_RENDER_TARGETS_RESET";
|
||||||
return 0;
|
// return 0;
|
||||||
|
|
||||||
// case SDL_RENDER_DEVICE_RESET :
|
// case SDL_RENDER_DEVICE_RESET :
|
||||||
// Debug() << "****** SDL_RENDER_DEVICE_RESET";
|
// Debug() << "****** SDL_RENDER_DEVICE_RESET";
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
|
@ -249,201 +250,65 @@ strcpySafe(char *dst, const char *src,
|
||||||
return cpyMax;
|
return cpyMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Attempt to locate an extension string in a filename.
|
||||||
|
* Either a pointer into the input string pointing at the
|
||||||
|
* extension, or null is returned */
|
||||||
|
static const char *
|
||||||
|
findExt(const char *filename)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (len = strlen(filename); len > 0; --len)
|
||||||
|
{
|
||||||
|
if (filename[len] == '/')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (filename[len] == '.')
|
||||||
|
return &filename[len+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
initReadOps(PHYSFS_File *handle,
|
||||||
|
SDL_RWops &ops,
|
||||||
|
bool freeOnClose)
|
||||||
|
{
|
||||||
|
ops.size = SDL_RWopsSize;
|
||||||
|
ops.seek = SDL_RWopsSeek;
|
||||||
|
ops.read = SDL_RWopsRead;
|
||||||
|
ops.write = SDL_RWopsWrite;
|
||||||
|
|
||||||
|
if (freeOnClose)
|
||||||
|
ops.close = SDL_RWopsCloseFree;
|
||||||
|
else
|
||||||
|
ops.close = SDL_RWopsClose;
|
||||||
|
|
||||||
|
ops.type = SDL_RWOPS_PHYSFS;
|
||||||
|
ops.hidden.unknown.data1 = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strTolower(std::string &str)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < str.size(); ++i)
|
||||||
|
str[i] = tolower(str[i]);
|
||||||
|
}
|
||||||
|
|
||||||
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
|
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
|
||||||
|
|
||||||
struct FileSystemPrivate
|
struct FileSystemPrivate
|
||||||
{
|
{
|
||||||
/* Maps: lower case filepath without extension,
|
/* Maps: lower case full filepath,
|
||||||
* To: mixed case full filepath
|
* To: mixed case full filepath */
|
||||||
* This is for compatibility with games that take Windows'
|
|
||||||
* case insensitivity for granted */
|
|
||||||
BoostHash<std::string, std::string> pathCache;
|
BoostHash<std::string, std::string> pathCache;
|
||||||
|
/* Maps: lower case directory path,
|
||||||
|
* To: list of lower case filenames */
|
||||||
|
BoostHash<std::string, std::vector<std::string> > fileLists;
|
||||||
|
|
||||||
|
/* This is for compatibility with games that take Windows'
|
||||||
|
* case insensitivity for granted */
|
||||||
bool havePathCache;
|
bool havePathCache;
|
||||||
|
|
||||||
/* Attempt to locate an extension string in a filename.
|
|
||||||
* Either a pointer into the input string pointing at the
|
|
||||||
* extension, or null is returned */
|
|
||||||
const char *findExt(const char *filename)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
for (len = strlen(filename); len > 0; --len)
|
|
||||||
{
|
|
||||||
if (filename[len] == '/')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (filename[len] == '.')
|
|
||||||
return &filename[len+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
strcpySafe(outBuffer, filepath, outN, -1);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
*delim = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Otherwise the file is in the root directory */
|
|
||||||
d.outBuf = outBuffer;
|
|
||||||
d.filenameLen = len - (delim - outBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
d.found = false;
|
|
||||||
d.outBufN = outN - (d.outBuf - outBuffer);
|
|
||||||
|
|
||||||
PHYSFS_enumerateFilesCallback(root ? "" : outBuffer, completeFilenameRegCB, &d);
|
|
||||||
|
|
||||||
if (!d.found)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Now we put the deliminator back in to form the completed
|
|
||||||
* file path (if required) */
|
|
||||||
if (delim != outBuffer)
|
|
||||||
*delim = '/';
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool completeFilenamePC(const char *filepath,
|
|
||||||
char *outBuffer,
|
|
||||||
size_t outN)
|
|
||||||
{
|
|
||||||
std::string lowCase(filepath);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < lowCase.size(); ++i)
|
|
||||||
lowCase[i] = tolower(lowCase[i]);
|
|
||||||
|
|
||||||
if (!pathCache.contains(lowCase))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const std::string &fullPath = pathCache[lowCase];
|
|
||||||
strcpySafe(outBuffer, fullPath.c_str(), outN, fullPath.size());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool completeFilename(const char *filepath,
|
|
||||||
char *outBuffer,
|
|
||||||
size_t outN)
|
|
||||||
{
|
|
||||||
if (havePathCache)
|
|
||||||
return completeFilenamePC(filepath, outBuffer, outN);
|
|
||||||
else
|
|
||||||
return completeFilenameReg(filepath, outBuffer, outN);
|
|
||||||
}
|
|
||||||
|
|
||||||
PHYSFS_File *openReadHandle(const char *filename,
|
|
||||||
char *extBuf,
|
|
||||||
size_t extBufN)
|
|
||||||
{
|
|
||||||
char found[512];
|
|
||||||
|
|
||||||
if (!completeFilename(filename, found, sizeof(found)))
|
|
||||||
throw Exception(Exception::NoFileError, "%s", filename);
|
|
||||||
|
|
||||||
PHYSFS_File *handle = PHYSFS_openRead(found);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initReadOps(PHYSFS_File *handle,
|
|
||||||
SDL_RWops &ops,
|
|
||||||
bool freeOnClose)
|
|
||||||
{
|
|
||||||
ops.size = SDL_RWopsSize;
|
|
||||||
ops.seek = SDL_RWopsSeek;
|
|
||||||
ops.read = SDL_RWopsRead;
|
|
||||||
ops.write = SDL_RWopsWrite;
|
|
||||||
|
|
||||||
if (freeOnClose)
|
|
||||||
ops.close = SDL_RWopsCloseFree;
|
|
||||||
else
|
|
||||||
ops.close = SDL_RWopsClose;
|
|
||||||
|
|
||||||
ops.type = SDL_RWOPS_PHYSFS;
|
|
||||||
ops.hidden.unknown.data1 = handle;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FileSystem::FileSystem(const char *argv0,
|
FileSystem::FileSystem(const char *argv0,
|
||||||
|
@ -484,99 +349,105 @@ void FileSystem::addPath(const char *path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
struct CacheEnumData
|
||||||
struct CacheEnumCBData
|
|
||||||
{
|
{
|
||||||
FileSystemPrivate *p;
|
FileSystemPrivate *p;
|
||||||
|
std::stack<std::vector<std::string>*> fileLists;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
iconv_t nfd2nfc;
|
iconv_t nfd2nfc;
|
||||||
|
char buf[512];
|
||||||
|
#endif
|
||||||
|
|
||||||
CacheEnumCBData(FileSystemPrivate *fsp)
|
CacheEnumData(FileSystemPrivate *p)
|
||||||
|
: p(p)
|
||||||
{
|
{
|
||||||
p = fsp;
|
#ifdef __APPLE__
|
||||||
nfd2nfc = iconv_open("utf-8", "utf-8-mac");
|
nfd2nfc = iconv_open("utf-8", "utf-8-mac");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
~CacheEnumCBData()
|
~CacheEnumData()
|
||||||
{
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
iconv_close(nfd2nfc);
|
iconv_close(nfd2nfc);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfcFromNfd(char *dst, const char *src, size_t dstSize)
|
/* Converts in-place */
|
||||||
|
void toNFC(char *inout)
|
||||||
{
|
{
|
||||||
size_t srcSize = strlen(src);
|
#ifdef __APPLE__
|
||||||
|
size_t srcSize = strlen(inout);
|
||||||
|
size_t bufSize = sizeof(buf);
|
||||||
|
char *bufPtr = buf;
|
||||||
|
char *inoutPtr = inout;
|
||||||
|
|
||||||
/* Reserve room for null terminator */
|
/* Reserve room for null terminator */
|
||||||
--dstSize;
|
--bufSize;
|
||||||
/* iconv takes a char** instead of a const char**, even though
|
|
||||||
* the string data isn't written to. */
|
|
||||||
iconv(nfd2nfc,
|
iconv(nfd2nfc,
|
||||||
const_cast<char**>(&src), &srcSize,
|
&inoutPtr, &srcSize,
|
||||||
&dst, &dstSize);
|
&bufPtr, &bufSize);
|
||||||
/* Null-terminate */
|
/* Null-terminate */
|
||||||
*dst = 0;
|
*bufPtr = 0;
|
||||||
|
strcpy(inout, buf);
|
||||||
|
#else
|
||||||
|
(void) inout;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
static void cacheEnumCB(void *d, const char *origdir,
|
static void cacheEnumCB(void *d, const char *origdir,
|
||||||
const char *fname)
|
const char *fname)
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
CacheEnumData &data = *static_cast<CacheEnumData*>(d);
|
||||||
CacheEnumCBData *data = static_cast<CacheEnumCBData*>(d);
|
char fullPath[512];
|
||||||
FileSystemPrivate *p = data->p;
|
|
||||||
#else
|
|
||||||
FileSystemPrivate *p = static_cast<FileSystemPrivate*>(d);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char buf[512];
|
if (!*origdir)
|
||||||
|
snprintf(fullPath, sizeof(fullPath), "%s", fname);
|
||||||
if (*origdir == '\0')
|
|
||||||
strncpy(buf, fname, sizeof(buf));
|
|
||||||
else
|
else
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", origdir, fname);
|
snprintf(fullPath, sizeof(fullPath), "%s/%s", origdir, fname);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
/* Deal with OSX' weird UTF-8 standards */
|
||||||
char bufNfc[sizeof(buf)];
|
data.toNFC(fullPath);
|
||||||
data->nfcFromNfd(bufNfc, buf, sizeof(bufNfc));
|
|
||||||
#else
|
|
||||||
char *const bufNfc = buf;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char *ptr = bufNfc;
|
std::string mixedCase(fullPath);
|
||||||
|
std::string lowerCase = mixedCase;
|
||||||
|
strTolower(lowerCase);
|
||||||
|
|
||||||
/* Trim leading slash */
|
PHYSFS_Stat stat;
|
||||||
if (*ptr == '/')
|
PHYSFS_stat(fullPath, &stat);
|
||||||
++ptr;
|
|
||||||
|
|
||||||
std::string mixedCase(ptr);
|
if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY)
|
||||||
|
|
||||||
for (char *q = bufNfc; *q; ++q)
|
|
||||||
*q = tolower(*q);
|
|
||||||
|
|
||||||
p->pathCache.insert(std::string(ptr), mixedCase);
|
|
||||||
|
|
||||||
for (char *q = ptr+strlen(ptr); q > ptr; --q)
|
|
||||||
{
|
{
|
||||||
if (*q == '/')
|
/* Create a new list for this directory */
|
||||||
break;
|
std::vector<std::string> &list = data.p->fileLists[lowerCase];
|
||||||
|
|
||||||
if (*q != '.')
|
/* Iterate over its contents */
|
||||||
continue;
|
data.fileLists.push(&list);
|
||||||
|
PHYSFS_enumerateFilesCallback(fullPath, cacheEnumCB, d);
|
||||||
*q = '\0';
|
data.fileLists.pop();
|
||||||
p->pathCache.insert(std::string(ptr), mixedCase);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Get the file list for the directory we're currently
|
||||||
|
* traversing and append this filename to it */
|
||||||
|
std::vector<std::string> &list = *data.fileLists.top();
|
||||||
|
std::string lowerFilename(fname);
|
||||||
|
strTolower(lowerFilename);
|
||||||
|
list.push_back(lowerFilename);
|
||||||
|
|
||||||
PHYSFS_enumerateFilesCallback(mixedCase.c_str(), cacheEnumCB, d);
|
/* Add the lower -> mixed mapping of the file's full path */
|
||||||
|
data.p->pathCache.insert(lowerCase, mixedCase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::createPathCache()
|
void FileSystem::createPathCache()
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
CacheEnumData data(p);
|
||||||
CacheEnumCBData data(p);
|
data.fileLists.push(&p->fileLists[""]);
|
||||||
PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data);
|
PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data);
|
||||||
#else
|
|
||||||
PHYSFS_enumerateFilesCallback("", cacheEnumCB, p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
p->havePathCache = true;
|
p->havePathCache = true;
|
||||||
}
|
}
|
||||||
|
@ -591,10 +462,9 @@ static void fontSetEnumCB(void *data, const char *,
|
||||||
const char *fname)
|
const char *fname)
|
||||||
{
|
{
|
||||||
FontSetsCBData *d = static_cast<FontSetsCBData*>(data);
|
FontSetsCBData *d = static_cast<FontSetsCBData*>(data);
|
||||||
FileSystemPrivate *p = d->p;
|
|
||||||
|
|
||||||
/* Only consider filenames with font extensions */
|
/* Only consider filenames with font extensions */
|
||||||
const char *ext = p->findExt(fname);
|
const char *ext = findExt(fname);
|
||||||
|
|
||||||
if (!ext)
|
if (!ext)
|
||||||
return;
|
return;
|
||||||
|
@ -618,7 +488,7 @@ static void fontSetEnumCB(void *data, const char *,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SDL_RWops ops;
|
SDL_RWops ops;
|
||||||
p->initReadOps(handle, ops, false);
|
initReadOps(handle, ops, false);
|
||||||
|
|
||||||
d->sfs->initFontSetCB(ops, filename);
|
d->sfs->initFontSetCB(ops, filename);
|
||||||
|
|
||||||
|
@ -632,15 +502,147 @@ void FileSystem::initFontSets(SharedFontState &sfs)
|
||||||
PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d);
|
PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::openRead(SDL_RWops &ops,
|
struct OpenReadEnumData
|
||||||
const char *filename,
|
|
||||||
bool freeOnClose,
|
|
||||||
char *extBuf,
|
|
||||||
size_t extBufN)
|
|
||||||
{
|
{
|
||||||
PHYSFS_File *handle = p->openReadHandle(filename, extBuf, extBufN);
|
FileSystem::OpenHandler &handler;
|
||||||
|
SDL_RWops ops;
|
||||||
|
|
||||||
p->initReadOps(handle, ops, freeOnClose);
|
/* The filename (without directory) we're looking for */
|
||||||
|
const char *filename;
|
||||||
|
size_t filenameN;
|
||||||
|
|
||||||
|
/* Optional hash to translate full filepaths
|
||||||
|
* (used with path cache) */
|
||||||
|
BoostHash<std::string, std::string> *pathTrans;
|
||||||
|
|
||||||
|
/* Number of files we've attempted to read and parse */
|
||||||
|
size_t matchCount;
|
||||||
|
bool stopSearching;
|
||||||
|
|
||||||
|
/* In case of a PhysFS error, save it here so it
|
||||||
|
* doesn't get changed before we get back into our code */
|
||||||
|
const char *physfsError;
|
||||||
|
|
||||||
|
OpenReadEnumData(FileSystem::OpenHandler &handler,
|
||||||
|
const char *filename, size_t filenameN,
|
||||||
|
BoostHash<std::string, std::string> *pathTrans)
|
||||||
|
: handler(handler), filename(filename), filenameN(filenameN),
|
||||||
|
pathTrans(pathTrans), matchCount(0), stopSearching(false),
|
||||||
|
physfsError(0)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void openReadEnumCB(void *d, const char *dirpath,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
OpenReadEnumData &data = *static_cast<OpenReadEnumData*>(d);
|
||||||
|
char buffer[512];
|
||||||
|
const char *fullPath;
|
||||||
|
|
||||||
|
if (data.stopSearching)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If there's not even a partial match, continue searching */
|
||||||
|
if (strncmp(filename, data.filename, data.filenameN) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!*dirpath)
|
||||||
|
{
|
||||||
|
fullPath = filename;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s/%s", dirpath, filename);
|
||||||
|
fullPath = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
char last = filename[data.filenameN];
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
if (last != '.' && last != '\0')
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If the path cache is active, translate from lower case
|
||||||
|
* to mixed case path */
|
||||||
|
if (data.pathTrans)
|
||||||
|
fullPath = (*data.pathTrans)[fullPath].c_str();
|
||||||
|
|
||||||
|
PHYSFS_File *phys = PHYSFS_openRead(fullPath);
|
||||||
|
|
||||||
|
if (!phys)
|
||||||
|
{
|
||||||
|
/* Failing to open this file here means there must
|
||||||
|
* be a deeper rooted problem somewhere within PhysFS.
|
||||||
|
* Just abort alltogether. */
|
||||||
|
data.stopSearching = true;
|
||||||
|
data.physfsError = PHYSFS_getLastError();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initReadOps(phys, data.ops, false);
|
||||||
|
|
||||||
|
const char *ext = findExt(filename);
|
||||||
|
|
||||||
|
if (data.handler.tryRead(data.ops, ext))
|
||||||
|
data.stopSearching = true;
|
||||||
|
|
||||||
|
++data.matchCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::openRead(OpenHandler &handler, const char *filename)
|
||||||
|
{
|
||||||
|
char buffer[512];
|
||||||
|
size_t len = strcpySafe(buffer, filename, sizeof(buffer), -1);
|
||||||
|
char *delim;
|
||||||
|
|
||||||
|
if (p->havePathCache)
|
||||||
|
for (size_t i = 0; i < len; ++i)
|
||||||
|
buffer[i] = tolower(buffer[i]);
|
||||||
|
|
||||||
|
/* Find the deliminator separating directory and file name */
|
||||||
|
for (delim = buffer + len; delim > buffer; --delim)
|
||||||
|
if (*delim == '/')
|
||||||
|
break;
|
||||||
|
|
||||||
|
const bool root = (delim == buffer);
|
||||||
|
|
||||||
|
const char *file = buffer;
|
||||||
|
const char *dir = "";
|
||||||
|
|
||||||
|
if (!root)
|
||||||
|
{
|
||||||
|
/* Cut the buffer in half so we can use it
|
||||||
|
* for both filename and directory path */
|
||||||
|
*delim = '\0';
|
||||||
|
file = delim+1;
|
||||||
|
dir = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenReadEnumData data(handler, file, len + buffer - delim - !root,
|
||||||
|
p->havePathCache ? &p->pathCache : 0);
|
||||||
|
|
||||||
|
if (p->havePathCache)
|
||||||
|
{
|
||||||
|
/* Get the list of files contained in this directory
|
||||||
|
* and manually iterate over them */
|
||||||
|
const std::vector<std::string> &fileList = p->fileLists[dir];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < fileList.size(); ++i)
|
||||||
|
openReadEnumCB(&data, dir, fileList[i].c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PHYSFS_enumerateFilesCallback(dir, openReadEnumCB, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.physfsError)
|
||||||
|
throw Exception(Exception::PHYSFSError, "PhysFS: %s", data.physfsError);
|
||||||
|
|
||||||
|
if (data.matchCount == 0)
|
||||||
|
throw Exception(Exception::NoFileError, "%s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::openReadRaw(SDL_RWops &ops,
|
void FileSystem::openReadRaw(SDL_RWops &ops,
|
||||||
|
@ -650,12 +652,10 @@ void FileSystem::openReadRaw(SDL_RWops &ops,
|
||||||
PHYSFS_File *handle = PHYSFS_openRead(filename);
|
PHYSFS_File *handle = PHYSFS_openRead(filename);
|
||||||
assert(handle);
|
assert(handle);
|
||||||
|
|
||||||
p->initReadOps(handle, ops, freeOnClose);
|
initReadOps(handle, ops, freeOnClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileSystem::exists(const char *filename)
|
bool FileSystem::exists(const char *filename)
|
||||||
{
|
{
|
||||||
char found[512];
|
return PHYSFS_exists(filename);
|
||||||
|
|
||||||
return p->completeFilename(filename, found, sizeof(found));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,17 +43,28 @@ public:
|
||||||
* available font assets */
|
* available font assets */
|
||||||
void initFontSets(SharedFontState &sfs);
|
void initFontSets(SharedFontState &sfs);
|
||||||
|
|
||||||
void openRead(SDL_RWops &ops,
|
struct OpenHandler
|
||||||
const char *filename,
|
{
|
||||||
bool freeOnClose = false,
|
/* Try to read and interpret data provided from ops.
|
||||||
char *extBuf = 0,
|
* If data cannot be parsed, return false, otherwise true.
|
||||||
size_t extBufN = 0);
|
* Can be called multiple times until a parseable file is found.
|
||||||
|
* It's the handler's responsibility to close every passed
|
||||||
|
* ops structure, even when data could not be parsed.
|
||||||
|
* After this function returns, ops becomes invalid, so don't take
|
||||||
|
* references to it. Instead, copy the structure without closing
|
||||||
|
* if you need to further read from it later. */
|
||||||
|
virtual bool tryRead(SDL_RWops &ops, const char *ext) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void openRead(OpenHandler &handler,
|
||||||
|
const char *filename);
|
||||||
|
|
||||||
/* Circumvents extension supplementing */
|
/* Circumvents extension supplementing */
|
||||||
void openReadRaw(SDL_RWops &ops,
|
void openReadRaw(SDL_RWops &ops,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
bool freeOnClose = false);
|
bool freeOnClose = false);
|
||||||
|
|
||||||
|
/* Does not perform extension supplementing */
|
||||||
bool exists(const char *filename);
|
bool exists(const char *filename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
88
src/font.cpp
88
src/font.cpp
|
@ -174,7 +174,7 @@ _TTF_Font *SharedFontState::getFont(std::string family,
|
||||||
// FIXME 0.9 is guesswork at this point
|
// FIXME 0.9 is guesswork at this point
|
||||||
// float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
|
// float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
|
||||||
// font = TTF_OpenFontRW(ops, 1, gamma /** .90*/);
|
// font = TTF_OpenFontRW(ops, 1, gamma /** .90*/);
|
||||||
font = TTF_OpenFontRW(ops, 1, size* .90);
|
font = TTF_OpenFontRW(ops, 1, size* 0.90f);
|
||||||
|
|
||||||
if (!font)
|
if (!font)
|
||||||
throw Exception(Exception::SDLError, "%s", SDL_GetError());
|
throw Exception(Exception::SDLError, "%s", SDL_GetError());
|
||||||
|
@ -184,7 +184,7 @@ _TTF_Font *SharedFontState::getFont(std::string family,
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SharedFontState::fontPresent(std::string family)
|
bool SharedFontState::fontPresent(std::string family) const
|
||||||
{
|
{
|
||||||
/* Check for substitutions */
|
/* Check for substitutions */
|
||||||
if (p->subs.contains(family))
|
if (p->subs.contains(family))
|
||||||
|
@ -202,6 +202,26 @@ _TTF_Font *SharedFontState::openBundled(int size)
|
||||||
return TTF_OpenFontRW(ops, 1, size);
|
return TTF_OpenFontRW(ops, 1, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pickExistingFontName(const std::vector<std::string> &names,
|
||||||
|
std::string &out,
|
||||||
|
const SharedFontState &sfs)
|
||||||
|
{
|
||||||
|
/* Note: In RMXP, a names array with no existing entry
|
||||||
|
* results in no text being drawn at all (same for "" and []);
|
||||||
|
* we can't replicate this in mkxp due to the default substitute. */
|
||||||
|
|
||||||
|
for (size_t i = 0; i < names.size(); ++i)
|
||||||
|
{
|
||||||
|
if (sfs.fontPresent(names[i]))
|
||||||
|
{
|
||||||
|
out = names[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct FontPrivate
|
struct FontPrivate
|
||||||
{
|
{
|
||||||
|
@ -229,15 +249,15 @@ struct FontPrivate
|
||||||
static Color defaultColorTmp;
|
static Color defaultColorTmp;
|
||||||
static Color defaultOutColorTmp;
|
static Color defaultOutColorTmp;
|
||||||
|
|
||||||
|
static std::vector<std::string> initialDefaultNames;
|
||||||
|
|
||||||
/* The actual font is opened as late as possible
|
/* The actual font is opened as late as possible
|
||||||
* (when it is queried by a Bitmap), prior it is
|
* (when it is queried by a Bitmap), prior it is
|
||||||
* set to null */
|
* set to null */
|
||||||
TTF_Font *sdlFont;
|
TTF_Font *sdlFont;
|
||||||
|
|
||||||
FontPrivate(const char *name = 0,
|
FontPrivate(int size)
|
||||||
int size = 0)
|
: size(size),
|
||||||
: name(name ? std::string(name) : defaultName),
|
|
||||||
size(size ? size : defaultSize),
|
|
||||||
bold(defaultBold),
|
bold(defaultBold),
|
||||||
italic(defaultItalic),
|
italic(defaultItalic),
|
||||||
outline(defaultOutline),
|
outline(defaultOutline),
|
||||||
|
@ -290,6 +310,8 @@ Color *FontPrivate::defaultOutColor = &FontPrivate::defaultOutColorTmp;
|
||||||
Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
|
Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
|
||||||
Color FontPrivate::defaultOutColorTmp(0, 0, 0, 128);
|
Color FontPrivate::defaultOutColorTmp(0, 0, 0, 128);
|
||||||
|
|
||||||
|
std::vector<std::string> FontPrivate::initialDefaultNames;
|
||||||
|
|
||||||
bool Font::doesExist(const char *name)
|
bool Font::doesExist(const char *name)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -298,10 +320,15 @@ bool Font::doesExist(const char *name)
|
||||||
return shState->fontState().fontPresent(name);
|
return shState->fontState().fontPresent(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(const char *name,
|
Font::Font(const std::vector<std::string> *names,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
p = new FontPrivate(name, size);
|
p = new FontPrivate(size ? size : FontPrivate::defaultSize);
|
||||||
|
|
||||||
|
if (names)
|
||||||
|
setName(*names);
|
||||||
|
else
|
||||||
|
p->name = FontPrivate::defaultName;
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font(const Font &other)
|
Font::Font(const Font &other)
|
||||||
|
@ -321,17 +348,9 @@ const Font &Font::operator=(const Font &o)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Font::getName() const
|
void Font::setName(const std::vector<std::string> &names)
|
||||||
{
|
{
|
||||||
return p->name.c_str();
|
pickExistingFontName(names, p->name, shState->fontState());
|
||||||
}
|
|
||||||
|
|
||||||
void Font::setName(const char *value)
|
|
||||||
{
|
|
||||||
if (p->name == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p->name = value;
|
|
||||||
p->sdlFont = 0;
|
p->sdlFont = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,14 +386,15 @@ DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutline, bool, FontPrivate::defaultOutli
|
||||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color&, *FontPrivate::defaultColor)
|
DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color&, *FontPrivate::defaultColor)
|
||||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutColor, Color&, *FontPrivate::defaultOutColor)
|
DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutColor, Color&, *FontPrivate::defaultOutColor)
|
||||||
|
|
||||||
const char *Font::getDefaultName()
|
void Font::setDefaultName(const std::vector<std::string> &names,
|
||||||
|
const SharedFontState &sfs)
|
||||||
{
|
{
|
||||||
return FontPrivate::defaultName.c_str();
|
pickExistingFontName(names, FontPrivate::defaultName, sfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::setDefaultName(const char *value)
|
const std::vector<std::string> &Font::getInitialDefaultNames()
|
||||||
{
|
{
|
||||||
FontPrivate::defaultName = value;
|
return FontPrivate::initialDefaultNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::initDynAttribs()
|
void Font::initDynAttribs()
|
||||||
|
@ -393,8 +413,30 @@ void Font::initDefaultDynAttribs()
|
||||||
FontPrivate::defaultOutColor = new Color(FontPrivate::defaultOutColorTmp);
|
FontPrivate::defaultOutColor = new Color(FontPrivate::defaultOutColorTmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::initDefaults()
|
void Font::initDefaults(const SharedFontState &sfs)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> &names = FontPrivate::initialDefaultNames;
|
||||||
|
|
||||||
|
switch (rgssVer)
|
||||||
|
{
|
||||||
|
case 1 :
|
||||||
|
// FIXME: Japanese version has "MS PGothic" instead
|
||||||
|
names.push_back("Arial");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2 :
|
||||||
|
names.push_back("UmePlus Gothic");
|
||||||
|
names.push_back("MS Gothic");
|
||||||
|
names.push_back("Courier New");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case 3 :
|
||||||
|
names.push_back("VL Gothic");
|
||||||
|
}
|
||||||
|
|
||||||
|
setDefaultName(names, sfs);
|
||||||
|
|
||||||
FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false);
|
FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false);
|
||||||
FontPrivate::defaultShadow = (rgssVer == 2 ? true : false);
|
FontPrivate::defaultShadow = (rgssVer == 2 ? true : false);
|
||||||
}
|
}
|
||||||
|
|
69
src/font.h
69
src/font.h
|
@ -25,6 +25,9 @@
|
||||||
#include "etc.h"
|
#include "etc.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
struct SDL_RWops;
|
struct SDL_RWops;
|
||||||
struct _TTF_Font;
|
struct _TTF_Font;
|
||||||
struct Config;
|
struct Config;
|
||||||
|
@ -47,7 +50,7 @@ public:
|
||||||
_TTF_Font *getFont(std::string family,
|
_TTF_Font *getFont(std::string family,
|
||||||
int size);
|
int size);
|
||||||
|
|
||||||
bool fontPresent(std::string family);
|
bool fontPresent(std::string family) const;
|
||||||
|
|
||||||
static _TTF_Font *openBundled(int size);
|
static _TTF_Font *openBundled(int size);
|
||||||
|
|
||||||
|
@ -55,22 +58,6 @@ private:
|
||||||
SharedFontStatePrivate *p;
|
SharedFontStatePrivate *p;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Concerning Font::name/defaultName :
|
|
||||||
* In RGSS, this is not actually a string; any type of
|
|
||||||
* object is accepted, however anything but strings and
|
|
||||||
* arrays is ignored (and text drawing turns blank).
|
|
||||||
* Single strings are interpreted as font family names,
|
|
||||||
* and directly passed to the underlying C++ object;
|
|
||||||
* arrays however are searched for the first string
|
|
||||||
* object corresponding to a valid font family name,
|
|
||||||
* and rendering is done with that. In mkxp, we pass
|
|
||||||
* this first valid font family as the 'name' attribute
|
|
||||||
* back to the C++ object on assignment and object
|
|
||||||
* creation (in case Font.default_name is also an array).
|
|
||||||
* Invalid parameters (things other than strings or
|
|
||||||
* arrays not containing any valid family name) are
|
|
||||||
* passed back as "". */
|
|
||||||
|
|
||||||
struct FontPrivate;
|
struct FontPrivate;
|
||||||
|
|
||||||
class Font
|
class Font
|
||||||
|
@ -78,31 +65,43 @@ class Font
|
||||||
public:
|
public:
|
||||||
static bool doesExist(const char *name);
|
static bool doesExist(const char *name);
|
||||||
|
|
||||||
Font(const char *name = 0,
|
Font(const std::vector<std::string> *names = 0,
|
||||||
int size = 0);
|
int size = 0);
|
||||||
|
|
||||||
/* Clone constructor */
|
/* Clone constructor */
|
||||||
Font(const Font &other);
|
Font(const Font &other);
|
||||||
|
|
||||||
~Font();
|
~Font();
|
||||||
|
|
||||||
const Font &operator=(const Font &o);
|
const Font &operator=(const Font &o);
|
||||||
|
|
||||||
DECL_ATTR( Name, const char * )
|
DECL_ATTR( Size, int )
|
||||||
DECL_ATTR( Size, int )
|
DECL_ATTR( Bold, bool )
|
||||||
DECL_ATTR( Bold, bool )
|
DECL_ATTR( Italic, bool )
|
||||||
DECL_ATTR( Italic, bool )
|
DECL_ATTR( Color, Color& )
|
||||||
DECL_ATTR( Color, Color& )
|
DECL_ATTR( Shadow, bool )
|
||||||
DECL_ATTR( Shadow, bool )
|
DECL_ATTR( Outline, bool )
|
||||||
DECL_ATTR( Outline, bool )
|
DECL_ATTR( OutColor, Color& )
|
||||||
DECL_ATTR( OutColor, Color& )
|
|
||||||
|
|
||||||
DECL_ATTR_STATIC( DefaultName, const char* )
|
DECL_ATTR_STATIC( DefaultSize, int )
|
||||||
DECL_ATTR_STATIC( DefaultSize, int )
|
DECL_ATTR_STATIC( DefaultBold, bool )
|
||||||
DECL_ATTR_STATIC( DefaultBold, bool )
|
DECL_ATTR_STATIC( DefaultItalic, bool )
|
||||||
DECL_ATTR_STATIC( DefaultItalic, bool )
|
DECL_ATTR_STATIC( DefaultColor, Color& )
|
||||||
DECL_ATTR_STATIC( DefaultColor, Color& )
|
DECL_ATTR_STATIC( DefaultShadow, bool )
|
||||||
DECL_ATTR_STATIC( DefaultShadow, bool )
|
DECL_ATTR_STATIC( DefaultOutline, bool )
|
||||||
DECL_ATTR_STATIC( DefaultOutline, bool )
|
DECL_ATTR_STATIC( DefaultOutColor, Color& )
|
||||||
DECL_ATTR_STATIC( DefaultOutColor, Color& )
|
|
||||||
|
/* There is no point in providing getters for these,
|
||||||
|
* as the bindings will always return the stored native
|
||||||
|
* string/array object anyway. It's impossible to mirror
|
||||||
|
* in the C++ core.
|
||||||
|
* The core object picks the first existing name from the
|
||||||
|
* passed array and stores it internally (same for default). */
|
||||||
|
void setName(const std::vector<std::string> &names);
|
||||||
|
static void setDefaultName(const std::vector<std::string> &names,
|
||||||
|
const SharedFontState &sfs);
|
||||||
|
|
||||||
|
static const std::vector<std::string> &getInitialDefaultNames();
|
||||||
|
|
||||||
/* Assigns heap allocated objects to object properties;
|
/* Assigns heap allocated objects to object properties;
|
||||||
* using this in pure C++ will cause memory leaks
|
* using this in pure C++ will cause memory leaks
|
||||||
|
@ -110,7 +109,7 @@ public:
|
||||||
void initDynAttribs();
|
void initDynAttribs();
|
||||||
static void initDefaultDynAttribs();
|
static void initDefaultDynAttribs();
|
||||||
|
|
||||||
static void initDefaults();
|
static void initDefaults(const SharedFontState &sfs);
|
||||||
|
|
||||||
/* internal */
|
/* internal */
|
||||||
_TTF_Font *getSdlFont();
|
_TTF_Font *getSdlFont();
|
||||||
|
|
|
@ -169,15 +169,15 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t)
|
void requestViewportRender(const Vec4 &c, const Vec4 &f, const Vec4 &t)
|
||||||
{
|
{
|
||||||
const IntRect &viewpRect = glState.scissorBox.get();
|
const IntRect &viewpRect = glState.scissorBox.get();
|
||||||
const IntRect &screenRect = geometry.rect;
|
const IntRect &screenRect = geometry.rect;
|
||||||
|
|
||||||
bool toneRGBEffect = t.xyzHasEffect();
|
const bool toneRGBEffect = t.xyzNotNull();
|
||||||
bool toneGrayEffect = t.w != 0;
|
const bool toneGrayEffect = t.w != 0;
|
||||||
bool colorEffect = c.w > 0;
|
const bool colorEffect = c.w > 0;
|
||||||
bool flashEffect = f.w > 0;
|
const bool flashEffect = f.w > 0;
|
||||||
|
|
||||||
if (toneGrayEffect)
|
if (toneGrayEffect)
|
||||||
{
|
{
|
||||||
|
@ -240,7 +240,7 @@ public:
|
||||||
/* Then apply them using hardware blending */
|
/* Then apply them using hardware blending */
|
||||||
gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE);
|
gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE);
|
||||||
|
|
||||||
if (add.xyzHasEffect())
|
if (add.xyzNotNull())
|
||||||
{
|
{
|
||||||
gl.BlendEquation(GL_FUNC_ADD);
|
gl.BlendEquation(GL_FUNC_ADD);
|
||||||
shader.setColor(add);
|
shader.setColor(add);
|
||||||
|
@ -248,7 +248,7 @@ public:
|
||||||
screenQuad.draw();
|
screenQuad.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sub.xyzHasEffect())
|
if (sub.xyzNotNull())
|
||||||
{
|
{
|
||||||
gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||||
shader.setColor(sub);
|
shader.setColor(sub);
|
||||||
|
@ -281,9 +281,9 @@ public:
|
||||||
|
|
||||||
void setBrightness(float norm)
|
void setBrightness(float norm)
|
||||||
{
|
{
|
||||||
brightnessQuad.setColor(Vec4(0, 0, 0, 1.0 - norm));
|
brightnessQuad.setColor(Vec4(0, 0, 0, 1.0f - norm));
|
||||||
|
|
||||||
brightEffect = norm < 1.0;
|
brightEffect = norm < 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateReso(int width, int height)
|
void updateReso(int width, int height)
|
||||||
|
@ -742,7 +742,7 @@ void Graphics::transition(int duration,
|
||||||
shader.setFrozenScene(p->frozenScene.tex);
|
shader.setFrozenScene(p->frozenScene.tex);
|
||||||
shader.setCurrentScene(p->currentScene.tex);
|
shader.setCurrentScene(p->currentScene.tex);
|
||||||
shader.setTransMap(transMap->getGLTypes().tex);
|
shader.setTransMap(transMap->getGLTypes().tex);
|
||||||
shader.setVague(vague / 256.0);
|
shader.setVague(vague / 256.0f);
|
||||||
shader.setTexSize(p->scRes);
|
shader.setTexSize(p->scRes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -780,7 +780,7 @@ void Graphics::transition(int duration,
|
||||||
|
|
||||||
p->checkSyncLock();
|
p->checkSyncLock();
|
||||||
|
|
||||||
const float prog = i * (1.0 / duration);
|
const float prog = i * (1.0f / duration);
|
||||||
|
|
||||||
if (transMap)
|
if (transMap)
|
||||||
{
|
{
|
||||||
|
@ -858,7 +858,7 @@ void Graphics::fadeout(int duration)
|
||||||
FBO::unbind();
|
FBO::unbind();
|
||||||
|
|
||||||
float curr = p->brightness;
|
float curr = p->brightness;
|
||||||
float diff = 255.0 - curr;
|
float diff = 255.0f - curr;
|
||||||
|
|
||||||
for (int i = duration-1; i > -1; --i)
|
for (int i = duration-1; i > -1; --i)
|
||||||
{
|
{
|
||||||
|
@ -888,7 +888,7 @@ void Graphics::fadein(int duration)
|
||||||
FBO::unbind();
|
FBO::unbind();
|
||||||
|
|
||||||
float curr = p->brightness;
|
float curr = p->brightness;
|
||||||
float diff = 255.0 - curr;
|
float diff = 255.0f - curr;
|
||||||
|
|
||||||
for (int i = 1; i <= duration; ++i)
|
for (int i = 1; i <= duration; ++i)
|
||||||
{
|
{
|
||||||
|
@ -963,6 +963,11 @@ void Graphics::resizeScreen(int width, int height)
|
||||||
shState->eThread().requestWindowResize(width, height);
|
shState->eThread().requestWindowResize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Graphics::playMovie(const char *filename)
|
||||||
|
{
|
||||||
|
Debug() << "Graphics.playMovie(" << filename << ") not implemented";
|
||||||
|
}
|
||||||
|
|
||||||
DEF_ATTR_RD_SIMPLE(Graphics, Brightness, int, p->brightness)
|
DEF_ATTR_RD_SIMPLE(Graphics, Brightness, int, p->brightness)
|
||||||
|
|
||||||
void Graphics::setBrightness(int value)
|
void Graphics::setBrightness(int value)
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
int width() const;
|
int width() const;
|
||||||
int height() const;
|
int height() const;
|
||||||
void resizeScreen(int width, int height);
|
void resizeScreen(int width, int height);
|
||||||
|
void playMovie(const char *filename);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
|
|
@ -320,7 +320,7 @@ readEvent(MidiReadHandler *handler, MemChunk &chunk,
|
||||||
| (data[2] << 0x00);
|
| (data[2] << 0x00);
|
||||||
|
|
||||||
e.type = Tempo;
|
e.type = Tempo;
|
||||||
e.e.tempo.bpm = 60000000.0 / mpqn;
|
e.e.tempo.bpm = 60000000 / mpqn;
|
||||||
}
|
}
|
||||||
else if (metaType == 0x2F)
|
else if (metaType == 0x2F)
|
||||||
{
|
{
|
||||||
|
@ -626,9 +626,20 @@ struct MidiSource : ALDataSource, MidiReadHandler
|
||||||
std::vector<uint8_t> data(dataLen);
|
std::vector<uint8_t> data(dataLen);
|
||||||
|
|
||||||
if (SDL_RWread(&ops, &data[0], 1, dataLen) < dataLen)
|
if (SDL_RWread(&ops, &data[0], 1, dataLen) < dataLen)
|
||||||
|
{
|
||||||
|
SDL_RWclose(&ops);
|
||||||
throw Exception(Exception::MKXPError, "Reading midi data failed");
|
throw Exception(Exception::MKXPError, "Reading midi data failed");
|
||||||
|
}
|
||||||
|
|
||||||
readMidi(this, data);
|
try
|
||||||
|
{
|
||||||
|
readMidi(this, data);
|
||||||
|
}
|
||||||
|
catch (const Exception &)
|
||||||
|
{
|
||||||
|
SDL_RWclose(&ops);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
synth = shState->midiState().allocateSynth();
|
synth = shState->midiState().allocateSynth();
|
||||||
|
|
||||||
|
@ -688,7 +699,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
|
||||||
|
|
||||||
void updatePlaybackSpeed(uint32_t bpm)
|
void updatePlaybackSpeed(uint32_t bpm)
|
||||||
{
|
{
|
||||||
float deltaLength = 60.0 / (dpb * bpm);
|
float deltaLength = 60.0f / (dpb * bpm);
|
||||||
playbackSpeed = TICK_FRAMES / (deltaLength * freq);
|
playbackSpeed = TICK_FRAMES / (deltaLength * freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,7 +910,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
|
||||||
bool setPitch(float value)
|
bool setPitch(float value)
|
||||||
{
|
{
|
||||||
// not completely correct, but close
|
// not completely correct, but close
|
||||||
pitchShift = round((value > 1.0 ? 14 : 24) * (value - 1.0));
|
pitchShift = round((value > 1.0f ? 14 : 24) * (value - 1.0f));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,8 @@ struct PlanePrivate
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Scaled (zoomed) bitmap dimensions */
|
/* Scaled (zoomed) bitmap dimensions */
|
||||||
double sw = bitmap->width() * zoomX;
|
float sw = bitmap->width() * zoomX;
|
||||||
double sh = bitmap->height() * zoomY;
|
float sh = bitmap->height() * zoomY;
|
||||||
|
|
||||||
/* Plane offset wrapped by scaled bitmap dims */
|
/* Plane offset wrapped by scaled bitmap dims */
|
||||||
float wox = fwrap(ox, sw);
|
float wox = fwrap(ox, sw);
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct RGSS_entryData
|
||||||
|
|
||||||
struct RGSS_entryHandle
|
struct RGSS_entryHandle
|
||||||
{
|
{
|
||||||
RGSS_entryData data;
|
const RGSS_entryData data;
|
||||||
uint32_t currentMagic;
|
uint32_t currentMagic;
|
||||||
uint64_t currentOffset;
|
uint64_t currentOffset;
|
||||||
PHYSFS_Io *io;
|
PHYSFS_Io *io;
|
||||||
|
@ -229,7 +229,7 @@ RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset)
|
||||||
static PHYSFS_sint64
|
static PHYSFS_sint64
|
||||||
RGSS_ioTell(PHYSFS_Io *self)
|
RGSS_ioTell(PHYSFS_Io *self)
|
||||||
{
|
{
|
||||||
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
|
const RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
|
||||||
|
|
||||||
return entry->currentOffset;
|
return entry->currentOffset;
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ RGSS_ioTell(PHYSFS_Io *self)
|
||||||
static PHYSFS_sint64
|
static PHYSFS_sint64
|
||||||
RGSS_ioLength(PHYSFS_Io *self)
|
RGSS_ioLength(PHYSFS_Io *self)
|
||||||
{
|
{
|
||||||
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
|
const RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
|
||||||
|
|
||||||
return entry->data.size;
|
return entry->data.size;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ RGSS_ioLength(PHYSFS_Io *self)
|
||||||
static PHYSFS_Io*
|
static PHYSFS_Io*
|
||||||
RGSS_ioDuplicate(PHYSFS_Io *self)
|
RGSS_ioDuplicate(PHYSFS_Io *self)
|
||||||
{
|
{
|
||||||
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
|
const RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
|
||||||
RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry);
|
RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry);
|
||||||
|
|
||||||
PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io);
|
PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io);
|
||||||
|
@ -448,7 +448,7 @@ RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
|
||||||
|
|
||||||
if (hasFile)
|
if (hasFile)
|
||||||
{
|
{
|
||||||
RGSS_entryData &entry = data->entryHash[filename];
|
const RGSS_entryData &entry = data->entryHash[filename];
|
||||||
|
|
||||||
stat->filesize = entry.size;
|
stat->filesize = entry.size;
|
||||||
stat->filetype = PHYSFS_FILETYPE_REGULAR;
|
stat->filetype = PHYSFS_FILETYPE_REGULAR;
|
||||||
|
|
|
@ -55,7 +55,9 @@ public:
|
||||||
virtual ~Scene();
|
virtual ~Scene();
|
||||||
|
|
||||||
virtual void composite();
|
virtual void composite();
|
||||||
virtual void requestViewportRender(Vec4& /*color*/, Vec4& /*flash*/, Vec4& /*tone*/) {}
|
virtual void requestViewportRender(const Vec4& /* color */,
|
||||||
|
const Vec4& /* flash */,
|
||||||
|
const Vec4& /* tone */) {}
|
||||||
|
|
||||||
const Geometry &getGeometry() const { return geometry; }
|
const Geometry &getGeometry() const { return geometry; }
|
||||||
|
|
||||||
|
|
|
@ -764,13 +764,13 @@ void Widget::click(int x, int y, uint8_t button)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ratio of cell area to total widget width */
|
/* Ratio of cell area to total widget width */
|
||||||
#define BW_CELL_R 0.75
|
#define BW_CELL_R 0.75f
|
||||||
|
|
||||||
void BindingWidget::drawHandler(SDL_Surface *surf)
|
void BindingWidget::drawHandler(SDL_Surface *surf)
|
||||||
{
|
{
|
||||||
const int cellW = (rect.w*BW_CELL_R) / 2;
|
const int cellW = (rect.w*BW_CELL_R) / 2;
|
||||||
const int cellH = rect.h / 2;
|
const int cellH = rect.h / 2;
|
||||||
const int cellOffX = (1.0-BW_CELL_R) * rect.w;
|
const int cellOffX = (1.0f-BW_CELL_R) * rect.w;
|
||||||
|
|
||||||
const int cellOff[] =
|
const int cellOff[] =
|
||||||
{
|
{
|
||||||
|
@ -860,7 +860,7 @@ int BindingWidget::cellIndex(int x, int y) const
|
||||||
{
|
{
|
||||||
const int cellW = (rect.w*BW_CELL_R) / 2;
|
const int cellW = (rect.w*BW_CELL_R) / 2;
|
||||||
const int cellH = rect.h / 2;
|
const int cellH = rect.h / 2;
|
||||||
const int cellOff = (1.0-BW_CELL_R) * rect.w;
|
const int cellOff = (1.0f-BW_CELL_R) * rect.w;
|
||||||
|
|
||||||
if (x < cellOff)
|
if (x < cellOff)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -80,7 +80,7 @@ struct SharedMidiState
|
||||||
return;
|
return;
|
||||||
|
|
||||||
flSettings = fluid.new_settings();
|
flSettings = fluid.new_settings();
|
||||||
fluid.settings_setnum(flSettings, "synth.gain", 1.0);
|
fluid.settings_setnum(flSettings, "synth.gain", 1.0f);
|
||||||
fluid.settings_setnum(flSettings, "synth.sample-rate", SYNTH_SAMPLERATE);
|
fluid.settings_setnum(flSettings, "synth.sample-rate", SYNTH_SAMPLERATE);
|
||||||
fluid.settings_setstr(flSettings, "synth.chorus.active", conf.midi.chorus ? "yes" : "no");
|
fluid.settings_setstr(flSettings, "synth.chorus.active", conf.midi.chorus ? "yes" : "no");
|
||||||
fluid.settings_setstr(flSettings, "synth.reverb.active", conf.midi.reverb ? "yes" : "no");
|
fluid.settings_setstr(flSettings, "synth.reverb.active", conf.midi.reverb ? "yes" : "no");
|
||||||
|
|
|
@ -172,7 +172,6 @@ void SharedState::initInstance(RGSSThreadData *threadData)
|
||||||
* Font depends on SharedState existing */
|
* Font depends on SharedState existing */
|
||||||
|
|
||||||
rgssVersion = threadData->config.rgssVersion;
|
rgssVersion = threadData->config.rgssVersion;
|
||||||
Font::initDefaults();
|
|
||||||
|
|
||||||
_globalIBO = new GlobalIBO();
|
_globalIBO = new GlobalIBO();
|
||||||
_globalIBO->ensureSize(1);
|
_globalIBO->ensureSize(1);
|
||||||
|
@ -183,6 +182,7 @@ void SharedState::initInstance(RGSSThreadData *threadData)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SharedState::instance = new SharedState(threadData);
|
SharedState::instance = new SharedState(threadData);
|
||||||
|
Font::initDefaults(instance->p->fontState);
|
||||||
defaultFont = new Font();
|
defaultFont = new Font();
|
||||||
}
|
}
|
||||||
catch (const Exception &exc)
|
catch (const Exception &exc)
|
||||||
|
|
|
@ -123,8 +123,8 @@ void SoundEmitter::play(const std::string &filename,
|
||||||
int volume,
|
int volume,
|
||||||
int pitch)
|
int pitch)
|
||||||
{
|
{
|
||||||
float _volume = clamp<int>(volume, 0, 100) / 100.f;
|
float _volume = clamp<int>(volume, 0, 100) / 100.0f;
|
||||||
float _pitch = clamp<int>(pitch, 50, 150) / 100.f;
|
float _pitch = clamp<int>(pitch, 50, 150) / 100.0f;
|
||||||
|
|
||||||
SoundBuffer *buffer = allocateBuffer(filename);
|
SoundBuffer *buffer = allocateBuffer(filename);
|
||||||
|
|
||||||
|
@ -184,6 +184,44 @@ void SoundEmitter::stop()
|
||||||
AL::Source::stop(alSrcs[i]);
|
AL::Source::stop(alSrcs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SoundOpenHandler : FileSystem::OpenHandler
|
||||||
|
{
|
||||||
|
SoundBuffer *buffer;
|
||||||
|
|
||||||
|
SoundOpenHandler()
|
||||||
|
: buffer(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool tryRead(SDL_RWops &ops, const char *ext)
|
||||||
|
{
|
||||||
|
Sound_Sample *sample = Sound_NewSample(&ops, ext, 0, STREAM_BUF_SIZE);
|
||||||
|
|
||||||
|
if (!sample)
|
||||||
|
{
|
||||||
|
SDL_RWclose(&ops);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do all of the decoding in the handler so we don't have
|
||||||
|
* to keep the source ops around */
|
||||||
|
uint32_t decBytes = Sound_DecodeAll(sample);
|
||||||
|
uint8_t sampleSize = formatSampleSize(sample->actual.format);
|
||||||
|
uint32_t sampleCount = decBytes / sampleSize;
|
||||||
|
|
||||||
|
buffer = new SoundBuffer;
|
||||||
|
buffer->bytes = sampleSize * sampleCount;
|
||||||
|
|
||||||
|
ALenum alFormat = chooseALFormat(sampleSize, sample->actual.channels);
|
||||||
|
|
||||||
|
AL::Buffer::uploadData(buffer->alBuffer, alFormat, sample->buffer,
|
||||||
|
buffer->bytes, sample->actual.rate);
|
||||||
|
|
||||||
|
Sound_FreeSample(sample);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
|
SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
|
||||||
{
|
{
|
||||||
SoundBuffer *buffer = bufferHash.value(filename, 0);
|
SoundBuffer *buffer = bufferHash.value(filename, 0);
|
||||||
|
@ -199,40 +237,22 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Buffer not in cashe, needs to be loaded */
|
/* Buffer not in cache, needs to be loaded */
|
||||||
SDL_RWops dataSource;
|
SoundOpenHandler handler;
|
||||||
char ext[8];
|
shState->fileSystem().openRead(handler, filename.c_str());
|
||||||
|
buffer = handler.buffer;
|
||||||
|
|
||||||
shState->fileSystem().openRead(dataSource, filename.c_str(),
|
if (!buffer)
|
||||||
false, ext, sizeof(ext));
|
|
||||||
|
|
||||||
Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, ext, 0, STREAM_BUF_SIZE);
|
|
||||||
|
|
||||||
if (!sampleHandle)
|
|
||||||
{
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
snprintf(buf, sizeof(buf), "Unable to decode sound: %s.%s: %s",
|
snprintf(buf, sizeof(buf), "Unable to decode sound: %s: %s",
|
||||||
filename.c_str(), ext, Sound_GetError());
|
filename.c_str(), Sound_GetError());
|
||||||
Debug() << buf;
|
Debug() << buf;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t decBytes = Sound_DecodeAll(sampleHandle);
|
|
||||||
uint8_t sampleSize = formatSampleSize(sampleHandle->actual.format);
|
|
||||||
uint32_t sampleCount = decBytes / sampleSize;
|
|
||||||
|
|
||||||
buffer = new SoundBuffer;
|
|
||||||
buffer->key = filename;
|
buffer->key = filename;
|
||||||
buffer->bytes = sampleSize * sampleCount;
|
|
||||||
|
|
||||||
ALenum alFormat = chooseALFormat(sampleSize, sampleHandle->actual.channels);
|
|
||||||
|
|
||||||
AL::Buffer::uploadData(buffer->alBuffer, alFormat, sampleHandle->buffer,
|
|
||||||
buffer->bytes, sampleHandle->actual.rate);
|
|
||||||
|
|
||||||
Sound_FreeSample(sampleHandle);
|
|
||||||
|
|
||||||
uint32_t wouldBeBytes = bufferBytes + buffer->bytes;
|
uint32_t wouldBeBytes = bufferBytes + buffer->bytes;
|
||||||
|
|
||||||
/* If memory limit is reached, delete lowest priority buffer
|
/* If memory limit is reached, delete lowest priority buffer
|
||||||
|
|
|
@ -109,7 +109,7 @@ struct SpritePrivate
|
||||||
wave.amp = 0;
|
wave.amp = 0;
|
||||||
wave.length = 180;
|
wave.length = 180;
|
||||||
wave.speed = 360;
|
wave.speed = 360;
|
||||||
wave.phase = 0.0;
|
wave.phase = 0.0f;
|
||||||
wave.dirty = false;
|
wave.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ struct SpritePrivate
|
||||||
(srcRect->y + srcRect->height) +
|
(srcRect->y + srcRect->height) +
|
||||||
bitmap->height();
|
bitmap->height();
|
||||||
|
|
||||||
efBushDepth = 1.0 - texBushDepth / bitmap->height();
|
efBushDepth = 1.0f - texBushDepth / bitmap->height();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSrcRectChange()
|
void onSrcRectChange()
|
||||||
|
@ -194,7 +194,7 @@ struct SpritePrivate
|
||||||
void emitWaveChunk(SVertex *&vert, float phase, int width,
|
void emitWaveChunk(SVertex *&vert, float phase, int width,
|
||||||
float zoomY, int chunkY, int chunkLength)
|
float zoomY, int chunkY, int chunkLength)
|
||||||
{
|
{
|
||||||
float wavePos = phase + (chunkY / (float) wave.length) * M_PI * 2;
|
float wavePos = phase + (chunkY / (float) wave.length) * (float) (M_PI * 2);
|
||||||
float chunkX = sin(wavePos) * wave.amp;
|
float chunkX = sin(wavePos) * wave.amp;
|
||||||
|
|
||||||
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
|
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
|
||||||
|
@ -261,7 +261,7 @@ struct SpritePrivate
|
||||||
wave.qArray.resize(!!firstLength + chunks + !!lastLength);
|
wave.qArray.resize(!!firstLength + chunks + !!lastLength);
|
||||||
SVertex *vert = &wave.qArray.vertices[0];
|
SVertex *vert = &wave.qArray.vertices[0];
|
||||||
|
|
||||||
float phase = (wave.phase * M_PI) / 180.f;
|
float phase = (wave.phase * (float) M_PI) / 180.0f;
|
||||||
|
|
||||||
if (firstLength > 0)
|
if (firstLength > 0)
|
||||||
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
|
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
|
||||||
|
|
|
@ -51,14 +51,14 @@ extern const int autotileVXRectsBN;
|
||||||
/* Waterfall (C) autotile patterns */
|
/* Waterfall (C) autotile patterns */
|
||||||
static const StaticRect autotileVXRectsC[] =
|
static const StaticRect autotileVXRectsC[] =
|
||||||
{
|
{
|
||||||
{ 32.5, 0.5, 15, 31 },
|
{ 32.5f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 16.5, 0.5, 15, 31 },
|
{ 16.5f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 0.0, 0.5, 15, 31 },
|
{ 0.0f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 16.5, 0.5, 15, 31 },
|
{ 16.5f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 32.5, 0.5, 15, 31 },
|
{ 32.5f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 48.5, 0.5, 15, 31 },
|
{ 48.5f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 0.0, 0.5, 15, 31 },
|
{ 0.0f, 0.5f, 15.0f, 31.0f },
|
||||||
{ 48.5, 0.5, 15, 31 }
|
{ 48.5f, 0.5f, 15.0f, 31.0f }
|
||||||
};
|
};
|
||||||
|
|
||||||
static elementsN(autotileVXRectsC);
|
static elementsN(autotileVXRectsC);
|
||||||
|
@ -500,7 +500,7 @@ onTileA4(Reader &reader, int16_t tileID,
|
||||||
Vec2i orig = blitsA4[0].dst;
|
Vec2i orig = blitsA4[0].dst;
|
||||||
tileID -= 0x1700;
|
tileID -= 0x1700;
|
||||||
|
|
||||||
const int offY[] = { 0, 3, 5, 8, 10, 13 };
|
static const int offY[] = { 0, 3, 5, 8, 10, 13 };
|
||||||
|
|
||||||
int patternID = tileID % 0x30;
|
int patternID = tileID % 0x30;
|
||||||
int autotileID = tileID / 0x30;
|
int autotileID = tileID / 0x30;
|
||||||
|
|
|
@ -46,6 +46,13 @@ wrap(int value, int range)
|
||||||
return res < 0 ? res + range : res;
|
return res < 0 ? res + range : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline Vec2i
|
||||||
|
wrap(const Vec2i &value, int range)
|
||||||
|
{
|
||||||
|
return Vec2i(wrap(value.x, range),
|
||||||
|
wrap(value.y, range));
|
||||||
|
}
|
||||||
|
|
||||||
static inline int16_t
|
static inline int16_t
|
||||||
tableGetWrapped(const Table &t, int x, int y, int z = 0)
|
tableGetWrapped(const Table &t, int x, int y, int z = 0)
|
||||||
{
|
{
|
||||||
|
@ -54,6 +61,16 @@ tableGetWrapped(const Table &t, int x, int y, int z = 0)
|
||||||
z);
|
z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate the tile x/y on which this pixel x/y lies */
|
||||||
|
static inline Vec2i
|
||||||
|
getTilePos(const Vec2i &pixelPos)
|
||||||
|
{
|
||||||
|
/* Round the pixel position down to the nearest top left
|
||||||
|
* tile boundary, by masking off the lower 5 bits (2^5 = 32).
|
||||||
|
* Then divide by 32 to convert into tile units. */
|
||||||
|
return (pixelPos & ~(32-1)) / 32;
|
||||||
|
}
|
||||||
|
|
||||||
enum AtSubPos
|
enum AtSubPos
|
||||||
{
|
{
|
||||||
TopLeft = 0,
|
TopLeft = 0,
|
||||||
|
|
|
@ -236,7 +236,7 @@ struct TilemapPrivate
|
||||||
Table *mapData;
|
Table *mapData;
|
||||||
Table *priorities;
|
Table *priorities;
|
||||||
bool visible;
|
bool visible;
|
||||||
Vec2i offset;
|
Vec2i origin;
|
||||||
|
|
||||||
Vec2i dispPos;
|
Vec2i dispPos;
|
||||||
|
|
||||||
|
@ -294,7 +294,6 @@ struct TilemapPrivate
|
||||||
/* Used layers out of 'zlayers' (rest is hidden) */
|
/* Used layers out of 'zlayers' (rest is hidden) */
|
||||||
size_t activeLayers;
|
size_t activeLayers;
|
||||||
Scene::Geometry sceneGeo;
|
Scene::Geometry sceneGeo;
|
||||||
Vec2i sceneOffset;
|
|
||||||
} elem;
|
} elem;
|
||||||
|
|
||||||
/* Affected by: autotiles, tileset */
|
/* Affected by: autotiles, tileset */
|
||||||
|
@ -394,7 +393,7 @@ struct TilemapPrivate
|
||||||
|
|
||||||
void updateFlashMapViewport()
|
void updateFlashMapViewport()
|
||||||
{
|
{
|
||||||
flashMap.setViewport(IntRect(viewpPos.x, viewpPos.y, viewpW, viewpH));
|
flashMap.setViewport(IntRect(viewpPos, Vec2i(viewpW, viewpH)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateAtlasInfo()
|
void updateAtlasInfo()
|
||||||
|
@ -442,13 +441,8 @@ struct TilemapPrivate
|
||||||
|
|
||||||
void updateSceneGeometry(const Scene::Geometry &geo)
|
void updateSceneGeometry(const Scene::Geometry &geo)
|
||||||
{
|
{
|
||||||
elem.sceneOffset = geo.offset();
|
|
||||||
elem.sceneGeo = geo;
|
elem.sceneGeo = geo;
|
||||||
}
|
mapViewportDirty = true;
|
||||||
|
|
||||||
void updatePosition()
|
|
||||||
{
|
|
||||||
dispPos = -(offset - viewpPos * 32) + elem.sceneOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void invalidateAtlasSize()
|
void invalidateAtlasSize()
|
||||||
|
@ -698,7 +692,7 @@ struct TilemapPrivate
|
||||||
int tileY = tsInd / 8;
|
int tileY = tsInd / 8;
|
||||||
|
|
||||||
Vec2i texPos = TileAtlas::tileToAtlasCoor(tileX, tileY, atlas.efTilesetH, atlas.size.y);
|
Vec2i texPos = TileAtlas::tileToAtlasCoor(tileX, tileY, atlas.efTilesetH, atlas.size.y);
|
||||||
FloatRect texRect((float) texPos.x+.5, (float) texPos.y+.5, 31, 31);
|
FloatRect texRect((float) texPos.x+0.5f, (float) texPos.y+0.5f, 31, 31);
|
||||||
FloatRect posRect(x*32, y*32, 32, 32);
|
FloatRect posRect(x*32, y*32, 32, 32);
|
||||||
|
|
||||||
SVertex v[4];
|
SVertex v[4];
|
||||||
|
@ -898,38 +892,17 @@ struct TilemapPrivate
|
||||||
|
|
||||||
void updateMapViewport()
|
void updateMapViewport()
|
||||||
{
|
{
|
||||||
int tileOX, tileOY;
|
const Vec2i combOrigin = origin + elem.sceneGeo.orig;
|
||||||
|
const Vec2i mvpPos = getTilePos(combOrigin);
|
||||||
|
|
||||||
if (offset.x >= 0)
|
if (mvpPos != viewpPos)
|
||||||
tileOX = offset.x / 32;
|
|
||||||
else
|
|
||||||
tileOX = -(-(offset.x-31) / 32);
|
|
||||||
|
|
||||||
if (offset.y >= 0)
|
|
||||||
tileOY = offset.y / 32;
|
|
||||||
else
|
|
||||||
tileOY = -(-(offset.y-31) / 32);
|
|
||||||
|
|
||||||
bool dirty = false;
|
|
||||||
|
|
||||||
if (tileOX < viewpPos.x || tileOX + 21 > viewpPos.x + viewpW)
|
|
||||||
{
|
|
||||||
viewpPos.x = tileOX;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tileOY < viewpPos.y || tileOY + 16 > viewpPos.y + viewpH)
|
|
||||||
{
|
|
||||||
viewpPos.y = tileOY;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty)
|
|
||||||
{
|
{
|
||||||
|
viewpPos = mvpPos;
|
||||||
buffersDirty = true;
|
buffersDirty = true;
|
||||||
updateFlashMapViewport();
|
updateFlashMapViewport();
|
||||||
updatePosition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispPos = elem.sceneGeo.rect.pos() - wrap(combOrigin, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare()
|
void prepare()
|
||||||
|
@ -1024,7 +997,6 @@ void GroundLayer::drawInt()
|
||||||
void GroundLayer::onGeometryChange(const Scene::Geometry &geo)
|
void GroundLayer::onGeometryChange(const Scene::Geometry &geo)
|
||||||
{
|
{
|
||||||
p->updateSceneGeometry(geo);
|
p->updateSceneGeometry(geo);
|
||||||
p->updatePosition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLayer::ZLayer(TilemapPrivate *p, Viewport *viewport)
|
ZLayer::ZLayer(TilemapPrivate *p, Viewport *viewport)
|
||||||
|
@ -1072,7 +1044,7 @@ void ZLayer::drawInt()
|
||||||
|
|
||||||
int ZLayer::calculateZ(TilemapPrivate *p, int index)
|
int ZLayer::calculateZ(TilemapPrivate *p, int index)
|
||||||
{
|
{
|
||||||
return 32 * (index + p->viewpPos.y + 1) - p->offset.y;
|
return 32 * (index + p->viewpPos.y + 1) - p->origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLayer::initUpdateZ()
|
void ZLayer::initUpdateZ()
|
||||||
|
@ -1172,8 +1144,8 @@ DEF_ATTR_RD_SIMPLE(Tilemap, MapData, Table*, p->mapData)
|
||||||
DEF_ATTR_RD_SIMPLE(Tilemap, FlashData, Table*, p->flashMap.getData())
|
DEF_ATTR_RD_SIMPLE(Tilemap, FlashData, Table*, p->flashMap.getData())
|
||||||
DEF_ATTR_RD_SIMPLE(Tilemap, Priorities, Table*, p->priorities)
|
DEF_ATTR_RD_SIMPLE(Tilemap, Priorities, Table*, p->priorities)
|
||||||
DEF_ATTR_RD_SIMPLE(Tilemap, Visible, bool, p->visible)
|
DEF_ATTR_RD_SIMPLE(Tilemap, Visible, bool, p->visible)
|
||||||
DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->offset.x)
|
DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->origin.x)
|
||||||
DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->offset.y)
|
DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->origin.y)
|
||||||
|
|
||||||
void Tilemap::setTileset(Bitmap *value)
|
void Tilemap::setTileset(Bitmap *value)
|
||||||
{
|
{
|
||||||
|
@ -1259,11 +1231,10 @@ void Tilemap::setOX(int value)
|
||||||
{
|
{
|
||||||
guardDisposed();
|
guardDisposed();
|
||||||
|
|
||||||
if (p->offset.x == value)
|
if (p->origin.x == value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p->offset.x = value;
|
p->origin.x = value;
|
||||||
p->updatePosition();
|
|
||||||
p->mapViewportDirty = true;
|
p->mapViewportDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1271,11 +1242,10 @@ void Tilemap::setOY(int value)
|
||||||
{
|
{
|
||||||
guardDisposed();
|
guardDisposed();
|
||||||
|
|
||||||
if (p->offset.y == value)
|
if (p->origin.y == value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p->offset.y = value;
|
p->origin.y = value;
|
||||||
p->updatePosition();
|
|
||||||
p->zOrderDirty = true;
|
p->zOrderDirty = true;
|
||||||
p->mapViewportDirty = true;
|
p->mapViewportDirty = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,12 +57,12 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
|
||||||
|
|
||||||
Table *mapData;
|
Table *mapData;
|
||||||
Table *flags;
|
Table *flags;
|
||||||
Vec2i offset;
|
Vec2i origin;
|
||||||
|
|
||||||
Vec2i dispPos;
|
/* Subregion of the map that is drawn to screen (map viewport) */
|
||||||
/* Map viewport position */
|
|
||||||
IntRect mapViewp;
|
IntRect mapViewp;
|
||||||
Vec2i sceneOffset;
|
/* Position on screen the map subregion is drawn at */
|
||||||
|
Vec2i dispPos;
|
||||||
Scene::Geometry sceneGeo;
|
Scene::Geometry sceneGeo;
|
||||||
|
|
||||||
std::vector<SVertex> groundVert;
|
std::vector<SVertex> groundVert;
|
||||||
|
@ -179,49 +179,31 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
|
||||||
TileAtlasVX::build(atlas, bitmaps);
|
TileAtlasVX::build(atlas, bitmaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updatePosition()
|
|
||||||
{
|
|
||||||
dispPos.x = -(offset.x - mapViewp.x * 32) + sceneOffset.x;
|
|
||||||
dispPos.y = -(offset.y - mapViewp.y * 32) + sceneOffset.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateMapViewport()
|
void updateMapViewport()
|
||||||
{
|
{
|
||||||
int tileOX, tileOY;
|
/* Note: We include one extra row at the top above
|
||||||
|
* the normal map viewport to ensure the legs of table
|
||||||
|
* tiles off screen are properly drawn */
|
||||||
|
|
||||||
Vec2i offs(offset.x-sceneOffset.x, offset.y-sceneOffset.y);
|
IntRect newMvp;
|
||||||
|
|
||||||
if (offs.x >= 0)
|
const Vec2i combOrigin = origin + sceneGeo.orig;
|
||||||
tileOX = offs.x / 32;
|
const Vec2i geoSize = sceneGeo.rect.size();
|
||||||
else
|
|
||||||
tileOX = -(-(offs.x-31) / 32);
|
|
||||||
|
|
||||||
if (offs.y >= 0)
|
newMvp.setPos(getTilePos(combOrigin) - Vec2i(0, 1));
|
||||||
tileOY = offs.y / 32;
|
|
||||||
else
|
|
||||||
tileOY = -(-(offs.y-31) / 32);
|
|
||||||
|
|
||||||
bool dirty = false;
|
/* Ensure that the size is big enough to cover the whole viewport,
|
||||||
|
* and add one tile row/column as a buffer for scrolling */
|
||||||
|
newMvp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1, 2));
|
||||||
|
|
||||||
if (tileOX < mapViewp.x || tileOX > mapViewp.x)
|
if (newMvp != mapViewp)
|
||||||
{
|
|
||||||
mapViewp.x = tileOX;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tileOY < mapViewp.y || tileOY > mapViewp.y)
|
|
||||||
{
|
|
||||||
mapViewp.y = tileOY;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty)
|
|
||||||
{
|
{
|
||||||
|
mapViewp = newMvp;
|
||||||
|
flashMap.setViewport(newMvp);
|
||||||
buffersDirty = true;
|
buffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition();
|
dispPos = sceneGeo.rect.pos() - wrap(combOrigin, 32) - Vec2i(0, 32);
|
||||||
flashMap.setViewport(mapViewp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t quadBytes(size_t quads)
|
static size_t quadBytes(size_t quads)
|
||||||
|
@ -366,10 +348,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
|
||||||
|
|
||||||
void onGeometryChange(const Scene::Geometry &geo)
|
void onGeometryChange(const Scene::Geometry &geo)
|
||||||
{
|
{
|
||||||
const Vec2i geoSize = geo.rect.size();
|
|
||||||
mapViewp.setSize((geoSize / 32) + !!(geoSize % 32) + Vec2i(1));
|
|
||||||
|
|
||||||
sceneOffset = geo.offset();
|
|
||||||
sceneGeo = geo;
|
sceneGeo = geo;
|
||||||
|
|
||||||
buffersDirty = true;
|
buffersDirty = true;
|
||||||
|
@ -380,7 +358,7 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader
|
||||||
|
|
||||||
/* TileAtlasVX::Reader */
|
/* TileAtlasVX::Reader */
|
||||||
void onQuads(const FloatRect *t, const FloatRect *p,
|
void onQuads(const FloatRect *t, const FloatRect *p,
|
||||||
size_t n, bool overPlayer)
|
size_t n, bool overPlayer)
|
||||||
{
|
{
|
||||||
SVertex *vert = allocVert(overPlayer ? aboveVert : groundVert, n*4);
|
SVertex *vert = allocVert(overPlayer ? aboveVert : groundVert, n*4);
|
||||||
|
|
||||||
|
@ -467,8 +445,8 @@ TilemapVX::BitmapArray &TilemapVX::getBitmapArray()
|
||||||
DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData)
|
DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData)
|
||||||
DEF_ATTR_RD_SIMPLE(TilemapVX, FlashData, Table*, p->flashMap.getData())
|
DEF_ATTR_RD_SIMPLE(TilemapVX, FlashData, Table*, p->flashMap.getData())
|
||||||
DEF_ATTR_RD_SIMPLE(TilemapVX, Flags, Table*, p->flags)
|
DEF_ATTR_RD_SIMPLE(TilemapVX, Flags, Table*, p->flags)
|
||||||
DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->offset.x)
|
DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->origin.x)
|
||||||
DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->offset.y)
|
DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->origin.y)
|
||||||
|
|
||||||
Viewport *TilemapVX::getViewport() const
|
Viewport *TilemapVX::getViewport() const
|
||||||
{
|
{
|
||||||
|
@ -541,10 +519,10 @@ void TilemapVX::setOX(int value)
|
||||||
{
|
{
|
||||||
guardDisposed();
|
guardDisposed();
|
||||||
|
|
||||||
if (p->offset.x == value)
|
if (p->origin.x == value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p->offset.x = value;
|
p->origin.x = value;
|
||||||
p->mapViewportDirty = true;
|
p->mapViewportDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,10 +530,10 @@ void TilemapVX::setOY(int value)
|
||||||
{
|
{
|
||||||
guardDisposed();
|
guardDisposed();
|
||||||
|
|
||||||
if (p->offset.y == value)
|
if (p->origin.y == value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
p->offset.y = value;
|
p->origin.y = value;
|
||||||
p->mapViewportDirty = true;
|
p->mapViewportDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ private:
|
||||||
if (rotation < 0)
|
if (rotation < 0)
|
||||||
rotation += 360;
|
rotation += 360;
|
||||||
|
|
||||||
float angle = rotation * 3.141592654f / 180.f;
|
float angle = rotation * 3.141592654f / 180.0f;
|
||||||
float cosine = (float) cos(angle);
|
float cosine = (float) cos(angle);
|
||||||
float sine = (float) sin(angle);
|
float sine = (float) sin(angle);
|
||||||
float sxc = scale.x * cosine;
|
float sxc = scale.x * cosine;
|
||||||
|
|
|
@ -642,7 +642,7 @@ struct WindowPrivate
|
||||||
|
|
||||||
if (active && cursorVert.vert)
|
if (active && cursorVert.vert)
|
||||||
{
|
{
|
||||||
float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0;
|
float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0f;
|
||||||
|
|
||||||
cursorVert.setAlpha(alpha);
|
cursorVert.setAlpha(alpha);
|
||||||
|
|
||||||
|
@ -651,7 +651,7 @@ struct WindowPrivate
|
||||||
|
|
||||||
if (pause && pauseAniVert.vert)
|
if (pause && pauseAniVert.vert)
|
||||||
{
|
{
|
||||||
float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0;
|
float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0f;
|
||||||
FloatRect frameRect = pauseAniSrc[pauseAniQuad[pauseAniQuadIdx]];
|
FloatRect frameRect = pauseAniSrc[pauseAniQuad[pauseAniQuadIdx]];
|
||||||
|
|
||||||
pauseAniVert.setAlpha(alpha);
|
pauseAniVert.setAlpha(alpha);
|
||||||
|
|
|
@ -482,7 +482,7 @@ struct WindowVXPrivate
|
||||||
void updateBaseQuad()
|
void updateBaseQuad()
|
||||||
{
|
{
|
||||||
const FloatRect tex(0, 0, geo.w, geo.h);
|
const FloatRect tex(0, 0, geo.w, geo.h);
|
||||||
const FloatRect pos(0, (geo.h / 2.0) * (1 - openness.norm),
|
const FloatRect pos(0, (geo.h / 2.0f) * (1.0f - openness.norm),
|
||||||
geo.w, geo.h * openness.norm);
|
geo.w, geo.h * openness.norm);
|
||||||
|
|
||||||
base.quad.setTexPosRect(tex, pos);
|
base.quad.setTexPosRect(tex, pos);
|
||||||
|
@ -633,7 +633,7 @@ struct WindowVXPrivate
|
||||||
Quad::setTexRect(pauseVert, pauseSrc[pauseQuad[pauseQuadIdx]]);
|
Quad::setTexRect(pauseVert, pauseSrc[pauseQuad[pauseQuadIdx]]);
|
||||||
|
|
||||||
/* Set opacity */
|
/* Set opacity */
|
||||||
Quad::setColor(pauseVert, Vec4(1, 1, 1, pauseAlpha[pauseAlphaIdx] / 255.0));
|
Quad::setColor(pauseVert, Vec4(1, 1, 1, pauseAlpha[pauseAlphaIdx] / 255.0f));
|
||||||
|
|
||||||
ctrlVertArrayDirty = true;
|
ctrlVertArrayDirty = true;
|
||||||
}
|
}
|
||||||
|
@ -643,7 +643,7 @@ struct WindowVXPrivate
|
||||||
if (cursorVert.count() == 0)
|
if (cursorVert.count() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Vec4 color(1, 1, 1, cursorAlpha[cursorAlphaIdx] / 255.0);
|
Vec4 color(1, 1, 1, cursorAlpha[cursorAlphaIdx] / 255.0f);
|
||||||
|
|
||||||
for (size_t i = 0; i < cursorVert.count(); ++i)
|
for (size_t i = 0; i < cursorVert.count(); ++i)
|
||||||
Quad::setColor(&cursorVert.vertices[i*4], color);
|
Quad::setColor(&cursorVert.vertices[i*4], color);
|
||||||
|
|
Loading…
Reference in New Issue