diff --git a/README.md b/README.md index fede712..d9f9c09 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ Matz's Ruby Interpreter, also called CRuby, is the most widely deployed version For a list of differences, see: 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) 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. +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. ### null diff --git a/binding-mri/filesystem-binding.cpp b/binding-mri/filesystem-binding.cpp index 17cf50d..4bc5e03 100644 --- a/binding-mri/filesystem-binding.cpp +++ b/binding-mri/filesystem-binding.cpp @@ -46,7 +46,7 @@ fileIntForPath(const char *path, bool rubyExc) try { - shState->fileSystem().openRead(*ops, path); + shState->fileSystem().openReadRaw(*ops, path); } catch (const Exception &e) { diff --git a/binding-mri/font-binding.cpp b/binding-mri/font-binding.cpp index 2a8856a..9a6e264 100644 --- a/binding-mri/font-binding.cpp +++ b/binding-mri/font-binding.cpp @@ -27,6 +27,29 @@ #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); RB_METHOD(fontDoesExist) @@ -48,12 +71,30 @@ RB_METHOD(FontSetName); RB_METHOD(fontInitialize) { - VALUE name = Qnil; + VALUE namesObj = Qnil; 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); @@ -65,13 +106,6 @@ RB_METHOD(fontInitialize) if (rgssVer >= 3) 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; } @@ -105,57 +139,17 @@ RB_METHOD(FontGetName) 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) { Font *f = getPrivateData<Font>(self); - char result[256]; - fontSetNameHelper(self, argc, argv, "name", - result, sizeof(result)); + rb_check_argc(argc, 1); - 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]; } @@ -223,11 +217,15 @@ RB_METHOD(FontGetDefaultName) RB_METHOD(FontSetDefaultName) { - char result[256]; - fontSetNameHelper(self, argc, argv, "default_name", - result, sizeof(result)); + RB_UNUSED_PARAM; - 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]; } @@ -267,7 +265,24 @@ fontBindingInit() Font::initDefaultDynAttribs(); 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) wrapProperty(klass, &Font::getDefaultOutColor(), "default_out_color", ColorType); @@ -310,14 +325,4 @@ fontBindingInit() INIT_PROP_BIND(Font, Outline, "outline"); 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); - } } diff --git a/binding-mri/graphics-binding.cpp b/binding-mri/graphics-binding.cpp index a585e17..6b39697 100644 --- a/binding-mri/graphics-binding.cpp +++ b/binding-mri/graphics-binding.cpp @@ -183,6 +183,18 @@ RB_METHOD(graphicsReset) 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(FrameCount) DEF_GRA_PROP_I(Brightness) @@ -223,6 +235,11 @@ void graphicsBindingInit() 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( ShowCursor, "show_cursor" ); } diff --git a/binding-mri/sprite-binding.cpp b/binding-mri/sprite-binding.cpp index 2404e4a..dc7f902 100644 --- a/binding-mri/sprite-binding.cpp +++ b/binding-mri/sprite-binding.cpp @@ -56,6 +56,7 @@ DEF_PROP_I(Sprite, Y) DEF_PROP_I(Sprite, OX) DEF_PROP_I(Sprite, OY) DEF_PROP_I(Sprite, BushDepth) +DEF_PROP_I(Sprite, BushOpacity) DEF_PROP_I(Sprite, Opacity) DEF_PROP_I(Sprite, BlendType) DEF_PROP_I(Sprite, WaveAmp) @@ -126,6 +127,8 @@ spriteBindingInit() _rb_define_method(klass, "width", spriteWidth); _rb_define_method(klass, "height", spriteHeight); + INIT_PROP_BIND( Sprite, BushOpacity, "bush_opacity" ); + INIT_PROP_BIND( Sprite, WaveAmp, "wave_amp" ); INIT_PROP_BIND( Sprite, WaveLength, "wave_length" ); INIT_PROP_BIND( Sprite, WaveSpeed, "wave_speed" ); diff --git a/binding-mruby/binding-mruby.cpp b/binding-mruby/binding-mruby.cpp index f895de3..867d2d6 100644 --- a/binding-mruby/binding-mruby.cpp +++ b/binding-mruby/binding-mruby.cpp @@ -266,7 +266,7 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx) mrb_state *scriptMrb = mrb_open(); SDL_RWops ops; - shState->fileSystem().openRead(ops, scriptPack.c_str()); + shState->fileSystem().openReadRaw(ops, scriptPack.c_str()); mrb_value scriptArray = mrb_nil_value(); std::string readError; diff --git a/mkxp.conf.sample b/mkxp.conf.sample index e128755..b88f216 100644 --- a/mkxp.conf.sample +++ b/mkxp.conf.sample @@ -57,9 +57,9 @@ # Apply linear interpolation when game screen # is upscaled -# (default: disabled) +# (default: enabled) # -# smoothScaling=false +# smoothScaling=true # Sync screen redraws to the monitor refresh rate diff --git a/src/al-util.h b/src/al-util.h index 78ae615..51801e7 100644 --- a/src/al-util.h +++ b/src/al-util.h @@ -238,6 +238,6 @@ inline ALenum chooseALFormat(int sampleSize, int channelCount) #define AUDIO_SLEEP 10 #define STREAM_BUF_SIZE 32768 -#define GLOBAL_VOLUME 0.8 +#define GLOBAL_VOLUME 0.8f #endif // ALUTIL_H diff --git a/src/alstream.cpp b/src/alstream.cpp index 18799ff..487f09f 100644 --- a/src/alstream.cpp +++ b/src/alstream.cpp @@ -42,12 +42,12 @@ ALStream::ALStream(LoopMode loopMode, source(0), thread(0), preemptPause(false), - pitch(1.0) + pitch(1.0f) { alSrc = AL::Source::gen(); - AL::Source::setVolume(alSrc, 1.0); - AL::Source::setPitch(alSrc, 1.0); + AL::Source::setVolume(alSrc, 1.0f); + AL::Source::setPitch(alSrc, 1.0f); AL::Source::detachBuffer(alSrc); for (int i = 0; i < STREAM_BUFS; ++i) @@ -172,7 +172,7 @@ void ALStream::setPitch(float value) /* If the source supports setting pitch natively, * we don't have to do it via OpenAL */ if (source && source->setPitch(value)) - AL::Source::setPitch(alSrc, 1.0); + AL::Source::setPitch(alSrc, 1.0f); else AL::Source::setPitch(alSrc, value); } @@ -199,43 +199,73 @@ void ALStream::closeSource() 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) { - char ext[8]; - shState->fileSystem().openRead(srcOps, filename.c_str(), false, ext, sizeof(ext)); + ALStreamOpenHandler handler(srcOps, looped); + shState->fileSystem().openRead(handler, filename.c_str()); + source = handler.source; needsRewind.clear(); - /* 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; - } - - 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) + if (!source) { char buf[512]; - snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s.%s: %s", - filename.c_str(), ext, e.msg.c_str()); + snprintf(buf, sizeof(buf), "Unable to decode audio stream: %s: %s", + filename.c_str(), handler.errorMsg.c_str()); Debug() << buf; } diff --git a/src/audio.cpp b/src/audio.cpp index 945aed0..d536c70 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -170,7 +170,7 @@ struct AudioPrivate else { /* BGM is stopped. -> MeNotPlaying */ - bgm.setVolume(AudioStream::External, 1.0); + bgm.setVolume(AudioStream::External, 1.0f); if (!bgm.noResumeStop) bgm.stream.play(); @@ -193,7 +193,7 @@ struct AudioPrivate if (bgm.stream.queryState() == ALStream::Stopped) { /* BGM stopped midway fade in. -> MeNotPlaying */ - bgm.setVolume(AudioStream::External, 1.0); + bgm.setVolume(AudioStream::External, 1.0f); meWatch.state = MeNotPlaying; bgm.unlockStream(); @@ -219,7 +219,7 @@ struct AudioPrivate if (vol >= 1) { /* BGM fully faded in. -> MeNotPlaying */ - vol = 1.0; + vol = 1.0f; meWatch.state = MeNotPlaying; } diff --git a/src/audiostream.cpp b/src/audiostream.cpp index ae572ef..1d96553 100644 --- a/src/audiostream.cpp +++ b/src/audiostream.cpp @@ -34,11 +34,11 @@ AudioStream::AudioStream(ALStream::LoopMode loopMode, noResumeStop(false), stream(loopMode, threadId) { - current.volume = 1.0; - current.pitch = 1.0; + current.volume = 1.0f; + current.pitch = 1.0f; for (size_t i = 0; i < VolumeTypeCount; ++i) - volumes[i] = 1.0; + volumes[i] = 1.0f; fade.thread = 0; fade.threadName = std::string("audio_fadeout (") + threadId + ")"; @@ -82,8 +82,8 @@ void AudioStream::play(const std::string &filename, lockStream(); - float _volume = clamp<int>(volume, 0, 100) / 100.f; - float _pitch = clamp<int>(pitch, 50, 150) / 100.f; + float _volume = clamp<int>(volume, 0, 100) / 100.0f; + float _pitch = clamp<int>(pitch, 50, 150) / 100.0f; ALStream::State sState = stream.queryState(); @@ -211,7 +211,7 @@ void AudioStream::fadeOut(int duration) } fade.active.set(); - fade.msStep = (1.0) / duration; + fade.msStep = 1.0f / duration; fade.reqFini.clear(); fade.reqTerm.clear(); fade.startTicks = SDL_GetTicks(); @@ -302,7 +302,7 @@ void AudioStream::fadeOutThread() lockStream(); 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(); @@ -313,7 +313,7 @@ void AudioStream::fadeOutThread() if (state != ALStream::Paused) stream.stop(); - setVolume(FadeOut, 1.0); + setVolume(FadeOut, 1.0f); unlockStream(); break; @@ -340,15 +340,15 @@ void AudioStream::fadeInThread() /* Fade in duration is always 1 second */ uint32_t cur = SDL_GetTicks() - fadeIn.startTicks; - float prog = cur / 1000.0; + float prog = cur / 1000.0f; ALStream::State state = stream.queryState(); if (state != ALStream::Playing - || prog >= 1.0 + || prog >= 1.0f || fadeIn.rqFini) { - setVolume(FadeIn, 1.0); + setVolume(FadeIn, 1.0f); unlockStream(); break; diff --git a/src/bitmap.cpp b/src/bitmap.cpp index 48f3337..28b0d7e 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -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) { - SDL_RWops ops; - char ext[8]; - - shState->fileSystem().openRead(ops, filename, false, ext, sizeof(ext)); - SDL_Surface *imgSurf = IMG_LoadTyped_RW(&ops, 1, ext); + BitmapOpenHandler handler; + shState->fileSystem().openRead(handler, filename); + SDL_Surface *imgSurf = handler.surf; if (!imgSurf) 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 (0, in->w+1, in->h+1, fm.BitsPerPixel, fm.Rmask, fm.Gmask, fm.Bmask, fm.Amask); - float fr = c.r / 255.0; - float fg = c.g / 255.0; - float fb = c.b / 255.0; + float fr = c.r / 255.0f; + float fg = c.g / 255.0f; + float fb = c.b / 255.0f; /* 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 @@ -1048,11 +1061,11 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C continue; } - float fSrcA = srcA / 255.0; - float fShdA = shdA / 255.0; + float fSrcA = srcA / 255.0f; + float fShdA = shdA / 255.0f; /* Because opacity == 1, co1 == fSrcA */ - float co2 = fShdA * (1.0 - fSrcA); + float co2 = fShdA * (1.0f - fSrcA); /* Result alpha */ float fa = fSrcA + co2; /* 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 */ uint8_t r, g, b, a; - r = clamp<float>(fr * co3, 0, 1) * 255; - g = clamp<float>(fg * co3, 0, 1) * 255; - b = clamp<float>(fb * co3, 0, 1) * 255; - a = clamp<float>(fa, 0, 1) * 255; + r = clamp<float>(fr * co3, 0, 1) * 255.0f; + g = clamp<float>(fg * co3, 0, 1) * 255.0f; + b = clamp<float>(fb * co3, 0, 1) * 255.0f; + a = clamp<float>(fa, 0, 1) * 255.0f; *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; 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 (squeeze == 1.0 && !shState->config().subImageFix) + if (squeeze == 1.0f && !shState->config().subImageFix) { /* Even faster: upload directly to bitmap texture. * We have to make sure the posRect lies within the texture diff --git a/src/config.cpp b/src/config.cpp index 6166da3..248c2c2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -151,7 +151,7 @@ void Config::read(int argc, char *argv[]) PO_DESC(winResizable, bool, false) \ PO_DESC(fullscreen, bool, false) \ PO_DESC(fixedAspectRatio, bool, true) \ - PO_DESC(smoothScaling, bool, false) \ + PO_DESC(smoothScaling, bool, true) \ PO_DESC(vsync, bool, false) \ PO_DESC(defScreenW, int, 0) \ PO_DESC(defScreenH, int, 0) \ diff --git a/src/config.h b/src/config.h index e3c7573..9e43faf 100644 --- a/src/config.h +++ b/src/config.h @@ -31,49 +31,6 @@ struct CropTexture 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 { int rgssVersion; diff --git a/src/etc-internal.h b/src/etc-internal.h index c9bd520..4cbc704 100644 --- a/src/etc-internal.h +++ b/src/etc-internal.h @@ -61,9 +61,9 @@ struct Vec4 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; } + bool operator!=(const Vec2i &other) const + { + return !(*this == other); + } + Vec2i &operator+=(const Vec2i &value) { x += value.x; @@ -131,6 +136,11 @@ struct Vec2i return Vec2i(x % value, y % value); } + Vec2i operator&(unsigned value) const + { + return Vec2i(x & value, y & value); + } + Vec2i operator-() const { return Vec2i(-x, -y); @@ -176,6 +186,11 @@ struct IntRect : SDL_Rect w == other.w && h == other.h); } + bool operator!=(const IntRect &other) const + { + return !(*this == other); + } + Vec2i pos() const { return Vec2i(x, y); @@ -259,13 +274,13 @@ struct NormValue NormValue(int unNorm) : unNorm(unNorm), - norm(unNorm / 255.0) + norm(unNorm / 255.0f) {} void operator =(int value) { unNorm = clamp(value, 0, 255); - norm = unNorm / 255.0; + norm = unNorm / 255.0f; } bool operator ==(int value) const diff --git a/src/eventthread.cpp b/src/eventthread.cpp index a3de5cf..00c1b3e 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -111,7 +111,11 @@ void EventThread::process(RGSSThreadData &rtData) UnidirMessage<Vec2i> &windowSizeMsg = rtData.windowSizeMsg; initALCFunctions(rtData.alcDev); + + // XXX this function breaks input focus on OSX +#ifndef __MACOSX__ SDL_SetEventFilter(eventFilter, &rtData); +#endif fullscreen = rtData.config.fullscreen; int toggleFSMod = rtData.config.anyAltToggleFS ? KMOD_ALT : KMOD_LALT; @@ -127,7 +131,9 @@ void EventThread::process(RGSSThreadData &rtData) bool displayingFPS = false; bool cursorInWindow = false; - bool windowFocused = false; + + /* SDL doesn't send an initial FOCUS_GAINED event */ + bool windowFocused = true; bool terminate = false; @@ -490,9 +496,9 @@ int EventThread::eventFilter(void *data, SDL_Event *event) Debug() << "SDL_APP_LOWMEMORY"; return 0; - case SDL_RENDER_TARGETS_RESET : - Debug() << "****** SDL_RENDER_TARGETS_RESET"; - return 0; +// case SDL_RENDER_TARGETS_RESET : +// Debug() << "****** SDL_RENDER_TARGETS_RESET"; +// return 0; // case SDL_RENDER_DEVICE_RESET : // Debug() << "****** SDL_RENDER_DEVICE_RESET"; diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 6642d3b..fe5d403 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -37,6 +37,7 @@ #include <string.h> #include <algorithm> #include <vector> +#include <stack> #ifdef __APPLE__ #include <iconv.h> @@ -249,201 +250,65 @@ strcpySafe(char *dst, const char *src, 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; 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 */ + /* 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; - - /* 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, @@ -484,99 +349,105 @@ void FileSystem::addPath(const char *path) } } -#ifdef __APPLE__ -struct CacheEnumCBData +struct CacheEnumData { FileSystemPrivate *p; + std::stack<std::vector<std::string>*> fileLists; + +#ifdef __APPLE__ 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"); +#endif } - ~CacheEnumCBData() + ~CacheEnumData() { +#ifdef __APPLE__ 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 */ - --dstSize; - /* iconv takes a char** instead of a const char**, even though - * the string data isn't written to. */ + --bufSize; + iconv(nfd2nfc, - const_cast<char**>(&src), &srcSize, - &dst, &dstSize); + &inoutPtr, &srcSize, + &bufPtr, &bufSize); /* Null-terminate */ - *dst = 0; + *bufPtr = 0; + strcpy(inout, buf); +#else + (void) inout; +#endif } }; -#endif static void cacheEnumCB(void *d, const char *origdir, const char *fname) { -#ifdef __APPLE__ - CacheEnumCBData *data = static_cast<CacheEnumCBData*>(d); - FileSystemPrivate *p = data->p; -#else - FileSystemPrivate *p = static_cast<FileSystemPrivate*>(d); -#endif + CacheEnumData &data = *static_cast<CacheEnumData*>(d); + char fullPath[512]; - char buf[512]; - - if (*origdir == '\0') - strncpy(buf, fname, sizeof(buf)); + if (!*origdir) + snprintf(fullPath, sizeof(fullPath), "%s", fname); else - snprintf(buf, sizeof(buf), "%s/%s", origdir, fname); + snprintf(fullPath, sizeof(fullPath), "%s/%s", origdir, fname); -#ifdef __APPLE__ - char bufNfc[sizeof(buf)]; - data->nfcFromNfd(bufNfc, buf, sizeof(bufNfc)); -#else - char *const bufNfc = buf; -#endif + /* Deal with OSX' weird UTF-8 standards */ + data.toNFC(fullPath); - char *ptr = bufNfc; + std::string mixedCase(fullPath); + std::string lowerCase = mixedCase; + strTolower(lowerCase); - /* Trim leading slash */ - if (*ptr == '/') - ++ptr; + PHYSFS_Stat stat; + PHYSFS_stat(fullPath, &stat); - std::string mixedCase(ptr); - - 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 (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) { - if (*q == '/') - break; + /* Create a new list for this directory */ + std::vector<std::string> &list = data.p->fileLists[lowerCase]; - if (*q != '.') - continue; - - *q = '\0'; - p->pathCache.insert(std::string(ptr), mixedCase); + /* Iterate over its contents */ + data.fileLists.push(&list); + PHYSFS_enumerateFilesCallback(fullPath, cacheEnumCB, d); + data.fileLists.pop(); } + 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() { -#ifdef __APPLE__ - CacheEnumCBData data(p); + CacheEnumData data(p); + data.fileLists.push(&p->fileLists[""]); PHYSFS_enumerateFilesCallback("", cacheEnumCB, &data); -#else - PHYSFS_enumerateFilesCallback("", cacheEnumCB, p); -#endif p->havePathCache = true; } @@ -591,10 +462,9 @@ static void fontSetEnumCB(void *data, const char *, const char *fname) { FontSetsCBData *d = static_cast<FontSetsCBData*>(data); - FileSystemPrivate *p = d->p; /* Only consider filenames with font extensions */ - const char *ext = p->findExt(fname); + const char *ext = findExt(fname); if (!ext) return; @@ -618,7 +488,7 @@ static void fontSetEnumCB(void *data, const char *, return; SDL_RWops ops; - p->initReadOps(handle, ops, false); + initReadOps(handle, ops, false); d->sfs->initFontSetCB(ops, filename); @@ -632,15 +502,147 @@ void FileSystem::initFontSets(SharedFontState &sfs) PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d); } -void FileSystem::openRead(SDL_RWops &ops, - const char *filename, - bool freeOnClose, - char *extBuf, - size_t extBufN) +struct OpenReadEnumData { - 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, @@ -650,12 +652,10 @@ void FileSystem::openReadRaw(SDL_RWops &ops, PHYSFS_File *handle = PHYSFS_openRead(filename); assert(handle); - p->initReadOps(handle, ops, freeOnClose); + initReadOps(handle, ops, freeOnClose); } bool FileSystem::exists(const char *filename) { - char found[512]; - - return p->completeFilename(filename, found, sizeof(found)); + return PHYSFS_exists(filename); } diff --git a/src/filesystem.h b/src/filesystem.h index a98d96d..1f9f79f 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -43,17 +43,28 @@ public: * available font assets */ void initFontSets(SharedFontState &sfs); - void openRead(SDL_RWops &ops, - const char *filename, - bool freeOnClose = false, - char *extBuf = 0, - size_t extBufN = 0); + struct OpenHandler + { + /* Try to read and interpret data provided from ops. + * If data cannot be parsed, return false, otherwise true. + * 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 */ void openReadRaw(SDL_RWops &ops, const char *filename, bool freeOnClose = false); + /* Does not perform extension supplementing */ bool exists(const char *filename); private: diff --git a/src/font.cpp b/src/font.cpp index 058dd21..62ab3e8 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -174,7 +174,7 @@ _TTF_Font *SharedFontState::getFont(std::string family, // FIXME 0.9 is guesswork at this point // float gamma = (96.0/45.0)*(5.0/14.0)*(size-5); // font = TTF_OpenFontRW(ops, 1, gamma /** .90*/); - font = TTF_OpenFontRW(ops, 1, size* .90); + font = TTF_OpenFontRW(ops, 1, size* 0.90f); if (!font) throw Exception(Exception::SDLError, "%s", SDL_GetError()); @@ -184,7 +184,7 @@ _TTF_Font *SharedFontState::getFont(std::string family, return font; } -bool SharedFontState::fontPresent(std::string family) +bool SharedFontState::fontPresent(std::string family) const { /* Check for substitutions */ if (p->subs.contains(family)) @@ -202,6 +202,26 @@ _TTF_Font *SharedFontState::openBundled(int 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 { @@ -229,15 +249,15 @@ struct FontPrivate static Color defaultColorTmp; static Color defaultOutColorTmp; + static std::vector<std::string> initialDefaultNames; + /* The actual font is opened as late as possible * (when it is queried by a Bitmap), prior it is * set to null */ TTF_Font *sdlFont; - FontPrivate(const char *name = 0, - int size = 0) - : name(name ? std::string(name) : defaultName), - size(size ? size : defaultSize), + FontPrivate(int size) + : size(size), bold(defaultBold), italic(defaultItalic), outline(defaultOutline), @@ -290,6 +310,8 @@ Color *FontPrivate::defaultOutColor = &FontPrivate::defaultOutColorTmp; Color FontPrivate::defaultColorTmp(255, 255, 255, 255); Color FontPrivate::defaultOutColorTmp(0, 0, 0, 128); +std::vector<std::string> FontPrivate::initialDefaultNames; + bool Font::doesExist(const char *name) { if (!name) @@ -298,10 +320,15 @@ bool Font::doesExist(const char *name) return shState->fontState().fontPresent(name); } -Font::Font(const char *name, +Font::Font(const std::vector<std::string> *names, 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) @@ -321,17 +348,9 @@ const Font &Font::operator=(const Font &o) return o; } -const char *Font::getName() const +void Font::setName(const std::vector<std::string> &names) { - return p->name.c_str(); -} - -void Font::setName(const char *value) -{ - if (p->name == value) - return; - - p->name = value; + pickExistingFontName(names, p->name, shState->fontState()); 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, 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() @@ -393,8 +413,30 @@ void Font::initDefaultDynAttribs() 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::defaultShadow = (rgssVer == 2 ? true : false); } diff --git a/src/font.h b/src/font.h index 73bb83f..6024007 100644 --- a/src/font.h +++ b/src/font.h @@ -25,6 +25,9 @@ #include "etc.h" #include "util.h" +#include <vector> +#include <string> + struct SDL_RWops; struct _TTF_Font; struct Config; @@ -47,7 +50,7 @@ public: _TTF_Font *getFont(std::string family, int size); - bool fontPresent(std::string family); + bool fontPresent(std::string family) const; static _TTF_Font *openBundled(int size); @@ -55,22 +58,6 @@ private: 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; class Font @@ -78,31 +65,43 @@ class Font public: static bool doesExist(const char *name); - Font(const char *name = 0, + Font(const std::vector<std::string> *names = 0, int size = 0); + /* Clone constructor */ Font(const Font &other); + ~Font(); const Font &operator=(const Font &o); - DECL_ATTR( Name, const char * ) - DECL_ATTR( Size, int ) - DECL_ATTR( Bold, bool ) - DECL_ATTR( Italic, bool ) - DECL_ATTR( Color, Color& ) - DECL_ATTR( Shadow, bool ) - DECL_ATTR( Outline, bool ) - DECL_ATTR( OutColor, Color& ) + DECL_ATTR( Size, int ) + DECL_ATTR( Bold, bool ) + DECL_ATTR( Italic, bool ) + DECL_ATTR( Color, Color& ) + DECL_ATTR( Shadow, bool ) + DECL_ATTR( Outline, bool ) + DECL_ATTR( OutColor, Color& ) - DECL_ATTR_STATIC( DefaultName, const char* ) - DECL_ATTR_STATIC( DefaultSize, int ) - DECL_ATTR_STATIC( DefaultBold, bool ) - DECL_ATTR_STATIC( DefaultItalic, bool ) - DECL_ATTR_STATIC( DefaultColor, Color& ) - DECL_ATTR_STATIC( DefaultShadow, bool ) - DECL_ATTR_STATIC( DefaultOutline, bool ) - DECL_ATTR_STATIC( DefaultOutColor, Color& ) + DECL_ATTR_STATIC( DefaultSize, int ) + DECL_ATTR_STATIC( DefaultBold, bool ) + DECL_ATTR_STATIC( DefaultItalic, bool ) + DECL_ATTR_STATIC( DefaultColor, Color& ) + DECL_ATTR_STATIC( DefaultShadow, bool ) + DECL_ATTR_STATIC( DefaultOutline, bool ) + 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; * using this in pure C++ will cause memory leaks @@ -110,7 +109,7 @@ public: void initDynAttribs(); static void initDefaultDynAttribs(); - static void initDefaults(); + static void initDefaults(const SharedFontState &sfs); /* internal */ _TTF_Font *getSdlFont(); diff --git a/src/graphics.cpp b/src/graphics.cpp index 79de27d..687cb3e 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -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 &screenRect = geometry.rect; - bool toneRGBEffect = t.xyzHasEffect(); - bool toneGrayEffect = t.w != 0; - bool colorEffect = c.w > 0; - bool flashEffect = f.w > 0; + const bool toneRGBEffect = t.xyzNotNull(); + const bool toneGrayEffect = t.w != 0; + const bool colorEffect = c.w > 0; + const bool flashEffect = f.w > 0; if (toneGrayEffect) { @@ -240,7 +240,7 @@ public: /* Then apply them using hardware blending */ gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE); - if (add.xyzHasEffect()) + if (add.xyzNotNull()) { gl.BlendEquation(GL_FUNC_ADD); shader.setColor(add); @@ -248,7 +248,7 @@ public: screenQuad.draw(); } - if (sub.xyzHasEffect()) + if (sub.xyzNotNull()) { gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT); shader.setColor(sub); @@ -281,9 +281,9 @@ public: 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) @@ -742,7 +742,7 @@ void Graphics::transition(int duration, shader.setFrozenScene(p->frozenScene.tex); shader.setCurrentScene(p->currentScene.tex); shader.setTransMap(transMap->getGLTypes().tex); - shader.setVague(vague / 256.0); + shader.setVague(vague / 256.0f); shader.setTexSize(p->scRes); } else @@ -780,7 +780,7 @@ void Graphics::transition(int duration, p->checkSyncLock(); - const float prog = i * (1.0 / duration); + const float prog = i * (1.0f / duration); if (transMap) { @@ -858,7 +858,7 @@ void Graphics::fadeout(int duration) FBO::unbind(); float curr = p->brightness; - float diff = 255.0 - curr; + float diff = 255.0f - curr; for (int i = duration-1; i > -1; --i) { @@ -888,7 +888,7 @@ void Graphics::fadein(int duration) FBO::unbind(); float curr = p->brightness; - float diff = 255.0 - curr; + float diff = 255.0f - curr; for (int i = 1; i <= duration; ++i) { @@ -963,6 +963,11 @@ void Graphics::resizeScreen(int width, int 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) void Graphics::setBrightness(int value) diff --git a/src/graphics.h b/src/graphics.h index e914178..aa30189 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -54,6 +54,7 @@ public: int width() const; int height() const; void resizeScreen(int width, int height); + void playMovie(const char *filename); void reset(); diff --git a/src/midisource.cpp b/src/midisource.cpp index fdca2e4..3d569a7 100644 --- a/src/midisource.cpp +++ b/src/midisource.cpp @@ -320,7 +320,7 @@ readEvent(MidiReadHandler *handler, MemChunk &chunk, | (data[2] << 0x00); e.type = Tempo; - e.e.tempo.bpm = 60000000.0 / mpqn; + e.e.tempo.bpm = 60000000 / mpqn; } else if (metaType == 0x2F) { @@ -626,9 +626,20 @@ struct MidiSource : ALDataSource, MidiReadHandler std::vector<uint8_t> data(dataLen); if (SDL_RWread(&ops, &data[0], 1, dataLen) < dataLen) + { + SDL_RWclose(&ops); 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(); @@ -688,7 +699,7 @@ struct MidiSource : ALDataSource, MidiReadHandler void updatePlaybackSpeed(uint32_t bpm) { - float deltaLength = 60.0 / (dpb * bpm); + float deltaLength = 60.0f / (dpb * bpm); playbackSpeed = TICK_FRAMES / (deltaLength * freq); } @@ -899,7 +910,7 @@ struct MidiSource : ALDataSource, MidiReadHandler bool setPitch(float value) { // 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; } diff --git a/src/plane.cpp b/src/plane.cpp index f275e85..e3de3a0 100644 --- a/src/plane.cpp +++ b/src/plane.cpp @@ -105,8 +105,8 @@ struct PlanePrivate return; /* Scaled (zoomed) bitmap dimensions */ - double sw = bitmap->width() * zoomX; - double sh = bitmap->height() * zoomY; + float sw = bitmap->width() * zoomX; + float sh = bitmap->height() * zoomY; /* Plane offset wrapped by scaled bitmap dims */ float wox = fwrap(ox, sw); diff --git a/src/rgssad.cpp b/src/rgssad.cpp index e8606b9..17e8417 100644 --- a/src/rgssad.cpp +++ b/src/rgssad.cpp @@ -34,7 +34,7 @@ struct RGSS_entryData struct RGSS_entryHandle { - RGSS_entryData data; + const RGSS_entryData data; uint32_t currentMagic; uint64_t currentOffset; PHYSFS_Io *io; @@ -229,7 +229,7 @@ RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset) static PHYSFS_sint64 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; } @@ -237,7 +237,7 @@ RGSS_ioTell(PHYSFS_Io *self) static PHYSFS_sint64 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; } @@ -245,7 +245,7 @@ RGSS_ioLength(PHYSFS_Io *self) static PHYSFS_Io* 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); PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io); @@ -448,7 +448,7 @@ RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat) if (hasFile) { - RGSS_entryData &entry = data->entryHash[filename]; + const RGSS_entryData &entry = data->entryHash[filename]; stat->filesize = entry.size; stat->filetype = PHYSFS_FILETYPE_REGULAR; diff --git a/src/scene.h b/src/scene.h index edee331..7685407 100644 --- a/src/scene.h +++ b/src/scene.h @@ -55,7 +55,9 @@ public: virtual ~Scene(); 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; } diff --git a/src/settingsmenu.cpp b/src/settingsmenu.cpp index a14b488..6518d7f 100644 --- a/src/settingsmenu.cpp +++ b/src/settingsmenu.cpp @@ -764,13 +764,13 @@ void Widget::click(int x, int y, uint8_t button) } /* 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) { const int cellW = (rect.w*BW_CELL_R) / 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[] = { @@ -860,7 +860,7 @@ int BindingWidget::cellIndex(int x, int y) const { const int cellW = (rect.w*BW_CELL_R) / 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) return -1; diff --git a/src/sharedmidistate.h b/src/sharedmidistate.h index 00de6dc..1692848 100644 --- a/src/sharedmidistate.h +++ b/src/sharedmidistate.h @@ -80,7 +80,7 @@ struct SharedMidiState return; 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_setstr(flSettings, "synth.chorus.active", conf.midi.chorus ? "yes" : "no"); fluid.settings_setstr(flSettings, "synth.reverb.active", conf.midi.reverb ? "yes" : "no"); diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index 023ff6b..9872af7 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -172,7 +172,6 @@ void SharedState::initInstance(RGSSThreadData *threadData) * Font depends on SharedState existing */ rgssVersion = threadData->config.rgssVersion; - Font::initDefaults(); _globalIBO = new GlobalIBO(); _globalIBO->ensureSize(1); @@ -183,6 +182,7 @@ void SharedState::initInstance(RGSSThreadData *threadData) try { SharedState::instance = new SharedState(threadData); + Font::initDefaults(instance->p->fontState); defaultFont = new Font(); } catch (const Exception &exc) diff --git a/src/soundemitter.cpp b/src/soundemitter.cpp index 3850c0b..74eaf03 100644 --- a/src/soundemitter.cpp +++ b/src/soundemitter.cpp @@ -123,8 +123,8 @@ void SoundEmitter::play(const std::string &filename, int volume, int pitch) { - float _volume = clamp<int>(volume, 0, 100) / 100.f; - float _pitch = clamp<int>(pitch, 50, 150) / 100.f; + float _volume = clamp<int>(volume, 0, 100) / 100.0f; + float _pitch = clamp<int>(pitch, 50, 150) / 100.0f; SoundBuffer *buffer = allocateBuffer(filename); @@ -184,6 +184,44 @@ void SoundEmitter::stop() 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 *buffer = bufferHash.value(filename, 0); @@ -199,40 +237,22 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename) } else { - /* Buffer not in cashe, needs to be loaded */ - SDL_RWops dataSource; - char ext[8]; + /* Buffer not in cache, needs to be loaded */ + SoundOpenHandler handler; + shState->fileSystem().openRead(handler, filename.c_str()); + buffer = handler.buffer; - shState->fileSystem().openRead(dataSource, filename.c_str(), - false, ext, sizeof(ext)); - - Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, ext, 0, STREAM_BUF_SIZE); - - if (!sampleHandle) + if (!buffer) { char buf[512]; - snprintf(buf, sizeof(buf), "Unable to decode sound: %s.%s: %s", - filename.c_str(), ext, Sound_GetError()); + snprintf(buf, sizeof(buf), "Unable to decode sound: %s: %s", + filename.c_str(), Sound_GetError()); Debug() << buf; 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->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; /* If memory limit is reached, delete lowest priority buffer diff --git a/src/sprite.cpp b/src/sprite.cpp index 0313444..760bb0b 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -109,7 +109,7 @@ struct SpritePrivate wave.amp = 0; wave.length = 180; wave.speed = 360; - wave.phase = 0.0; + wave.phase = 0.0f; wave.dirty = false; } @@ -129,7 +129,7 @@ struct SpritePrivate (srcRect->y + srcRect->height) + bitmap->height(); - efBushDepth = 1.0 - texBushDepth / bitmap->height(); + efBushDepth = 1.0f - texBushDepth / bitmap->height(); } void onSrcRectChange() @@ -194,7 +194,7 @@ struct SpritePrivate void emitWaveChunk(SVertex *&vert, float phase, int width, 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; FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY); @@ -261,7 +261,7 @@ struct SpritePrivate wave.qArray.resize(!!firstLength + chunks + !!lastLength); 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) emitWaveChunk(vert, phase, width, zoomY, 0, firstLength); diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp index 8f3ec47..663eca3 100644 --- a/src/tileatlasvx.cpp +++ b/src/tileatlasvx.cpp @@ -51,14 +51,14 @@ extern const int autotileVXRectsBN; /* Waterfall (C) autotile patterns */ static const StaticRect autotileVXRectsC[] = { - { 32.5, 0.5, 15, 31 }, - { 16.5, 0.5, 15, 31 }, - { 0.0, 0.5, 15, 31 }, - { 16.5, 0.5, 15, 31 }, - { 32.5, 0.5, 15, 31 }, - { 48.5, 0.5, 15, 31 }, - { 0.0, 0.5, 15, 31 }, - { 48.5, 0.5, 15, 31 } + { 32.5f, 0.5f, 15.0f, 31.0f }, + { 16.5f, 0.5f, 15.0f, 31.0f }, + { 0.0f, 0.5f, 15.0f, 31.0f }, + { 16.5f, 0.5f, 15.0f, 31.0f }, + { 32.5f, 0.5f, 15.0f, 31.0f }, + { 48.5f, 0.5f, 15.0f, 31.0f }, + { 0.0f, 0.5f, 15.0f, 31.0f }, + { 48.5f, 0.5f, 15.0f, 31.0f } }; static elementsN(autotileVXRectsC); @@ -500,7 +500,7 @@ onTileA4(Reader &reader, int16_t tileID, Vec2i orig = blitsA4[0].dst; 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 autotileID = tileID / 0x30; diff --git a/src/tilemap-common.h b/src/tilemap-common.h index 45ee91c..028dfd7 100644 --- a/src/tilemap-common.h +++ b/src/tilemap-common.h @@ -46,6 +46,13 @@ wrap(int value, int range) 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 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); } +/* 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 { TopLeft = 0, diff --git a/src/tilemap.cpp b/src/tilemap.cpp index d3cf437..8b61ea7 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -236,7 +236,7 @@ struct TilemapPrivate Table *mapData; Table *priorities; bool visible; - Vec2i offset; + Vec2i origin; Vec2i dispPos; @@ -294,7 +294,6 @@ struct TilemapPrivate /* Used layers out of 'zlayers' (rest is hidden) */ size_t activeLayers; Scene::Geometry sceneGeo; - Vec2i sceneOffset; } elem; /* Affected by: autotiles, tileset */ @@ -394,7 +393,7 @@ struct TilemapPrivate void updateFlashMapViewport() { - flashMap.setViewport(IntRect(viewpPos.x, viewpPos.y, viewpW, viewpH)); + flashMap.setViewport(IntRect(viewpPos, Vec2i(viewpW, viewpH))); } void updateAtlasInfo() @@ -442,13 +441,8 @@ struct TilemapPrivate void updateSceneGeometry(const Scene::Geometry &geo) { - elem.sceneOffset = geo.offset(); elem.sceneGeo = geo; - } - - void updatePosition() - { - dispPos = -(offset - viewpPos * 32) + elem.sceneOffset; + mapViewportDirty = true; } void invalidateAtlasSize() @@ -698,7 +692,7 @@ struct TilemapPrivate int tileY = tsInd / 8; 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); SVertex v[4]; @@ -898,38 +892,17 @@ struct TilemapPrivate void updateMapViewport() { - int tileOX, tileOY; + const Vec2i combOrigin = origin + elem.sceneGeo.orig; + const Vec2i mvpPos = getTilePos(combOrigin); - if (offset.x >= 0) - 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) + if (mvpPos != viewpPos) { + viewpPos = mvpPos; buffersDirty = true; updateFlashMapViewport(); - updatePosition(); } + + dispPos = elem.sceneGeo.rect.pos() - wrap(combOrigin, 32); } void prepare() @@ -1024,7 +997,6 @@ void GroundLayer::drawInt() void GroundLayer::onGeometryChange(const Scene::Geometry &geo) { p->updateSceneGeometry(geo); - p->updatePosition(); } ZLayer::ZLayer(TilemapPrivate *p, Viewport *viewport) @@ -1072,7 +1044,7 @@ void ZLayer::drawInt() 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() @@ -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, Priorities, Table*, p->priorities) DEF_ATTR_RD_SIMPLE(Tilemap, Visible, bool, p->visible) -DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->offset.x) -DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->offset.y) +DEF_ATTR_RD_SIMPLE(Tilemap, OX, int, p->origin.x) +DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->origin.y) void Tilemap::setTileset(Bitmap *value) { @@ -1259,11 +1231,10 @@ void Tilemap::setOX(int value) { guardDisposed(); - if (p->offset.x == value) + if (p->origin.x == value) return; - p->offset.x = value; - p->updatePosition(); + p->origin.x = value; p->mapViewportDirty = true; } @@ -1271,11 +1242,10 @@ void Tilemap::setOY(int value) { guardDisposed(); - if (p->offset.y == value) + if (p->origin.y == value) return; - p->offset.y = value; - p->updatePosition(); + p->origin.y = value; p->zOrderDirty = true; p->mapViewportDirty = true; } diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp index 6291fd9..50d8df0 100644 --- a/src/tilemapvx.cpp +++ b/src/tilemapvx.cpp @@ -57,12 +57,12 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader Table *mapData; Table *flags; - Vec2i offset; + Vec2i origin; - Vec2i dispPos; - /* Map viewport position */ + /* Subregion of the map that is drawn to screen (map viewport) */ IntRect mapViewp; - Vec2i sceneOffset; + /* Position on screen the map subregion is drawn at */ + Vec2i dispPos; Scene::Geometry sceneGeo; std::vector<SVertex> groundVert; @@ -179,49 +179,31 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader 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() { - 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) - tileOX = offs.x / 32; - else - tileOX = -(-(offs.x-31) / 32); + const Vec2i combOrigin = origin + sceneGeo.orig; + const Vec2i geoSize = sceneGeo.rect.size(); - if (offs.y >= 0) - tileOY = offs.y / 32; - else - tileOY = -(-(offs.y-31) / 32); + newMvp.setPos(getTilePos(combOrigin) - Vec2i(0, 1)); - 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) - { - mapViewp.x = tileOX; - dirty = true; - } - - if (tileOY < mapViewp.y || tileOY > mapViewp.y) - { - mapViewp.y = tileOY; - dirty = true; - } - - if (dirty) + if (newMvp != mapViewp) { + mapViewp = newMvp; + flashMap.setViewport(newMvp); buffersDirty = true; } - updatePosition(); - flashMap.setViewport(mapViewp); + dispPos = sceneGeo.rect.pos() - wrap(combOrigin, 32) - Vec2i(0, 32); } static size_t quadBytes(size_t quads) @@ -366,10 +348,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader 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; buffersDirty = true; @@ -380,7 +358,7 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader /* TileAtlasVX::Reader */ 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); @@ -467,8 +445,8 @@ TilemapVX::BitmapArray &TilemapVX::getBitmapArray() DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData) DEF_ATTR_RD_SIMPLE(TilemapVX, FlashData, Table*, p->flashMap.getData()) DEF_ATTR_RD_SIMPLE(TilemapVX, Flags, Table*, p->flags) -DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->offset.x) -DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->offset.y) +DEF_ATTR_RD_SIMPLE(TilemapVX, OX, int, p->origin.x) +DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->origin.y) Viewport *TilemapVX::getViewport() const { @@ -541,10 +519,10 @@ void TilemapVX::setOX(int value) { guardDisposed(); - if (p->offset.x == value) + if (p->origin.x == value) return; - p->offset.x = value; + p->origin.x = value; p->mapViewportDirty = true; } @@ -552,10 +530,10 @@ void TilemapVX::setOY(int value) { guardDisposed(); - if (p->offset.y == value) + if (p->origin.y == value) return; - p->offset.y = value; + p->origin.y = value; p->mapViewportDirty = true; } diff --git a/src/transform.h b/src/transform.h index cefd09f..7a129f9 100644 --- a/src/transform.h +++ b/src/transform.h @@ -130,7 +130,7 @@ private: if (rotation < 0) rotation += 360; - float angle = rotation * 3.141592654f / 180.f; + float angle = rotation * 3.141592654f / 180.0f; float cosine = (float) cos(angle); float sine = (float) sin(angle); float sxc = scale.x * cosine; diff --git a/src/window.cpp b/src/window.cpp index a32481d..71a8cc9 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -642,7 +642,7 @@ struct WindowPrivate if (active && cursorVert.vert) { - float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0; + float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0f; cursorVert.setAlpha(alpha); @@ -651,7 +651,7 @@ struct WindowPrivate if (pause && pauseAniVert.vert) { - float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0; + float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0f; FloatRect frameRect = pauseAniSrc[pauseAniQuad[pauseAniQuadIdx]]; pauseAniVert.setAlpha(alpha); diff --git a/src/windowvx.cpp b/src/windowvx.cpp index 0bafb5b..02a70d9 100644 --- a/src/windowvx.cpp +++ b/src/windowvx.cpp @@ -482,7 +482,7 @@ struct WindowVXPrivate void updateBaseQuad() { 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); base.quad.setTexPosRect(tex, pos); @@ -633,7 +633,7 @@ struct WindowVXPrivate Quad::setTexRect(pauseVert, pauseSrc[pauseQuad[pauseQuadIdx]]); /* 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; } @@ -643,7 +643,7 @@ struct WindowVXPrivate if (cursorVert.count() == 0) 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) Quad::setColor(&cursorVert.vertices[i*4], color);