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

This commit is contained in:
Jonas Kulla 2016-02-25 17:30:01 +01:00
commit d9f13c39e9
38 changed files with 792 additions and 686 deletions

View File

@ -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

View File

@ -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)
{ {

View File

@ -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);
}
} }

View File

@ -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" );
} }

View File

@ -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" );

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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,23 +199,34 @@ void ALStream::closeSource()
delete source; delete source;
} }
void ALStream::openSource(const std::string &filename) struct ALStreamOpenHandler : FileSystem::OpenHandler
{ {
char ext[8]; SDL_RWops *srcOps;
shState->fileSystem().openRead(srcOps, filename.c_str(), false, ext, sizeof(ext)); bool looped;
needsRewind.clear(); 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 */ /* Try to read ogg file signature */
char sig[5] = { 0 }; char sig[5] = { 0 };
SDL_RWread(&srcOps, sig, 1, 4); SDL_RWread(srcOps, sig, 1, 4);
SDL_RWseek(&srcOps, 0, RW_SEEK_SET); SDL_RWseek(srcOps, 0, RW_SEEK_SET);
try try
{ {
if (!strcmp(sig, "OggS")) if (!strcmp(sig, "OggS"))
{ {
source = createVorbisSource(srcOps, looped); source = createVorbisSource(*srcOps, looped);
return; return true;
} }
if (!strcmp(sig, "MThd")) if (!strcmp(sig, "MThd"))
@ -224,18 +235,37 @@ void ALStream::openSource(const std::string &filename)
if (HAVE_FLUID) if (HAVE_FLUID)
{ {
source = createMidiSource(srcOps, looped); source = createMidiSource(*srcOps, looped);
return; return true;
} }
} }
source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped); source = createSDLSource(*srcOps, ext, STREAM_BUF_SIZE, looped);
} }
catch (const Exception &e) 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)
{
ALStreamOpenHandler handler(srcOps, looped);
shState->fileSystem().openRead(handler, filename.c_str());
source = handler.source;
needsRewind.clear();
if (!source)
{ {
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;
} }

View File

@ -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;
} }

View File

@ -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;

View File

@ -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

View File

@ -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) \

View File

@ -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;

View File

@ -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

View File

@ -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";

View File

@ -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,22 +250,12 @@ strcpySafe(char *dst, const char *src,
return cpyMax; return cpyMax;
} }
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10; /* Attempt to locate an extension string in a filename.
struct FileSystemPrivate
{
/* Maps: lower case filepath without extension,
* To: mixed case full filepath
* This is for compatibility with games that take Windows'
* case insensitivity for granted */
BoostHash<std::string, std::string> pathCache;
bool havePathCache;
/* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the * Either a pointer into the input string pointing at the
* extension, or null is returned */ * extension, or null is returned */
const char *findExt(const char *filename) static const char *
{ findExt(const char *filename)
{
size_t len; size_t len;
for (len = strlen(filename); len > 0; --len) for (len = strlen(filename); len > 0; --len)
@ -277,160 +268,13 @@ struct FileSystemPrivate
} }
return 0; return 0;
} }
struct CompleteFilenameData static void
{ initReadOps(PHYSFS_File *handle,
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, SDL_RWops &ops,
bool freeOnClose) bool freeOnClose)
{ {
ops.size = SDL_RWopsSize; ops.size = SDL_RWopsSize;
ops.seek = SDL_RWopsSeek; ops.seek = SDL_RWopsSeek;
ops.read = SDL_RWopsRead; ops.read = SDL_RWopsRead;
@ -443,7 +287,28 @@ struct FileSystemPrivate
ops.type = SDL_RWOPS_PHYSFS; ops.type = SDL_RWOPS_PHYSFS;
ops.hidden.unknown.data1 = handle; 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;
struct FileSystemPrivate
{
/* Maps: lower case full filepath,
* To: mixed case full filepath */
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;
}; };
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));
} }

View File

@ -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:

View File

@ -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);
} }

View File

@ -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,15 +65,16 @@ 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 )
@ -95,7 +83,6 @@ public:
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 )
@ -104,13 +91,25 @@ public:
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
* (ie. only to be used in GCed language bindings) */ * (ie. only to be used in GCed language bindings) */
void initDynAttribs(); void initDynAttribs();
static void initDefaultDynAttribs(); static void initDefaultDynAttribs();
static void initDefaults(); static void initDefaults(const SharedFontState &sfs);
/* internal */ /* internal */
_TTF_Font *getSdlFont(); _TTF_Font *getSdlFont();

View File

@ -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)

View File

@ -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();

View File

@ -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");
}
try
{
readMidi(this, data); 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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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; }

View File

@ -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;

View File

@ -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");

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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;
} }

View File

@ -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;
@ -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;
} }

View File

@ -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;

View File

@ -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);

View File

@ -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);