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 + +static void +collectStrings(VALUE obj, std::vector &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 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(self); - char result[256]; - fontSetNameHelper(self, argc, argv, "name", - result, sizeof(result)); + rb_check_argc(argc, 1); - f->setName(result); + std::vector 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 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 &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(volume, 0, 100) / 100.f; - float _pitch = clamp(pitch, 50, 150) / 100.f; + float _volume = clamp(volume, 0, 100) / 100.0f; + float _pitch = clamp(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(fr * co3, 0, 1) * 255; - g = clamp(fg * co3, 0, 1) * 255; - b = clamp(fb * co3, 0, 1) * 255; - a = clamp(fa, 0, 1) * 255; + r = clamp(fr * co3, 0, 1) * 255.0f; + g = clamp(fg * co3, 0, 1) * 255.0f; + b = clamp(fb * co3, 0, 1) * 255.0f; + a = clamp(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