From 4b08eee81ff87913c1f1b568d772e483284e2626 Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Sep 2014 19:11:56 +0200 Subject: [PATCH 001/239] add RGSS2/3 Input.repeat? --- src/input.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 5e1085b..9e38436 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -599,8 +599,13 @@ void Input::update() { p->repeatCount++; - /* Repeatsequence is [r...............(r...)+] */ - if (p->repeatCount > 15 && ((p->repeatCount % 4) == 0)) + bool repeated; + if (rgssVer >= 2) + repeated = p->repeatCount >= 24 && (p->repeatCount % 6) == 0; + else + repeated = p->repeatCount >= 16 && (p->repeatCount % 4) == 0; + + if (repeated) p->getState(p->repeating).repeated = true; return; From a366862076a4edc23df8ef01f6b6cd56db2fc0ac Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Sep 2014 19:10:33 +0200 Subject: [PATCH 002/239] define case and hash equality for etc classes RGSS also defines #=== and #eql? for Color, Tone, and Rect: Color.instance_method(:==) == Color.instance_method(:===) # => true Color.instance_method(:==) == Color.instance_method(:eql?) # => true --- binding-mri/etc-binding.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/binding-mri/etc-binding.cpp b/binding-mri/etc-binding.cpp index 32ad494..a0f4472 100644 --- a/binding-mri/etc-binding.cpp +++ b/binding-mri/etc-binding.cpp @@ -177,6 +177,8 @@ INITCOPY_FUN(Rect) _rb_define_method(klass, "initialize_copy", Klass##InitializeCopy); \ _rb_define_method(klass, "set", Klass##Set); \ _rb_define_method(klass, "==", Klass##Equal); \ + _rb_define_method(klass, "===", Klass##Equal); \ + _rb_define_method(klass, "eql?", Klass##Equal); \ _rb_define_method(klass, "to_s", Klass##Stringify); \ _rb_define_method(klass, "inspect", Klass##Stringify); \ } From 7acbb06fbd720a7d8cba9f5102a0d2e04b4bbda8 Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Sep 2014 19:45:50 +0200 Subject: [PATCH 003/239] add RGSS 3.0.1 etc classes equality comparison RGSS 3.0.1 finally fixed #==, #===, #eql? for Color, Tone, and Rect. Now instances of them can be compared to other kinds of objects. --- binding-mri/etc-binding.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/binding-mri/etc-binding.cpp b/binding-mri/etc-binding.cpp index 32ad494..731ccca 100644 --- a/binding-mri/etc-binding.cpp +++ b/binding-mri/etc-binding.cpp @@ -22,6 +22,7 @@ #include "etc.h" #include "binding-util.h" #include "serializable-binding.h" +#include "sharedstate.h" DEF_TYPE(Color); DEF_TYPE(Tone); @@ -68,6 +69,9 @@ ATTR_INT_RW(Rect, Height) VALUE otherObj; \ Klass *other; \ rb_get_args(argc, argv, "o", &otherObj RB_ARG_END); \ + if (rgssVer >= 3) \ + if (!rb_typeddata_is_kind_of(otherObj, &Klass##Type)) \ + return Qfalse; \ other = getPrivateDataCheck(otherObj, Klass##Type); \ return rb_bool_new(*p == *other); \ } From fd4f7c66d1af89a6518676c90c824a4ef0e19608 Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Sep 2014 19:48:47 +0200 Subject: [PATCH 004/239] bump RGSS_VERSION to 3.0.1 --- binding-mri/binding-mri.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 12c9e86..962b51e 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -114,7 +114,7 @@ static void mriBindingInit() _rb_define_module_function(rb_mKernel, "msgbox", mriPrint); _rb_define_module_function(rb_mKernel, "msgbox_p", mriP); - rb_define_global_const("RGSS_VERSION", rb_str_new_cstr("3.0.0")); + rb_define_global_const("RGSS_VERSION", rb_str_new_cstr("3.0.1")); } else { From 10186e8dcccda3c21b67ed2f2bc51a06199e71e8 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Wed, 3 Sep 2014 02:35:57 +0200 Subject: [PATCH 005/239] Input: Fix isRepeated off-by-one error and do small optim. --- src/input.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 9e38436..d646db0 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -601,12 +601,11 @@ void Input::update() bool repeated; if (rgssVer >= 2) - repeated = p->repeatCount >= 24 && (p->repeatCount % 6) == 0; + repeated = p->repeatCount >= 23 && ((p->repeatCount+1) % 6) == 0; else - repeated = p->repeatCount >= 16 && (p->repeatCount % 4) == 0; + repeated = p->repeatCount >= 15 && ((p->repeatCount+1) % 4) == 0; - if (repeated) - p->getState(p->repeating).repeated = true; + p->getState(p->repeating).repeated |= repeated; return; } From f665d8b41cb049cd6fef0defa621b99d48e08940 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 01:06:08 +0200 Subject: [PATCH 006/239] BoostSet: Add 'remove' and rename BoostHash::erase to remove This is more consistent with Qt's method naming. --- src/boost-hash.h | 7 ++++++- src/soundemitter.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/boost-hash.h b/src/boost-hash.h index 0bfa56d..3ce746a 100644 --- a/src/boost-hash.h +++ b/src/boost-hash.h @@ -53,7 +53,7 @@ public: p.insert(PairType(key, value)); } - inline void erase(const K &key) + inline void remove(const K &key) { p.erase(key); } @@ -116,6 +116,11 @@ public: p.insert(key); } + inline void remove(const K &key) + { + p.erase(key); + } + inline const_iterator cbegin() const { return p.cbegin(); diff --git a/src/soundemitter.cpp b/src/soundemitter.cpp index 65fe5e6..965556c 100644 --- a/src/soundemitter.cpp +++ b/src/soundemitter.cpp @@ -233,7 +233,7 @@ SoundBuffer *SoundEmitter::allocateBuffer(const std::string &filename) while (wouldBeBytes > SE_CACHE_MEM && !buffers.isEmpty()) { SoundBuffer *last = buffers.tail(); - bufferHash.erase(last->key); + bufferHash.remove(last->key); buffers.remove(last->link); wouldBeBytes -= last->bytes; From f8c26fc515cb4fb6b24b766889d4b0b0a3c12a26 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 01:26:03 +0200 Subject: [PATCH 007/239] Core/MRI: Fix handling of Etc/Font properties The gist of it is that for Etc and Font props, the assignment operator (eg. 'sprite.color=') does not take a reference of the right hand parameter and replaces its previous one with it (this was the old behavior). Rather, it keeps its internal property object and copies the parameter object into it by value. The getter is unchanged; it still returns a reference to the internal property object. s = Sprite.new c = Color.new s.color = c p s.color == c # => true p s.color.object_id == c.object_id # => false (true before) c = s.color p s.color.object_id == c.object_id # => true --- binding-mri/binding-util.h | 42 ++++++------ binding-mri/bitmap-binding.cpp | 31 ++++++--- binding-mri/etc-binding.cpp | 2 +- binding-mri/font-binding.cpp | 41 ++++++------ binding-mri/plane-binding.cpp | 9 ++- binding-mri/sprite-binding.cpp | 12 ++-- binding-mri/tilemap-binding.cpp | 8 +-- binding-mri/tilemapvx-binding.cpp | 9 ++- binding-mri/viewport-binding.cpp | 10 ++- binding-mri/window-binding.cpp | 9 +-- binding-mri/windowvx-binding.cpp | 12 ++-- src/bitmap.cpp | 12 +++- src/bitmap.h | 4 ++ src/etc.cpp | 104 ++++++++++++++++-------------- src/etc.h | 64 +++++++++--------- src/font.cpp | 77 ++++++++++++++++------ src/font.h | 8 +++ src/plane.cpp | 11 +++- src/plane.h | 2 + src/sprite.cpp | 32 +++++---- src/sprite.h | 2 + src/util.h | 14 ++++ src/viewport.cpp | 15 ++--- src/viewport.h | 2 + src/window.cpp | 21 +++--- src/window.h | 2 + src/windowvx.cpp | 23 ++----- src/windowvx.h | 2 + 28 files changed, 337 insertions(+), 243 deletions(-) diff --git a/binding-mri/binding-util.h b/binding-mri/binding-util.h index 703d525..c3f54e3 100644 --- a/binding-mri/binding-util.h +++ b/binding-mri/binding-util.h @@ -316,30 +316,11 @@ rb_check_argc(int actual, int expected) return self; \ } -#define DEF_PROP_OBJ(Klass, PropKlass, PropName, prop_iv) \ - RB_METHOD(Klass##Get##PropName) \ - { \ - RB_UNUSED_PARAM; \ - checkDisposed(self); \ - return rb_iv_get(self, prop_iv); \ - } \ - RB_METHOD(Klass##Set##PropName) \ - { \ - rb_check_argc(argc, 1); \ - Klass *k = getPrivateData(self); \ - VALUE propObj = *argv; \ - PropKlass *prop; \ - prop = getPrivateDataCheck(propObj, PropKlass##Type); \ - GUARD_EXC( k->set##PropName(prop); ) \ - rb_iv_set(self, prop_iv, propObj); \ - return propObj; \ - } - -/* Object property with allowed NIL +/* Object property which is copied by reference, with allowed NIL * FIXME: Getter assumes prop is disposable, * because self.disposed? is not checked in this case. * Should make this more clear */ -#define DEF_PROP_OBJ_NIL(Klass, PropKlass, PropName, prop_iv) \ +#define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ RB_METHOD(Klass##Get##PropName) \ { \ RB_UNUSED_PARAM; \ @@ -361,6 +342,25 @@ rb_check_argc(int actual, int expected) return propObj; \ } +/* Object property which is copied by value, not reference */ +#define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ + RB_METHOD(Klass##Get##PropName) \ + { \ + RB_UNUSED_PARAM; \ + checkDisposed(self); \ + return rb_iv_get(self, prop_iv); \ + } \ + RB_METHOD(Klass##Set##PropName) \ + { \ + rb_check_argc(argc, 1); \ + Klass *k = getPrivateData(self); \ + VALUE propObj = *argv; \ + PropKlass *prop; \ + prop = getPrivateDataCheck(propObj, PropKlass##Type); \ + GUARD_EXC( k->set##PropName(prop); ) \ + return propObj; \ + } + #define DEF_PROP(Klass, type, PropName, arg_fun, value_fun) \ RB_METHOD(Klass##Get##PropName) \ { \ diff --git a/binding-mri/bitmap-binding.cpp b/binding-mri/bitmap-binding.cpp index a49d3e5..b2448d6 100644 --- a/binding-mri/bitmap-binding.cpp +++ b/binding-mri/bitmap-binding.cpp @@ -43,7 +43,7 @@ void bitmapInitProps(Bitmap *b, VALUE self) rb_obj_call_init(fontObj, 0, 0); Font *font = getPrivateData(fontObj); - b->setFont(font); + b->setInitFont(font); rb_iv_set(self, "font", fontObj); } @@ -323,7 +323,7 @@ RB_METHOD(bitmapTextSize) return wrapObject(rect, RectType); } -DEF_PROP_OBJ(Bitmap, Font, Font, "font") +DEF_PROP_OBJ_VAL(Bitmap, Font, Font, "font") RB_METHOD(bitmapGradientFillRect) { @@ -413,12 +413,25 @@ RB_METHOD(bitmapRadialBlur) return Qnil; } -// FIXME: This isn't entire correct as the cloned bitmap -// does not get a cloned version of the original bitmap's 'font' -// attribute (the internal font attrb is the default one, whereas -// the stored iv visible to ruby would still be the same as the original) -// Not sure if this needs fixing though -INITCOPY_FUN(Bitmap) +RB_METHOD(bitmapInitializeCopy) +{ + rb_check_argc(argc, 1); + VALUE origObj = argv[0]; + + if (!OBJ_INIT_COPY(self, origObj)) + return self; + + Bitmap *orig = getPrivateData(origObj); + Bitmap *b = 0; + GUARD_EXC( b = new Bitmap(*orig); ); + + bitmapInitProps(b, self); + b->setFont(orig->getFont()); + + setPrivateData(self, b); + + return self; +} void @@ -430,7 +443,7 @@ bitmapBindingInit() disposableBindingInit(klass); _rb_define_method(klass, "initialize", bitmapInitialize); - _rb_define_method(klass, "initialize_copy", BitmapInitializeCopy); + _rb_define_method(klass, "initialize_copy", bitmapInitializeCopy); _rb_define_method(klass, "width", bitmapWidth); _rb_define_method(klass, "height", bitmapHeight); diff --git a/binding-mri/etc-binding.cpp b/binding-mri/etc-binding.cpp index 6b848ca..2c2cdd2 100644 --- a/binding-mri/etc-binding.cpp +++ b/binding-mri/etc-binding.cpp @@ -110,7 +110,7 @@ INIT_FUN(Rect, int, "iiii", 0) { \ VALUE otherObj = argv[0]; \ Klass *other = getPrivateDataCheck(otherObj, Klass##Type); \ - k->set(*other); \ + *k = *other; \ } \ else \ { \ diff --git a/binding-mri/font-binding.cpp b/binding-mri/font-binding.cpp index 8849197..c6f468a 100644 --- a/binding-mri/font-binding.cpp +++ b/binding-mri/font-binding.cpp @@ -58,14 +58,12 @@ RB_METHOD(fontInitialize) setPrivateData(self, f); /* Wrap property objects */ - f->setColor(new Color(*f->getColor())); + f->initDynAttribs(); + wrapProperty(self, f->getColor(), "color", ColorType); if (rgssVer >= 3) - { - f->setOutColor(new Color(*f->getOutColor())); - 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"); @@ -90,14 +88,12 @@ RB_METHOD(fontInitializeCopy) setPrivateData(self, f); /* Wrap property objects */ - f->setColor(new Color(*f->getColor())); + f->initDynAttribs(); + wrapProperty(self, f->getColor(), "color", ColorType); if (rgssVer >= 3) - { - f->setOutColor(new Color(*f->getOutColor())); - wrapProperty(self, f->getOutColor(), "out_color", ColorType); - } + wrapProperty(self, f->getOutColor(), "out_color", ColorType); return self; } @@ -164,13 +160,15 @@ RB_METHOD(FontSetName) return argv[0]; } +DEF_PROP_OBJ_VAL(Font, Color, Color, "color") +DEF_PROP_OBJ_VAL(Font, Color, OutColor, "out_color") + DEF_PROP_I(Font, Size) + DEF_PROP_B(Font, Bold) DEF_PROP_B(Font, Italic) DEF_PROP_B(Font, Shadow) DEF_PROP_B(Font, Outline) -DEF_PROP_OBJ(Font, Color, Color, "color") -DEF_PROP_OBJ(Font, Color, OutColor, "out_color") #define DEF_KLASS_PROP(Klass, type, PropName, param_t_s, value_fun) \ RB_METHOD(Klass##Get##PropName) \ @@ -187,10 +185,10 @@ DEF_PROP_OBJ(Font, Color, OutColor, "out_color") return value_fun(value); \ } -DEF_KLASS_PROP(Font, int, DefaultSize, "i", rb_fix_new) -DEF_KLASS_PROP(Font, bool, DefaultBold, "b", rb_bool_new) -DEF_KLASS_PROP(Font, bool, DefaultItalic, "b", rb_bool_new) -DEF_KLASS_PROP(Font, bool, DefaultShadow, "b", rb_bool_new) +DEF_KLASS_PROP(Font, int, DefaultSize, "i", rb_fix_new) +DEF_KLASS_PROP(Font, bool, DefaultBold, "b", rb_bool_new) +DEF_KLASS_PROP(Font, bool, DefaultItalic, "b", rb_bool_new) +DEF_KLASS_PROP(Font, bool, DefaultShadow, "b", rb_bool_new) DEF_KLASS_PROP(Font, bool, DefaultOutline, "b", rb_bool_new) RB_METHOD(FontGetDefaultOutColor) @@ -201,13 +199,14 @@ RB_METHOD(FontGetDefaultOutColor) RB_METHOD(FontSetDefaultOutColor) { + RB_UNUSED_PARAM; + VALUE colorObj; rb_get_args(argc, argv, "o", &colorObj RB_ARG_END); Color *c = getPrivateDataCheck(colorObj, ColorType); Font::setDefaultOutColor(c); - rb_iv_set(self, "default_out_color", colorObj); return colorObj; } @@ -239,13 +238,14 @@ RB_METHOD(FontGetDefaultColor) RB_METHOD(FontSetDefaultColor) { + RB_UNUSED_PARAM; + VALUE colorObj; rb_get_args(argc, argv, "o", &colorObj RB_ARG_END); Color *c = getPrivateDataCheck(colorObj, ColorType); Font::setDefaultColor(c); - rb_iv_set(self, "default_color", colorObj); return colorObj; } @@ -262,10 +262,13 @@ fontBindingInit() VALUE klass = rb_define_class("Font", rb_cObject); rb_define_alloc_func(klass, classAllocate<&FontType>); - Font::setDefaultColor(new Color(*Font::getDefaultColor())); + Font::initDefaultDynAttribs(); wrapProperty(klass, Font::getDefaultColor(), "default_color", ColorType); rb_iv_set(klass, "default_name", rb_str_new_cstr(Font::getDefaultName())); + if (rgssVer >= 3) + wrapProperty(klass, Font::getDefaultOutColor(), "default_out_color", ColorType); + INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name"); INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size"); INIT_KLASS_PROP_BIND(Font, DefaultBold, "default_bold"); diff --git a/binding-mri/plane-binding.cpp b/binding-mri/plane-binding.cpp index 0cbb48f..5d2c407 100644 --- a/binding-mri/plane-binding.cpp +++ b/binding-mri/plane-binding.cpp @@ -33,8 +33,7 @@ RB_METHOD(planeInitialize) setPrivateData(self, p); - p->setColor(new Color); - p->setTone(new Tone); + p->initDynAttribs(); wrapNilProperty(self, "bitmap"); wrapProperty(self, p->getColor(), "color", ColorType); @@ -43,9 +42,9 @@ RB_METHOD(planeInitialize) return self; } -DEF_PROP_OBJ_NIL(Plane, Bitmap, Bitmap, "bitmap") -DEF_PROP_OBJ(Plane, Color, Color, "color") -DEF_PROP_OBJ(Plane, Tone, Tone, "tone") +DEF_PROP_OBJ_REF(Plane, Bitmap, Bitmap, "bitmap") +DEF_PROP_OBJ_VAL(Plane, Color, Color, "color") +DEF_PROP_OBJ_VAL(Plane, Tone, Tone, "tone") DEF_PROP_I(Plane, OX) DEF_PROP_I(Plane, OY) diff --git a/binding-mri/sprite-binding.cpp b/binding-mri/sprite-binding.cpp index 830ef87..427d7b8 100644 --- a/binding-mri/sprite-binding.cpp +++ b/binding-mri/sprite-binding.cpp @@ -37,9 +37,7 @@ RB_METHOD(spriteInitialize) setPrivateData(self, s); /* Wrap property objects */ - s->setSrcRect(new Rect); - s->setColor(new Color); - s->setTone(new Tone); + s->initDynAttribs(); wrapNilProperty(self, "bitmap"); wrapProperty(self, s->getSrcRect(), "src_rect", RectType); @@ -49,10 +47,10 @@ RB_METHOD(spriteInitialize) return self; } -DEF_PROP_OBJ_NIL(Sprite, Bitmap, Bitmap, "bitmap") -DEF_PROP_OBJ(Sprite, Rect, SrcRect, "src_rect") -DEF_PROP_OBJ(Sprite, Color, Color, "color") -DEF_PROP_OBJ(Sprite, Tone, Tone, "tone") +DEF_PROP_OBJ_REF(Sprite, Bitmap, Bitmap, "bitmap") +DEF_PROP_OBJ_VAL(Sprite, Rect, SrcRect, "src_rect") +DEF_PROP_OBJ_VAL(Sprite, Color, Color, "color") +DEF_PROP_OBJ_VAL(Sprite, Tone, Tone, "tone") DEF_PROP_I(Sprite, X) DEF_PROP_I(Sprite, Y) diff --git a/binding-mri/tilemap-binding.cpp b/binding-mri/tilemap-binding.cpp index 58674b9..54cbd05 100644 --- a/binding-mri/tilemap-binding.cpp +++ b/binding-mri/tilemap-binding.cpp @@ -124,10 +124,10 @@ RB_METHOD(tilemapGetViewport) return rb_iv_get(self, "viewport"); } -DEF_PROP_OBJ(Tilemap, Bitmap, Tileset, "tileset") -DEF_PROP_OBJ(Tilemap, Table, MapData, "map_data") -DEF_PROP_OBJ(Tilemap, Table, FlashData, "flash_data") -DEF_PROP_OBJ(Tilemap, Table, Priorities, "priorities") +DEF_PROP_OBJ_REF(Tilemap, Bitmap, Tileset, "tileset") +DEF_PROP_OBJ_REF(Tilemap, Table, MapData, "map_data") +DEF_PROP_OBJ_REF(Tilemap, Table, FlashData, "flash_data") +DEF_PROP_OBJ_REF(Tilemap, Table, Priorities, "priorities") DEF_PROP_B(Tilemap, Visible) diff --git a/binding-mri/tilemapvx-binding.cpp b/binding-mri/tilemapvx-binding.cpp index 7e51d2f..af15968 100644 --- a/binding-mri/tilemapvx-binding.cpp +++ b/binding-mri/tilemapvx-binding.cpp @@ -85,11 +85,10 @@ RB_METHOD(tilemapVXUpdate) return Qnil; } -DEF_PROP_OBJ_NIL(TilemapVX, Viewport, Viewport, "viewport") - -DEF_PROP_OBJ(TilemapVX, Table, MapData, "map_data") -DEF_PROP_OBJ(TilemapVX, Table, FlashData, "flash_data") -DEF_PROP_OBJ(TilemapVX, Table, Flags, "flags") +DEF_PROP_OBJ_REF(TilemapVX, Viewport, Viewport, "viewport") +DEF_PROP_OBJ_REF(TilemapVX, Table, MapData, "map_data") +DEF_PROP_OBJ_REF(TilemapVX, Table, FlashData, "flash_data") +DEF_PROP_OBJ_REF(TilemapVX, Table, Flags, "flags") DEF_PROP_B(TilemapVX, Visible) diff --git a/binding-mri/viewport-binding.cpp b/binding-mri/viewport-binding.cpp index 612ac16..566d66e 100644 --- a/binding-mri/viewport-binding.cpp +++ b/binding-mri/viewport-binding.cpp @@ -62,9 +62,7 @@ RB_METHOD(viewportInitialize) setPrivateData(self, v); /* Wrap property objects */ - v->setRect(new Rect(*v->getRect())); - v->setColor(new Color); - v->setTone(new Tone); + v->initDynAttribs(); wrapProperty(self, v->getRect(), "rect", RectType); wrapProperty(self, v->getColor(), "color", ColorType); @@ -78,9 +76,9 @@ RB_METHOD(viewportInitialize) return self; } -DEF_PROP_OBJ(Viewport, Rect, Rect, "rect") -DEF_PROP_OBJ(Viewport, Color, Color, "color") -DEF_PROP_OBJ(Viewport, Tone, Tone, "tone") +DEF_PROP_OBJ_VAL(Viewport, Rect, Rect, "rect") +DEF_PROP_OBJ_VAL(Viewport, Color, Color, "color") +DEF_PROP_OBJ_VAL(Viewport, Tone, Tone, "tone") DEF_PROP_I(Viewport, OX) DEF_PROP_I(Viewport, OY) diff --git a/binding-mri/window-binding.cpp b/binding-mri/window-binding.cpp index 5df0e7b..1cd0ac3 100644 --- a/binding-mri/window-binding.cpp +++ b/binding-mri/window-binding.cpp @@ -32,7 +32,8 @@ RB_METHOD(windowInitialize) setPrivateData(self, w); - w->setCursorRect(new Rect); + w->initDynAttribs(); + wrapNilProperty(self, "windowskin"); wrapNilProperty(self, "contents"); wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType); @@ -51,9 +52,9 @@ RB_METHOD(windowUpdate) return Qnil; } -DEF_PROP_OBJ_NIL(Window, Bitmap, Windowskin, "windowskin") -DEF_PROP_OBJ_NIL(Window, Bitmap, Contents, "contents") -DEF_PROP_OBJ(Window, Rect, CursorRect, "cursor_rect") +DEF_PROP_OBJ_REF(Window, Bitmap, Windowskin, "windowskin") +DEF_PROP_OBJ_REF(Window, Bitmap, Contents, "contents") +DEF_PROP_OBJ_VAL(Window, Rect, CursorRect, "cursor_rect") DEF_PROP_B(Window, Stretch) DEF_PROP_B(Window, Active) diff --git a/binding-mri/windowvx-binding.cpp b/binding-mri/windowvx-binding.cpp index d70f02e..17bdd77 100644 --- a/binding-mri/windowvx-binding.cpp +++ b/binding-mri/windowvx-binding.cpp @@ -51,8 +51,8 @@ RB_METHOD(windowVXInitialize) setPrivateData(self, w); - w->setCursorRect(new Rect); - w->setTone(new Tone); + w->initDynAttribs(); + wrapNilProperty(self, "windowskin"); wrapProperty(self, w->getTone(), "tone", ToneType); wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType); @@ -109,11 +109,11 @@ RB_METHOD(windowVXIsClosed) return rb_bool_new(w->isClosed()); } -DEF_PROP_OBJ_NIL(WindowVX, Bitmap, Windowskin, "windowskin") -DEF_PROP_OBJ_NIL(WindowVX, Bitmap, Contents, "contents") +DEF_PROP_OBJ_REF(WindowVX, Bitmap, Windowskin, "windowskin") +DEF_PROP_OBJ_REF(WindowVX, Bitmap, Contents, "contents") -DEF_PROP_OBJ(WindowVX, Rect, CursorRect, "cursor_rect") -DEF_PROP_OBJ(WindowVX, Tone, Tone, "tone") +DEF_PROP_OBJ_VAL(WindowVX, Rect, CursorRect, "cursor_rect") +DEF_PROP_OBJ_VAL(WindowVX, Tone, Tone, "tone") DEF_PROP_I(WindowVX, X) DEF_PROP_I(WindowVX, Y) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index f508334..beff91b 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -1067,7 +1067,17 @@ IntRect Bitmap::textSize(const char *str) return IntRect(0, 0, w, h); } -DEF_ATTR_SIMPLE(Bitmap, Font, Font*, p->font) +DEF_ATTR_RD_SIMPLE(Bitmap, Font, Font*, p->font) + +void Bitmap::setFont(Font *value) +{ + *p->font = *value; +} + +void Bitmap::setInitFont(Font *value) +{ + p->font = value; +} TEXFBO &Bitmap::getGLTypes() { diff --git a/src/bitmap.h b/src/bitmap.h index 22da2fe..89216d0 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -101,6 +101,10 @@ public: DECL_ATTR(Font, Font*) + /* Sets initial reference without copying by value, + * use at construction */ + void setInitFont(Font *value); + /* */ TEXFBO &getGLTypes(); SDL_Surface *megaSurface() const; diff --git a/src/etc.cpp b/src/etc.cpp index 7764c85..14f8f4c 100644 --- a/src/etc.cpp +++ b/src/etc.cpp @@ -52,20 +52,15 @@ bool Color::operator==(const Color &o) const alpha == o.alpha; } -void Color::updateInternal() +const Color &Color::operator=(const Color &o) { - norm.x = red / 255; - norm.y = green / 255; - norm.z = blue / 255; - norm.w = alpha / 255; -} + red = o.red; + green = o.green; + blue = o.blue; + alpha = o.alpha; + norm = o.norm; -void Color::updateExternal() -{ - red = norm.x * 255; - green = norm.y * 255; - blue = norm.z * 255; - alpha = norm.w * 255; + return o; } void Color::set(double red, double green, double blue, double alpha) @@ -78,15 +73,6 @@ void Color::set(double red, double green, double blue, double alpha) updateInternal(); } -void Color::set(const Color &other) -{ - red = other.red; - green = other.green; - blue = other.blue; - alpha = other.alpha; - norm = other.norm; -} - void Color::setRed(double value) { red = value; @@ -111,15 +97,6 @@ void Color::setAlpha(double value) norm.w = clamp(value, 0, 255) / 255; } -void Color::toSDLColor(SDL_Color &c) const -{ - c.r = clamp(red, 0, 255); - c.g = clamp(green, 0, 255); - c.b = clamp(blue, 0, 255); -// c.a = clamp(alpha, 0, 255); - c.a = 255; -} - /* Serializable */ int Color::serialSize() const { @@ -153,6 +130,31 @@ Color *Color::deserialize(const char *data, int len) return c; } +void Color::updateInternal() +{ + norm.x = red / 255; + norm.y = green / 255; + norm.z = blue / 255; + norm.w = alpha / 255; +} + +void Color::updateExternal() +{ + red = norm.x * 255; + green = norm.y * 255; + blue = norm.z * 255; + alpha = norm.w * 255; +} + +void Color::toSDLColor(SDL_Color &c) const +{ + c.r = clamp(red, 0, 255); + c.g = clamp(green, 0, 255); + c.b = clamp(blue, 0, 255); +// c.a = clamp(alpha, 0, 255); + c.a = 255; +} + Tone::Tone(double red, double green, double blue, double gray) : red(red), green(green), blue(blue), gray(gray) @@ -173,14 +175,6 @@ bool Tone::operator==(const Tone &o) const gray == o.gray; } -void Tone::updateInternal() -{ - norm.x = (float) clamp(red, -255, 255) / 255; - norm.y = (float) clamp(green, -255, 255) / 255; - norm.z = (float) clamp(blue, -255, 255) / 255; - norm.w = (float) clamp(gray, 0, 255) / 255; -} - void Tone::set(double red, double green, double blue, double gray) { this->red = red; @@ -192,15 +186,17 @@ void Tone::set(double red, double green, double blue, double gray) valueChanged(); } -void Tone::set(const Tone &other) +const Tone& Tone::operator=(const Tone &o) { - red = other.red; - green= other.green; - blue = other.blue; - gray = other.gray; - norm = other.norm; + red = o.red; + green = o.green; + blue = o.blue; + gray = o.gray; + norm = o.norm; valueChanged(); + + return o; } void Tone::setRed(double value) @@ -268,6 +264,14 @@ Tone *Tone::deserialize(const char *data, int len) return t; } +void Tone::updateInternal() +{ + norm.x = (float) clamp(red, -255, 255) / 255; + norm.y = (float) clamp(green, -255, 255) / 255; + norm.z = (float) clamp(blue, -255, 255) / 255; + norm.w = (float) clamp(gray, 0, 255) / 255; +} + Rect::Rect(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) @@ -315,14 +319,16 @@ void Rect::set(int x, int y, int w, int h) valueChanged(); } -void Rect::set(const Rect &other) +const Rect &Rect::operator=(const Rect &o) { - x = other.x; - y = other.y; - width = other.width; - height = other.height; + x = o.x; + y = o.y; + width = o.width; + height = o.height; valueChanged(); + + return o; } void Rect::empty() diff --git a/src/etc.h b/src/etc.h index d977569..3fba42f 100644 --- a/src/etc.h +++ b/src/etc.h @@ -50,13 +50,10 @@ struct Color : public Serializable virtual ~Color() {} - bool operator==(const Color &o) const; - - void updateInternal(); - void updateExternal(); - + const Color &operator=(const Color &o); void set(double red, double green, double blue, double alpha); - void set(const Color &other); + + bool operator==(const Color &o) const; void setRed(double value); void setGreen(double value); @@ -68,6 +65,15 @@ struct Color : public Serializable double getBlue() const { return blue; } double getAlpha() const { return alpha; } + /* Serializable */ + int serialSize() const; + void serialize(char *buffer) const; + static Color *deserialize(const char *data, int len); + + /* Internal */ + void updateInternal(); + void updateExternal(); + bool hasEffect() const { return (alpha != 0); @@ -75,11 +81,6 @@ struct Color : public Serializable void toSDLColor(SDL_Color &c) const; - /* Serializable */ - int serialSize() const; - void serialize(char *buffer) const; - static Color *deserialize(const char *data, int len); - /* Range (0.0 ~ 255.0) */ double red; double green; @@ -103,10 +104,8 @@ struct Tone : public Serializable bool operator==(const Tone &o) const; - void updateInternal(); - void set(double red, double green, double blue, double gray); - void set(const Tone &other); + const Tone &operator=(const Tone &o); void setRed(double value); void setGreen(double value); @@ -118,6 +117,14 @@ struct Tone : public Serializable double getBlue() const { return blue; } double getGray() const { return gray; } + /* Serializable */ + int serialSize() const; + void serialize(char *buffer) const; + static Tone *deserialize(const char *data, int len); + + /* Internal */ + void updateInternal(); + bool hasEffect() const { return ((int)red != 0 || @@ -126,11 +133,6 @@ struct Tone : public Serializable (int)gray != 0); } - /* Serializable */ - int serialSize() const; - void serialize(char *buffer) const; - static Tone *deserialize(const char *data, int len); - /* Range (-255.0 ~ 255.0) */ double red; double green; @@ -159,17 +161,7 @@ struct Rect : public Serializable bool operator==(const Rect &o) const; void operator=(const IntRect &rect); void set(int x, int y, int w, int h); - void set(const Rect &other); - - FloatRect toFloatRect() const - { - return FloatRect(x, y, width, height); - } - - IntRect toIntRect() - { - return IntRect(x, y, width, height); - } + const Rect &operator=(const Rect &o); void empty(); bool isEmpty() const; @@ -184,10 +176,22 @@ struct Rect : public Serializable int getWidth() const { return width; } int getHeight() const { return height; } + /* Serializable */ int serialSize() const; void serialize(char *buffer) const; static Rect *deserialize(const char *data, int len); + /* Internal */ + FloatRect toFloatRect() const + { + return FloatRect(x, y, width, height); + } + + IntRect toIntRect() + { + return IntRect(x, y, width, height); + } + int x; int y; int width; diff --git a/src/font.cpp b/src/font.cpp index 8a85f6c..09b5ec8 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -255,6 +255,20 @@ struct FontPrivate outColorTmp(*other.outColor), sdlFont(other.sdlFont) {} + + void operator=(const FontPrivate &o) + { + name = o.name; + size = o.size; + bold = o.bold; + italic = o.italic; + outline = o.outline; + shadow = o.shadow; + *color = *o.color; + *outColor = *o.outColor; + + sdlFont = 0; + } }; std::string FontPrivate::defaultName = "Arial"; @@ -269,12 +283,6 @@ Color *FontPrivate::defaultOutColor = &FontPrivate::defaultOutColorTmp; Color FontPrivate::defaultColorTmp(255, 255, 255, 255); Color FontPrivate::defaultOutColorTmp(0, 0, 0, 128); -void Font::initDefaults() -{ - FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false); - FontPrivate::defaultShadow = (rgssVer >= 3 ? false : true ); -} - bool Font::doesExist(const char *name) { if (!name) @@ -299,6 +307,13 @@ Font::~Font() delete p; } +const Font &Font::operator=(const Font &o) +{ + *p = *o.p; + + return o; +} + const char *Font::getName() const { return p->name.c_str(); @@ -329,21 +344,21 @@ void Font::setSize(int value) #undef CHK_DISP #define CHK_DISP -DEF_ATTR_RD_SIMPLE(Font, Size, int, p->size) -DEF_ATTR_SIMPLE(Font, Bold, bool, p->bold) -DEF_ATTR_SIMPLE(Font, Italic, bool, p->italic) -DEF_ATTR_SIMPLE(Font, Color, Color*, p->color) -DEF_ATTR_SIMPLE(Font, Shadow, bool, p->shadow) -DEF_ATTR_SIMPLE(Font, Outline, bool, p->outline) -DEF_ATTR_SIMPLE(Font, OutColor, Color*, p->outColor) +DEF_ATTR_RD_SIMPLE(Font, Size, int, p->size) +DEF_ATTR_SIMPLE (Font, Bold, bool, p->bold) +DEF_ATTR_SIMPLE (Font, Italic, bool, p->italic) +DEF_ATTR_SIMPLE (Font, Shadow, bool, p->shadow) +DEF_ATTR_SIMPLE (Font, Outline, bool, p->outline) +DEF_ATTR_OBJ_VALUE(Font, Color, Color*, p->color) +DEF_ATTR_OBJ_VALUE(Font, OutColor, Color*, p->outColor) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultSize, int, FontPrivate::defaultSize) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultBold, bool, FontPrivate::defaultBold) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultItalic, bool, FontPrivate::defaultItalic) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color*, FontPrivate::defaultColor) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultShadow, bool, FontPrivate::defaultShadow) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutline, bool, FontPrivate::defaultOutline) -DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutColor, Color*, FontPrivate::defaultOutColor) +DEF_ATTR_SIMPLE_STATIC (Font, DefaultSize, int, FontPrivate::defaultSize) +DEF_ATTR_SIMPLE_STATIC (Font, DefaultBold, bool, FontPrivate::defaultBold) +DEF_ATTR_SIMPLE_STATIC (Font, DefaultItalic, bool, FontPrivate::defaultItalic) +DEF_ATTR_SIMPLE_STATIC (Font, DefaultShadow, bool, FontPrivate::defaultShadow) +DEF_ATTR_SIMPLE_STATIC (Font, DefaultOutline, bool, FontPrivate::defaultOutline) +DEF_ATTR_OBJ_VALUE_STATIC(Font, DefaultColor, Color*, FontPrivate::defaultColor) +DEF_ATTR_OBJ_VALUE_STATIC(Font, DefaultOutColor, Color*, FontPrivate::defaultOutColor) const char *Font::getDefaultName() { @@ -355,6 +370,28 @@ void Font::setDefaultName(const char *value) FontPrivate::defaultName = value; } +void Font::initDynAttribs() +{ + p->color = new Color(p->colorTmp); + + if (rgssVer >= 3) + p->outColor = new Color(p->outColorTmp);; +} + +void Font::initDefaultDynAttribs() +{ + FontPrivate::defaultColor = new Color(FontPrivate::defaultColorTmp); + + if (rgssVer >= 3) + FontPrivate::defaultOutColor = new Color(FontPrivate::defaultOutColorTmp); +} + +void Font::initDefaults() +{ + FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false); + FontPrivate::defaultShadow = (rgssVer >= 3 ? false : true ); +} + _TTF_Font *Font::getSdlFont() { if (!p->sdlFont) diff --git a/src/font.h b/src/font.h index 8a5b075..9320600 100644 --- a/src/font.h +++ b/src/font.h @@ -82,6 +82,8 @@ public: Font(const Font &other); ~Font(); + const Font &operator=(const Font &o); + const char *getName() const; void setName(const char *value); @@ -102,6 +104,12 @@ public: DECL_ATTR_STATIC( DefaultOutline, bool ) DECL_ATTR_STATIC( DefaultOutColor, Color* ) + /* Assigns heap allocated objects to object properties; + * using this in pure C++ will cause memory leaks + * (ie. only to be used in GCed language bindings */ + void initDynAttribs(); + static void initDefaultDynAttribs(); + static void initDefaults(); /* internal */ diff --git a/src/plane.cpp b/src/plane.cpp index 8b0f308..1982bce 100644 --- a/src/plane.cpp +++ b/src/plane.cpp @@ -163,9 +163,9 @@ DEF_ATTR_RD_SIMPLE(Plane, ZoomX, float, p->zoomX) DEF_ATTR_RD_SIMPLE(Plane, ZoomY, float, p->zoomY) DEF_ATTR_RD_SIMPLE(Plane, BlendType, int, p->blendType) -DEF_ATTR_SIMPLE(Plane, Opacity, int, p->opacity) -DEF_ATTR_SIMPLE(Plane, Color, Color*, p->color) -DEF_ATTR_SIMPLE(Plane, Tone, Tone*, p->tone) +DEF_ATTR_SIMPLE (Plane, Opacity, int, p->opacity) +DEF_ATTR_OBJ_VALUE(Plane, Color, Color*, p->color) +DEF_ATTR_OBJ_VALUE(Plane, Tone, Tone*, p->tone) Plane::~Plane() { @@ -238,6 +238,11 @@ void Plane::setBlendType(int value) } } +void Plane::initDynAttribs() +{ + p->color = new Color; + p->tone = new Tone; +} void Plane::draw() { diff --git a/src/plane.h b/src/plane.h index 9f4cd25..1b55278 100644 --- a/src/plane.h +++ b/src/plane.h @@ -47,6 +47,8 @@ public: DECL_ATTR( Color, Color* ) DECL_ATTR( Tone, Tone* ) + void initDynAttribs(); + private: PlanePrivate *p; diff --git a/src/sprite.cpp b/src/sprite.cpp index 50a2415..b436db2 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -304,7 +304,6 @@ Sprite::~Sprite() } DEF_ATTR_RD_SIMPLE(Sprite, Bitmap, Bitmap*, p->bitmap) -DEF_ATTR_RD_SIMPLE(Sprite, SrcRect, Rect*, p->srcRect) DEF_ATTR_RD_SIMPLE(Sprite, X, int, p->trans.getPosition().x) DEF_ATTR_RD_SIMPLE(Sprite, Y, int, p->trans.getPosition().y) DEF_ATTR_RD_SIMPLE(Sprite, OX, int, p->trans.getOrigin().x) @@ -322,10 +321,12 @@ DEF_ATTR_RD_SIMPLE(Sprite, WaveLength, int, p->wave.length) DEF_ATTR_RD_SIMPLE(Sprite, WaveSpeed, int, p->wave.speed) DEF_ATTR_RD_SIMPLE(Sprite, WavePhase, float, p->wave.phase) -DEF_ATTR_SIMPLE(Sprite, BushOpacity, int, p->bushOpacity) -DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity) -DEF_ATTR_SIMPLE(Sprite, Color, Color*, p->color) -DEF_ATTR_SIMPLE(Sprite, Tone, Tone*, p->tone) +DEF_ATTR_SIMPLE (Sprite, BushOpacity, int, p->bushOpacity) +DEF_ATTR_SIMPLE (Sprite, Opacity, int, p->opacity) + +DEF_ATTR_OBJ_VALUE(Sprite, SrcRect, Rect*, p->srcRect) +DEF_ATTR_OBJ_VALUE(Sprite, Color, Color*, p->color) +DEF_ATTR_OBJ_VALUE(Sprite, Tone, Tone*, p->tone) void Sprite::setBitmap(Bitmap *bitmap) { @@ -347,18 +348,6 @@ void Sprite::setBitmap(Bitmap *bitmap) p->wave.dirty = true; } -void Sprite::setSrcRect(Rect *rect) -{ - if (p->srcRect == rect) - return; - - p->srcRect = rect; - p->updateSrcRectCon(); - - if (p->bitmap) - p->onSrcRectChange(); -} - void Sprite::setX(int value) { if (p->trans.getPosition().x == value) @@ -476,6 +465,15 @@ DEF_WAVE_SETTER(Phase, phase, float) #undef DEF_WAVE_SETTER +void Sprite::initDynAttribs() +{ + p->srcRect = new Rect; + p->color = new Color; + p->tone = new Tone; + + p->updateSrcRectCon(); +} + /* Flashable */ void Sprite::update() { diff --git a/src/sprite.h b/src/sprite.h index 3783f90..b1645bb 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -67,6 +67,8 @@ public: DECL_ATTR( WaveSpeed, int ) DECL_ATTR( WavePhase, float ) + void initDynAttribs(); + private: SpritePrivate *p; diff --git a/src/util.h b/src/util.h index 3f63b5e..b8b42f4 100644 --- a/src/util.h +++ b/src/util.h @@ -137,4 +137,18 @@ inline bool contains(const C &c, const V &v) #define DEF_ATTR_SIMPLE_STATIC(klass, name, type, location) \ DEF_ATTR_SIMPLE_DETAILED(klass, name, type, location, ) +#define DEF_ATTR_OBJ_VALUE(klass, name, type, location) \ + DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, const) \ + void klass :: set##name(type value) \ + { \ + *location = *value; \ + } + +#define DEF_ATTR_OBJ_VALUE_STATIC(klass, name, type, location) \ + DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, ) \ + void klass :: set##name(type value) \ + { \ + *location = *value; \ + } + #endif // UTIL_H diff --git a/src/viewport.cpp b/src/viewport.cpp index 38aa89f..49c3798 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -141,10 +141,10 @@ Viewport::~Viewport() DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.xOrigin) DEF_ATTR_RD_SIMPLE(Viewport, OY, int, geometry.yOrigin) -DEF_ATTR_RD_SIMPLE(Viewport, Rect, Rect*, p->rect) -DEF_ATTR_SIMPLE(Viewport, Color, Color*, p->color) -DEF_ATTR_SIMPLE(Viewport, Tone, Tone*, p->tone) +DEF_ATTR_OBJ_VALUE(Viewport, Rect, Rect*, p->rect) +DEF_ATTR_OBJ_VALUE(Viewport, Color, Color*, p->color) +DEF_ATTR_OBJ_VALUE(Viewport, Tone, Tone*, p->tone) void Viewport::setOX(int value) { @@ -164,14 +164,13 @@ void Viewport::setOY(int value) notifyGeometryChange(); } -void Viewport::setRect(Rect *value) +void Viewport::initDynAttribs() { - if (p->rect == value) - return; + p->rect = new Rect(*p->rect); + p->color = new Color; + p->tone = new Tone; - p->rect = value; p->updateRectCon(); - p->onRectChange(); } /* Scene */ diff --git a/src/viewport.h b/src/viewport.h index 6d340b6..325da41 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -43,6 +43,8 @@ public: DECL_ATTR( Color, Color* ) DECL_ATTR( Tone, Tone* ) + void initDynAttribs(); + private: void initViewport(int x, int y, int width, int height); void geometryChanged(); diff --git a/src/window.cpp b/src/window.cpp index 6f985fd..1d43d95 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -711,7 +711,6 @@ DEF_ATTR_SIMPLE(Window, Y, int, p->position.y) DEF_ATTR_RD_SIMPLE(Window, Windowskin, Bitmap*, p->windowskin) DEF_ATTR_RD_SIMPLE(Window, Contents, Bitmap*, p->contents) DEF_ATTR_RD_SIMPLE(Window, Stretch, bool, p->bgStretch) -DEF_ATTR_RD_SIMPLE(Window, CursorRect, Rect*, p->cursorRect) DEF_ATTR_RD_SIMPLE(Window, Active, bool, p->active) DEF_ATTR_RD_SIMPLE(Window, Pause, bool, p->pause) DEF_ATTR_RD_SIMPLE(Window, Width, int, p->size.x) @@ -722,6 +721,8 @@ DEF_ATTR_RD_SIMPLE(Window, Opacity, int, p->opacity) DEF_ATTR_RD_SIMPLE(Window, BackOpacity, int, p->backOpacity) DEF_ATTR_RD_SIMPLE(Window, ContentsOpacity, int, p->contentsOpacity) +DEF_ATTR_OBJ_VALUE(Window, CursorRect, Rect*, p->cursorRect) + void Window::setWindowskin(Bitmap *value) { p->windowskin = value; @@ -758,17 +759,6 @@ void Window::setStretch(bool value) p->baseVertDirty = true; } -void Window::setCursorRect(Rect *value) -{ - if (p->cursorRect == value) - return; - - p->cursorRect = value; - - p->refreshCursorRectCon(); - p->markControlVertDirty(); -} - void Window::setActive(bool value) { if (p->active == value) @@ -852,6 +842,13 @@ void Window::setContentsOpacity(int value) p->contentsQuad.setColor(Vec4(1, 1, 1, p->contentsOpacity.norm)); } +void Window::initDynAttribs() +{ + p->cursorRect = new Rect; + + p->refreshCursorRectCon(); +} + void Window::draw() { p->drawBase(); diff --git a/src/window.h b/src/window.h index 50e88e9..a3fb315 100644 --- a/src/window.h +++ b/src/window.h @@ -56,6 +56,8 @@ public: DECL_ATTR( BackOpacity, int ) DECL_ATTR( ContentsOpacity, int ) + void initDynAttribs(); + private: WindowPrivate *p; diff --git a/src/windowvx.cpp b/src/windowvx.cpp index 936792f..103bc44 100644 --- a/src/windowvx.cpp +++ b/src/windowvx.cpp @@ -870,7 +870,6 @@ DEF_ATTR_SIMPLE(WindowVX, Y, int, p->geo.y) DEF_ATTR_RD_SIMPLE(WindowVX, Windowskin, Bitmap*, p->windowskin) DEF_ATTR_RD_SIMPLE(WindowVX, Contents, Bitmap*, p->contents) -DEF_ATTR_RD_SIMPLE(WindowVX, CursorRect, Rect*, p->cursorRect) DEF_ATTR_RD_SIMPLE(WindowVX, Active, bool, p->active) DEF_ATTR_RD_SIMPLE(WindowVX, ArrowsVisible, bool, p->arrowsVisible) DEF_ATTR_RD_SIMPLE(WindowVX, Pause, bool, p->pause) @@ -884,7 +883,9 @@ DEF_ATTR_RD_SIMPLE(WindowVX, Opacity, int, p->opacity) DEF_ATTR_RD_SIMPLE(WindowVX, BackOpacity, int, p->backOpacity) DEF_ATTR_RD_SIMPLE(WindowVX, ContentsOpacity, int, p->contentsOpacity) DEF_ATTR_RD_SIMPLE(WindowVX, Openness, int, p->openness) -DEF_ATTR_RD_SIMPLE(WindowVX, Tone, Tone*, p->tone) + +DEF_ATTR_OBJ_VALUE(WindowVX, CursorRect, Rect*, p->cursorRect) +DEF_ATTR_OBJ_VALUE(WindowVX, Tone, Tone*, p->tone) void WindowVX::setWindowskin(Bitmap *value) { @@ -909,16 +910,6 @@ void WindowVX::setContents(Bitmap *value) p->ctrlVertDirty = true; } -void WindowVX::setCursorRect(Rect *value) -{ - if (p->cursorRect == value) - return; - - p->cursorRect = value; - p->cursorVertDirty = true; - p->refreshCursorRectCon(); -} - void WindowVX::setActive(bool value) { if (p->active == value) @@ -1050,12 +1041,12 @@ void WindowVX::setOpenness(int value) p->updateBaseQuad(); } -void WindowVX::setTone(Tone *value) +void WindowVX::initDynAttribs() { - if (p->tone == value) - return; + p->cursorRect = new Rect; + p->tone = new Tone; - p->tone = value; + p->refreshCursorRectCon(); p->refreshToneCon(); } diff --git a/src/windowvx.h b/src/windowvx.h index 3d42410..d90840f 100644 --- a/src/windowvx.h +++ b/src/windowvx.h @@ -66,6 +66,8 @@ public: DECL_ATTR( Openness, int ) DECL_ATTR( Tone, Tone* ) + void initDynAttribs(); + private: WindowVXPrivate *p; From 0131ed09f0e38a5592035619bb54c711644e805d Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 01:52:12 +0200 Subject: [PATCH 008/239] Bindings: Remove 'wrapNilProperty' It's completely useless lol. --- binding-mri/binding-util.h | 6 ------ binding-mri/plane-binding.cpp | 1 - binding-mri/sprite-binding.cpp | 1 - binding-mri/window-binding.cpp | 2 -- binding-mri/windowvx-binding.cpp | 1 - binding-mruby/binding-util.h | 9 --------- binding-mruby/plane-binding.cpp | 1 - binding-mruby/sprite-binding.cpp | 1 - binding-mruby/window-binding.cpp | 2 -- 9 files changed, 24 deletions(-) diff --git a/binding-mri/binding-util.h b/binding-mri/binding-util.h index c3f54e3..f8718b2 100644 --- a/binding-mri/binding-util.h +++ b/binding-mri/binding-util.h @@ -160,12 +160,6 @@ wrapProperty(VALUE self, void *prop, const char *iv, return propObj; } -inline void -wrapNilProperty(VALUE self, const char *iv) -{ - rb_iv_set(self, iv, Qnil); -} - /* Implemented: oSszfibn| */ int rb_get_args(int argc, VALUE *argv, const char *format, ...); diff --git a/binding-mri/plane-binding.cpp b/binding-mri/plane-binding.cpp index 5d2c407..0680263 100644 --- a/binding-mri/plane-binding.cpp +++ b/binding-mri/plane-binding.cpp @@ -35,7 +35,6 @@ RB_METHOD(planeInitialize) p->initDynAttribs(); - wrapNilProperty(self, "bitmap"); wrapProperty(self, p->getColor(), "color", ColorType); wrapProperty(self, p->getTone(), "tone", ToneType); diff --git a/binding-mri/sprite-binding.cpp b/binding-mri/sprite-binding.cpp index 427d7b8..0fa4b46 100644 --- a/binding-mri/sprite-binding.cpp +++ b/binding-mri/sprite-binding.cpp @@ -39,7 +39,6 @@ RB_METHOD(spriteInitialize) /* Wrap property objects */ s->initDynAttribs(); - wrapNilProperty(self, "bitmap"); wrapProperty(self, s->getSrcRect(), "src_rect", RectType); wrapProperty(self, s->getColor(), "color", ColorType); wrapProperty(self, s->getTone(), "tone", ToneType); diff --git a/binding-mri/window-binding.cpp b/binding-mri/window-binding.cpp index 1cd0ac3..ed61b11 100644 --- a/binding-mri/window-binding.cpp +++ b/binding-mri/window-binding.cpp @@ -34,8 +34,6 @@ RB_METHOD(windowInitialize) w->initDynAttribs(); - wrapNilProperty(self, "windowskin"); - wrapNilProperty(self, "contents"); wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType); return self; diff --git a/binding-mri/windowvx-binding.cpp b/binding-mri/windowvx-binding.cpp index 17bdd77..21cc7c3 100644 --- a/binding-mri/windowvx-binding.cpp +++ b/binding-mri/windowvx-binding.cpp @@ -53,7 +53,6 @@ RB_METHOD(windowVXInitialize) w->initDynAttribs(); - wrapNilProperty(self, "windowskin"); wrapProperty(self, w->getTone(), "tone", ToneType); wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType); diff --git a/binding-mruby/binding-util.h b/binding-mruby/binding-util.h index 448bf4a..fd2e8d1 100644 --- a/binding-mruby/binding-util.h +++ b/binding-mruby/binding-util.h @@ -312,15 +312,6 @@ wrapProperty(mrb_state *mrb, mrb_value self, propObj); } -inline void -wrapNilProperty(mrb_state *mrb, mrb_value self, CommonSymbol iv) -{ - mrb_obj_iv_set(mrb, - mrb_obj_ptr(self), - getSym(mrb, iv), - mrb_nil_value()); -} - inline mrb_value getProperty(mrb_state *mrb, mrb_value self, CommonSymbol iv) { diff --git a/binding-mruby/plane-binding.cpp b/binding-mruby/plane-binding.cpp index 430250b..5ad4e25 100644 --- a/binding-mruby/plane-binding.cpp +++ b/binding-mruby/plane-binding.cpp @@ -36,7 +36,6 @@ MRB_METHOD(planeInitialize) p->setColor(new Color); p->setTone(new Tone); - wrapNilProperty(mrb, self, CSbitmap); wrapProperty(mrb, self, p->getColor(), CScolor, ColorType); wrapProperty(mrb, self, p->getTone(), CStone, ToneType); diff --git a/binding-mruby/sprite-binding.cpp b/binding-mruby/sprite-binding.cpp index ddfee1e..adc2f9b 100644 --- a/binding-mruby/sprite-binding.cpp +++ b/binding-mruby/sprite-binding.cpp @@ -39,7 +39,6 @@ MRB_METHOD(spriteInitialize) s->setColor(new Color); s->setTone(new Tone); - wrapNilProperty(mrb, self, CSbitmap); wrapProperty(mrb, self, s->getSrcRect(), CSsrc_rect, RectType); wrapProperty(mrb, self, s->getColor(), CScolor, ColorType); wrapProperty(mrb, self, s->getTone(), CStone, ToneType); diff --git a/binding-mruby/window-binding.cpp b/binding-mruby/window-binding.cpp index ac2ece5..5ba9d64 100644 --- a/binding-mruby/window-binding.cpp +++ b/binding-mruby/window-binding.cpp @@ -33,8 +33,6 @@ MRB_METHOD(windowInitialize) setPrivateData(self, w, WindowType); w->setCursorRect(new Rect); - wrapNilProperty(mrb, self, CSwindowskin); - wrapNilProperty(mrb, self, CScontents); wrapProperty(mrb, self, w->getCursorRect(), CScursor_rect, RectType); return self; From 4d54fce8ee9e143317f8df7551cd322d84ae8281 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 01:56:28 +0200 Subject: [PATCH 009/239] Small compilation fix (mruby is still broken though) --- binding-mruby/sprite-binding.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/binding-mruby/sprite-binding.cpp b/binding-mruby/sprite-binding.cpp index adc2f9b..e6244af 100644 --- a/binding-mruby/sprite-binding.cpp +++ b/binding-mruby/sprite-binding.cpp @@ -20,6 +20,7 @@ */ #include "sprite.h" +#include "sharedstate.h" #include "disposable-binding.h" #include "flashable-binding.h" #include "sceneelement-binding.h" From 7f41b9cc45f17bee22843b8c002169a832d75378 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 21:54:16 +0200 Subject: [PATCH 010/239] Config: Correctly setup rgssVer / screen size with customScript --- src/config.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 5ba2fde..5fb3c49 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -241,11 +241,26 @@ static std::string baseName(const std::string &path) return path.substr(pos + 1); } +static void setupScreenSize(Config &conf) +{ + if (conf.defScreenW <= 0) + conf.defScreenW = (conf.rgssVersion == 1 ? 640 : 544); + + if (conf.defScreenH <= 0) + conf.defScreenH = (conf.rgssVersion == 1 ? 480 : 416); +} + void Config::readGameINI() { if (!customScript.empty()) { game.title = baseName(customScript); + + if (rgssVersion == 0) + rgssVersion = 1; + + setupScreenSize(*this); + return; } @@ -355,9 +370,5 @@ void Config::readGameINI() } } - if (defScreenW <= 0) - defScreenW = (rgssVersion == 1 ? 640 : 544); - - if (defScreenH <= 0) - defScreenH = (rgssVersion == 1 ? 480 : 416); + setupScreenSize(*this); } From 9461449cc9ecb8fb493158679268f699743468f9 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 22:53:19 +0200 Subject: [PATCH 011/239] MRuby: Fix handling of Etc/Font properties Port of f8c26fc515cb4fb6b24b766889d4b0b0a3c12a26. --- binding-mruby/binding-util.cpp | 2 + binding-mruby/binding-util.h | 14 +++-- binding-mruby/bitmap-binding.cpp | 14 +++-- binding-mruby/font-binding.cpp | 93 ++++++++++++++++++++++++------ binding-mruby/plane-binding.cpp | 11 ++-- binding-mruby/sprite-binding.cpp | 12 ++-- binding-mruby/tilemap-binding.cpp | 8 +-- binding-mruby/viewport-binding.cpp | 10 ++-- binding-mruby/window-binding.cpp | 8 +-- 9 files changed, 117 insertions(+), 55 deletions(-) diff --git a/binding-mruby/binding-util.cpp b/binding-mruby/binding-util.cpp index 6a35a65..0cee594 100644 --- a/binding-mruby/binding-util.cpp +++ b/binding-mruby/binding-util.cpp @@ -37,6 +37,7 @@ struct SYMD(viewport), SYMD(bitmap), SYMD(color), + SYMD(out_color), SYMD(tone), SYMD(rect), SYMD(src_rect), @@ -51,6 +52,7 @@ struct SYMD(path), SYMD(array), SYMD(default_color), + SYMD(default_out_color), SYMD(children), SYMD(dispose) }; diff --git a/binding-mruby/binding-util.h b/binding-mruby/binding-util.h index fd2e8d1..19f359b 100644 --- a/binding-mruby/binding-util.h +++ b/binding-mruby/binding-util.h @@ -38,6 +38,7 @@ enum CommonSymbol CSviewport, CSbitmap, CScolor, + CSout_color, CStone, CSrect, CSsrc_rect, @@ -52,6 +53,7 @@ enum CommonSymbol CSpath, CSarray, CSdefault_color, + CSdefault_out_color, CSchildren, CSdispose, @@ -149,7 +151,8 @@ defineClass(mrb_state *mrb, const char *name) #define MRB_FUN_UNUSED_PARAM { (void) mrb; } -#define DEF_PROP_OBJ(Klass, PropKlass, PropName, prop_iv) \ +/* Object property which is copied by value, not reference */ +#define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ MRB_METHOD(Klass##Get##PropName) \ { \ checkDisposed(mrb, self); \ @@ -163,12 +166,11 @@ defineClass(mrb_state *mrb, const char *name) mrb_get_args(mrb, "o", &propObj); \ prop = getPrivateDataCheck(mrb, propObj, PropKlass##Type); \ GUARD_EXC( k->set##PropName(prop); ) \ - setProperty(mrb, self, prop_iv, propObj); \ return propObj; \ } -/* Object property with allowed NIL */ -#define DEF_PROP_OBJ_NIL(Klass, PropKlass, PropName, prop_iv) \ +/* Object property which is copied by reference, with allowed NIL */ +#define DEF_PROP_OBJ_REF(Klass, PropKlass, PropName, prop_iv) \ MRB_METHOD(Klass##Get##PropName) \ { \ return getProperty(mrb, self, prop_iv); \ @@ -300,7 +302,7 @@ wrapObject(mrb_state *mrb, void *p, const mrb_data_type &type) return obj; } -inline void +inline mrb_value wrapProperty(mrb_state *mrb, mrb_value self, void *prop, CommonSymbol iv, const mrb_data_type &type) { @@ -310,6 +312,8 @@ wrapProperty(mrb_state *mrb, mrb_value self, mrb_obj_ptr(self), getSym(mrb, iv), propObj); + + return propObj; } inline mrb_value diff --git a/binding-mruby/bitmap-binding.cpp b/binding-mruby/bitmap-binding.cpp index 57a4db9..f4cd260 100644 --- a/binding-mruby/bitmap-binding.cpp +++ b/binding-mruby/bitmap-binding.cpp @@ -22,6 +22,7 @@ #include "bitmap.h" #include "font.h" #include "exception.h" +#include "sharedstate.h" #include "disposable-binding.h" #include "binding-util.h" #include "binding-types.h" @@ -51,11 +52,15 @@ MRB_METHOD(bitmapInitialize) /* Wrap properties */ Font *font = new Font(); - b->setFont(font); - font->setColor(new Color(*font->getColor())); + b->setInitFont(font); + font->initDynAttribs(); - wrapProperty(mrb, self, font, CSfont, FontType); - wrapProperty(mrb, getProperty(mrb, self, CSfont), font->getColor(), CScolor, ColorType); + mrb_value fontProp = wrapProperty(mrb, self, font, CSfont, FontType); + + wrapProperty(mrb, fontProp, font->getColor(), CScolor, ColorType); + + if (rgssVer >= 3) + wrapProperty(mrb, fontProp, font->getOutColor(), CSout_color, ColorType); return self; } @@ -292,7 +297,6 @@ MRB_METHOD(bitmapSetFont) font = getPrivateDataCheck(mrb, fontObj, FontType); GUARD_EXC( b->setFont(font); ) - setProperty(mrb, self, CSfont, fontObj); return mrb_nil_value(); } diff --git a/binding-mruby/font-binding.cpp b/binding-mruby/font-binding.cpp index e06b882..d811869 100644 --- a/binding-mruby/font-binding.cpp +++ b/binding-mruby/font-binding.cpp @@ -20,6 +20,7 @@ */ #include "font.h" +#include "sharedstate.h" #include "binding-util.h" #include "binding-types.h" #include "exception.h" @@ -53,9 +54,13 @@ MRB_METHOD(fontInitialize) setPrivateData(self, f, FontType); /* Wrap property objects */ - f->setColor(new Color(*f->getColor())); + f->initDynAttribs(); + wrapProperty(mrb, self, f->getColor(), CScolor, ColorType); + if (rgssVer >= 3) + wrapProperty(mrb, self, f->getOutColor(), CSout_color, ColorType); + return self; } @@ -69,9 +74,13 @@ MRB_METHOD(fontInitializeCopy) setPrivateData(self, f, FontType); /* Wrap property objects */ - f->setColor(new Color(*f->getColor())); + f->initDynAttribs(); + wrapProperty(mrb, self, f->getColor(), CScolor, ColorType); + if (rgssVer >= 3) + wrapProperty(mrb, self, f->getOutColor(), CSout_color, ColorType); + return self; } @@ -97,7 +106,10 @@ MRB_METHOD(FontSetName) DEF_PROP_I(Font, Size) DEF_PROP_B(Font, Bold) DEF_PROP_B(Font, Italic) -DEF_PROP_OBJ(Font, Color, Color, CScolor) +DEF_PROP_B(Font, Outline) +DEF_PROP_B(Font, Shadow) +DEF_PROP_OBJ_VAL(Font, Color, Color, CScolor) +DEF_PROP_OBJ_VAL(Font, Color, OutColor, CSout_color) #define DEF_KLASS_PROP(Klass, mrb_type, PropName, arg_type, conv_t) \ static mrb_value \ @@ -114,9 +126,11 @@ DEF_PROP_OBJ(Font, Color, Color, CScolor) return mrb_##conv_t##_value(value); \ } -DEF_KLASS_PROP(Font, mrb_int, DefaultSize, "i", fixnum) -DEF_KLASS_PROP(Font, mrb_bool, DefaultBold, "b", bool) -DEF_KLASS_PROP(Font, mrb_bool, DefaultItalic, "b", bool) +DEF_KLASS_PROP(Font, mrb_int, DefaultSize, "i", fixnum) +DEF_KLASS_PROP(Font, mrb_bool, DefaultBold, "b", bool) +DEF_KLASS_PROP(Font, mrb_bool, DefaultItalic, "b", bool) +DEF_KLASS_PROP(Font, mrb_bool, DefaultOutline, "b", bool) +DEF_KLASS_PROP(Font, mrb_bool, DefaultShadow, "b", bool) MRB_FUNCTION(FontGetDefaultName) { @@ -140,13 +154,33 @@ MRB_METHOD(FontGetDefaultColor) MRB_METHOD(FontSetDefaultColor) { + MRB_UNUSED_PARAM; + mrb_value colorObj; mrb_get_args(mrb, "o", &colorObj); Color *c = getPrivateDataCheck(mrb, colorObj, ColorType); Font::setDefaultColor(c); - setProperty(mrb, self, CSdefault_color, colorObj); + + return colorObj; +} + +MRB_METHOD(FontGetDefaultOutColor) +{ + return getProperty(mrb, self, CSdefault_out_color); +} + +MRB_METHOD(FontSetDefaultOutColor) +{ + MRB_UNUSED_PARAM; + + mrb_value colorObj; + mrb_get_args(mrb, "o", &colorObj); + + Color *c = getPrivateDataCheck(mrb, colorObj, ColorType); + + Font::setDefaultOutColor(c); return colorObj; } @@ -162,25 +196,48 @@ fontBindingInit(mrb_state *mrb) { RClass *klass = defineClass(mrb, "Font"); - Font::setDefaultColor(new Color(*Font::getDefaultColor())); + Font::initDefaultDynAttribs(); wrapProperty(mrb, mrb_obj_value(klass), Font::getDefaultColor(), CSdefault_color, ColorType); mrb_define_class_method(mrb, klass, "exist?", fontDoesExist, MRB_ARGS_REQ(1)); - INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name"); - INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size"); - INIT_KLASS_PROP_BIND(Font, DefaultBold, "default_bold"); - INIT_KLASS_PROP_BIND(Font, DefaultItalic, "default_italic"); - INIT_KLASS_PROP_BIND(Font, DefaultColor, "default_color"); + INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name"); + INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size"); + INIT_KLASS_PROP_BIND(Font, DefaultBold, "default_bold"); + INIT_KLASS_PROP_BIND(Font, DefaultItalic, "default_italic"); + INIT_KLASS_PROP_BIND(Font, DefaultColor, "default_color"); + + if (rgssVer >= 2) + { + INIT_KLASS_PROP_BIND(Font, DefaultShadow, "default_shadow"); + } + + if (rgssVer >= 3) + { + INIT_KLASS_PROP_BIND(Font, DefaultOutline, "default_outline"); + INIT_KLASS_PROP_BIND(Font, DefaultOutColor, "default_out_color"); + wrapProperty(mrb, mrb_obj_value(klass), Font::getDefaultOutColor(), CSdefault_out_color, ColorType); + } mrb_define_method(mrb, klass, "initialize", fontInitialize, MRB_ARGS_OPT(2)); mrb_define_method(mrb, klass, "initialize_copy", fontInitializeCopy, MRB_ARGS_REQ(1)); - INIT_PROP_BIND(Font, Name, "name"); - INIT_PROP_BIND(Font, Size, "size"); - INIT_PROP_BIND(Font, Bold, "bold"); - INIT_PROP_BIND(Font, Italic, "italic"); - INIT_PROP_BIND(Font, Color, "color"); + INIT_PROP_BIND(Font, Name, "name"); + INIT_PROP_BIND(Font, Size, "size"); + INIT_PROP_BIND(Font, Bold, "bold"); + INIT_PROP_BIND(Font, Italic, "italic"); + INIT_PROP_BIND(Font, Color, "color"); + + if (rgssVer >= 2) + { + INIT_PROP_BIND(Font, Shadow, "shadow"); + } + + if (rgssVer >= 3) + { + INIT_PROP_BIND(Font, Outline, "outline"); + INIT_PROP_BIND(Font, OutColor, "out_color"); + } mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE()); } diff --git a/binding-mruby/plane-binding.cpp b/binding-mruby/plane-binding.cpp index 5ad4e25..f61803d 100644 --- a/binding-mruby/plane-binding.cpp +++ b/binding-mruby/plane-binding.cpp @@ -33,18 +33,17 @@ MRB_METHOD(planeInitialize) setPrivateData(self, p, PlaneType); - p->setColor(new Color); - p->setTone(new Tone); + p->initDynAttribs(); wrapProperty(mrb, self, p->getColor(), CScolor, ColorType); - wrapProperty(mrb, self, p->getTone(), CStone, ToneType); + wrapProperty(mrb, self, p->getTone(), CStone, ToneType); return self; } -DEF_PROP_OBJ(Plane, Bitmap, Bitmap, CSbitmap) -DEF_PROP_OBJ(Plane, Color, Color, CScolor) -DEF_PROP_OBJ(Plane, Tone, Tone, CStone) +DEF_PROP_OBJ_REF(Plane, Bitmap, Bitmap, CSbitmap) +DEF_PROP_OBJ_VAL(Plane, Color, Color, CScolor) +DEF_PROP_OBJ_VAL(Plane, Tone, Tone, CStone) DEF_PROP_I(Plane, OX) DEF_PROP_I(Plane, OY) diff --git a/binding-mruby/sprite-binding.cpp b/binding-mruby/sprite-binding.cpp index e6244af..2575063 100644 --- a/binding-mruby/sprite-binding.cpp +++ b/binding-mruby/sprite-binding.cpp @@ -36,9 +36,7 @@ MRB_METHOD(spriteInitialize) setPrivateData(self, s, SpriteType); /* Wrap property objects */ - s->setSrcRect(new Rect); - s->setColor(new Color); - s->setTone(new Tone); + s->initDynAttribs(); wrapProperty(mrb, self, s->getSrcRect(), CSsrc_rect, RectType); wrapProperty(mrb, self, s->getColor(), CScolor, ColorType); @@ -47,10 +45,10 @@ MRB_METHOD(spriteInitialize) return self; } -DEF_PROP_OBJ_NIL(Sprite, Bitmap, Bitmap, CSbitmap) -DEF_PROP_OBJ(Sprite, Rect, SrcRect, CSsrc_rect) -DEF_PROP_OBJ(Sprite, Color, Color, CScolor) -DEF_PROP_OBJ(Sprite, Tone, Tone, CStone) +DEF_PROP_OBJ_REF(Sprite, Bitmap, Bitmap, CSbitmap) +DEF_PROP_OBJ_VAL(Sprite, Rect, SrcRect, CSsrc_rect) +DEF_PROP_OBJ_VAL(Sprite, Color, Color, CScolor) +DEF_PROP_OBJ_VAL(Sprite, Tone, Tone, CStone) DEF_PROP_I(Sprite, X) DEF_PROP_I(Sprite, Y) diff --git a/binding-mruby/tilemap-binding.cpp b/binding-mruby/tilemap-binding.cpp index e208275..2ec1eb0 100644 --- a/binding-mruby/tilemap-binding.cpp +++ b/binding-mruby/tilemap-binding.cpp @@ -125,10 +125,10 @@ MRB_METHOD(tilemapGetViewport) return getProperty(mrb, self, CSviewport); } -DEF_PROP_OBJ(Tilemap, Bitmap, Tileset, CStileset) -DEF_PROP_OBJ(Tilemap, Table, MapData, CSmap_data) -DEF_PROP_OBJ(Tilemap, Table, FlashData, CSflash_data) -DEF_PROP_OBJ(Tilemap, Table, Priorities, CSpriorities) +DEF_PROP_OBJ_REF(Tilemap, Bitmap, Tileset, CStileset) +DEF_PROP_OBJ_REF(Tilemap, Table, MapData, CSmap_data) +DEF_PROP_OBJ_REF(Tilemap, Table, FlashData, CSflash_data) +DEF_PROP_OBJ_REF(Tilemap, Table, Priorities, CSpriorities) DEF_PROP_B(Tilemap, Visible) diff --git a/binding-mruby/viewport-binding.cpp b/binding-mruby/viewport-binding.cpp index 0e97c34..0061a2d 100644 --- a/binding-mruby/viewport-binding.cpp +++ b/binding-mruby/viewport-binding.cpp @@ -57,9 +57,7 @@ MRB_METHOD(viewportInitialize) setPrivateData(self, v, ViewportType); /* Wrap property objects */ - v->setRect(new Rect(*v->getRect())); - v->setColor(new Color); - v->setTone(new Tone); + v->initDynAttribs(); wrapProperty(mrb, self, v->getRect(), CSrect, RectType); wrapProperty(mrb, self, v->getColor(), CScolor, ColorType); @@ -68,9 +66,9 @@ MRB_METHOD(viewportInitialize) return self; } -DEF_PROP_OBJ(Viewport, Rect, Rect, CSrect) -DEF_PROP_OBJ(Viewport, Color, Color, CScolor) -DEF_PROP_OBJ(Viewport, Tone, Tone, CStone) +DEF_PROP_OBJ_VAL(Viewport, Rect, Rect, CSrect) +DEF_PROP_OBJ_VAL(Viewport, Color, Color, CScolor) +DEF_PROP_OBJ_VAL(Viewport, Tone, Tone, CStone) DEF_PROP_I(Viewport, OX) DEF_PROP_I(Viewport, OY) diff --git a/binding-mruby/window-binding.cpp b/binding-mruby/window-binding.cpp index 5ba9d64..1f31b77 100644 --- a/binding-mruby/window-binding.cpp +++ b/binding-mruby/window-binding.cpp @@ -32,7 +32,7 @@ MRB_METHOD(windowInitialize) setPrivateData(self, w, WindowType); - w->setCursorRect(new Rect); + w->initDynAttribs(); wrapProperty(mrb, self, w->getCursorRect(), CScursor_rect, RectType); return self; @@ -47,9 +47,9 @@ MRB_METHOD(windowUpdate) return mrb_nil_value(); } -DEF_PROP_OBJ_NIL(Window, Bitmap, Windowskin, CSwindowskin) -DEF_PROP_OBJ_NIL(Window, Bitmap, Contents, CScontents) -DEF_PROP_OBJ(Window, Rect, CursorRect, CScursor_rect) +DEF_PROP_OBJ_REF(Window, Bitmap, Windowskin, CSwindowskin) +DEF_PROP_OBJ_REF(Window, Bitmap, Contents, CScontents) +DEF_PROP_OBJ_VAL(Window, Rect, CursorRect, CScursor_rect) DEF_PROP_B(Window, Stretch) DEF_PROP_B(Window, Active) From bca95adc0e4e8dfbecd6a7837e40b43c9464c27d Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 5 Sep 2014 22:54:57 +0200 Subject: [PATCH 012/239] MRI: WindowVX dummy contents object is always created The check was against rgssVer >= 2, but since that's always true if WindowVX is used, it was pointless. --- binding-mri/windowvx-binding.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/binding-mri/windowvx-binding.cpp b/binding-mri/windowvx-binding.cpp index 21cc7c3..50ee979 100644 --- a/binding-mri/windowvx-binding.cpp +++ b/binding-mri/windowvx-binding.cpp @@ -56,13 +56,10 @@ RB_METHOD(windowVXInitialize) wrapProperty(self, w->getTone(), "tone", ToneType); wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType); - if (rgssVer >= 2) - { - Bitmap *contents = new Bitmap(1, 1); - VALUE contentsObj = wrapObject(contents, BitmapType); - bitmapInitProps(contents, contentsObj); - rb_iv_set(self, "contents", contentsObj); - } + Bitmap *contents = new Bitmap(1, 1); + VALUE contentsObj = wrapObject(contents, BitmapType); + bitmapInitProps(contents, contentsObj); + rb_iv_set(self, "contents", contentsObj); return self; } From 6bc3460294a2045b20a075c06253a0ffad8d8e7c Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sat, 6 Sep 2014 02:01:20 +0200 Subject: [PATCH 013/239] Core, MRI: Don't expose RGSS3 functionality in 2 --- binding-mri/windowvx-binding.cpp | 22 ++++++++++++++-------- src/windowvx.cpp | 9 ++++++--- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/binding-mri/windowvx-binding.cpp b/binding-mri/windowvx-binding.cpp index 50ee979..c9bcee3 100644 --- a/binding-mri/windowvx-binding.cpp +++ b/binding-mri/windowvx-binding.cpp @@ -53,9 +53,11 @@ RB_METHOD(windowVXInitialize) w->initDynAttribs(); - wrapProperty(self, w->getTone(), "tone", ToneType); wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType); + if (rgssVer >= 3) + wrapProperty(self, w->getTone(), "tone", ToneType); + Bitmap *contents = new Bitmap(1, 1); VALUE contentsObj = wrapObject(contents, BitmapType); bitmapInitProps(contents, contentsObj); @@ -138,17 +140,12 @@ windowVXBindingInit() viewportElementBindingInit(klass); _rb_define_method(klass, "initialize", windowVXInitialize); - _rb_define_method(klass, "update", windowVXUpdate); - _rb_define_method(klass, "move", windowVXMove); - _rb_define_method(klass, "open?", windowVXIsOpen); - _rb_define_method(klass, "close?", windowVXIsClosed); INIT_PROP_BIND( WindowVX, Windowskin, "windowskin" ); INIT_PROP_BIND( WindowVX, Contents, "contents" ); INIT_PROP_BIND( WindowVX, CursorRect, "cursor_rect" ); INIT_PROP_BIND( WindowVX, Active, "active" ); - INIT_PROP_BIND( WindowVX, ArrowsVisible, "arrows_visible" ); INIT_PROP_BIND( WindowVX, Pause, "pause" ); INIT_PROP_BIND( WindowVX, X, "x" ); INIT_PROP_BIND( WindowVX, Y, "y" ); @@ -156,11 +153,20 @@ windowVXBindingInit() INIT_PROP_BIND( WindowVX, Height, "height" ); INIT_PROP_BIND( WindowVX, OX, "ox" ); INIT_PROP_BIND( WindowVX, OY, "oy" ); - INIT_PROP_BIND( WindowVX, Padding, "padding" ); - INIT_PROP_BIND( WindowVX, PaddingBottom, "padding_bottom" ); INIT_PROP_BIND( WindowVX, Opacity, "opacity" ); INIT_PROP_BIND( WindowVX, BackOpacity, "back_opacity" ); INIT_PROP_BIND( WindowVX, ContentsOpacity, "contents_opacity" ); INIT_PROP_BIND( WindowVX, Openness, "openness" ); + + if (rgssVer >= 3) + { + _rb_define_method(klass, "move", windowVXMove); + _rb_define_method(klass, "open?", windowVXIsOpen); + _rb_define_method(klass, "close?", windowVXIsClosed); + + INIT_PROP_BIND( WindowVX, ArrowsVisible, "arrows_visible" ); + INIT_PROP_BIND( WindowVX, Padding, "padding" ); + INIT_PROP_BIND( WindowVX, PaddingBottom, "padding_bottom" ); INIT_PROP_BIND( WindowVX, Tone, "tone" ); + } } diff --git a/src/windowvx.cpp b/src/windowvx.cpp index 103bc44..399e7b0 100644 --- a/src/windowvx.cpp +++ b/src/windowvx.cpp @@ -1044,10 +1044,13 @@ void WindowVX::setOpenness(int value) void WindowVX::initDynAttribs() { p->cursorRect = new Rect; - p->tone = new Tone; - p->refreshCursorRectCon(); - p->refreshToneCon(); + + if (rgssVer >= 3) + { + p->tone = new Tone; + p->refreshToneCon(); + } } void WindowVX::draw() From ac9b98157e69970be44c155f6e66b09e6dc9291a Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sat, 6 Sep 2014 21:35:26 +0200 Subject: [PATCH 014/239] TilemapVX: Use SimpleShader for unanimated ground layers Also remove some useless member variables. --- src/tilemapvx.cpp | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp index 37391b5..f9f09d3 100644 --- a/src/tilemapvx.cpp +++ b/src/tilemapvx.cpp @@ -69,8 +69,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader size_t aboveQuads; uint16_t frameIdx; - uint8_t aniIdxA; - uint8_t aniIdxC; Vec2 aniOffset; bool atlasDirty; @@ -110,8 +108,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader groundQuads(0), aboveQuads(0), frameIdx(0), - aniIdxA(0), - aniIdxC(0), atlasDirty(true), buffersDirty(false), mapViewportDirty(false), @@ -292,12 +288,27 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader /* SceneElement */ void draw() { - TilemapVXShader &shader = shState->shaders().tilemapVX; - shader.bind(); - shader.setTexSize(Vec2i(atlas.width, atlas.height)); - shader.applyViewportProj(); - shader.setTranslation(dispPos); - shader.setAniOffset(aniOffset); + ShaderBase *shader; + + if (bitmaps[BM_A1] != 0) + { + /* Animated tileset */ + TilemapVXShader &tmShader = shState->shaders().tilemapVX; + tmShader.bind(); + tmShader.setAniOffset(aniOffset); + + shader = &tmShader; + } + else + { + /* Static tileset */ + shader = &shState->shaders().simple; + shader->bind(); + } + + shader->setTexSize(Vec2i(atlas.width, atlas.height)); + shader->applyViewportProj(); + shader->setTranslation(dispPos); TEX::bind(atlas.tex); GLMeta::vaoBind(vao); @@ -400,10 +411,10 @@ void TilemapVX::update() const uint8_t aniIndicesC[3*4] = { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2 }; - p->aniIdxA = aniIndicesA[p->frameIdx / 30]; - p->aniIdxC = aniIndicesC[p->frameIdx / 30]; + uint8_t aniIdxA = aniIndicesA[p->frameIdx / 30]; + uint8_t aniIdxC = aniIndicesC[p->frameIdx / 30]; - p->aniOffset = Vec2(p->aniIdxA * 2 * 32, p->aniIdxC * 32); + p->aniOffset = Vec2(aniIdxA * 2 * 32, aniIdxC * 32); } TilemapVX::BitmapArray &TilemapVX::getBitmapArray() const From 673a25f811a278dad8e44bd36cac916da11c3a3d Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sun, 7 Sep 2014 19:11:20 +0200 Subject: [PATCH 015/239] Bitmap: Don't use 'pixman_region_clear' It's not included in older pixman versions. --- src/bitmap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index beff91b..c95afaa 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -125,7 +125,8 @@ struct BitmapPrivate void clearTaintedArea() { - pixman_region_clear(&tainted); + pixman_region_fini(&tainted); + pixman_region_init(&tainted); } void addTaintedArea(const IntRect &rect) From 757a1d5e3996d2f30b2e7cfd79d01866b64bf220 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sun, 7 Sep 2014 05:23:10 +0200 Subject: [PATCH 016/239] Load fluidsynth entrypoints dynamically (and make them optional) This removes the static dependency on fluidsynth being present at buildtime (even headers aren't needed anymore). Even though midi is a default format for the RPG XP/VX series, it has fallen more and more out of use, with VX Ace completely abandoning it from the RTP and making ogg vorbis the de facto standard. Midi support is kept for legacy reasons, but isn't encouraged. On top of all this, fluidsynth together with glib is a heavy dependency that often times won't even be used. Making it optional at build time is an attempt to unify and keep build config fragmentation low. In RGSS3, fluidsynth / midi is not initialized at all by default, but rather on demand when either a midi track is played back or Audio.setup_midi is called. --- CMakeLists.txt | 22 ++++++------ README.md | 3 +- mkxp.pro | 26 +++++--------- src/aldatasource.h | 2 -- src/alstream.cpp | 32 ++++++++---------- src/audio.cpp | 7 +--- src/filesystem.cpp | 2 -- src/fluid-fun.cpp | 73 +++++++++++++++++++++++++++++++++++++++ src/fluid-fun.h | 60 ++++++++++++++++++++++++++++++++ src/midisource.cpp | 18 +++++----- src/sharedmidistate.h | 79 ++++++++++++++++++++++++------------------- src/sharedstate.cpp | 14 +------- src/sharedstate.h | 5 --- 13 files changed, 223 insertions(+), 120 deletions(-) create mode 100644 src/fluid-fun.cpp create mode 100644 src/fluid-fun.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 932d3a6..98c65bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ Project(mkxp) ## Setup options ## -option(MIDI "Enable midi support" ON) +option(SHARED_FLUID "Dynamically link fluidsynth at build time" OFF) option(WORKDIR_CURRENT "Keep current directory on startup" OFF) option(FORCE32 "Force 32bit compile on 64bit OS" OFF) set(BINDING "MRI" CACHE STRING "The Binding Type (MRI, MRUBY, NULL)") @@ -151,6 +151,8 @@ set(MAIN_HEADERS src/windowvx.h src/tilemapvx.h src/tileatlasvx.h + src/sharedmidistate.h + src/fluid-fun.h ) set(MAIN_SOURCE @@ -193,6 +195,8 @@ set(MAIN_SOURCE src/tilemapvx.cpp src/tileatlasvx.cpp src/autotilesvx.cpp + src/midisource.cpp + src/fluid-fun.cpp ) source_group("MKXP Source" FILES ${MAIN_SOURCE} ${MAIN_HEADERS}) @@ -227,16 +231,10 @@ if (RGSS2) ) endif() -if (MIDI) - pkg_check_modules(MIDI REQUIRED fluidsynth) +if (SHARED_FLUID) + pkg_check_modules(FLUID REQUIRED fluidsynth) list(APPEND DEFINES - MIDI - ) - list(APPEND MAIN_HEADERS - src/sharedmidistate.h - ) - list(APPEND MAIN_SOURCE - src/midisource.cpp + SHARED_FLUID ) endif() @@ -400,7 +398,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIR} ${MRI_INCLUDE_DIRS} ${VORBISFILE_INCLUDE_DIRS} - ${MIDI_INCLUDE_DIRS} + ${FLUID_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} ) @@ -415,7 +413,7 @@ target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${MRI_LIBRARIES} ${VORBISFILE_LIBRARIES} - ${MIDI_LIBRARIES} + ${FLUID_LIBRARIES} ${OPENAL_LIBRARY} ${ZLIB_LIBRARY} diff --git a/README.md b/README.md index e21e854..bdf7322 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,6 @@ This binding only exists for testing purposes and does nothing (the engine quits * SDL_sound (latest hg, apply provided patches!) * vorbisfile * pixman -* fluidsynth (if midi enabled) * zlib (only ruby bindings) * OpenGL header (alternatively GLES2 with `DEFINES+=GLES2_HEADER`) * libiconv (on Windows, optional with INI_ENCODING) @@ -72,7 +71,7 @@ qmake will use pkg-config to locate the respective include/library paths. If you The exception is boost, which is weird in that it still hasn't managed to pull off pkg-config support (seriously?). *If you installed boost in a non-standard prefix*, you will need to pass its include path via `BOOST_I` and library path via `BOOST_L`, either as direct arguments to qmake (`qmake BOOST_I="/usr/include" ...`) or via environment variables. You can specify a library suffix (eg. "-mt") via `BOOST_LIB_SUFFIX` if needed. -Midi support is enabled by default; you can disable it via `qmake CONFIG+=DISABLE_MIDI`, in which case the fluidsynth dependency is dropped. When building fluidsynth yourself, you can disable almost all options (audio drivers etc.) as they are not used. Note that upstream fluidsynth has support for sharing soundfont data between synthesizers (mkxp uses multiple synths), so if your memory usage is very high, you might want to try compiling fluidsynth from git master. +Midi support is enabled by default and requires fluidsynth to be present at runtime (not needed for building); if mkxp can't find it at runtime, midi playback is disabled. It looks for `libfluidsynth.so.1` on Linux, `libfluidsynth.dylib.1` on OSX and `fluidsynth.dll` on Windows, so make sure to have one of these in your link path. If you still need fluidsynth to be hard linked at buildtime, use `CONFIG+=SHARED_FLUID`. When building fluidsynth yourself, you can disable almost all options (audio drivers etc.) as they are not used. Note that upstream fluidsynth has support for sharing soundfont data between synthesizers (mkxp uses multiple synths), so if your memory usage is very high, you might want to try compiling fluidsynth from git master. By default, mkxp switches into the directory where its binary is contained and then starts reading the configuration and resolving relative paths. In case this is undesired (eg. when the binary is to be installed to a system global, read-only location), it can be turned off by adding `DEFINES+=WORKDIR_CURRENT` to qmake's arguments. diff --git a/mkxp.pro b/mkxp.pro index 1cbed85..37c348c 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -8,12 +8,6 @@ INCLUDEPATH += . src CONFIG(release, debug|release): DEFINES += NDEBUG -CONFIG += MIDI - -DISABLE_MIDI { - CONFIG -= MIDI -} - isEmpty(BINDING) { BINDING = MRI } @@ -50,7 +44,7 @@ unix { PKGCONFIG += sigc++-2.0 pixman-1 zlib physfs vorbisfile \ sdl2 SDL2_image SDL2_ttf SDL_sound openal - MIDI { + SHARED_FLUID { PKGCONFIG += fluidsynth } @@ -135,7 +129,9 @@ HEADERS += \ src/rgssad.h \ src/windowvx.h \ src/tilemapvx.h \ - src/tileatlasvx.h + src/tileatlasvx.h \ + src/sharedmidistate.h \ + src/fluid-fun.h SOURCES += \ src/main.cpp \ @@ -176,7 +172,9 @@ SOURCES += \ src/windowvx.cpp \ src/tilemapvx.cpp \ src/tileatlasvx.cpp \ - src/autotilesvx.cpp + src/autotilesvx.cpp \ + src/midisource.cpp \ + src/fluid-fun.cpp EMBED = \ shader/transSimple.frag \ @@ -200,14 +198,8 @@ EMBED = \ shader/tilemapvx.vert \ assets/liberation.ttf -MIDI { - HEADERS += \ - src/sharedmidistate.h - - SOURCES += \ - src/midisource.cpp - - DEFINES += MIDI +SHARED_FLUID { + DEFINES += SHARED_FLUID } INI_ENCODING { diff --git a/src/aldatasource.h b/src/aldatasource.h index b607a80..6db63db 100644 --- a/src/aldatasource.h +++ b/src/aldatasource.h @@ -61,9 +61,7 @@ ALDataSource *createSDLSource(SDL_RWops &ops, ALDataSource *createVorbisSource(SDL_RWops &ops, bool looped); -#ifdef MIDI ALDataSource *createMidiSource(SDL_RWops &ops, bool looped); -#endif #endif // ALDATASOURCE_H diff --git a/src/alstream.cpp b/src/alstream.cpp index 80d8695..6ab6358 100644 --- a/src/alstream.cpp +++ b/src/alstream.cpp @@ -22,8 +22,10 @@ #include "alstream.h" #include "sharedstate.h" +#include "sharedmidistate.h" #include "filesystem.h" #include "aldatasource.h" +#include "fluid-fun.h" #include #include @@ -198,32 +200,26 @@ void ALStream::openSource(const std::string &filename) shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext); needsRewind = false; - bool readSig = rgssVer >= 2; + /* Try to read ogg file signature */ + char sig[5] = { 0 }; + SDL_RWread(&srcOps, sig, 1, 4); + SDL_RWseek(&srcOps, 0, RW_SEEK_SET); -#ifdef MIDI - readSig = true; -#endif - - if (readSig) + if (!strcmp(sig, "OggS")) { - /* Try to read ogg file signature */ - char sig[5] = { 0 }; - SDL_RWread(&srcOps, sig, 1, 4); - SDL_RWseek(&srcOps, 0, RW_SEEK_SET); + source = createVorbisSource(srcOps, looped); + return; + } - if (!strcmp(sig, "OggS")) - { - source = createVorbisSource(srcOps, looped); - return; - } + if (!strcmp(sig, "MThd")) + { + shState->midiState().initIfNeeded(shState->config()); -#ifdef MIDI - if (!strcmp(sig, "MThd")) + if (HAVE_FLUID) { source = createMidiSource(srcOps, looped); return; } -#endif } source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped); diff --git a/src/audio.cpp b/src/audio.cpp index aa418e5..b99ab04 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -24,10 +24,7 @@ #include "audiostream.h" #include "soundemitter.h" #include "sharedstate.h" - -#ifdef MIDI #include "sharedmidistate.h" -#endif #include @@ -317,9 +314,7 @@ void Audio::seStop() void Audio::setupMidi() { -#ifdef MIDI - shState->midiState().initDefaultSynths(); -#endif + shState->midiState().initIfNeeded(shState->config()); } float Audio::bgmPos() diff --git a/src/filesystem.cpp b/src/filesystem.cpp index d2ece9c..f5cfddc 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -340,10 +340,8 @@ FileSystem::FileSystem(const char *argv0, if (rgssVer >= 2 && !contains(p->extensions[Audio], std::string("ogg"))) p->extensions[Audio].push_back("ogg"); -#if MIDI p->extensions[Audio].push_back("mid"); p->extensions[Audio].push_back("midi"); -#endif /* Font extensions */ p->extensions[Font].push_back("ttf"); diff --git a/src/fluid-fun.cpp b/src/fluid-fun.cpp new file mode 100644 index 0000000..4b8a751 --- /dev/null +++ b/src/fluid-fun.cpp @@ -0,0 +1,73 @@ +#include "fluid-fun.h" + +#include +#include +#include + +#include "debugwriter.h" + +#ifdef SHARED_FLUID +#include +#endif + +#ifdef __LINUX__ +#define FLUID_LIB "libfluidsynth.so.1" +#elif __MACOSX__ +#define FLUID_LIB "libfluidsynth.dylib.1" +#elif __WINDOWS__ +#define FLUID_LIB "fluidsynth.dll" +#else +#error "platform not recognized" +#endif + +struct FluidFunctions fluid; + +static void *so; + +void initFluidFunctions() +{ +#ifdef SHARED_FLUID + +#define FLUID_FUN(name, type) \ + fluid.name = fluid_##name; + +#define FLUID_FUN2(name, type, real_name) \ + fluid.name = real_name; + +#else + so = SDL_LoadObject(FLUID_LIB); + + if (!so) + goto fail; + +#define FLUID_FUN(name, type) \ + fluid.name = (type) SDL_LoadFunction(so, "fluid_" #name); \ + if (!fluid.name) \ + goto fail; + +#define FLUID_FUN2(name, type, real_name) \ + fluid.name = (type) SDL_LoadFunction(so, #real_name); \ + if (!fluid.name) \ + goto fail; +#endif + +FLUID_FUNCS +FLUID_FUNCS2 + + return; + +#ifndef SHARED_FLUID +fail: + Debug() << "Failed to load " FLUID_LIB ". Midi playback is disabled."; + + memset(&fluid, 0, sizeof(fluid)); + finiFluidFunctions(); +#endif +} + +void finiFluidFunctions() +{ +#ifndef SHARED_FLUID + SDL_UnloadObject(so); +#endif +} diff --git a/src/fluid-fun.h b/src/fluid-fun.h new file mode 100644 index 0000000..2aff2e2 --- /dev/null +++ b/src/fluid-fun.h @@ -0,0 +1,60 @@ +#ifndef FLUIDFUN_H +#define FLUIDFUN_H + +typedef struct _fluid_hashtable_t fluid_settings_t; +typedef struct _fluid_synth_t fluid_synth_t; + +typedef fluid_settings_t* (*NEWFLUIDSETTINGSPROC)(void); +typedef int (*FLUIDSETTINGSSETNUMPROC)(fluid_settings_t* settings, const char *name, double val); +typedef int (*FLUIDSETTINGSSETSTRPROC)(fluid_settings_t* settings, const char *name, const char *str); +typedef void (*DELETEFLUIDSETTINGSPROC)(fluid_settings_t* settings); +typedef fluid_synth_t* (*NEWFLUIDSYNTHPROC)(fluid_settings_t* settings); +typedef int (*DELETEFLUIDSYNTHPROC)(fluid_synth_t* synth); +typedef int (*FLUIDSYNTHSFLOADPROC)(fluid_synth_t* synth, const char* filename, int reset_presets); +typedef int (*FLUIDSYNTHSYSTEMRESETPROC)(fluid_synth_t* synth); +typedef int (*FLUIDSYNTHWRITES16PROC)(fluid_synth_t* synth, int len, void* lout, int loff, int lincr, void* rout, int roff, int rincr); +typedef int (*FLUIDSYNTHNOTEONPROC)(fluid_synth_t* synth, int chan, int key, int vel); +typedef int (*FLUIDSYNTHNOTEOFFPROC)(fluid_synth_t* synth, int chan, int key); +typedef int (*FLUIDSYNTHCHANNELPRESSUREPROC)(fluid_synth_t* synth, int chan, int val); +typedef int (*FLUIDSYNTHPITCHBENDPROC)(fluid_synth_t* synth, int chan, int val); +typedef int (*FLUIDSYNTHCCPROC)(fluid_synth_t* synth, int chan, int ctrl, int val); +typedef int (*FLUIDSYNTHPROGRAMCHANGEPROC)(fluid_synth_t* synth, int chan, int program); + +#define FLUID_FUNCS \ + FLUID_FUN(settings_setnum, FLUIDSETTINGSSETNUMPROC) \ + FLUID_FUN(settings_setstr, FLUIDSETTINGSSETSTRPROC) \ + FLUID_FUN(synth_sfload, FLUIDSYNTHSFLOADPROC) \ + FLUID_FUN(synth_system_reset, FLUIDSYNTHSYSTEMRESETPROC) \ + FLUID_FUN(synth_write_s16, FLUIDSYNTHWRITES16PROC) \ + FLUID_FUN(synth_noteon, FLUIDSYNTHNOTEONPROC) \ + FLUID_FUN(synth_noteoff, FLUIDSYNTHNOTEOFFPROC) \ + FLUID_FUN(synth_channel_pressure, FLUIDSYNTHCHANNELPRESSUREPROC) \ + FLUID_FUN(synth_pitch_bend, FLUIDSYNTHPITCHBENDPROC) \ + FLUID_FUN(synth_cc, FLUIDSYNTHCCPROC) \ + FLUID_FUN(synth_program_change, FLUIDSYNTHPROGRAMCHANGEPROC) + +/* Functions that don't fit into the default prefix naming scheme */ +#define FLUID_FUNCS2 \ + FLUID_FUN2(new_settings, NEWFLUIDSETTINGSPROC, new_fluid_settings) \ + FLUID_FUN2(new_synth, NEWFLUIDSYNTHPROC, new_fluid_synth) \ + FLUID_FUN2(delete_settings, DELETEFLUIDSETTINGSPROC, delete_fluid_settings) \ + FLUID_FUN2(delete_synth, DELETEFLUIDSYNTHPROC, delete_fluid_synth) + +struct FluidFunctions +{ +#define FLUID_FUN(name, type) type name; +#define FLUID_FUN2(name, type, rn) type name; + FLUID_FUNCS + FLUID_FUNCS2 +#undef FLUID_FUN +#undef FLUID_FUN2 +}; + +#define HAVE_FLUID fluid.new_synth + +extern FluidFunctions fluid; + +void initFluidFunctions(); +void finiFluidFunctions(); + +#endif // FLUIDFUN_H diff --git a/src/midisource.cpp b/src/midisource.cpp index 3e82577..1522299 100644 --- a/src/midisource.cpp +++ b/src/midisource.cpp @@ -27,8 +27,8 @@ #include "sharedmidistate.h" #include "util.h" #include "debugwriter.h" +#include "fluid-fun.h" -#include #include #include @@ -648,22 +648,22 @@ struct MidiSource : ALDataSource, MidiReadHandler switch (e.type) { case NoteOn: - fluid_synth_noteon(synth, e.e.note.chan, key, e.e.note.vel); + fluid.synth_noteon(synth, e.e.note.chan, key, e.e.note.vel); break; case NoteOff: - fluid_synth_noteoff(synth, e.e.note.chan, key); + fluid.synth_noteoff(synth, e.e.note.chan, key); break; case ChanTouch: - fluid_synth_channel_pressure(synth, e.e.chanTouch.chan, e.e.chanTouch.val); + fluid.synth_channel_pressure(synth, e.e.chanTouch.chan, e.e.chanTouch.val); break; case PitchBend: - fluid_synth_pitch_bend(synth, e.e.pitchBend.chan, e.e.pitchBend.val); + fluid.synth_pitch_bend(synth, e.e.pitchBend.chan, e.e.pitchBend.val); break; case CC: - fluid_synth_cc(synth, e.e.cc.chan, e.e.cc.ctrl, e.e.cc.val); + fluid.synth_cc(synth, e.e.cc.chan, e.e.cc.ctrl, e.e.cc.val); break; case PC: - fluid_synth_program_change(synth, e.e.pc.chan, e.e.pc.prog); + fluid.synth_program_change(synth, e.e.pc.chan, e.e.pc.prog); break; case Tempo: updatePlaybackSpeed(e.e.tempo.bpm); @@ -679,7 +679,7 @@ struct MidiSource : ALDataSource, MidiReadHandler int len = count * TICK_FRAMES; void *buffer = &synthBuf[bufOffset]; - fluid_synth_write_s16(synth, len, buffer, 0, 2, buffer, 1, 2); + fluid.synth_write_s16(synth, len, buffer, 0, 2, buffer, 1, 2); } /* MidiReadHandler */ @@ -817,7 +817,7 @@ struct MidiSource : ALDataSource, MidiReadHandler void seekToOffset(float) { /* Reset synth */ - fluid_synth_system_reset(synth); + fluid.synth_system_reset(synth); /* Reset runtime variables */ genDeltasCarry = 0; diff --git a/src/sharedmidistate.h b/src/sharedmidistate.h index 9066981..455e4b0 100644 --- a/src/sharedmidistate.h +++ b/src/sharedmidistate.h @@ -24,8 +24,7 @@ #include "config.h" #include "debugwriter.h" - -#include +#include "fluid-fun.h" #include #include @@ -50,58 +49,52 @@ struct SharedMidiState SharedMidiState(const Config &conf) : inited(false), soundFont(conf.midi.soundFont) - { - flSettings = new_fluid_settings(); - fluid_settings_setnum(flSettings, "synth.gain", 1.0); - 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"); - } + {} ~SharedMidiState() { - delete_fluid_settings(flSettings); + if (!HAVE_FLUID || !inited) + return; + + fluid.delete_settings(flSettings); for (size_t i = 0; i < synths.size(); ++i) { assert(!synths[i].inUse); - delete_fluid_synth(synths[i].synth); + fluid.delete_synth(synths[i].synth); } + + finiFluidFunctions(); } - fluid_synth_t *addSynth(bool usedNow) - { - fluid_synth_t *syn = new_fluid_synth(flSettings); - - if (!soundFont.empty()) - fluid_synth_sfload(syn, soundFont.c_str(), 1); - else - Debug() << "Warning: No soundfont specified, sound might be mute"; - - Synth synth; - synth.inUse = usedNow; - synth.synth = syn; - synths.push_back(synth); - - return syn; - } - - void initDefaultSynths() + void initIfNeeded(const Config &conf) { if (inited) return; + inited = true; + + initFluidFunctions(); + + if (!HAVE_FLUID) + return; + + flSettings = fluid.new_settings(); + fluid.settings_setnum(flSettings, "synth.gain", 1.0); + 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"); + for (size_t i = 0; i < SYNTH_INIT_COUNT; ++i) addSynth(false); - - inited = true; } fluid_synth_t *allocateSynth() { - size_t i; + assert(HAVE_FLUID); + assert(inited); - initDefaultSynths(); + size_t i; for (i = 0; i < synths.size(); ++i) if (!synths[i].inUse) @@ -110,7 +103,7 @@ struct SharedMidiState if (i < synths.size()) { fluid_synth_t *syn = synths[i].synth; - fluid_synth_system_reset(syn); + fluid.synth_system_reset(syn); synths[i].inUse = true; return syn; @@ -133,6 +126,24 @@ struct SharedMidiState synths[i].inUse = false; } + +private: + fluid_synth_t *addSynth(bool usedNow) + { + fluid_synth_t *syn = fluid.new_synth(flSettings); + + if (!soundFont.empty()) + fluid.synth_sfload(syn, soundFont.c_str(), 1); + else + Debug() << "Warning: No soundfont specified, sound might be mute"; + + Synth synth; + synth.inUse = usedNow; + synth.synth = syn; + synths.push_back(synth); + + return syn; + } }; #endif // SHAREDMIDISTATE_H diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index eff10c0..27a632d 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -36,10 +36,7 @@ #include "quad.h" #include "binding.h" #include "exception.h" - -#ifdef MIDI #include "sharedmidistate.h" -#endif #include #include @@ -74,9 +71,7 @@ struct SharedStatePrivate RGSSThreadData &rtData; Config &config; -#ifdef MIDI SharedMidiState midiState; -#endif Graphics graphics; Input input; @@ -109,9 +104,7 @@ struct SharedStatePrivate eThread(*threadData->ethread), rtData(*threadData), config(threadData->config), -#ifdef MIDI midiState(threadData->config), -#endif graphics(threadData), audio(threadData->config), fontState(threadData->config), @@ -164,10 +157,8 @@ struct SharedStatePrivate /* RGSS3 games will call setup_midi, so there's * no need to do it on startup */ -#if MIDI if (rgssVer <= 2) - midiState.initDefaultSynths(); -#endif + midiState.initIfNeeded(threadData->config); } ~SharedStatePrivate() @@ -245,10 +236,7 @@ GSATT(ShaderSet&, shaders) GSATT(TexPool&, texPool) GSATT(Quad&, gpQuad) GSATT(SharedFontState&, fontState) - -#ifdef MIDI GSATT(SharedMidiState&, midiState) -#endif void SharedState::setBindingData(void *data) { diff --git a/src/sharedstate.h b/src/sharedstate.h index 6ce964d..c713b26 100644 --- a/src/sharedstate.h +++ b/src/sharedstate.h @@ -49,10 +49,7 @@ class SharedFontState; struct GlobalIBO; struct Config; struct Vec2i; - -#ifdef MIDI struct SharedMidiState; -#endif struct SharedState { @@ -83,9 +80,7 @@ struct SharedState SharedFontState &fontState() const; Font &defaultFont() const; -#ifdef MIDI SharedMidiState &midiState() const; -#endif sigc::signal prepareDraw; From 0c318ee0b2f298fb44cc4d985b5409ecd77ec29f Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 12 Sep 2014 06:33:44 +0200 Subject: [PATCH 017/239] SDL_sound: Add wave IMA ADPCM (4bit) support patch --- patches/SDL_sound/ima-adpcm.patch | 353 ++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 patches/SDL_sound/ima-adpcm.patch diff --git a/patches/SDL_sound/ima-adpcm.patch b/patches/SDL_sound/ima-adpcm.patch new file mode 100644 index 0000000..62585e0 --- /dev/null +++ b/patches/SDL_sound/ima-adpcm.patch @@ -0,0 +1,353 @@ +diff -r 719dade41745 decoders/wav.c +--- a/decoders/wav.c Wed Aug 15 23:52:18 2012 -0400 ++++ b/decoders/wav.c Fri Sep 12 06:37:52 2014 +0200 +@@ -113,8 +113,9 @@ + + #define fmtID 0x20746D66 /* "fmt ", in ascii. */ + +-#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */ +-#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */ ++#define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */ ++#define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */ ++#define FMT_IMA 0x0011 /* IMA ADPCM compressed waveform data. */ + + typedef struct + { +@@ -130,6 +131,12 @@ + Sint16 iSamp2; + } ADPCMBLOCKHEADER; + ++typedef struct ++{ ++ Sint16 iPrevSamp; ++ Uint8 iStepIndex; ++} IMAADPCMDATA; ++ + typedef struct S_WAV_FMT_T + { + Uint32 chunkID; +@@ -166,6 +173,25 @@ + Sint8 nibble; + } adpcm; + ++ struct ++ { ++ /* per channel decoder state */ ++ IMAADPCMDATA *d; ++ /* auxiliary buffer */ ++ Uint8 *buf; ++ ++ Uint16 block_frames; ++ Uint16 block_framesets; ++ Uint16 enc_frameset_size; ++ Uint16 headerset_size; ++ Uint16 dec_frame_size; ++ Uint16 dec_frameset_size; ++ Uint16 rem_block_framesets; ++ ++ /* whether the next word(s) are the start of a new block */ ++ int read_header; ++ } ima; ++ + /* put other format-specific data here... */ + } fmt; + } fmt_t; +@@ -614,6 +640,284 @@ + + + /***************************************************************************** ++ * IMA ADPCM compression handler... * ++ *****************************************************************************/ ++ ++static const int ima_index_table[16] = ++{ ++ -1, -1, -1, -1, 2, 4, 6, 8, ++ -1, -1, -1, -1, 2, 4, 6, 8 ++}; ++ ++static const int ima_step_table[89] = ++{ ++ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, ++ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, ++ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, ++ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, ++ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, ++ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, ++ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, ++ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, ++ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 ++}; ++ ++/* 1 frameset = 4 bytes (per channel) = 8 nibbles = 8 frames */ ++#define FRAMESET_FRAMES 8 ++ ++ ++static int read_ima_block_headers(SDL_RWops *rw, IMAADPCMDATA *d, ++ Uint16 chan_count, Sint16 *out) ++{ ++ Uint16 i; ++ Uint8 dummy; ++ ++ for (i = 0; i < chan_count; i++) ++ { ++ BAIL_IF_MACRO(!read_le16(rw, &d[i].iPrevSamp), NULL, 0); ++ BAIL_IF_MACRO(!read_uint8(rw, &d[i].iStepIndex), NULL, 0); ++ BAIL_IF_MACRO(!read_uint8(rw, &dummy), NULL, 0); ++ ++ out[i] = d[i].iPrevSamp; ++ } /* for */ ++ ++ return(1); ++} /* read_ima_block_headers */ ++ ++ ++static Sint16 decode_ima_nibble(Uint8 nibble, IMAADPCMDATA *state) ++{ ++ int step = ima_step_table[state->iStepIndex]; ++ int diff = 0; ++ ++ if (nibble & 0x4) ++ diff += step >> 0; ++ if (nibble & 0x2) ++ diff += step >> 1; ++ if (nibble & 0x1) ++ diff += step >> 2; ++ ++ diff += step >> 3; ++ ++ if (nibble & 0x8) ++ diff = -diff; ++ ++ int samp = state->iPrevSamp + diff; ++ samp = SDL_max(SDL_min(samp, 32767), -32768); ++ state->iPrevSamp = samp; ++ ++ int index = state->iStepIndex + ima_index_table[nibble]; ++ state->iStepIndex = SDL_max(SDL_min(index, 88), 0); ++ ++ return samp; ++} /* decode_ima_nibble */ ++ ++ ++static int read_ima_frameset(SDL_RWops *rw, wav_t *wav, Sint16 *out) ++{ ++ fmt_t *fmt = wav->fmt; ++ Uint16 i, j; ++ Uint8 *fs_buf = fmt->fmt.ima.buf; ++ Uint32 fs_buf_size = fmt->fmt.ima.enc_frameset_size; ++ Uint16 chan_count = fmt->wChannels; ++ IMAADPCMDATA *data = fmt->fmt.ima.d; ++ ++ /* read encoded frameset into temp buffer */ ++ BAIL_IF_MACRO(!SDL_RWread(rw, fs_buf, fs_buf_size, 1), NULL, 0); ++ ++ for (i = 0; i < chan_count; i++) ++ { ++ for (j = 0; j < 4; j++) ++ { ++ Uint8 byte = fs_buf[i*4+j]; ++ Sint16 *_out = out + j*chan_count*2+i; ++ ++ /* low nibble */ ++ *_out = decode_ima_nibble(byte & 0xF, &data[i]); ++ ++ _out += chan_count; ++ ++ /* high nibble */ ++ *_out = decode_ima_nibble(byte >> 4, &data[i]); ++ } ++ } /* for */ ++ ++ return(1); ++} /* read_ima_frameset */ ++ ++static Uint32 read_sample_fmt_ima(Sound_Sample *sample) ++{ ++ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; ++ wav_t *w = (wav_t *) internal->decoder_private; ++ fmt_t *fmt = w->fmt; ++ void *const out_buf = internal->buffer; ++ Uint32 bw = 0; ++ ++ while (1) ++ { ++ if (fmt->fmt.ima.read_header) ++ { ++ if (w->bytesLeft < fmt->fmt.ima.headerset_size) ++ { ++ sample->flags |= SOUND_SAMPLEFLAG_EOF; ++ break; ++ } /* if */ ++ ++ if (bw+fmt->fmt.ima.dec_frame_size > internal->buffer_size) ++ break; ++ ++ read_ima_block_headers(internal->rw, fmt->fmt.ima.d, ++ fmt->wChannels, (Sint16*) (out_buf+bw)); ++ ++ w->bytesLeft -= fmt->fmt.ima.headerset_size; ++ bw += fmt->fmt.ima.dec_frame_size; ++ ++ fmt->fmt.ima.read_header = 0; ++ fmt->fmt.ima.rem_block_framesets = fmt->fmt.ima.block_framesets; ++ } /* if */ ++ ++ if (w->bytesLeft < fmt->fmt.ima.enc_frameset_size) ++ { ++ sample->flags |= SOUND_SAMPLEFLAG_EOF; ++ break; ++ } /* if */ ++ ++ if (bw+fmt->fmt.ima.dec_frameset_size > internal->buffer_size) ++ break; ++ ++ int rc = read_ima_frameset(internal->rw, w, (Sint16*) (out_buf+bw)); ++ ++ if (!rc) ++ { ++ sample->flags |= SOUND_SAMPLEFLAG_ERROR; ++ return 0; ++ } /* if */ ++ ++ bw += fmt->fmt.ima.dec_frameset_size; ++ w->bytesLeft -= fmt->fmt.ima.enc_frameset_size; ++ ++ if (--fmt->fmt.ima.rem_block_framesets == 0) ++ fmt->fmt.ima.read_header = 1; ++ } /* while */ ++ ++ return(bw); ++} /* read_sample_fmt_ima */ ++ ++static void free_fmt_ima(fmt_t *fmt) ++{ ++ free(fmt->fmt.ima.d); ++ free(fmt->fmt.ima.buf); ++} /* free_fmt_ima */ ++ ++static int rewind_sample_fmt_ima(Sound_Sample *sample) ++{ ++ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; ++ wav_t *w = (wav_t *) internal->decoder_private; ++ fmt_t *fmt = w->fmt; ++ ++ fmt->fmt.ima.read_header = 1; ++ ++ return(1); ++} /* rewind_sample_fmt_ima */ ++ ++ ++static int seek_sample_fmt_ima(Sound_Sample *sample, Uint32 ms) ++{ ++ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; ++ wav_t *w = (wav_t *) internal->decoder_private; ++ fmt_t *fmt = w->fmt; ++ Sint16 *dummy_buf = (Sint16*) (fmt->fmt.ima.buf + ++ fmt->fmt.ima.enc_frameset_size); ++ Uint32 i; ++ int rc, pos; ++ ++ Uint32 seek_frames = (fmt->dwSamplesPerSec * ms) / 1000; ++ Uint32 seek_blocks = seek_frames / fmt->fmt.ima.block_frames; ++ Uint32 seek_framesets; ++ seek_frames %= fmt->fmt.ima.block_frames; ++ ++ w->bytesLeft = fmt->total_bytes; ++ pos = seek_blocks * fmt->wBlockAlign + fmt->data_starting_offset; ++ rc = SDL_RWseek(internal->rw, pos, SEEK_SET); ++ BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0); ++ w->bytesLeft -= seek_blocks * fmt->wBlockAlign; ++ ++ fmt->fmt.ima.read_header = 0; ++ ++ if (seek_frames == 0) ++ { ++ fmt->fmt.ima.read_header = 1; ++ return(1); ++ } /* if */ ++ ++ rc = read_ima_block_headers(internal->rw, fmt->fmt.ima.d, ++ fmt->wChannels, dummy_buf); ++ BAIL_IF_MACRO(!rc, NULL, 0); ++ w->bytesLeft -= fmt->fmt.ima.headerset_size; ++ ++ if (w->bytesLeft < fmt->fmt.ima.headerset_size) ++ { ++ sample->flags |= SOUND_SAMPLEFLAG_EOF; ++ return(1); ++ } /* if */ ++ ++ seek_frames -= 1; ++ seek_framesets = seek_frames / FRAMESET_FRAMES; ++ ++ for (i = 0; i < seek_framesets; i++) ++ { ++ rc = read_ima_frameset(internal->rw, w, dummy_buf); ++ BAIL_IF_MACRO(!rc, NULL, 0); ++ w->bytesLeft -= fmt->fmt.ima.enc_frameset_size; ++ } /* for */ ++ ++ fmt->fmt.ima.rem_block_framesets = ++ fmt->fmt.ima.block_framesets - seek_framesets; ++ ++ if (w->bytesLeft < fmt->fmt.ima.enc_frameset_size) ++ sample->flags |= SOUND_SAMPLEFLAG_EOF; ++ ++ return(1); /* success. */ ++} /* seek_sample_fmt_ima */ ++ ++static int read_fmt_ima(SDL_RWops *rw, fmt_t *fmt) ++{ ++ Uint16 chan = fmt->wChannels; ++ int rc; ++ ++ /* setup function pointers */ ++ fmt->free = free_fmt_ima; ++ fmt->read_sample = read_sample_fmt_ima; ++ fmt->rewind_sample = rewind_sample_fmt_ima; ++ fmt->seek_sample = seek_sample_fmt_ima; ++ ++ Sint16 extraBytes; ++ BAIL_IF_MACRO(!read_le16(rw, &extraBytes), NULL, 0); ++ BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.ima.block_frames), NULL, 0); ++ ++ /* skip to end of fmt chunk */ ++ rc = SDL_RWseek(rw, extraBytes-2, SEEK_CUR); ++ BAIL_IF_MACRO(!rc, NULL, 0); ++ ++ fmt->fmt.ima.block_framesets = (fmt->fmt.ima.block_frames-1) / FRAMESET_FRAMES; ++ fmt->fmt.ima.enc_frameset_size = 4 * chan; ++ fmt->fmt.ima.headerset_size = 4 * chan; ++ fmt->fmt.ima.dec_frame_size = sizeof(Uint16) * chan; ++ fmt->fmt.ima.dec_frameset_size = fmt->fmt.ima.dec_frame_size * FRAMESET_FRAMES; ++ fmt->fmt.ima.read_header = 1; ++ ++ fmt->fmt.ima.d = malloc(sizeof(IMAADPCMDATA) * chan); ++ ++ size_t buf_size = fmt->fmt.ima.enc_frameset_size + ++ fmt->fmt.ima.dec_frameset_size; ++ fmt->fmt.ima.buf = malloc(buf_size); ++ ++ return(1); ++} /* read_fmt_ima */ ++ ++ ++ ++/***************************************************************************** + * Everything else... * + *****************************************************************************/ + +@@ -642,6 +946,13 @@ + SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n")); + return(read_fmt_adpcm(rw, fmt)); + ++ case FMT_IMA: ++ if (fmt->wBitsPerSample == 4) ++ { ++ SNDDBG(("WAV: Appears to be 4bit IMA ADPCM compressed audio.\n")); ++ return(read_fmt_ima(rw, fmt)); ++ } ++ + /* add other types here. */ + + default: From a365a7a754a08353ed0a2eefdba42c69480a3577 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 12 Sep 2014 06:42:18 +0200 Subject: [PATCH 018/239] Spacing --- patches/SDL_sound/ima-adpcm.patch | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/patches/SDL_sound/ima-adpcm.patch b/patches/SDL_sound/ima-adpcm.patch index 62585e0..815b98e 100644 --- a/patches/SDL_sound/ima-adpcm.patch +++ b/patches/SDL_sound/ima-adpcm.patch @@ -1,6 +1,6 @@ diff -r 719dade41745 decoders/wav.c --- a/decoders/wav.c Wed Aug 15 23:52:18 2012 -0400 -+++ b/decoders/wav.c Fri Sep 12 06:37:52 2014 +0200 ++++ b/decoders/wav.c Fri Sep 12 06:42:05 2014 +0200 @@ -113,8 +113,9 @@ #define fmtID 0x20746D66 /* "fmt ", in ascii. */ @@ -52,7 +52,7 @@ diff -r 719dade41745 decoders/wav.c /* put other format-specific data here... */ } fmt; } fmt_t; -@@ -614,6 +640,284 @@ +@@ -614,6 +640,288 @@ /***************************************************************************** @@ -161,6 +161,7 @@ diff -r 719dade41745 decoders/wav.c + return(1); +} /* read_ima_frameset */ + ++ +static Uint32 read_sample_fmt_ima(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; @@ -219,12 +220,14 @@ diff -r 719dade41745 decoders/wav.c + return(bw); +} /* read_sample_fmt_ima */ + ++ +static void free_fmt_ima(fmt_t *fmt) +{ + free(fmt->fmt.ima.d); + free(fmt->fmt.ima.buf); +} /* free_fmt_ima */ + ++ +static int rewind_sample_fmt_ima(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; @@ -296,6 +299,7 @@ diff -r 719dade41745 decoders/wav.c + return(1); /* success. */ +} /* seek_sample_fmt_ima */ + ++ +static int read_fmt_ima(SDL_RWops *rw, fmt_t *fmt) +{ + Uint16 chan = fmt->wChannels; @@ -337,7 +341,7 @@ diff -r 719dade41745 decoders/wav.c * Everything else... * *****************************************************************************/ -@@ -642,6 +946,13 @@ +@@ -642,6 +950,13 @@ SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n")); return(read_fmt_adpcm(rw, fmt)); From 29dfda0011e7ecaf88611679dcf0a3b9dd3f84da Mon Sep 17 00:00:00 2001 From: cremno Date: Tue, 2 Sep 2014 19:09:17 +0200 Subject: [PATCH 019/239] check Ruby strings for embedded null bytes The RGSS doesn't do it. But doing it shouldn't be a problem, as it's the correct way. If a game is broken by this commit (unlikely), then the game needs to be fixed as silent truncation is highly unlikely to be wanted. --- binding-mri/binding-util.cpp | 2 +- binding-mri/bitmap-binding.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/binding-mri/binding-util.cpp b/binding-mri/binding-util.cpp index 6312406..5843ad3 100644 --- a/binding-mri/binding-util.cpp +++ b/binding-mri/binding-util.cpp @@ -189,7 +189,7 @@ rb_get_args(int argc, VALUE *argv, const char *format, ...) if (!RB_TYPE_P(tmp, RUBY_T_STRING)) rb_raise(rb_eTypeError, "Argument %d: Expected string", argI); - *s = RSTRING_PTR(tmp); + *s = StringValueCStr(tmp); ++argI; break; diff --git a/binding-mri/bitmap-binding.cpp b/binding-mri/bitmap-binding.cpp index b2448d6..5f805e8 100644 --- a/binding-mri/bitmap-binding.cpp +++ b/binding-mri/bitmap-binding.cpp @@ -32,7 +32,7 @@ DEF_TYPE(Bitmap); static const char *objAsStringPtr(VALUE obj) { VALUE str = rb_obj_as_string(obj); - return RSTRING_PTR(str); + return StringValueCStr(str); } void bitmapInitProps(Bitmap *b, VALUE self) From 6abc207f1eb69d39c3d0ea98c6c0cad67b88ab44 Mon Sep 17 00:00:00 2001 From: cremno Date: Fri, 12 Sep 2014 15:15:16 +0200 Subject: [PATCH 020/239] VX tilemap has 9 bitmaps --- binding-mri/tilemapvx-binding.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/binding-mri/tilemapvx-binding.cpp b/binding-mri/tilemapvx-binding.cpp index af15968..88e56ed 100644 --- a/binding-mri/tilemapvx-binding.cpp +++ b/binding-mri/tilemapvx-binding.cpp @@ -58,8 +58,8 @@ RB_METHOD(tilemapVXInitialize) VALUE autotilesObj = rb_iv_get(self, "bitmap_array"); - VALUE ary = rb_ary_new2(7); - for (int i = 0; i < 7; ++i) + VALUE ary = rb_ary_new2(9); + for (int i = 0; i < 9; ++i) rb_ary_push(ary, Qnil); rb_iv_set(autotilesObj, "array", ary); @@ -119,7 +119,7 @@ RB_METHOD(tilemapVXBitmapsGet) int i; rb_get_args (argc, argv, "i", &i RB_ARG_END); - if (i < 0 || i > 6) + if (i < 0 || i > 8) return Qnil; VALUE ary = rb_iv_get(self, "array"); From 05041fdb03b0462624994442a91d7f094cd62c7d Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 12 Sep 2014 06:50:45 +0200 Subject: [PATCH 021/239] Couple fixes to last SDL_sound patch --- patches/SDL_sound/ima-adpcm.patch | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/patches/SDL_sound/ima-adpcm.patch b/patches/SDL_sound/ima-adpcm.patch index 815b98e..bf6ba73 100644 --- a/patches/SDL_sound/ima-adpcm.patch +++ b/patches/SDL_sound/ima-adpcm.patch @@ -1,6 +1,6 @@ diff -r 719dade41745 decoders/wav.c --- a/decoders/wav.c Wed Aug 15 23:52:18 2012 -0400 -+++ b/decoders/wav.c Fri Sep 12 06:42:05 2014 +0200 ++++ b/decoders/wav.c Fri Sep 12 06:50:35 2014 +0200 @@ -113,8 +113,9 @@ #define fmtID 0x20746D66 /* "fmt ", in ascii. */ @@ -52,7 +52,7 @@ diff -r 719dade41745 decoders/wav.c /* put other format-specific data here... */ } fmt; } fmt_t; -@@ -614,6 +640,288 @@ +@@ -614,6 +640,296 @@ /***************************************************************************** @@ -105,6 +105,7 @@ diff -r 719dade41745 decoders/wav.c +{ + int step = ima_step_table[state->iStepIndex]; + int diff = 0; ++ int samp, index; + + if (nibble & 0x4) + diff += step >> 0; @@ -118,11 +119,11 @@ diff -r 719dade41745 decoders/wav.c + if (nibble & 0x8) + diff = -diff; + -+ int samp = state->iPrevSamp + diff; ++ samp = state->iPrevSamp + diff; + samp = SDL_max(SDL_min(samp, 32767), -32768); + state->iPrevSamp = samp; + -+ int index = state->iStepIndex + ima_index_table[nibble]; ++ index = state->iStepIndex + ima_index_table[nibble]; + state->iStepIndex = SDL_max(SDL_min(index, 88), 0); + + return samp; @@ -169,6 +170,7 @@ diff -r 719dade41745 decoders/wav.c + fmt_t *fmt = w->fmt; + void *const out_buf = internal->buffer; + Uint32 bw = 0; ++ int rc; + + while (1) + { @@ -183,8 +185,14 @@ diff -r 719dade41745 decoders/wav.c + if (bw+fmt->fmt.ima.dec_frame_size > internal->buffer_size) + break; + -+ read_ima_block_headers(internal->rw, fmt->fmt.ima.d, -+ fmt->wChannels, (Sint16*) (out_buf+bw)); ++ rc = read_ima_block_headers(internal->rw, fmt->fmt.ima.d, ++ fmt->wChannels, (Sint16*) (out_buf+bw)); ++ ++ if (!rc) ++ { ++ sample->flags |= SOUND_SAMPLEFLAG_ERROR; ++ return 0; ++ } /* if */ + + w->bytesLeft -= fmt->fmt.ima.headerset_size; + bw += fmt->fmt.ima.dec_frame_size; @@ -202,7 +210,7 @@ diff -r 719dade41745 decoders/wav.c + if (bw+fmt->fmt.ima.dec_frameset_size > internal->buffer_size) + break; + -+ int rc = read_ima_frameset(internal->rw, w, (Sint16*) (out_buf+bw)); ++ rc = read_ima_frameset(internal->rw, w, (Sint16*) (out_buf+bw)); + + if (!rc) + { @@ -303,6 +311,7 @@ diff -r 719dade41745 decoders/wav.c +static int read_fmt_ima(SDL_RWops *rw, fmt_t *fmt) +{ + Uint16 chan = fmt->wChannels; ++ Sint16 extraBytes; + int rc; + + /* setup function pointers */ @@ -311,7 +320,6 @@ diff -r 719dade41745 decoders/wav.c + fmt->rewind_sample = rewind_sample_fmt_ima; + fmt->seek_sample = seek_sample_fmt_ima; + -+ Sint16 extraBytes; + BAIL_IF_MACRO(!read_le16(rw, &extraBytes), NULL, 0); + BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.ima.block_frames), NULL, 0); + @@ -341,7 +349,7 @@ diff -r 719dade41745 decoders/wav.c * Everything else... * *****************************************************************************/ -@@ -642,6 +950,13 @@ +@@ -642,6 +958,13 @@ SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n")); return(read_fmt_adpcm(rw, fmt)); From 3a29385df0414183bb7c6d850865eac1d0db7558 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sat, 13 Sep 2014 02:54:44 +0200 Subject: [PATCH 022/239] MRI: load_data: Catch exceptions and pass onto ruby --- binding-mri/filesystem-binding.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/binding-mri/filesystem-binding.cpp b/binding-mri/filesystem-binding.cpp index 8ff531e..050f25c 100644 --- a/binding-mri/filesystem-binding.cpp +++ b/binding-mri/filesystem-binding.cpp @@ -43,7 +43,16 @@ static VALUE fileIntForPath(const char *path) { SDL_RWops *ops = SDL_AllocRW(); - shState->fileSystem().openRead(*ops, path); + + try + { + shState->fileSystem().openRead(*ops, path); + } + catch (const Exception &e) + { + SDL_FreeRW(ops); + raiseRbExc(e); + } VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt")); From 5c3c73ee946335aa442ecd4e948d094a309e9e87 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Mon, 15 Sep 2014 09:42:09 +0200 Subject: [PATCH 023/239] README: Remove erroneous line about cmake --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bdf7322..beea7dd 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ mkxp is a project that seeks to provide a fully open source implementation of th It is licensed under the GNU General Public License v2+. ## RGSS2 / RGSS3 -Support for these RGSS versions is experimental. A lot is implemented (to the point that you can play the VX Ace sample game, with caveats), but not everything is in place yet. Note that there is no cmake support for building these at the moment. +Support for these RGSS versions is experimental. A lot is implemented (to the point that you can play the VX Ace sample game, with caveats), but not everything is in place yet. Missing RGSS2 functionality: From 8d67b7c91d623768d56507e2580d78aacc907f2f Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 23 Sep 2014 12:05:28 +0200 Subject: [PATCH 024/239] MRI: Init default font names to correct value (RGSS2) --- binding-mri/font-binding.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/binding-mri/font-binding.cpp b/binding-mri/font-binding.cpp index c6f468a..99d6fa5 100644 --- a/binding-mri/font-binding.cpp +++ b/binding-mri/font-binding.cpp @@ -307,4 +307,14 @@ fontBindingInit() INIT_PROP_BIND(Font, Outline, "outline"); INIT_PROP_BIND(Font, OutColor, "out_color"); } + + if (rgssVer >= 2) + { + VALUE defNames = rb_ary_new_capa(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); + } } From 17efcbbbbde99a78f8358ab60afa60337c7487cd Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 23 Sep 2014 17:26:30 +0200 Subject: [PATCH 025/239] tl;dr: I fucking suck at coding (fix double free) MRI: Filesystem: A garbage collected SDL_RWops file handle will call close on itself even if 'close' was explicitly called on it on the script side before. --- src/filesystem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/filesystem.cpp b/src/filesystem.cpp index f5cfddc..2b1e6ee 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -117,6 +117,7 @@ static int SDL_RWopsClose(SDL_RWops *ops) return -1; int result = PHYSFS_close(f); + ops->hidden.unknown.data1 = 0; return (result != 0) ? 0 : -1; } From 3983fe66e902ed8c33d8c8e87852de74442935a2 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 23 Sep 2014 19:23:11 +0200 Subject: [PATCH 026/239] Config: Print parsing errors instead of ignoring them --- src/config.cpp | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 5fb3c49..8abc66b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -121,6 +121,8 @@ static bool validUtf8(const char *string) typedef std::vector StringVec; namespace po = boost::program_options; +#define CONF_FILE "mkxp.conf" + Config::Config() : rgssVersion(0), debugMode(false), @@ -190,26 +192,36 @@ void Config::read(int argc, char *argv[]) po::variables_map vm; /* Parse command line options */ - po::parsed_options cmdPo = - po::command_line_parser(argc, argv).options(podesc) - .allow_unregistered() - .run(); + try + { + po::parsed_options cmdPo = + po::command_line_parser(argc, argv).options(podesc).run(); + po::store(cmdPo, vm); + } + catch (po::error &error) + { + Debug() << "Command line:" << error.what(); + } - GUARD_ALL( po::store(cmdPo, vm); ) - - /* Parse configuration file (mkxp.conf) */ + /* Parse configuration file */ std::ifstream confFile; - confFile.open("mkxp.conf"); + confFile.open(CONF_FILE); if (confFile) { - GUARD_ALL( po::store(po::parse_config_file(confFile, podesc, true), vm); ) + try + { + po::store(po::parse_config_file(confFile, podesc, true), vm); + po::notify(vm); + } + catch (po::error &error) + { + Debug() << CONF_FILE":" << error.what(); + } + + confFile.close(); } - confFile.close(); - - po::notify(vm); - #undef PO_DESC #define PO_DESC(key, type) GUARD_ALL( key = vm[#key].as< type >(); ) @@ -276,7 +288,7 @@ void Config::readGameINI() iniFile.open((iniPath).c_str()); po::variables_map vm; - GUARD_ALL( po::store(po::parse_config_file(iniFile, podesc, true), vm); ) + po::store(po::parse_config_file(iniFile, podesc, true), vm); po::notify(vm); iniFile.close(); From 81ac0780f8e1c9414cb16c56415861b0f2c13224 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 23 Sep 2014 21:12:58 +0200 Subject: [PATCH 027/239] Revert Disposable concept back into core Pretty much a revert of e858bbdcf5cc8120dd169d7efb8ae8d13ab0b5c5. We need this in core to properly implement F12 reset. --- binding-mri/binding-util.h | 18 ++---- binding-mri/bitmap-binding.cpp | 4 +- binding-mri/disposable-binding.h | 28 ++++++-- binding-mri/font-binding.cpp | 3 + binding-mri/tilemap-binding.cpp | 4 +- binding-mri/tilemapvx-binding.cpp | 2 + binding-mri/viewportelement-binding.h | 2 +- binding-mruby/binding-util.h | 17 ++--- binding-mruby/bitmap-binding.cpp | 6 +- binding-mruby/disposable-binding.h | 30 ++++++--- binding-mruby/font-binding.cpp | 3 + binding-mruby/tilemap-binding.cpp | 4 +- binding-mruby/viewportelement-binding.h | 2 +- src/bitmap.cpp | 86 ++++++++++++++++++------- src/bitmap.h | 7 +- src/disposable.h | 86 ++++++++++++------------- src/font.cpp | 3 +- src/graphics.cpp | 6 +- src/plane.cpp | 30 ++++++--- src/plane.h | 5 ++ src/scene.cpp | 8 +++ src/scene.h | 8 +++ src/sprite.cpp | 43 ++++++++++--- src/sprite.h | 5 ++ src/tileatlasvx.cpp | 2 +- src/tilemap.cpp | 51 +++++++++------ src/tilemap.h | 3 + src/tilemapvx.cpp | 47 ++++++++++---- src/tilemapvx.h | 3 + src/util.h | 4 ++ src/viewport.cpp | 20 +++++- src/viewport.h | 7 ++ src/window.cpp | 57 +++++++++++----- src/window.h | 5 ++ src/windowvx.cpp | 72 ++++++++++++++++----- src/windowvx.h | 5 ++ 36 files changed, 476 insertions(+), 210 deletions(-) diff --git a/binding-mri/binding-util.h b/binding-mri/binding-util.h index f8718b2..b84a50b 100644 --- a/binding-mri/binding-util.h +++ b/binding-mri/binding-util.h @@ -101,22 +101,12 @@ static void freeInstance(void *inst) void raiseDisposedAccess(VALUE self); -inline void -checkDisposed(VALUE self) -{ - if (!RTYPEDDATA_DATA(self)) - raiseDisposedAccess(self); -} - template inline C * getPrivateData(VALUE self) { C *c = static_cast(RTYPEDDATA_DATA(self)); - if (!c) - raiseDisposedAccess(self); - return c; } @@ -124,8 +114,6 @@ template static inline C * getPrivateDataCheck(VALUE self, const rb_data_type_t &type) { - /* We don't check for disposed here because any disposable - * property is always also nullable */ void *obj = Check_TypedStruct(self, &type); return static_cast(obj); } @@ -341,7 +329,7 @@ rb_check_argc(int actual, int expected) RB_METHOD(Klass##Get##PropName) \ { \ RB_UNUSED_PARAM; \ - checkDisposed(self); \ + checkDisposed(self); \ return rb_iv_get(self, prop_iv); \ } \ RB_METHOD(Klass##Set##PropName) \ @@ -360,7 +348,9 @@ rb_check_argc(int actual, int expected) { \ RB_UNUSED_PARAM; \ Klass *k = getPrivateData(self); \ - return value_fun(k->get##PropName()); \ + type value; \ + GUARD_EXC( value = k->get##PropName(); ) \ + return value_fun(value); \ } \ RB_METHOD(Klass##Set##PropName) \ { \ diff --git a/binding-mri/bitmap-binding.cpp b/binding-mri/bitmap-binding.cpp index 5f805e8..8781d05 100644 --- a/binding-mri/bitmap-binding.cpp +++ b/binding-mri/bitmap-binding.cpp @@ -128,7 +128,7 @@ RB_METHOD(bitmapBlt) src = getPrivateDataCheck(srcObj, BitmapType); srcRect = getPrivateDataCheck(srcRectObj, RectType); - GUARD_EXC( b->blt(x, y, src, srcRect->toIntRect(), opacity); ); + GUARD_EXC( b->blt(x, y, *src, srcRect->toIntRect(), opacity); ); return self; } @@ -151,7 +151,7 @@ RB_METHOD(bitmapStretchBlt) destRect = getPrivateDataCheck(destRectObj, RectType); srcRect = getPrivateDataCheck(srcRectObj, RectType); - GUARD_EXC( b->stretchBlt(destRect->toIntRect(), src, srcRect->toIntRect(), opacity); ); + GUARD_EXC( b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(), opacity); ); return self; } diff --git a/binding-mri/disposable-binding.h b/binding-mri/disposable-binding.h index 0df8b48..7dfe928 100644 --- a/binding-mri/disposable-binding.h +++ b/binding-mri/disposable-binding.h @@ -64,32 +64,48 @@ RB_METHOD(disposableDispose) { RB_UNUSED_PARAM; - C *c = static_cast(RTYPEDDATA_DATA(self)); + C *d = getPrivateData(self); + + if (!d) + return Qnil; /* Nothing to do if already disposed */ - if (!c) + if (d->isDisposed()) return Qnil; disposableDisposeChildren(self); - delete c; - setPrivateData(self, 0); + d->dispose(); return Qnil; } +template RB_METHOD(disposableIsDisposed) { RB_UNUSED_PARAM; - return rb_bool_new(RTYPEDDATA_DATA(self) == 0); + C *d = getPrivateData(self); + + if (!d) + return Qtrue; + + return rb_bool_new(d->isDisposed()); } template static void disposableBindingInit(VALUE klass) { _rb_define_method(klass, "dispose", disposableDispose); - _rb_define_method(klass, "disposed?", disposableIsDisposed); + _rb_define_method(klass, "disposed?", disposableIsDisposed); +} + +template +inline void +checkDisposed(VALUE self) +{ + if (disposableIsDisposed(0, 0, self) == Qtrue) + raiseDisposedAccess(self); } #endif // DISPOSABLEBINDING_H diff --git a/binding-mri/font-binding.cpp b/binding-mri/font-binding.cpp index 99d6fa5..809f0da 100644 --- a/binding-mri/font-binding.cpp +++ b/binding-mri/font-binding.cpp @@ -160,6 +160,9 @@ RB_METHOD(FontSetName) return argv[0]; } +template +static void checkDisposed(VALUE) {} + DEF_PROP_OBJ_VAL(Font, Color, Color, "color") DEF_PROP_OBJ_VAL(Font, Color, OutColor, "out_color") diff --git a/binding-mri/tilemap-binding.cpp b/binding-mri/tilemap-binding.cpp index 54cbd05..bdb429f 100644 --- a/binding-mri/tilemap-binding.cpp +++ b/binding-mri/tilemap-binding.cpp @@ -101,6 +101,8 @@ RB_METHOD(tilemapGetAutotiles) { RB_UNUSED_PARAM; + checkDisposed(self); + return rb_iv_get(self, "autotiles"); } @@ -119,7 +121,7 @@ RB_METHOD(tilemapGetViewport) { RB_UNUSED_PARAM; - checkDisposed(self); + checkDisposed(self); return rb_iv_get(self, "viewport"); } diff --git a/binding-mri/tilemapvx-binding.cpp b/binding-mri/tilemapvx-binding.cpp index 88e56ed..58a586d 100644 --- a/binding-mri/tilemapvx-binding.cpp +++ b/binding-mri/tilemapvx-binding.cpp @@ -71,6 +71,8 @@ RB_METHOD(tilemapVXGetBitmapArray) { RB_UNUSED_PARAM; + checkDisposed(self); + return rb_iv_get(self, "bitmap_array"); } diff --git a/binding-mri/viewportelement-binding.h b/binding-mri/viewportelement-binding.h index 21e3fef..f3c5928 100644 --- a/binding-mri/viewportelement-binding.h +++ b/binding-mri/viewportelement-binding.h @@ -35,7 +35,7 @@ RB_METHOD(viewportElementGetViewport) { RB_UNUSED_PARAM; - checkDisposed(self); + checkDisposed(self); return rb_iv_get(self, "viewport"); } diff --git a/binding-mruby/binding-util.h b/binding-mruby/binding-util.h index 19f359b..28e1211 100644 --- a/binding-mruby/binding-util.h +++ b/binding-mruby/binding-util.h @@ -155,7 +155,7 @@ defineClass(mrb_state *mrb, const char *name) #define DEF_PROP_OBJ_VAL(Klass, PropKlass, PropName, prop_iv) \ MRB_METHOD(Klass##Get##PropName) \ { \ - checkDisposed(mrb, self); \ + checkDisposed(mrb, self); \ return getProperty(mrb, self, prop_iv); \ } \ MRB_METHOD(Klass##Set##PropName) \ @@ -194,7 +194,9 @@ defineClass(mrb_state *mrb, const char *name) MRB_METHOD(Klass##Get##PropName) \ { \ Klass *k = getPrivateData(mrb, self); \ - return mrb_##conv_t##_value(k->get##PropName()); \ + mrb_type value; \ + GUARD_EXC( value = k->get##PropName(); ) \ + return mrb_##conv_t##_value(value); \ } \ MRB_METHOD(Klass##Set##PropName) \ { \ @@ -256,21 +258,12 @@ getSym(mrb_state *mrb, CommonSymbol sym) void raiseDisposedAccess(mrb_state *mrb, mrb_value self); -inline void checkDisposed(mrb_state *mrb, mrb_value self) -{ - if (!DATA_PTR(self)) - raiseDisposedAccess(mrb, self); -} - template inline C * -getPrivateData(mrb_state *mrb, mrb_value self) +getPrivateData(mrb_state *, mrb_value self) { C *c = static_cast(DATA_PTR(self)); - if (!c) - raiseDisposedAccess(mrb, self); - return c; } diff --git a/binding-mruby/bitmap-binding.cpp b/binding-mruby/bitmap-binding.cpp index f4cd260..d200a83 100644 --- a/binding-mruby/bitmap-binding.cpp +++ b/binding-mruby/bitmap-binding.cpp @@ -114,7 +114,7 @@ MRB_METHOD(bitmapBlt) src = getPrivateDataCheck(mrb, srcObj, BitmapType); srcRect = getPrivateDataCheck(mrb, srcRectObj, RectType); - GUARD_EXC( b->blt(x, y, src, srcRect->toIntRect(), opacity); ) + GUARD_EXC( b->blt(x, y, *src, srcRect->toIntRect(), opacity); ) return mrb_nil_value(); } @@ -137,7 +137,7 @@ MRB_METHOD(bitmapStretchBlt) destRect = getPrivateDataCheck(mrb, destRectObj, RectType); srcRect = getPrivateDataCheck(mrb, srcRectObj, RectType); - GUARD_EXC( b->stretchBlt(destRect->toIntRect(), src, srcRect->toIntRect(), opacity); ) + GUARD_EXC( b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(), opacity); ) return mrb_nil_value(); } @@ -280,7 +280,7 @@ MRB_METHOD(bitmapTextSize) MRB_METHOD(bitmapGetFont) { - checkDisposed(mrb, self); + checkDisposed(mrb, self); return getProperty(mrb, self, CSfont); } diff --git a/binding-mruby/disposable-binding.h b/binding-mruby/disposable-binding.h index eda37de..9b1895c 100644 --- a/binding-mruby/disposable-binding.h +++ b/binding-mruby/disposable-binding.h @@ -66,33 +66,47 @@ disposableDisposeChildren(mrb_state *mrb, mrb_value disp) template MRB_METHOD(disposableDispose) { - C *c = static_cast(DATA_PTR(self)); + C *d = static_cast(DATA_PTR(self)); - /* Nothing to do if already disposed */ - if (!c) + if (!d) + return mrb_nil_value(); + + if (d->isDisposed()) return mrb_nil_value(); disposableDisposeChildren(mrb, self); - delete c; - DATA_PTR(self) = 0; + d->dispose(); return mrb_nil_value(); } template -MRB_METHOD(disposableDisposed) +MRB_METHOD(disposableIsDisposed) { MRB_UNUSED_PARAM; - return mrb_bool_value(DATA_PTR(self) == 0); + C *d = static_cast(DATA_PTR(self)); + + if (!d) + return mrb_true_value(); + + return mrb_bool_value(d->isDisposed()); } template static void disposableBindingInit(mrb_state *mrb, RClass *klass) { mrb_define_method(mrb, klass, "dispose", disposableDispose, MRB_ARGS_NONE()); - mrb_define_method(mrb, klass, "disposed?", disposableDisposed, MRB_ARGS_NONE()); + mrb_define_method(mrb, klass, "disposed?", disposableIsDisposed, MRB_ARGS_NONE()); +} + +template +inline void +checkDisposed(mrb_state *mrb, mrb_value self) +{ + if (mrb_test(disposableIsDisposed(0, self))) + raiseDisposedAccess(mrb, self); } #endif // DISPOSABLEBINDING_H diff --git a/binding-mruby/font-binding.cpp b/binding-mruby/font-binding.cpp index d811869..22e34cd 100644 --- a/binding-mruby/font-binding.cpp +++ b/binding-mruby/font-binding.cpp @@ -103,6 +103,9 @@ MRB_METHOD(FontSetName) return name; } +template +static void checkDisposed(mrb_state *, mrb_value) {} + DEF_PROP_I(Font, Size) DEF_PROP_B(Font, Bold) DEF_PROP_B(Font, Italic) diff --git a/binding-mruby/tilemap-binding.cpp b/binding-mruby/tilemap-binding.cpp index 2ec1eb0..1d4efcf 100644 --- a/binding-mruby/tilemap-binding.cpp +++ b/binding-mruby/tilemap-binding.cpp @@ -106,6 +106,8 @@ MRB_METHOD(tilemapInitialize) MRB_METHOD(tilemapGetAutotiles) { + checkDisposed(mrb, self); + return getProperty(mrb, self, CSautotiles); } @@ -120,7 +122,7 @@ MRB_METHOD(tilemapUpdate) MRB_METHOD(tilemapGetViewport) { - checkDisposed(mrb, self); + checkDisposed(mrb, self); return getProperty(mrb, self, CSviewport); } diff --git a/binding-mruby/viewportelement-binding.h b/binding-mruby/viewportelement-binding.h index a4ea09c..38cd3d1 100644 --- a/binding-mruby/viewportelement-binding.h +++ b/binding-mruby/viewportelement-binding.h @@ -32,7 +32,7 @@ template MRB_METHOD(viewportElementGetViewport) { - checkDisposed(mrb, self); + checkDisposed(mrb, self); return getProperty(mrb, self, CSviewport); } diff --git a/src/bitmap.cpp b/src/bitmap.cpp index c95afaa..119dc24 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -297,21 +297,18 @@ Bitmap::Bitmap(const Bitmap &other) p->gl = shState->texPool().request(other.width(), other.height()); - blt(0, 0, &other, rect()); + blt(0, 0, other, rect()); } Bitmap::~Bitmap() { - if (p->megaSurface) - SDL_FreeSurface(p->megaSurface); - else - shState->texPool().release(p->gl); - - delete p; + dispose(); } int Bitmap::width() const { + guardDisposed(); + if (p->megaSurface) return p->megaSurface->w; @@ -320,6 +317,8 @@ int Bitmap::width() const int Bitmap::height() const { + guardDisposed(); + if (p->megaSurface) return p->megaSurface->h; @@ -328,14 +327,16 @@ int Bitmap::height() const IntRect Bitmap::rect() const { + guardDisposed(); + return IntRect(0, 0, width(), height()); } void Bitmap::blt(int x, int y, - const Bitmap *source, IntRect rect, + const Bitmap &source, IntRect rect, int opacity) { - if (!source) + if (source.isDisposed()) return; // FIXME: RGSS allows the source rect to both lie outside @@ -344,23 +345,25 @@ void Bitmap::blt(int x, int y, // doesn't fix anything for a direct stretch_blt call). /* Clamp rect to source bitmap size */ - if (rect.x + rect.w > source->width()) - rect.w = source->width() - rect.x; + if (rect.x + rect.w > source.width()) + rect.w = source.width() - rect.x; - if (rect.y + rect.h > source->height()) - rect.h = source->height() - rect.y; + if (rect.y + rect.h > source.height()) + rect.h = source.height() - rect.y; stretchBlt(IntRect(x, y, rect.w, rect.h), source, rect, opacity); } void Bitmap::stretchBlt(const IntRect &destRect, - const Bitmap *source, const IntRect &sourceRect, + const Bitmap &source, const IntRect &sourceRect, int opacity) { + guardDisposed(); + GUARD_MEGA; - if (!source) + if (source.isDisposed()) return; opacity = clamp(opacity, 0, 255); @@ -368,13 +371,13 @@ void Bitmap::stretchBlt(const IntRect &destRect, if (opacity == 0) return; - if (source->megaSurface()) + if (source.megaSurface()) { /* Don't do transparent blits for now */ if (opacity < 255) - source->ensureNonMega(); + source.ensureNonMega(); - SDL_Surface *srcSurf = source->megaSurface(); + SDL_Surface *srcSurf = source.megaSurface(); SDL_Rect srcRect = sourceRect; SDL_Rect dstRect = destRect; @@ -421,7 +424,7 @@ void Bitmap::stretchBlt(const IntRect &destRect, { /* Fast blit */ GLMeta::blitBegin(p->gl); - GLMeta::blitSource(source->p->gl); + GLMeta::blitSource(source.p->gl); GLMeta::blitRectangle(sourceRect, destRect); GLMeta::blitEnd(); } @@ -437,10 +440,10 @@ void Bitmap::stretchBlt(const IntRect &destRect, GLMeta::blitRectangle(destRect, Vec2i()); GLMeta::blitEnd(); - FloatRect bltSubRect((float) sourceRect.x / source->width(), - (float) sourceRect.y / source->height(), - ((float) source->width() / sourceRect.w) * ((float) destRect.w / gpTex.width), - ((float) source->height() / sourceRect.h) * ((float) destRect.h / gpTex.height)); + FloatRect bltSubRect((float) sourceRect.x / source.width(), + (float) sourceRect.y / source.height(), + ((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width), + ((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height)); BltShader &shader = shState->shaders().blt; shader.bind(); @@ -452,7 +455,7 @@ void Bitmap::stretchBlt(const IntRect &destRect, quad.setTexPosRect(sourceRect, destRect); quad.setColor(Vec4(1, 1, 1, normOpacity)); - source->p->bindTexture(shader); + source.p->bindTexture(shader); p->bindFBO(); p->pushSetViewport(shader); @@ -475,6 +478,8 @@ void Bitmap::fillRect(int x, int y, void Bitmap::fillRect(const IntRect &rect, const Vec4 &color) { + guardDisposed(); + GUARD_MEGA; p->fillRect(rect, color); @@ -501,6 +506,8 @@ void Bitmap::gradientFillRect(const IntRect &rect, const Vec4 &color1, const Vec4 &color2, bool vertical) { + guardDisposed(); + GUARD_MEGA; SimpleColorShader &shader = shState->shaders().simpleColor; @@ -545,6 +552,8 @@ void Bitmap::clearRect(int x, int y, int width, int height) void Bitmap::clearRect(const IntRect &rect) { + guardDisposed(); + GUARD_MEGA; p->fillRect(rect, Vec4()); @@ -554,6 +563,8 @@ void Bitmap::clearRect(const IntRect &rect) void Bitmap::blur() { + guardDisposed(); + GUARD_MEGA; Quad &quad = shState->gpQuad(); @@ -597,6 +608,8 @@ void Bitmap::blur() void Bitmap::radialBlur(int angle, int divisions) { + guardDisposed(); + GUARD_MEGA; angle = clamp(angle, 0, 359); @@ -690,6 +703,8 @@ void Bitmap::radialBlur(int angle, int divisions) void Bitmap::clear() { + guardDisposed(); + GUARD_MEGA; p->bindFBO(); @@ -707,6 +722,8 @@ void Bitmap::clear() Color Bitmap::getPixel(int x, int y) const { + guardDisposed(); + GUARD_MEGA; if (x < 0 || y < 0 || x >= width() || y >= height()) @@ -737,6 +754,8 @@ Color Bitmap::getPixel(int x, int y) const void Bitmap::setPixel(int x, int y, const Color &color) { + guardDisposed(); + GUARD_MEGA; uint8_t pixel[] = @@ -757,6 +776,8 @@ void Bitmap::setPixel(int x, int y, const Color &color) void Bitmap::hueChange(int hue) { + guardDisposed(); + GUARD_MEGA; if ((hue % 360) == 0) @@ -818,6 +839,8 @@ static std::string fixupString(const char *str) void Bitmap::drawText(const IntRect &rect, const char *str, int align) { + guardDisposed(); + GUARD_MEGA; std::string fixed = fixupString(str); @@ -1046,6 +1069,8 @@ static uint16_t utf8_to_ucs2(const char *_input, IntRect Bitmap::textSize(const char *str) { + guardDisposed(); + GUARD_MEGA; TTF_Font *font = p->font->getSdlFont(); @@ -1092,6 +1117,9 @@ SDL_Surface *Bitmap::megaSurface() const void Bitmap::ensureNonMega() const { + if (isDisposed()) + return; + GUARD_MEGA; } @@ -1104,3 +1132,13 @@ void Bitmap::taintArea(const IntRect &rect) { p->addTaintedArea(rect); } + +void Bitmap::releaseResources() +{ + if (p->megaSurface) + SDL_FreeSurface(p->megaSurface); + else + shState->texPool().release(p->gl); + + delete p; +} diff --git a/src/bitmap.h b/src/bitmap.h index 89216d0..6217da1 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -49,11 +49,11 @@ public: IntRect rect() const; void blt(int x, int y, - const Bitmap *source, IntRect rect, + const Bitmap &source, IntRect rect, int opacity = 255); void stretchBlt(const IntRect &destRect, - const Bitmap *source, const IntRect &sourceRect, + const Bitmap &source, const IntRect &sourceRect, int opacity = 255); void fillRect(int x, int y, @@ -120,6 +120,9 @@ public: sigc::signal modified; private: + void releaseResources(); + const char *klassName() const { return "bitmap"; } + BitmapPrivate *p; }; diff --git a/src/disposable.h b/src/disposable.h index a83f36f..412b058 100644 --- a/src/disposable.h +++ b/src/disposable.h @@ -24,69 +24,65 @@ #include "exception.h" +#include #include #include class Disposable { public: - ~Disposable() + Disposable() + : disposed(false) + {} + + virtual ~Disposable() { + assert(disposed); + } + + void dispose() + { + if (disposed) + return; + + releaseResources(); + disposed = true; wasDisposed(); } - sigc::signal wasDisposed; -}; - -/* A helper struct which monitors the dispose signal of - * properties, and automatically sets the prop pointer to - * null. Can call an optional notify method when prop is - * nulled */ -template -struct DisposeWatch -{ - typedef void (C::*NotifyFun)(); - - DisposeWatch(C &owner, P *&propLocation, NotifyFun notify = 0) - : owner(owner), - notify(notify), - propLocation(propLocation) - {} - - ~DisposeWatch() + bool isDisposed() const { - dispCon.disconnect(); + return disposed; } - /* Call this when a new object was set for the prop */ - void update(Disposable *prop) + sigc::signal wasDisposed; + +protected: + void guardDisposed() const { - dispCon.disconnect(); - - if (!prop) - return; - - dispCon = prop->wasDisposed.connect - (sigc::mem_fun(this, &DisposeWatch::onDisposed)); + if (isDisposed()) + throw Exception(Exception::RGSSError, + "disposed %s", klassName()); } private: - /* The object owning the prop (and this helper) */ - C &owner; - /* Optional notify method */ - const NotifyFun notify; - /* Location of the prop pointer inside the owner */ - P * &propLocation; - sigc::connection dispCon; + virtual void releaseResources() = 0; + virtual const char *klassName() const = 0; - void onDisposed() - { - dispCon.disconnect(); - propLocation = 0; - - if (notify) - (owner.*notify)(); - } + bool disposed; }; +template +inline bool +nullOrDisposed(const C *d) +{ + if (!d) + return true; + + if (d->isDisposed()) + return true; + + return false; +} + #endif // DISPOSABLE_H diff --git a/src/font.cpp b/src/font.cpp index 09b5ec8..e4ddcd9 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -341,8 +341,7 @@ void Font::setSize(int value) p->sdlFont = 0; } -#undef CHK_DISP -#define CHK_DISP +static void guardDisposed() {} DEF_ATTR_RD_SIMPLE(Font, Size, int, p->size) DEF_ATTR_SIMPLE (Font, Bold, bool, p->bold) diff --git a/src/graphics.cpp b/src/graphics.cpp index 9f69076..ebcc456 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -674,11 +674,7 @@ void Graphics::frameReset() p->fpsLimiter.resetFrameAdjust(); } -#undef RET_IF_DISP -#define RET_IF_DISP(x) - -#undef CHK_DISP -#define CHK_DISP +static void guardDisposed() {} DEF_ATTR_RD_SIMPLE(Graphics, FrameRate, int, p->frameRate) diff --git a/src/plane.cpp b/src/plane.cpp index 1982bce..f050489 100644 --- a/src/plane.cpp +++ b/src/plane.cpp @@ -45,7 +45,6 @@ static float fwrap(float value, float range) struct PlanePrivate { Bitmap *bitmap; - DisposeWatch bitmapWatch; NormValue opacity; BlendType blendType; @@ -67,7 +66,6 @@ struct PlanePrivate PlanePrivate() : bitmap(0), - bitmapWatch(*this, bitmap), opacity(255), blendType(BlendNormal), color(&tmp.color), @@ -103,7 +101,7 @@ struct PlanePrivate return; } - if (!bitmap) + if (nullOrDisposed(bitmap)) return; /* Scaled (zoomed) bitmap dimensions */ @@ -169,15 +167,14 @@ DEF_ATTR_OBJ_VALUE(Plane, Tone, Tone*, p->tone) Plane::~Plane() { - unlink(); - - delete p; + dispose(); } void Plane::setBitmap(Bitmap *value) { + guardDisposed(); + p->bitmap = value; - p->bitmapWatch.update(value); if (!value) return; @@ -187,6 +184,8 @@ void Plane::setBitmap(Bitmap *value) void Plane::setOX(int value) { + guardDisposed(); + if (p->ox == value) return; @@ -196,6 +195,8 @@ void Plane::setOX(int value) void Plane::setOY(int value) { + guardDisposed(); + if (p->oy == value) return; @@ -205,6 +206,8 @@ void Plane::setOY(int value) void Plane::setZoomX(float value) { + guardDisposed(); + if (p->zoomX == value) return; @@ -214,6 +217,8 @@ void Plane::setZoomX(float value) void Plane::setZoomY(float value) { + guardDisposed(); + if (p->zoomY == value) return; @@ -223,6 +228,8 @@ void Plane::setZoomY(float value) void Plane::setBlendType(int value) { + guardDisposed(); + switch (value) { default : @@ -246,7 +253,7 @@ void Plane::initDynAttribs() void Plane::draw() { - if (!p->bitmap) + if (nullOrDisposed(p->bitmap)) return; if (!p->opacity) @@ -301,3 +308,10 @@ void Plane::onGeometryChange(const Scene::Geometry &geo) p->sceneGeo = geo; p->quadSourceDirty = true; } + +void Plane::releaseResources() +{ + unlink(); + + delete p; +} diff --git a/src/plane.h b/src/plane.h index 1b55278..91a9e03 100644 --- a/src/plane.h +++ b/src/plane.h @@ -54,6 +54,11 @@ private: void draw(); void onGeometryChange(const Scene::Geometry &); + + void releaseResources(); + const char *klassName() const { return "plane"; } + + ABOUT_TO_ACCESS_DISP }; #endif // PLANE_H diff --git a/src/scene.cpp b/src/scene.cpp index 9f660f7..a642288 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -134,11 +134,15 @@ void SceneElement::setScene(Scene &scene) int SceneElement::getZ() const { + aboutToAccess(); + return z; } void SceneElement::setZ(int value) { + aboutToAccess(); + if (z == value) return; @@ -148,11 +152,15 @@ void SceneElement::setZ(int value) bool SceneElement::getVisible() const { + aboutToAccess(); + return visible; } void SceneElement::setVisible(bool value) { + aboutToAccess(); + visible = value; } diff --git a/src/scene.h b/src/scene.h index d32dc8b..4dd46b3 100644 --- a/src/scene.h +++ b/src/scene.h @@ -79,6 +79,8 @@ public: DECL_ATTR_VIRT( Z, int ) DECL_ATTR_VIRT( Visible, bool ) + virtual void aboutToAccess() const = 0; + protected: /* A bit about OpenGL state: * @@ -134,4 +136,10 @@ private: int spriteY; }; +#define ABOUT_TO_ACCESS_NOOP \ + void aboutToAccess() const {} + +#define ABOUT_TO_ACCESS_DISP \ + void aboutToAccess() const { guardDisposed(); } + #endif // SCENE_H diff --git a/src/sprite.cpp b/src/sprite.cpp index b436db2..681e219 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -43,7 +43,6 @@ struct SpritePrivate { Bitmap *bitmap; - DisposeWatch bitmapWatch; Quad quad; Transform trans; @@ -87,7 +86,6 @@ struct SpritePrivate SpritePrivate() : bitmap(0), - bitmapWatch(*this, bitmap), srcRect(&tmp.rect), mirrored(false), bushDepth(0), @@ -159,7 +157,7 @@ struct SpritePrivate { isVisible = false; - if (!bitmap) + if (nullOrDisposed(bitmap)) return; if (!opacity) @@ -209,7 +207,7 @@ struct SpritePrivate void updateWave() { - if (!bitmap) + if (nullOrDisposed(bitmap)) return; if (wave.amp == 0) @@ -298,9 +296,7 @@ Sprite::Sprite(Viewport *viewport) Sprite::~Sprite() { - unlink(); - - delete p; + dispose(); } DEF_ATTR_RD_SIMPLE(Sprite, Bitmap, Bitmap*, p->bitmap) @@ -330,11 +326,12 @@ DEF_ATTR_OBJ_VALUE(Sprite, Tone, Tone*, p->tone) void Sprite::setBitmap(Bitmap *bitmap) { + guardDisposed(); + if (p->bitmap == bitmap) return; p->bitmap = bitmap; - p->bitmapWatch.update(bitmap); if (!bitmap) return; @@ -350,6 +347,8 @@ void Sprite::setBitmap(Bitmap *bitmap) void Sprite::setX(int value) { + guardDisposed(); + if (p->trans.getPosition().x == value) return; @@ -358,6 +357,8 @@ void Sprite::setX(int value) void Sprite::setY(int value) { + guardDisposed(); + if (p->trans.getPosition().y == value) return; @@ -372,6 +373,8 @@ void Sprite::setY(int value) void Sprite::setOX(int value) { + guardDisposed(); + if (p->trans.getOrigin().x == value) return; @@ -380,6 +383,8 @@ void Sprite::setOX(int value) void Sprite::setOY(int value) { + guardDisposed(); + if (p->trans.getOrigin().y == value) return; @@ -388,6 +393,8 @@ void Sprite::setOY(int value) void Sprite::setZoomX(float value) { + guardDisposed(); + if (p->trans.getScale().x == value) return; @@ -396,6 +403,8 @@ void Sprite::setZoomX(float value) void Sprite::setZoomY(float value) { + guardDisposed(); + if (p->trans.getScale().y == value) return; @@ -408,6 +417,8 @@ void Sprite::setZoomY(float value) void Sprite::setAngle(float value) { + guardDisposed(); + if (p->trans.getRotation() == value) return; @@ -416,6 +427,8 @@ void Sprite::setAngle(float value) void Sprite::setMirror(bool mirrored) { + guardDisposed(); + if (p->mirrored == mirrored) return; @@ -425,6 +438,8 @@ void Sprite::setMirror(bool mirrored) void Sprite::setBushDepth(int value) { + guardDisposed(); + if (p->bushDepth == value) return; @@ -434,6 +449,8 @@ void Sprite::setBushDepth(int value) void Sprite::setBlendType(int type) { + guardDisposed(); + switch (type) { default : @@ -452,6 +469,7 @@ void Sprite::setBlendType(int type) #define DEF_WAVE_SETTER(Name, name, type) \ void Sprite::setWave##Name(type value) \ { \ + guardDisposed(); \ if (p->wave.name == value) \ return; \ p->wave.name = value; \ @@ -477,6 +495,8 @@ void Sprite::initDynAttribs() /* Flashable */ void Sprite::update() { + guardDisposed(); + Flashable::update(); p->wave.phase += p->wave.speed / 180; @@ -556,3 +576,10 @@ void Sprite::onGeometryChange(const Scene::Geometry &geo) p->sceneRect.w = geo.rect.w; p->sceneRect.h = geo.rect.h; } + +void Sprite::releaseResources() +{ + unlink(); + + delete p; +} diff --git a/src/sprite.h b/src/sprite.h index b1645bb..8a9ba09 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -74,6 +74,11 @@ private: void draw(); void onGeometryChange(const Scene::Geometry &); + + void releaseResources(); + const char *klassName() const { return "sprite"; } + + ABOUT_TO_ACCESS_DISP }; #endif // SPRITE_H diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp index a2062ad..711675c 100644 --- a/src/tileatlasvx.cpp +++ b/src/tileatlasvx.cpp @@ -291,7 +291,7 @@ void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) Bitmap *bm; #define EXEC_BLITS(part) \ - if ((bm = bitmaps[BM_##part])) \ + if (!nullOrDisposed(bm = bitmaps[BM_##part])) \ { \ GLMeta::blitSource(bm->getGLTypes()); \ for (size_t i = 0; i < blits##part##N; ++i) \ diff --git a/src/tilemap.cpp b/src/tilemap.cpp index d0601e2..b92cc34 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -38,7 +38,6 @@ #include "tileatlas.h" #include -#include #include #include @@ -204,6 +203,8 @@ struct GroundLayer : public ViewportElement void drawFlashInt(); void onGeometryChange(const Scene::Geometry &geo); + + ABOUT_TO_ACCESS_NOOP }; struct ZLayer : public ViewportElement @@ -232,6 +233,8 @@ struct ZLayer : public ViewportElement void initUpdateZ(); void finiUpdateZ(ZLayer *prev); + + ABOUT_TO_ACCESS_NOOP }; struct TilemapPrivate @@ -242,7 +245,6 @@ struct TilemapPrivate Bitmap *autotiles[autotileCount]; Bitmap *tileset; - DisposeWatch tilesetWatch; Table *mapData; Table *flashData; @@ -347,7 +349,6 @@ struct TilemapPrivate TilemapPrivate(Viewport *viewport) : viewport(viewport), tileset(0), - tilesetWatch(*this, tileset), mapData(0), flashData(0), priorities(0), @@ -432,7 +433,7 @@ struct TilemapPrivate void updateAtlasInfo() { - if (!tileset) + if (nullOrDisposed(tileset)) { atlas.size = Vec2i(); return; @@ -458,7 +459,7 @@ struct TilemapPrivate for (int i = 0; i < autotileCount; ++i) { - if (!autotiles[i]) + if (nullOrDisposed(autotiles[i])) continue; if (autotiles[i]->megaSurface()) @@ -506,20 +507,10 @@ struct TilemapPrivate flashDirty = true; } - void onAutotileDisposed(int i) - { - /* RMXP actually crashes if an active autotile bitmap is disposed.. - * let's not crash ourselves, for consistency's sake */ - autotiles[i] = 0; - autotilesCon[i].disconnect(); - autotilesDispCon[i].disconnect(); - atlasDirty = true; - } - /* Checks for the minimum amount of data needed to display */ bool verifyResources() { - if (!tileset) + if (nullOrDisposed(tileset)) return false; if (!mapData) @@ -1208,7 +1199,7 @@ void Tilemap::Autotiles::set(int i, Bitmap *bitmap) p->autotilesDispCon[i].disconnect(); p->autotilesDispCon[i] = bitmap->wasDisposed.connect - (sigc::bind(sigc::mem_fun(p, &TilemapPrivate::onAutotileDisposed), i)); + (sigc::mem_fun(p, &TilemapPrivate::invalidateAtlasContents)); p->updateAutotileInfo(); } @@ -1229,11 +1220,13 @@ Tilemap::Tilemap(Viewport *viewport) Tilemap::~Tilemap() { - delete p; + dispose(); } void Tilemap::update() { + guardDisposed(); + if (!p->tilemapReady) return; @@ -1253,6 +1246,8 @@ void Tilemap::update() Tilemap::Autotiles &Tilemap::getAutotiles() const { + guardDisposed(); + return p->autotilesProxy; } @@ -1267,11 +1262,12 @@ DEF_ATTR_RD_SIMPLE(Tilemap, OY, int, p->offset.y) void Tilemap::setTileset(Bitmap *value) { + guardDisposed(); + if (p->tileset == value) return; p->tileset = value; - p->tilesetWatch.update(value); if (!value) return; @@ -1286,6 +1282,8 @@ void Tilemap::setTileset(Bitmap *value) void Tilemap::setMapData(Table *value) { + guardDisposed(); + if (p->mapData == value) return; @@ -1302,6 +1300,8 @@ void Tilemap::setMapData(Table *value) void Tilemap::setFlashData(Table *value) { + guardDisposed(); + if (p->flashData == value) return; @@ -1318,6 +1318,8 @@ void Tilemap::setFlashData(Table *value) void Tilemap::setPriorities(Table *value) { + guardDisposed(); + if (p->priorities == value) return; @@ -1334,6 +1336,8 @@ void Tilemap::setPriorities(Table *value) void Tilemap::setVisible(bool value) { + guardDisposed(); + if (p->visible == value) return; @@ -1349,6 +1353,8 @@ void Tilemap::setVisible(bool value) void Tilemap::setOX(int value) { + guardDisposed(); + if (p->offset.x == value) return; @@ -1359,6 +1365,8 @@ void Tilemap::setOX(int value) void Tilemap::setOY(int value) { + guardDisposed(); + if (p->offset.y == value) return; @@ -1367,3 +1375,8 @@ void Tilemap::setOY(int value) p->zOrderDirty = true; p->mapViewportDirty = true; } + +void Tilemap::releaseResources() +{ + delete p; +} diff --git a/src/tilemap.h b/src/tilemap.h index 89775c1..6e68d92 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -68,6 +68,9 @@ public: private: TilemapPrivate *p; + + void releaseResources(); + const char *klassName() const { return "tilemap"; } }; #endif // TILEMAP_H diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp index f9f09d3..fb5aae5 100644 --- a/src/tilemapvx.cpp +++ b/src/tilemapvx.cpp @@ -36,7 +36,6 @@ #include #include -#include // FIXME: Implement flash @@ -95,6 +94,8 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader { p->drawAbove(); } + + ABOUT_TO_ACCESS_NOOP }; AboveLayer above; @@ -154,15 +155,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader atlasDirty = true; } - void onBitmapDisposed(int i) - { - bitmaps[i] = 0; - bmChangedCons[i].disconnect(); - bmDisposedCons[i].disconnect(); - - atlasDirty = true; - } - void invalidateBuffers() { buffersDirty = true; @@ -290,7 +282,7 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader { ShaderBase *shader; - if (bitmaps[BM_A1] != 0) + if (!nullOrDisposed(bitmaps[BM_A1])) { /* Animated tileset */ TilemapVXShader &tmShader = shState->shaders().tilemapVX; @@ -351,6 +343,8 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader mapViewportDirty = true; } + ABOUT_TO_ACCESS_NOOP + /* TileAtlasVX::Reader */ void onQuads(const FloatRect *t, const FloatRect *p, size_t n, bool overPlayer) @@ -379,7 +373,7 @@ void TilemapVX::BitmapArray::set(int i, Bitmap *bitmap) p->bmDisposedCons[i].disconnect(); p->bmDisposedCons[i] = bitmap->wasDisposed.connect - (sigc::bind(sigc::mem_fun(p, &TilemapVXPrivate::onBitmapDisposed), i)); + (sigc::mem_fun(p, &TilemapVXPrivate::invalidateAtlas)); } Bitmap *TilemapVX::BitmapArray::get(int i) const @@ -398,11 +392,13 @@ TilemapVX::TilemapVX(Viewport *viewport) TilemapVX::~TilemapVX() { - delete p; + dispose(); } void TilemapVX::update() { + guardDisposed(); + if (++p->frameIdx >= 30*3*4) p->frameIdx = 0; @@ -419,6 +415,8 @@ void TilemapVX::update() TilemapVX::BitmapArray &TilemapVX::getBitmapArray() const { + guardDisposed(); + return p->bitmapsProxy; } @@ -430,22 +428,30 @@ DEF_ATTR_RD_SIMPLE(TilemapVX, OY, int, p->offset.y) Viewport *TilemapVX::getViewport() const { + guardDisposed(); + return p->getViewport(); } bool TilemapVX::getVisible() const { + guardDisposed(); + return p->getVisible(); } void TilemapVX::setViewport(Viewport *value) { + guardDisposed(); + p->setViewport(value); p->above.setViewport(value); } void TilemapVX::setMapData(Table *value) { + guardDisposed(); + if (p->mapData == value) return; @@ -459,6 +465,8 @@ void TilemapVX::setMapData(Table *value) void TilemapVX::setFlashData(Table *value) { + guardDisposed(); + if (p->flashData == value) return; @@ -467,6 +475,8 @@ void TilemapVX::setFlashData(Table *value) void TilemapVX::setFlags(Table *value) { + guardDisposed(); + if (p->flags == value) return; @@ -480,12 +490,16 @@ void TilemapVX::setFlags(Table *value) void TilemapVX::setVisible(bool value) { + guardDisposed(); + p->setVisible(value); p->above.setVisible(value); } void TilemapVX::setOX(int value) { + guardDisposed(); + if (p->offset.x == value) return; @@ -495,9 +509,16 @@ void TilemapVX::setOX(int value) void TilemapVX::setOY(int value) { + guardDisposed(); + if (p->offset.y == value) return; p->offset.y = value; p->mapViewportDirty = true; } + +void TilemapVX::releaseResources() +{ + delete p; +} diff --git a/src/tilemapvx.h b/src/tilemapvx.h index 1a0f313..0e2b4be 100644 --- a/src/tilemapvx.h +++ b/src/tilemapvx.h @@ -66,6 +66,9 @@ public: private: TilemapVXPrivate *p; + + void releaseResources(); + const char *klassName() const { return "tilemap"; } }; #endif // TILEMAPVX_H diff --git a/src/util.h b/src/util.h index b8b42f4..8009a26 100644 --- a/src/util.h +++ b/src/util.h @@ -119,6 +119,7 @@ inline bool contains(const C &c, const V &v) #define DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, keyword1) \ type klass :: get##name() keyword1 \ { \ + guardDisposed(); \ return location; \ } @@ -126,6 +127,7 @@ inline bool contains(const C &c, const V &v) DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, keyword1) \ void klass :: set##name(type value) \ { \ + guardDisposed(); \ location = value; \ } @@ -141,6 +143,7 @@ inline bool contains(const C &c, const V &v) DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, const) \ void klass :: set##name(type value) \ { \ + guardDisposed(); \ *location = *value; \ } @@ -148,6 +151,7 @@ inline bool contains(const C &c, const V &v) DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, ) \ void klass :: set##name(type value) \ { \ + guardDisposed(); \ *location = *value; \ } diff --git a/src/viewport.cpp b/src/viewport.cpp index 49c3798..fed9f18 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -134,9 +134,14 @@ void Viewport::initViewport(int x, int y, int width, int height) Viewport::~Viewport() { - unlink(); + dispose(); +} - delete p; +void Viewport::update() +{ + guardDisposed(); + + Flashable::update(); } DEF_ATTR_RD_SIMPLE(Viewport, OX, int, geometry.xOrigin) @@ -148,6 +153,8 @@ DEF_ATTR_OBJ_VALUE(Viewport, Tone, Tone*, p->tone) void Viewport::setOX(int value) { + guardDisposed(); + if (geometry.xOrigin == value) return; @@ -157,6 +164,8 @@ void Viewport::setOX(int value) void Viewport::setOY(int value) { + guardDisposed(); + if (geometry.yOrigin == value) return; @@ -212,6 +221,13 @@ void Viewport::onGeometryChange(const Geometry &geo) p->recomputeOnScreen(); } +void Viewport::releaseResources() +{ + unlink(); + + delete p; +} + ViewportElement::ViewportElement(Viewport *viewport, int z, int spriteY) : SceneElement(viewport ? *viewport : *shState->screen(), z, spriteY), diff --git a/src/viewport.h b/src/viewport.h index 325da41..416d4da 100644 --- a/src/viewport.h +++ b/src/viewport.h @@ -37,6 +37,8 @@ public: Viewport(); ~Viewport(); + void update(); + DECL_ATTR( Rect, Rect* ) DECL_ATTR( OX, int ) DECL_ATTR( OY, int ) @@ -54,6 +56,11 @@ private: void onGeometryChange(const Geometry &); bool isEffectiveViewport(Rect *&, Color *&, Tone *&) const; + void releaseResources(); + const char *klassName() const { return "viewport"; } + + ABOUT_TO_ACCESS_DISP + ViewportPrivate *p; friend struct ViewportPrivate; diff --git a/src/window.cpp b/src/window.cpp index 1d43d95..9ba18c7 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -169,10 +169,8 @@ struct QuadChunk struct WindowPrivate { Bitmap *windowskin; - DisposeWatch windowskinWatch; Bitmap *contents; - DisposeWatch contentsWatch; bool bgStretch; Rect *cursorRect; @@ -226,6 +224,8 @@ struct WindowPrivate { unlink(); } + + ABOUT_TO_ACCESS_NOOP }; WindowControls controlsElement; @@ -250,9 +250,7 @@ struct WindowPrivate WindowPrivate(Viewport *viewport = 0) : windowskin(0), - windowskinWatch(*this, windowskin), contents(0), - contentsWatch(*this, contents, &WindowPrivate::markControlVertDirty), bgStretch(true), cursorRect(&tmp.rect), active(true), @@ -550,7 +548,7 @@ struct WindowPrivate void drawBase() { - if (!windowskin) + if (nullOrDisposed(windowskin)) return; if (size == Vec2i(0, 0)) @@ -584,7 +582,7 @@ struct WindowPrivate void drawControls() { - if (!windowskin && !contents) + if (nullOrDisposed(windowskin) && nullOrDisposed(contents)) return; if (size == Vec2i(0, 0)) @@ -612,7 +610,7 @@ struct WindowPrivate shader.bind(); shader.applyViewportProj(); - if (windowskin) + if (!nullOrDisposed(windowskin)) { shader.setTranslation(Vec2i(effectX, effectY)); @@ -625,7 +623,7 @@ struct WindowPrivate TEX::setSmooth(false); } - if (contents) + if (!nullOrDisposed(contents)) { /* Draw contents bitmap */ glState.scissorBox.setIntersect(contentsRect); @@ -692,15 +690,13 @@ Window::Window(Viewport *viewport) Window::~Window() { - p->controlsElement.release(); - - unlink(); - - delete p; + dispose(); } void Window::update() { + guardDisposed(); + p->updateControls(); p->stepAnimations(); } @@ -725,8 +721,9 @@ DEF_ATTR_OBJ_VALUE(Window, CursorRect, Rect*, p->cursorRect) void Window::setWindowskin(Bitmap *value) { + guardDisposed(); + p->windowskin = value; - p->windowskinWatch.update(value); if (!value) return; @@ -736,11 +733,12 @@ void Window::setWindowskin(Bitmap *value) void Window::setContents(Bitmap *value) { + guardDisposed(); + if (p->contents == value) return; p->contents = value; - p->contentsWatch.update(value); p->controlsVertDirty = true; if (!value) @@ -752,6 +750,8 @@ void Window::setContents(Bitmap *value) void Window::setStretch(bool value) { + guardDisposed(); + if (value == p->bgStretch) return; @@ -761,6 +761,8 @@ void Window::setStretch(bool value) void Window::setActive(bool value) { + guardDisposed(); + if (p->active == value) return; @@ -770,6 +772,8 @@ void Window::setActive(bool value) void Window::setPause(bool value) { + guardDisposed(); + if (p->pause == value) return; @@ -781,6 +785,8 @@ void Window::setPause(bool value) void Window::setWidth(int value) { + guardDisposed(); + if (p->size.x == value) return; @@ -790,6 +796,8 @@ void Window::setWidth(int value) void Window::setHeight(int value) { + guardDisposed(); + if (p->size.y == value) return; @@ -799,6 +807,8 @@ void Window::setHeight(int value) void Window::setOX(int value) { + guardDisposed(); + if (p->contentsOffset.x == value) return; @@ -808,6 +818,8 @@ void Window::setOX(int value) void Window::setOY(int value) { + guardDisposed(); + if (p->contentsOffset.y == value) return; @@ -817,6 +829,8 @@ void Window::setOY(int value) void Window::setOpacity(int value) { + guardDisposed(); + if (p->opacity == value) return; @@ -826,6 +840,8 @@ void Window::setOpacity(int value) void Window::setBackOpacity(int value) { + guardDisposed(); + if (p->backOpacity == value) return; @@ -835,6 +851,8 @@ void Window::setBackOpacity(int value) void Window::setContentsOpacity(int value) { + guardDisposed(); + if (p->contentsOpacity == value) return; @@ -878,3 +896,12 @@ void Window::onViewportChange() { p->controlsElement.setScene(*this->scene); } + +void Window::releaseResources() +{ + p->controlsElement.release(); + + unlink(); + + delete p; +} diff --git a/src/window.h b/src/window.h index a3fb315..f7cfc04 100644 --- a/src/window.h +++ b/src/window.h @@ -67,6 +67,11 @@ private: void setVisible(bool value); void onViewportChange(); + + void releaseResources(); + const char *klassName() const { return "window"; } + + ABOUT_TO_ACCESS_DISP }; #endif // WINDOW_H diff --git a/src/windowvx.cpp b/src/windowvx.cpp index 399e7b0..9b7fd13 100644 --- a/src/windowvx.cpp +++ b/src/windowvx.cpp @@ -148,15 +148,11 @@ static const uint8_t pauseQuad[] = static elementsN(pauseQuad); -typedef DisposeWatch BitmapWatch; - struct WindowVXPrivate { Bitmap *windowskin; - BitmapWatch windowskinWatch; Bitmap *contents; - BitmapWatch contentsWatch; Rect *cursorRect; bool active; @@ -227,9 +223,7 @@ struct WindowVXPrivate WindowVXPrivate(int x, int y, int w, int h) : windowskin(0), - windowskinWatch(*this, windowskin), contents(0), - contentsWatch(*this, contents), cursorRect(&tmp.rect), active(true), arrowsVisible(true), @@ -401,7 +395,7 @@ struct WindowVXPrivate void redrawBaseTex() { - if (!windowskin) + if (nullOrDisposed(windowskin)) return; if (base.tex.tex == TEX::ID(0)) @@ -514,7 +508,7 @@ struct WindowVXPrivate size_t i = 0; Vertex *vert = &ctrlVert.vertices[0]; - if (contents && arrowsVisible) + if (!nullOrDisposed(contents) && arrowsVisible) { if (contentsOff.x > 0) i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.l, arrowPos.l); @@ -721,6 +715,9 @@ struct WindowVXPrivate if (base.tex.tex == TEX::ID(0)) return; + bool windowskinValid = !nullOrDisposed(windowskin); + bool contentsValid = !nullOrDisposed(contents); + Vec2i trans(geo.x + sceneOffset.x, geo.y + sceneOffset.y); @@ -728,7 +725,7 @@ struct WindowVXPrivate shader.bind(); shader.applyViewportProj(); - if (windowskin) + if (windowskinValid) { shader.setTranslation(trans); shader.setTexSize(Vec2i(base.tex.width, base.tex.height)); @@ -749,9 +746,9 @@ struct WindowVXPrivate if (openness < 255) return; - bool drawCursor = cursorVert.count() > 0 && windowskin; + bool drawCursor = cursorVert.count() > 0 && windowskinValid; - if (drawCursor || contents) + if (drawCursor || contentsValid) { /* Translate cliprect from local into screen space */ IntRect clip = clipRect; @@ -789,7 +786,7 @@ struct WindowVXPrivate TEX::setSmooth(false); } - if (contents) + if (contentsValid) { if (rgssVer <= 2) glState.scissorBox.setIntersect(clip); @@ -828,13 +825,13 @@ WindowVX::WindowVX(int x, int y, int width, int height) WindowVX::~WindowVX() { - unlink(); - - delete p; + dispose(); } void WindowVX::update() { + guardDisposed(); + p->stepAnimations(); p->updatePauseQuad(); @@ -843,6 +840,8 @@ void WindowVX::update() void WindowVX::move(int x, int y, int width, int height) { + guardDisposed(); + p->width = width; p->height = height; @@ -857,11 +856,15 @@ void WindowVX::move(int x, int y, int width, int height) bool WindowVX::isOpen() const { + guardDisposed(); + return p->openness == 255; } bool WindowVX::isClosed() const { + guardDisposed(); + return p->openness == 0; } @@ -889,21 +892,23 @@ DEF_ATTR_OBJ_VALUE(WindowVX, Tone, Tone*, p->tone) void WindowVX::setWindowskin(Bitmap *value) { + guardDisposed(); + if (p->windowskin == value) return; p->windowskin = value; - p->windowskinWatch.update(value); p->base.texDirty = true; } void WindowVX::setContents(Bitmap *value) { + guardDisposed(); + if (p->contents == value) return; p->contents = value; - p->contentsWatch.update(value); FloatRect rect = p->contents->rect(); p->contentsQuad.setTexPosRect(rect, rect); @@ -912,6 +917,8 @@ void WindowVX::setContents(Bitmap *value) void WindowVX::setActive(bool value) { + guardDisposed(); + if (p->active == value) return; @@ -922,6 +929,8 @@ void WindowVX::setActive(bool value) void WindowVX::setArrowsVisible(bool value) { + guardDisposed(); + if (p->arrowsVisible == value) return; @@ -931,6 +940,8 @@ void WindowVX::setArrowsVisible(bool value) void WindowVX::setPause(bool value) { + guardDisposed(); + if (p->pause == value) return; @@ -942,6 +953,8 @@ void WindowVX::setPause(bool value) void WindowVX::setWidth(int value) { + guardDisposed(); + if (p->width == value) return; @@ -956,6 +969,8 @@ void WindowVX::setWidth(int value) void WindowVX::setHeight(int value) { + guardDisposed(); + if (p->height == value) return; @@ -970,6 +985,8 @@ void WindowVX::setHeight(int value) void WindowVX::setOX(int value) { + guardDisposed(); + if (p->contentsOff.x == value) return; @@ -979,6 +996,8 @@ void WindowVX::setOX(int value) void WindowVX::setOY(int value) { + guardDisposed(); + if (p->contentsOff.y == value) return; @@ -988,6 +1007,8 @@ void WindowVX::setOY(int value) void WindowVX::setPadding(int value) { + guardDisposed(); + if (p->padding == value) return; @@ -998,6 +1019,8 @@ void WindowVX::setPadding(int value) void WindowVX::setPaddingBottom(int value) { + guardDisposed(); + if (p->paddingBottom == value) return; @@ -1007,6 +1030,8 @@ void WindowVX::setPaddingBottom(int value) void WindowVX::setOpacity(int value) { + guardDisposed(); + if (p->opacity == value) return; @@ -1016,6 +1041,8 @@ void WindowVX::setOpacity(int value) void WindowVX::setBackOpacity(int value) { + guardDisposed(); + if (p->backOpacity == value) return; @@ -1025,6 +1052,8 @@ void WindowVX::setBackOpacity(int value) void WindowVX::setContentsOpacity(int value) { + guardDisposed(); + if (p->contentsOpacity == value) return; @@ -1034,6 +1063,8 @@ void WindowVX::setContentsOpacity(int value) void WindowVX::setOpenness(int value) { + guardDisposed(); + if (p->openness == value) return; @@ -1063,3 +1094,10 @@ void WindowVX::onGeometryChange(const Scene::Geometry &geo) p->sceneOffset.x = geo.rect.x - geo.xOrigin; p->sceneOffset.y = geo.rect.y - geo.yOrigin; } + +void WindowVX::releaseResources() +{ + unlink(); + + delete p; +} diff --git a/src/windowvx.h b/src/windowvx.h index d90840f..d0e1eca 100644 --- a/src/windowvx.h +++ b/src/windowvx.h @@ -73,6 +73,11 @@ private: void draw(); void onGeometryChange(const Scene::Geometry &); + + void releaseResources(); + const char *klassName() const { return "window"; } + + ABOUT_TO_ACCESS_DISP }; #endif // WINDOWVX_H From 2550fd8ccccc96159356e0c4477f12537a6bd81c Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 23 Sep 2014 21:13:16 +0200 Subject: [PATCH 028/239] WindowVX: Initialize all dirty flags and connect tmp tone --- src/windowvx.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/windowvx.cpp b/src/windowvx.cpp index 9b7fd13..cc6d193 100644 --- a/src/windowvx.cpp +++ b/src/windowvx.cpp @@ -238,6 +238,11 @@ struct WindowVXPrivate contentsOpacity(255), openness(255), tone(&tmp.tone), + ctrlVertDirty(false), + ctrlVertArrayDirty(false), + clipRectDirty(false), + cursorVertDirty(false), + cursorVertArrayDirty(false), pauseAlphaIdx(0), pauseQuadIdx(0), cursorAlphaIdx(0) @@ -246,16 +251,23 @@ struct WindowVXPrivate ctrlVert.resize(4 + 1); pauseVert = &ctrlVert.vertices[4*4]; - base.vertDirty = true; - base.texSizeDirty = true; - base.texDirty = true; - ctrlVertDirty = true; - clipRectDirty = true; + base.vertDirty = false; + base.texSizeDirty = false; + base.texDirty = false; + + if (w > 0 || h > 0) + { + base.vertDirty = true; + base.texSizeDirty = true; + clipRectDirty = true; + ctrlVertDirty = true; + } prepareCon = shState->prepareDraw.connect (sigc::mem_fun(this, &WindowVXPrivate::prepare)); refreshCursorRectCon(); + refreshToneCon(); updateBaseQuad(); } From 3a2e560139acb63aacfd9cf7b2276eeb6ce92fd0 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 23 Sep 2014 22:08:13 +0200 Subject: [PATCH 029/239] Input: Fix default keybinds --- src/input.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index d646db0..fd53698 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -205,7 +205,10 @@ static const KbBindingData defaultKbBindings[] = { SDL_SCANCODE_B, Input::None }, { SDL_SCANCODE_D, Input::Z }, { SDL_SCANCODE_Q, Input::L }, - { SDL_SCANCODE_W, Input::R } + { SDL_SCANCODE_W, Input::R }, + { SDL_SCANCODE_V, Input::None }, + { SDL_SCANCODE_A, Input::X }, + { SDL_SCANCODE_S, Input::Y } }; /* RGSS1 */ @@ -213,9 +216,6 @@ static const KbBindingData defaultKbBindings1[] = { { SDL_SCANCODE_Z, Input::A }, { SDL_SCANCODE_C, Input::C }, - { SDL_SCANCODE_V, Input::Z }, - { SDL_SCANCODE_A, Input::Y }, - { SDL_SCANCODE_S, Input::X } }; /* RGSS2 and higher */ @@ -223,9 +223,6 @@ static const KbBindingData defaultKbBindings2[] = { { SDL_SCANCODE_Z, Input::C }, { SDL_SCANCODE_C, Input::None }, - { SDL_SCANCODE_V, Input::None }, - { SDL_SCANCODE_A, Input::X }, - { SDL_SCANCODE_S, Input::Y } }; static elementsN(defaultKbBindings); From d223d83cbf8240677049c8334ffb347b948f7a2b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sun, 24 Aug 2014 07:36:19 +0200 Subject: [PATCH 030/239] Implement F12 game reset (MRI only) Can be disabled with "enableReset=false". While at it, also replace the flakey volatile bool flags with proper atomics. --- README.md | 2 - binding-mri/audio-binding.cpp | 11 ++++ binding-mri/binding-mri.cpp | 100 ++++++++++++++++++++++++------- binding-mri/binding-util.cpp | 2 + binding-mri/binding-util.h | 1 + binding-mri/graphics-binding.cpp | 11 ++++ binding-mruby/binding-mruby.cpp | 11 +++- binding-null/binding-null.cpp | 10 +++- mkxp.conf.sample | 6 ++ src/audio.cpp | 8 +++ src/audio.h | 2 + src/binding.h | 4 ++ src/config.cpp | 2 + src/config.h | 1 + src/disposable.h | 15 ++++- src/eventthread.cpp | 32 +++++++++- src/eventthread.h | 54 +++++++++++++---- src/graphics.cpp | 89 ++++++++++++++++++++++++--- src/graphics.h | 14 ++++- src/intrulist.h | 9 +++ src/main.cpp | 6 +- src/sharedstate.cpp | 11 +++- src/sharedstate.h | 2 + 23 files changed, 343 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index beea7dd..a29f067 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ Missing RGSS3 functionality: * Text outline * Movie playback -* F12 reset * Audio fade-in Some other things might be implemented, but simply not bound yet. @@ -116,7 +115,6 @@ If a requested font is not found, no error is generated. Instead, a built-in fon * wma audio files * The Win32API ruby class (for obvious reasons) -* Restarting the game with F12 * Creating Bitmaps with sizes greater than the OpenGL texture size limit (around 8192 on modern cards)* \* There is an exception to this, called *mega surface*. When a Bitmap bigger than the texture limit is created from a file, it is not stored in VRAM, but regular RAM. Its sole purpose is to be used as a tileset bitmap. Any other operation to it (besides blitting to a regular Bitmap) will result in an error. diff --git a/binding-mri/audio-binding.cpp b/binding-mri/audio-binding.cpp index 4c8952e..262f5c7 100644 --- a/binding-mri/audio-binding.cpp +++ b/binding-mri/audio-binding.cpp @@ -97,6 +97,15 @@ DEF_FADE( me ) DEF_PLAY_STOP( se ) +RB_METHOD(audioReset) +{ + RB_UNUSED_PARAM; + + shState->audio().reset(); + + return Qnil; +} + #define BIND_PLAY_STOP(entity) \ _rb_define_module_function(module, #entity "_play", audio_##entity##Play); \ @@ -129,4 +138,6 @@ audioBindingInit() } BIND_PLAY_STOP( se ) + + _rb_define_module_function(module, "__reset__", audioReset); } diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 7178d75..b8d4445 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -27,6 +27,7 @@ #include "util.h" #include "debugwriter.h" #include "graphics.h" +#include "audio.h" #include "boost-hash.h" #include @@ -44,11 +45,13 @@ extern const char module_rpg3[]; static void mriBindingExecute(); static void mriBindingTerminate(); +static void mriBindingReset(); ScriptBinding scriptBindingImpl = { mriBindingExecute, - mriBindingTerminate + mriBindingTerminate, + mriBindingReset }; ScriptBinding *scriptBinding = &scriptBindingImpl; @@ -213,12 +216,51 @@ RB_METHOD(mriDataDirectory) return pathStr; } +static VALUE rgssMainCb(VALUE block) +{ + rb_funcall2(block, rb_intern("call"), 0, 0); + return Qnil; +} + +static VALUE rgssMainRescue(VALUE arg, VALUE exc) +{ + VALUE *excRet = (VALUE*) arg; + + *excRet = exc; + + return Qnil; +} + +static void processReset() +{ + shState->graphics().reset(); + shState->audio().reset(); + + shState->rtData().rqReset.clear(); + shState->graphics().repaintWait(shState->rtData().rqResetFinish, + false); +} + RB_METHOD(mriRgssMain) { RB_UNUSED_PARAM; - // TODO: Implement F12 reset - rb_yield(Qnil); + while (true) + { + VALUE exc = Qnil; + + rb_rescue2((VALUE(*)(ANYARGS)) rgssMainCb, rb_block_proc(), + (VALUE(*)(ANYARGS)) rgssMainRescue, (VALUE) &exc, + rb_eException, (VALUE) 0); + + if (NIL_P(exc)) + break; + + if (rb_obj_class(exc) == getRbData()->exc[Reset]) + processReset(); + else + rb_exc_raise(exc); + } return Qnil; } @@ -395,30 +437,39 @@ static void runRMXPScripts(BacktraceData &btData) for (size_t i = 0; i < conf.preloadScripts.size(); ++i) runCustomScript(conf.preloadScripts[i]); - for (long i = 0; i < scriptCount; ++i) + while (true) { - VALUE script = rb_ary_entry(scriptArray, i); - VALUE scriptDecoded = rb_ary_entry(script, 3); - VALUE string = newStringUTF8(RSTRING_PTR(scriptDecoded), - RSTRING_LEN(scriptDecoded)); + for (long i = 0; i < scriptCount; ++i) + { + VALUE script = rb_ary_entry(scriptArray, i); + VALUE scriptDecoded = rb_ary_entry(script, 3); + VALUE string = newStringUTF8(RSTRING_PTR(scriptDecoded), + RSTRING_LEN(scriptDecoded)); - VALUE fname; - const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1)); - char buf[512]; - int len; + VALUE fname; + const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1)); + char buf[512]; + int len; - if (conf.useScriptNames) - len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName); - else - len = snprintf(buf, sizeof(buf), SCRIPT_SECTION_FMT, i); + if (conf.useScriptNames) + len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName); + else + len = snprintf(buf, sizeof(buf), SCRIPT_SECTION_FMT, i); - fname = newStringUTF8(buf, len); - btData.scriptNames.insert(buf, scriptName); + fname = newStringUTF8(buf, len); + btData.scriptNames.insert(buf, scriptName); - int state; - evalString(string, fname, &state); - if (state) + int state; + evalString(string, fname, &state); + if (state) + break; + } + + VALUE exc = rb_gv_get("$!"); + if (rb_obj_class(exc) != getRbData()->exc[Reset]) break; + + processReset(); } } @@ -520,10 +571,15 @@ static void mriBindingExecute() ruby_cleanup(0); - shState->rtData().rqTermAck = true; + shState->rtData().rqTermAck.set(); } static void mriBindingTerminate() { rb_raise(rb_eSystemExit, " "); } + +static void mriBindingReset() +{ + rb_raise(getRbData()->exc[Reset], " "); +} diff --git a/binding-mri/binding-util.cpp b/binding-mri/binding-util.cpp index 5843ad3..33438b1 100644 --- a/binding-mri/binding-util.cpp +++ b/binding-mri/binding-util.cpp @@ -51,6 +51,8 @@ RbData::RbData() for (size_t i = 0; i < ARRAY_SIZE(customExc); ++i) exc[customExc[i].id] = rb_define_class(customExc[i].name, rb_eException); + exc[Reset] = rb_define_class(rgssVer >= 3 ? "RGSSReset" : "Reset", rb_eException); + exc[ErrnoENOENT] = rb_const_get(rb_const_get(rb_cObject, rb_intern("Errno")), rb_intern("ENOENT")); exc[IOError] = rb_eIOError; exc[TypeError] = rb_eTypeError; diff --git a/binding-mri/binding-util.h b/binding-mri/binding-util.h index b84a50b..6deac5d 100644 --- a/binding-mri/binding-util.h +++ b/binding-mri/binding-util.h @@ -29,6 +29,7 @@ enum RbException { RGSS = 0, + Reset, PHYSFS, SDL, MKXP, diff --git a/binding-mri/graphics-binding.cpp b/binding-mri/graphics-binding.cpp index 20bf593..c28be77 100644 --- a/binding-mri/graphics-binding.cpp +++ b/binding-mri/graphics-binding.cpp @@ -174,6 +174,15 @@ RB_METHOD(graphicsResizeScreen) return Qnil; } +RB_METHOD(graphicsReset) +{ + RB_UNUSED_PARAM; + + shState->graphics().reset(); + + return Qnil; +} + DEF_GRA_PROP_I(FrameRate) DEF_GRA_PROP_I(FrameCount) DEF_GRA_PROP_I(Brightness) @@ -196,6 +205,8 @@ void graphicsBindingInit() _rb_define_module_function(module, "transition", graphicsTransition); _rb_define_module_function(module, "frame_reset", graphicsFrameReset); + _rb_define_module_function(module, "__reset__", graphicsReset); + INIT_GRA_PROP_BIND( FrameRate, "frame_rate" ); INIT_GRA_PROP_BIND( FrameCount, "frame_count" ); diff --git a/binding-mruby/binding-mruby.cpp b/binding-mruby/binding-mruby.cpp index ad092db..dc1eb40 100644 --- a/binding-mruby/binding-mruby.cpp +++ b/binding-mruby/binding-mruby.cpp @@ -51,11 +51,13 @@ static void mrbBindingExecute(); static void mrbBindingTerminate(); +static void mrbBindingReset(); ScriptBinding scriptBindingImpl = { mrbBindingExecute, - mrbBindingTerminate + mrbBindingTerminate, + mrbBindingReset }; ScriptBinding *scriptBinding = &scriptBindingImpl; @@ -384,7 +386,7 @@ static void mrbBindingExecute() checkException(mrb); - shState->rtData().rqTermAck = true; + shState->rtData().rqTermAck.set(); shState->texPool().disable(); mrbc_context_free(mrb, ctx); @@ -398,3 +400,8 @@ static void mrbBindingTerminate() mrb_raise(mrb, data->exc[Shutdown], ""); } + +static void mrbBindingReset() +{ + // No idea how to do this with mruby yet +} diff --git a/binding-null/binding-null.cpp b/binding-null/binding-null.cpp index 62f4edb..a4799e3 100644 --- a/binding-null/binding-null.cpp +++ b/binding-null/binding-null.cpp @@ -27,7 +27,7 @@ static void nullBindingExecute() { Debug() << "The null binding doesn't do anything, so we're done!"; - shState->rtData().rqTermAck = true; + shState->rtData().rqTermAck.set(); } static void nullBindingTerminate() @@ -35,10 +35,16 @@ static void nullBindingTerminate() } +static void nullBindingReset() +{ + +} + ScriptBinding scriptBindingImpl = { nullBindingExecute, - nullBindingTerminate + nullBindingTerminate, + nullBindingReset }; ScriptBinding *scriptBinding = &scriptBindingImpl; diff --git a/mkxp.conf.sample b/mkxp.conf.sample index 78c0ffc..2f119f4 100644 --- a/mkxp.conf.sample +++ b/mkxp.conf.sample @@ -99,6 +99,12 @@ # anyAltToggleFS=false +# Enable F12 game reset +# (default: enabled) +# +# enableReset=true + + # Allow symlinks for game assets to be followed # (default: disabled) # diff --git a/src/audio.cpp b/src/audio.cpp index b99ab04..dcc0b90 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -327,4 +327,12 @@ float Audio::bgsPos() return p->bgs.playingOffset(); } +void Audio::reset() +{ + p->bgm.stop(); + p->bgs.stop(); + p->me.stop(); + p->se.stop(); +} + Audio::~Audio() { delete p; } diff --git a/src/audio.h b/src/audio.h index b600f54..ea2a357 100644 --- a/src/audio.h +++ b/src/audio.h @@ -67,6 +67,8 @@ public: float bgmPos(); float bgsPos(); + void reset(); + private: Audio(const Config &conf); ~Audio(); diff --git a/src/binding.h b/src/binding.h index 7b839e0..4f20b35 100644 --- a/src/binding.h +++ b/src/binding.h @@ -35,6 +35,10 @@ struct ScriptBinding * function will perform a longjmp instead of returning, * so be careful about any variables with local storage */ void (*terminate) (void); + + /* Instructs the binding to issue a game reset. + * Same conditions as for terminate apply */ + void (*reset) (void); }; /* VTable defined in the binding source */ diff --git a/src/config.cpp b/src/config.cpp index 8abc66b..62d0676 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -138,6 +138,7 @@ Config::Config() solidFonts(false), gameFolder("."), anyAltToggleFS(false), + enableReset(true), allowSymlinks(false), pathCache(true), useScriptNames(false) @@ -164,6 +165,7 @@ void Config::read(int argc, char *argv[]) PO_DESC(solidFonts, bool) \ PO_DESC(gameFolder, std::string) \ PO_DESC(anyAltToggleFS, bool) \ + PO_DESC(enableReset, bool) \ PO_DESC(allowSymlinks, bool) \ PO_DESC(iconPath, std::string) \ PO_DESC(titleLanguage, std::string) \ diff --git a/src/config.h b/src/config.h index e47cc32..78d75f7 100644 --- a/src/config.h +++ b/src/config.h @@ -47,6 +47,7 @@ struct Config std::string gameFolder; bool anyAltToggleFS; + bool enableReset; bool allowSymlinks; bool pathCache; diff --git a/src/disposable.h b/src/disposable.h index 412b058..afa39be 100644 --- a/src/disposable.h +++ b/src/disposable.h @@ -22,7 +22,10 @@ #ifndef DISPOSABLE_H #define DISPOSABLE_H +#include "intrulist.h" #include "exception.h" +#include "sharedstate.h" +#include "graphics.h" #include #include @@ -32,12 +35,15 @@ class Disposable { public: Disposable() - : disposed(false) - {} + : disposed(false), + link(this) + { + shState->graphics().addDisposable(this); + } virtual ~Disposable() { - assert(disposed); + shState->graphics().remDisposable(this); } void dispose() @@ -69,7 +75,10 @@ private: virtual void releaseResources() = 0; virtual const char *klassName() const = 0; + friend class Graphics; + bool disposed; + IntruListLink link; }; template diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 7348c32..fec1e5b 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -106,6 +106,8 @@ void EventThread::process(RGSSThreadData &rtData) char pendingTitle[128]; bool havePendingTitle = false; + bool resetting = false; + while (true) { if (!SDL_WaitEvent(&event)) @@ -206,10 +208,34 @@ void EventThread::process(RGSSThreadData &rtData) break; } + if (event.key.keysym.scancode == SDL_SCANCODE_F12) + { + if (!rtData.config.enableReset) + break; + + if (resetting) + break; + + resetting = true; + rtData.rqResetFinish.clear(); + rtData.rqReset.set(); + break; + } + keyStates[event.key.keysym.scancode] = true; break; case SDL_KEYUP : + if (event.key.keysym.scancode == SDL_SCANCODE_F12) + { + if (!rtData.config.enableReset) + break; + + resetting = false; + rtData.rqResetFinish.set(); + break; + } + keyStates[event.key.keysym.scancode] = false; break; @@ -271,7 +297,7 @@ void EventThread::process(RGSSThreadData &rtData) rtData.config.game.title.c_str(), (const char*) event.user.data1, win); free(event.user.data1); - msgBoxDone = true; + msgBoxDone.set(); break; case REQUEST_SETCURSORVISIBLE : @@ -377,7 +403,7 @@ void EventThread::requestShowCursor(bool mode) void EventThread::showMessageBox(const char *body, int flags) { - msgBoxDone = false; + msgBoxDone.clear(); SDL_Event event; event.user.code = flags; @@ -386,7 +412,7 @@ void EventThread::showMessageBox(const char *body, int flags) SDL_PushEvent(&event); /* Keep repainting screen while box is open */ - shState->graphics().repaintWait(&msgBoxDone); + shState->graphics().repaintWait(msgBoxDone); /* Prevent endless loops */ resetInputStates(); } diff --git a/src/eventthread.h b/src/eventthread.h index 79ac199..23402c5 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -38,6 +39,32 @@ struct RGSSThreadData; struct SDL_Thread; struct SDL_Window; +struct AtomicFlag +{ + AtomicFlag() + { + clear(); + } + + void set() + { + SDL_AtomicSet(&atom, 1); + } + + void clear() + { + SDL_AtomicSet(&atom, 0); + } + + operator bool() const + { + return SDL_AtomicGet(&atom); + } + +private: + mutable SDL_atomic_t atom; +}; + class EventThread { public: @@ -91,7 +118,7 @@ private: bool fullscreen; bool showCursor; - volatile bool msgBoxDone; + AtomicFlag msgBoxDone; struct { @@ -111,13 +138,12 @@ struct WindowSizeNotify { SDL_mutex *mutex; - volatile bool changedFlag; - volatile int w, h; + AtomicFlag changed; + int w, h; WindowSizeNotify() { mutex = SDL_CreateMutex(); - changedFlag = false; w = h = 0; } @@ -133,7 +159,7 @@ struct WindowSizeNotify this->w = w; this->h = h; - changedFlag = true; + changed.set(); SDL_UnlockMutex(mutex); } @@ -141,14 +167,14 @@ struct WindowSizeNotify /* Done from the receiving side */ bool pollChange(int *w, int *h) { - if (!changedFlag) + if (!changed) return false; SDL_LockMutex(mutex); *w = this->w; *h = this->h; - changedFlag = false; + changed.clear(); SDL_UnlockMutex(mutex); @@ -159,10 +185,16 @@ struct WindowSizeNotify struct RGSSThreadData { /* Main thread sets this to request RGSS thread to terminate */ - volatile bool rqTerm; + AtomicFlag rqTerm; /* In response, RGSS thread sets this to confirm * that it received the request and isn't stuck */ - volatile bool rqTermAck; + AtomicFlag rqTermAck; + + /* Set when F12 is pressed */ + AtomicFlag rqReset; + + /* Set when F12 is released */ + AtomicFlag rqResetFinish; EventThread *ethread; WindowSizeNotify windowSizeMsg; @@ -182,9 +214,7 @@ struct RGSSThreadData const char *argv0, SDL_Window *window, const Config& newconf) - : rqTerm(false), - rqTermAck(false), - ethread(ethread), + : ethread(ethread), argv0(argv0), window(window), sizeResoRatio(1, 1), diff --git a/src/graphics.cpp b/src/graphics.cpp index ebcc456..ecf850f 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -33,6 +33,8 @@ #include "texpool.h" #include "bitmap.h" #include "etc-internal.h" +#include "disposable.h" +#include "intrulist.h" #include "binding.h" #include "debugwriter.h" @@ -109,6 +111,19 @@ struct PingPong bind(); } + void clearBuffers() + { + glState.clearColor.pushSet(Vec4(0, 0, 0, 1)); + + for (int i = 0; i < 2; ++i) + { + FBO::bind(rt[i].fbo); + FBO::clear(); + } + + glState.clearColor.pop(); + } + private: void bind() { @@ -388,6 +403,10 @@ struct GraphicsPrivate Quad screenQuad; TEXFBO transBuffer; + /* Global list of all live Disposables + * (disposed on reset) */ + IntruList dispList; + GraphicsPrivate(RGSSThreadData *rtData) : scRes(DEF_SCREEN_W, DEF_SCREEN_H), scSize(scRes), @@ -472,9 +491,15 @@ struct GraphicsPrivate } } + void checkShutDownReset() + { + shState->checkShutdown(); + shState->checkReset(); + } + void shutdown() { - threadData->rqTermAck = true; + threadData->rqTermAck.set(); shState->texPool().disable(); scriptBinding->terminate(); @@ -540,7 +565,7 @@ Graphics::~Graphics() void Graphics::update() { - shState->checkShutdown(); + p->checkShutDownReset(); if (p->frozen) return; @@ -571,7 +596,7 @@ void Graphics::freeze() { p->frozen = true; - shState->checkShutdown(); + p->checkShutDownReset(); p->checkResize(); /* Capture scene into frozen buffer */ @@ -623,10 +648,23 @@ void Graphics::transition(int duration, for (int i = 0; i < duration; ++i) { + /* We need to clean up transMap properly before + * a possible longjmp, so we manually test for + * shutdown/reset here */ if (p->threadData->rqTerm) { + glState.blend.pop(); delete transMap; p->shutdown(); + return; + } + + if (p->threadData->rqReset) + { + glState.blend.pop(); + delete transMap; + scriptBinding->reset(); + return; } const float prog = i * (1.0 / duration); @@ -694,8 +732,7 @@ void Graphics::wait(int duration) { for (int i = 0; i < duration; ++i) { - shState->checkShutdown(); - p->checkResize(); + p->checkShutDownReset(); p->redrawScreen(); } } @@ -823,6 +860,29 @@ void Graphics::setBrightness(int value) p->screen.setBrightness(value / 255.0); } +void Graphics::reset() +{ + /* Dispose all live Disposables */ + IntruListLink *iter; + + for (iter = p->dispList.begin(); + iter != p->dispList.end(); + iter = iter->next) + { + iter->data->dispose(); + } + + p->dispList.clear(); + + /* Reset attributes (frame count not included) */ + p->fpsLimiter.resetFrameAdjust(); + p->frozen = false; + p->screen.getPP().clearBuffers(); + + setFrameRate(DEF_FRAMERATE); + setBrightness(255); +} + bool Graphics::getFullscreen() const { return p->threadData->ethread->getFullscreen(); @@ -848,9 +908,9 @@ Scene *Graphics::getScreen() const return &p->screen; } -void Graphics::repaintWait(volatile bool *exitCond) +void Graphics::repaintWait(const AtomicFlag &exitCond, bool checkReset) { - if (*exitCond) + if (exitCond) return; /* Repaint the screen with the last good frame we drew */ @@ -858,10 +918,13 @@ void Graphics::repaintWait(volatile bool *exitCond) GLMeta::blitBeginScreen(p->winSize); GLMeta::blitSource(lastFrame); - while (!*exitCond) + while (!exitCond) { shState->checkShutdown(); + if (checkReset) + shState->checkReset(); + FBO::clear(); p->metaBlitBufferFlippedScaled(); SDL_GL_SwapWindow(p->threadData->window); @@ -872,3 +935,13 @@ void Graphics::repaintWait(volatile bool *exitCond) GLMeta::blitEnd(); } + +void Graphics::addDisposable(Disposable *d) +{ + p->dispList.append(d->link); +} + +void Graphics::remDisposable(Disposable *d) +{ + p->dispList.remove(d->link); +} diff --git a/src/graphics.h b/src/graphics.h index b1ce016..05436bc 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -26,8 +26,10 @@ class Scene; class Bitmap; +class Disposable; struct RGSSThreadData; struct GraphicsPrivate; +struct AtomicFlag; class Graphics { @@ -53,6 +55,8 @@ public: int height() const; void resizeScreen(int width, int height); + void reset(); + /* Non-standard extension */ DECL_ATTR( Fullscreen, bool ) DECL_ATTR( ShowCursor, bool ) @@ -60,14 +64,20 @@ public: /* */ Scene *getScreen() const; /* Repaint screen with static image until exitCond - * turns true. Used in EThread::showMessageBox() */ - void repaintWait(volatile bool *exitCond); + * is set. Observes reset flag on top of shutdown + * if "checkReset" */ + void repaintWait(const AtomicFlag &exitCond, + bool checkReset = true); private: Graphics(RGSSThreadData *data); ~Graphics(); + void addDisposable(Disposable *); + void remDisposable(Disposable *); + friend struct SharedStatePrivate; + friend class Disposable; GraphicsPrivate *p; }; diff --git a/src/intrulist.h b/src/intrulist.h index fa691f6..040fb9b 100644 --- a/src/intrulist.h +++ b/src/intrulist.h @@ -105,6 +105,15 @@ public: size--; } + void clear() + { + remove(root); + root.prev = &root; + root.next = &root; + + size = 0; + } + T *tail() const { IntruListLink *node = root.prev; diff --git a/src/main.cpp b/src/main.cpp index b1403df..ae3def8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,7 @@ rgssThreadError(RGSSThreadData *rtData, const std::string &msg) { rtData->rgssErrorMsg = msg; rtData->ethread->requestTerminate(); - rtData->rqTermAck = true; + rtData->rqTermAck.set(); } static inline const char* @@ -147,7 +147,7 @@ int rgssThreadFun(void *userdata) /* Start script execution */ scriptBinding->execute(); - threadData->rqTermAck = true; + threadData->rqTermAck.set(); threadData->ethread->requestTerminate(); SharedState::finiInstance(); @@ -276,7 +276,7 @@ int main(int argc, char *argv[]) eventThread.process(rtData); /* Request RGSS thread to stop */ - rtData.rqTerm = true; + rtData.rqTerm.set(); /* Wait for RGSS thread response */ for (int i = 0; i < 1000; ++i) diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index 27a632d..f28f30d 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -330,11 +330,20 @@ void SharedState::checkShutdown() if (!p->rtData.rqTerm) return; - p->rtData.rqTermAck = true; + p->rtData.rqTermAck.set(); p->texPool.disable(); scriptBinding->terminate(); } +void SharedState::checkReset() +{ + if (!p->rtData.rqReset) + return; + + p->rtData.rqReset.clear(); + scriptBinding->reset(); +} + Font &SharedState::defaultFont() const { return *p->defaultFont; diff --git a/src/sharedstate.h b/src/sharedstate.h index c713b26..d2d6f29 100644 --- a/src/sharedstate.h +++ b/src/sharedstate.h @@ -109,6 +109,8 @@ struct SharedState * function will most likely not return */ void checkShutdown(); + void checkReset(); + static SharedState *instance; static int rgssVersion; From e9d0d0566b0201c9d6c5f961f3acf87151d2fb55 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 26 Sep 2014 18:20:27 +0200 Subject: [PATCH 031/239] RGSSError is a subclass of StandardError --- binding-mri/binding-util.cpp | 2 +- binding-mruby/binding-util.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/binding-mri/binding-util.cpp b/binding-mri/binding-util.cpp index 33438b1..a663a18 100644 --- a/binding-mri/binding-util.cpp +++ b/binding-mri/binding-util.cpp @@ -41,7 +41,6 @@ struct } static customExc[] = { { MKXP, "MKXPError" }, - { RGSS, "RGSSError" }, { PHYSFS, "PHYSFSError" }, { SDL, "SDLError" } }; @@ -51,6 +50,7 @@ RbData::RbData() for (size_t i = 0; i < ARRAY_SIZE(customExc); ++i) exc[customExc[i].id] = rb_define_class(customExc[i].name, rb_eException); + exc[RGSS] = rb_define_class("RGSSError", rb_eStandardError); exc[Reset] = rb_define_class(rgssVer >= 3 ? "RGSSReset" : "Reset", rb_eException); exc[ErrnoENOENT] = rb_const_get(rb_const_get(rb_cObject, rb_intern("Errno")), rb_intern("ENOENT")); diff --git a/binding-mruby/binding-util.cpp b/binding-mruby/binding-util.cpp index 0cee594..8973b75 100644 --- a/binding-mruby/binding-util.cpp +++ b/binding-mruby/binding-util.cpp @@ -68,7 +68,6 @@ struct MrbExcData static const MrbExcData excData[] = { { Shutdown, "SystemExit" }, - { RGSS, "RGSSError" }, { PHYSFS, "PHYSFSError" }, { SDL, "SDLError" }, { MKXP, "MKXPError" }, @@ -108,6 +107,8 @@ MrbData::MrbData(mrb_state *mrb) for (size_t i = 0; i < excDataN; ++i) exc[excData[i].ind] = mrb_define_class(mrb, excData[i].str, mrb->eException_class); + exc[RGSS] = mrb_define_class(mrb, "RGSSError", mrb->eStandardError_class); + RClass *errnoMod = mrb_define_module(mrb, "Errno"); for (size_t i = 0; i < enoExcDataN; ++i) From 9758e660c4422dc8ca52c09b56a733d9652e6a82 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 26 Sep 2014 18:21:50 +0200 Subject: [PATCH 032/239] Tilemap/VX: Ensure proxy objects don't outlive their parents Either of these would previously crash (same for VX): tm = Tilemap.new at = tm.autotiles tm = nil GC.start at[0] = Bitmap.new(1, 1) tm = Tilemap.new at = tm.autotiles tm.dispose at[0] = Bitmap.new(1, 1) Funnily, this makes RMXP itself crash too, but crashing is never acceptable except for possibly resource exhaustion. --- binding-mri/tilemap-binding.cpp | 4 ++++ binding-mri/tilemapvx-binding.cpp | 4 ++++ binding-mruby/binding-util.cpp | 1 + binding-mruby/binding-util.h | 1 + binding-mruby/tilemap-binding.cpp | 9 +++++++-- src/tilemap.cpp | 14 ++++++++++---- src/tilemap.h | 3 ++- src/tilemapvx.cpp | 14 ++++++++++---- src/tilemapvx.h | 3 ++- 9 files changed, 41 insertions(+), 12 deletions(-) diff --git a/binding-mri/tilemap-binding.cpp b/binding-mri/tilemap-binding.cpp index bdb429f..2217012 100644 --- a/binding-mri/tilemap-binding.cpp +++ b/binding-mri/tilemap-binding.cpp @@ -94,6 +94,10 @@ RB_METHOD(tilemapInitialize) rb_iv_set(autotilesObj, "array", ary); + /* Circular reference so both objects are always + * alive at the same time */ + rb_iv_set(autotilesObj, "tilemap", self); + return self; } diff --git a/binding-mri/tilemapvx-binding.cpp b/binding-mri/tilemapvx-binding.cpp index 58a586d..c451e52 100644 --- a/binding-mri/tilemapvx-binding.cpp +++ b/binding-mri/tilemapvx-binding.cpp @@ -64,6 +64,10 @@ RB_METHOD(tilemapVXInitialize) rb_iv_set(autotilesObj, "array", ary); + /* Circular reference so both objects are always + * alive at the same time */ + rb_iv_set(autotilesObj, "tilemap", self); + return self; } diff --git a/binding-mruby/binding-util.cpp b/binding-mruby/binding-util.cpp index 8973b75..49c2563 100644 --- a/binding-mruby/binding-util.cpp +++ b/binding-mruby/binding-util.cpp @@ -41,6 +41,7 @@ struct SYMD(tone), SYMD(rect), SYMD(src_rect), + SYMD(tilemap), SYMD(tileset), SYMD(autotiles), SYMD(map_data), diff --git a/binding-mruby/binding-util.h b/binding-mruby/binding-util.h index 28e1211..5883e43 100644 --- a/binding-mruby/binding-util.h +++ b/binding-mruby/binding-util.h @@ -42,6 +42,7 @@ enum CommonSymbol CStone, CSrect, CSsrc_rect, + CStilemap, CStileset, CSautotiles, CSmap_data, diff --git a/binding-mruby/tilemap-binding.cpp b/binding-mruby/tilemap-binding.cpp index 1d4efcf..e121ba8 100644 --- a/binding-mruby/tilemap-binding.cpp +++ b/binding-mruby/tilemap-binding.cpp @@ -93,13 +93,18 @@ MRB_METHOD(tilemapInitialize) wrapProperty(mrb, self, &t->getAutotiles(), CSautotiles, TilemapAutotilesType); - mrb_value autotilesObj = mrb_iv_get(mrb, self, getMrbData(mrb)->symbols[CSautotiles]); + MrbData &mrbData = *getMrbData(mrb); + mrb_value autotilesObj = mrb_iv_get(mrb, self, mrbData.symbols[CSautotiles]); mrb_value ary = mrb_ary_new_capa(mrb, 7); for (int i = 0; i < 7; ++i) mrb_ary_push(mrb, ary, mrb_nil_value()); - mrb_iv_set(mrb, autotilesObj, getMrbData(mrb)->symbols[CSarray], ary); + mrb_iv_set(mrb, autotilesObj, mrbData.symbols[CSarray], ary); + + /* Circular reference so both objects are always + * alive at the same time */ + mrb_iv_set(mrb, autotilesObj, mrbData.symbols[CStilemap], self); return self; } diff --git a/src/tilemap.cpp b/src/tilemap.cpp index b92cc34..9878275 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -241,7 +241,6 @@ struct TilemapPrivate { Viewport *viewport; - Tilemap::Autotiles autotilesProxy; Bitmap *autotiles[autotileCount]; Bitmap *tileset; @@ -1183,6 +1182,9 @@ void ZLayer::finiUpdateZ(ZLayer *prev) void Tilemap::Autotiles::set(int i, Bitmap *bitmap) { + if (!p) + return; + if (i < 0 || i > autotileCount-1) return; @@ -1206,6 +1208,9 @@ void Tilemap::Autotiles::set(int i, Bitmap *bitmap) Bitmap *Tilemap::Autotiles::get(int i) const { + if (!p) + return 0; + if (i < 0 || i > autotileCount-1) return 0; @@ -1215,7 +1220,7 @@ Bitmap *Tilemap::Autotiles::get(int i) const Tilemap::Tilemap(Viewport *viewport) { p = new TilemapPrivate(viewport); - p->autotilesProxy.p = p; + atProxy.p = p; } Tilemap::~Tilemap() @@ -1244,11 +1249,11 @@ void Tilemap::update() p->tiles.aniIdx = 0; } -Tilemap::Autotiles &Tilemap::getAutotiles() const +Tilemap::Autotiles &Tilemap::getAutotiles() { guardDisposed(); - return p->autotilesProxy; + return atProxy; } DEF_ATTR_RD_SIMPLE(Tilemap, Viewport, Viewport*, p->viewport) @@ -1379,4 +1384,5 @@ void Tilemap::setOY(int value) void Tilemap::releaseResources() { delete p; + atProxy.p = 0; } diff --git a/src/tilemap.h b/src/tilemap.h index 6e68d92..9afe00f 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -55,7 +55,7 @@ public: void update(); - Autotiles &getAutotiles() const; + Autotiles &getAutotiles(); Viewport *getViewport() const; DECL_ATTR( Tileset, Bitmap* ) @@ -68,6 +68,7 @@ public: private: TilemapPrivate *p; + Autotiles atProxy; void releaseResources(); const char *klassName() const { return "tilemap"; } diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp index fb5aae5..bbd925d 100644 --- a/src/tilemapvx.cpp +++ b/src/tilemapvx.cpp @@ -41,7 +41,6 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader { - TilemapVX::BitmapArray bitmapsProxy; Bitmap *bitmaps[BM_COUNT]; Table *mapData; @@ -358,6 +357,9 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader void TilemapVX::BitmapArray::set(int i, Bitmap *bitmap) { + if (!p) + return; + if (i < 0 || i >= BM_COUNT) return; @@ -378,6 +380,9 @@ void TilemapVX::BitmapArray::set(int i, Bitmap *bitmap) Bitmap *TilemapVX::BitmapArray::get(int i) const { + if (!p) + return 0; + if (i < 0 || i >= BM_COUNT) return 0; @@ -387,7 +392,7 @@ Bitmap *TilemapVX::BitmapArray::get(int i) const TilemapVX::TilemapVX(Viewport *viewport) { p = new TilemapVXPrivate(viewport); - p->bitmapsProxy.p = p; + bmProxy.p = p; } TilemapVX::~TilemapVX() @@ -413,11 +418,11 @@ void TilemapVX::update() p->aniOffset = Vec2(aniIdxA * 2 * 32, aniIdxC * 32); } -TilemapVX::BitmapArray &TilemapVX::getBitmapArray() const +TilemapVX::BitmapArray &TilemapVX::getBitmapArray() { guardDisposed(); - return p->bitmapsProxy; + return bmProxy; } DEF_ATTR_RD_SIMPLE(TilemapVX, MapData, Table*, p->mapData) @@ -521,4 +526,5 @@ void TilemapVX::setOY(int value) void TilemapVX::releaseResources() { delete p; + bmProxy.p = 0; } diff --git a/src/tilemapvx.h b/src/tilemapvx.h index 0e2b4be..a4df41d 100644 --- a/src/tilemapvx.h +++ b/src/tilemapvx.h @@ -54,7 +54,7 @@ public: void update(); - BitmapArray &getBitmapArray() const; + BitmapArray &getBitmapArray(); DECL_ATTR( Viewport, Viewport* ) DECL_ATTR( MapData, Table* ) @@ -66,6 +66,7 @@ public: private: TilemapVXPrivate *p; + BitmapArray bmProxy; void releaseResources(); const char *klassName() const { return "tilemap"; } From 9e64dff01cf59b3f0d0af7d3e5a53b39d93fd86f Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Mon, 29 Sep 2014 10:30:16 +0200 Subject: [PATCH 033/239] Bitmap: Fix mem leak --- src/bitmap.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmap.cpp b/src/bitmap.cpp index 119dc24..0fa0df8 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -113,6 +113,7 @@ struct BitmapPrivate ~BitmapPrivate() { + SDL_FreeFormat(format); pixman_region_fini(&tainted); } From 4a015c639709fb685b255750b9b07e6c181448df Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Mon, 29 Sep 2014 10:30:41 +0200 Subject: [PATCH 034/239] Bitmap: Add font shadow rendering --- README.md | 4 --- src/bitmap.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a29f067..cb3af89 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,6 @@ It is licensed under the GNU General Public License v2+. ## RGSS2 / RGSS3 Support for these RGSS versions is experimental. A lot is implemented (to the point that you can play the VX Ace sample game, with caveats), but not everything is in place yet. -Missing RGSS2 functionality: - -* Text shadow - Missing RGSS3 functionality: * Text outline diff --git a/src/bitmap.cpp b/src/bitmap.cpp index 0fa0df8..242c12b 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -838,6 +838,93 @@ static std::string fixupString(const char *str) return s; } +static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_Color &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; + + /* 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 + * it with x/y offset by 1, then blend the input surface over it at origin + * (0,0) using the bitmap blit equation (see shader/bitmapBlit.frag) */ + + for (int y = 0; y < in->h+1; ++y) + for (int x = 0; x < in->w+1; ++x) + { + /* src: input pixel, shd: shadow pixel */ + uint32_t src = 0, shd = 0; + + /* Output pixel location */ + uint32_t *outP = ((uint32_t*) ((uint8_t*) out->pixels + y*out->pitch)) + x; + + if (y < in->h && x < in->w) + src = ((uint32_t*) ((uint8_t*) in->pixels + y*in->pitch))[x]; + + if (y > 0 && x > 0) + shd = ((uint32_t*) ((uint8_t*) in->pixels + (y-1)*in->pitch))[x-1]; + + /* Set shadow pixel RGB values to 0 (black) */ + shd &= fm.Amask; + + if (x == 0 || y == 0) + { + *outP = src; + continue; + } + + if (x == in->w || y == in->h) + { + *outP = shd; + continue; + } + + /* Input and shadow alpha values */ + uint8_t srcA, shdA; + srcA = (src & fm.Amask) >> fm.Ashift; + shdA = (shd & fm.Amask) >> fm.Ashift; + + if (srcA == 255 || shdA == 0) + { + *outP = src; + continue; + } + + if (srcA == 0 && shdA == 0) + { + *outP = 0; + continue; + } + + float fSrcA = srcA / 255.0; + float fShdA = shdA / 255.0; + + /* Because opacity == 1, co1 == fSrcA */ + float co2 = fShdA * (1.0 - fSrcA); + /* Result alpha */ + float fa = fSrcA + co2; + /* Temp value to simplify arithmetic below */ + float co3 = fSrcA / fa; + + /* 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; + + *outP = SDL_MapRGBA(&fm, r, g, b, a); + } + + /* Store new surface in the input pointer */ + SDL_FreeSurface(in); + in = out; +} + void Bitmap::drawText(const IntRect &rect, const char *str, int align) { guardDisposed(); @@ -870,6 +957,11 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ABGR8888); + // While real outlining is not yet here, use shadow + // as a replacement to at least make text legible + if (p->font->getShadow() || p->font->getOutline()) + applyShadow(txtSurf, *p->format, c); + int alignX = rect.x; switch (align) From 3dd703f7328e4b00c39bb2ce3bbd3a943117f9b9 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 30 Sep 2014 00:48:22 +0200 Subject: [PATCH 035/239] MRI: Use ruby 2.0 compatible function name --- binding-mri/font-binding.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binding-mri/font-binding.cpp b/binding-mri/font-binding.cpp index 809f0da..7574d45 100644 --- a/binding-mri/font-binding.cpp +++ b/binding-mri/font-binding.cpp @@ -313,7 +313,7 @@ fontBindingInit() if (rgssVer >= 2) { - VALUE defNames = rb_ary_new_capa(3); + 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")); From 46497eae014da40e4c53f2def903d8640c445224 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 30 Sep 2014 01:34:10 +0200 Subject: [PATCH 036/239] CMakeLists.txt: Add missing shader source --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98c65bc..386452d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,7 @@ set(EMBEDDED_INPUT shader/simpleColor.vert shader/sprite.vert shader/tilemap.vert + shader/tilemapvx.vert shader/blur.frag shader/blurH.vert shader/blurV.vert From 51a0f3903c812b36f482dbaf289042deb430796b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 30 Sep 2014 09:13:12 +0200 Subject: [PATCH 037/239] Audio: Clean up threading and add AudioStream fadein (RGSS3) --- CMakeLists.txt | 1 + README.md | 1 - mkxp.pro | 3 +- src/alstream.cpp | 33 ++++------ src/alstream.h | 12 ++-- src/audio.cpp | 34 ++++------ src/audiostream.cpp | 149 +++++++++++++++++++++++++++++++------------- src/audiostream.h | 64 ++++++++++++------- src/eventthread.h | 29 +-------- src/sdl-util.h | 48 ++++++++++++++ 10 files changed, 228 insertions(+), 146 deletions(-) create mode 100644 src/sdl-util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 386452d..85e58e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ set(MAIN_HEADERS src/tileatlasvx.h src/sharedmidistate.h src/fluid-fun.h + src/sdl-util.h ) set(MAIN_SOURCE diff --git a/README.md b/README.md index cb3af89..f4ba120 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ Missing RGSS3 functionality: * Text outline * Movie playback -* Audio fade-in Some other things might be implemented, but simply not bound yet. diff --git a/mkxp.pro b/mkxp.pro index 37c348c..0adb918 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -131,7 +131,8 @@ HEADERS += \ src/tilemapvx.h \ src/tileatlasvx.h \ src/sharedmidistate.h \ - src/fluid-fun.h + src/fluid-fun.h \ + src/sdl-util.h SOURCES += \ src/main.cpp \ diff --git a/src/alstream.cpp b/src/alstream.cpp index 6ab6358..da1e844 100644 --- a/src/alstream.cpp +++ b/src/alstream.cpp @@ -26,6 +26,7 @@ #include "filesystem.h" #include "aldatasource.h" #include "fluid-fun.h" +#include "sdl-util.h" #include #include @@ -38,8 +39,6 @@ ALStream::ALStream(LoopMode loopMode, source(0), thread(0), preemptPause(false), - streamInited(false), - needsRewind(false), pitch(1.0) { alSrc = AL::Source::gen(); @@ -198,7 +197,7 @@ void ALStream::openSource(const std::string &filename) { const char *ext; shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext); - needsRewind = false; + needsRewind.clear(); /* Try to read ogg file signature */ char sig[5] = { 0 }; @@ -227,13 +226,13 @@ void ALStream::openSource(const std::string &filename) void ALStream::stopStream() { - threadTermReq = true; + threadTermReq.set(); if (thread) { SDL_WaitThread(thread, 0); thread = 0; - needsRewind = true; + needsRewind.set(); } /* Need to stop the source _after_ the thread has terminated, @@ -249,14 +248,15 @@ void ALStream::startStream(float offset) AL::Source::clearQueue(alSrc); preemptPause = false; - streamInited = false; - sourceExhausted = false; - threadTermReq = false; + streamInited.clear(); + sourceExhausted.clear(); + threadTermReq.clear(); startOffset = offset; procFrames = offset * source->sampleRate(); - thread = SDL_CreateThread(streamDataFun, threadName.c_str(), this); + thread = createSDLThread + (this, threadName); } void ALStream::pauseStream() @@ -344,7 +344,7 @@ void ALStream::streamData() resumeStream(); firstBuffer = false; - streamInited = true; + streamInited.set(); } if (threadTermReq) @@ -352,7 +352,7 @@ void ALStream::streamData() if (status == ALDataSource::EndOfStream) { - sourceExhausted = true; + sourceExhausted.set(); break; } } @@ -400,7 +400,7 @@ void ALStream::streamData() if (status == ALDataSource::Error) { - sourceExhausted = true; + sourceExhausted.set(); return; } @@ -419,7 +419,7 @@ void ALStream::streamData() lastBuf = buf; if (status == ALDataSource::EndOfStream) - sourceExhausted = true; + sourceExhausted.set(); } if (threadTermReq) @@ -428,10 +428,3 @@ void ALStream::streamData() SDL_Delay(AUDIO_SLEEP); } } - -int ALStream::streamDataFun(void *_self) -{ - ALStream &self = *static_cast(_self); - self.streamData(); - return 0; -} diff --git a/src/alstream.h b/src/alstream.h index 7de277d..e8c1606 100644 --- a/src/alstream.h +++ b/src/alstream.h @@ -23,12 +23,11 @@ #define ALSTREAM_H #include "al-util.h" +#include "sdl-util.h" #include #include -struct SDL_mutex; -struct SDL_thread; struct ALDataSource; #define STREAM_BUFS 3 @@ -59,12 +58,12 @@ struct ALStream /* When this flag isn't set and alSrc is * in 'STOPPED' state, stream isn't over * (it just hasn't started yet) */ - bool streamInited; - bool sourceExhausted; + AtomicFlag streamInited; + AtomicFlag sourceExhausted; - bool threadTermReq; + AtomicFlag threadTermReq; - bool needsRewind; + AtomicFlag needsRewind; float startOffset; float pitch; @@ -118,7 +117,6 @@ private: /* thread func */ void streamData(); - static int streamDataFun(void *); }; #endif // ALSTREAM_H diff --git a/src/audio.cpp b/src/audio.cpp index dcc0b90..aa16e7d 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -25,6 +25,7 @@ #include "soundemitter.h" #include "sharedstate.h" #include "sharedmidistate.h" +#include "sdl-util.h" #include @@ -55,8 +56,7 @@ struct AudioPrivate struct { SDL_Thread *thread; - bool active; - bool termReq; + AtomicFlag termReq; MeWatchState state; } meWatch; @@ -66,19 +66,18 @@ struct AudioPrivate me(ALStream::NotLooped, "me"), se(conf) { - meWatch.active = false; - meWatch.termReq = false; meWatch.state = MeNotPlaying; - meWatch.thread = SDL_CreateThread(meWatchFun, "audio_mewatch", this); + meWatch.thread = createSDLThread + (this, "audio_mewatch"); } ~AudioPrivate() { - meWatch.termReq = true; + meWatch.termReq.set(); SDL_WaitThread(meWatch.thread, 0); } - void meWatchFunInt() + void meWatchFun() { const float fadeOutStep = 1.f / (200 / AUDIO_SLEEP); const float fadeInStep = 1.f / (1000 / AUDIO_SLEEP); @@ -121,13 +120,13 @@ struct AudioPrivate bgm.lockStream(); - float vol = bgm.extVolume; + float vol = bgm.getVolume(AudioStream::External); vol -= fadeOutStep; if (vol < 0 || bgm.stream.queryState() != ALStream::Playing) { /* Either BGM has fully faded out, or stopped midway. -> MePlaying */ - bgm.setExtVolume1(0); + bgm.setVolume(AudioStream::External, 0); bgm.stream.pause(); meWatch.state = MePlaying; bgm.unlockStream(); @@ -136,7 +135,7 @@ struct AudioPrivate break; } - bgm.setExtVolume1(vol); + bgm.setVolume(AudioStream::External, vol); bgm.unlockStream(); me.unlockStream(); @@ -165,7 +164,7 @@ struct AudioPrivate else { /* BGM is stopped. -> MeNotPlaying */ - bgm.setExtVolume1(1.0); + bgm.setVolume(AudioStream::External, 1.0); if (!bgm.noResumeStop) bgm.stream.play(); @@ -188,7 +187,7 @@ struct AudioPrivate if (bgm.stream.queryState() == ALStream::Stopped) { /* BGM stopped midway fade in. -> MeNotPlaying */ - bgm.setExtVolume1(1.0); + bgm.setVolume(AudioStream::External, 1.0); meWatch.state = MeNotPlaying; bgm.unlockStream(); @@ -208,7 +207,7 @@ struct AudioPrivate break; } - float vol = bgm.extVolume; + float vol = bgm.getVolume(AudioStream::External); vol += fadeInStep; if (vol >= 1) @@ -218,7 +217,7 @@ struct AudioPrivate meWatch.state = MeNotPlaying; } - bgm.setExtVolume1(vol); + bgm.setVolume(AudioStream::External, vol); me.unlockStream(); bgm.unlockStream(); @@ -230,13 +229,6 @@ struct AudioPrivate SDL_Delay(AUDIO_SLEEP); } } - - static int meWatchFun(void *self) - { - static_cast(self)->meWatchFunInt(); - - return 0; - } }; Audio::Audio(const Config &conf) diff --git a/src/audiostream.cpp b/src/audiostream.cpp index d5975e9..16cade7 100644 --- a/src/audiostream.cpp +++ b/src/audiostream.cpp @@ -30,19 +30,21 @@ AudioStream::AudioStream(ALStream::LoopMode loopMode, const std::string &threadId) - : baseVolume(1.0), - fadeVolume(1.0), - extVolume(1.0), - extPaused(false), + : extPaused(false), noResumeStop(false), stream(loopMode, threadId) { current.volume = 1.0; current.pitch = 1.0; - fade.active = false; + for (size_t i = 0; i < VolumeTypeCount; ++i) + volumes[i] = 1.0; + fade.thread = 0; - fade.threadName = std::string("audio_fade (") + threadId + ")"; + fade.threadName = std::string("audio_fadeout (") + threadId + ")"; + + fadeIn.thread = 0; + fadeIn.threadName = std::string("audio_fadein (") + threadId + ")"; streamMut = SDL_CreateMutex(); } @@ -51,10 +53,16 @@ AudioStream::~AudioStream() { if (fade.thread) { - fade.reqTerm = true; + fade.reqTerm.set(); SDL_WaitThread(fade.thread, 0); } + if (fadeIn.thread) + { + fadeIn.rqTerm.set(); + SDL_WaitThread(fadeIn.thread, 0); + } + lockStream(); stream.stop(); @@ -70,7 +78,7 @@ void AudioStream::play(const std::string &filename, int pitch, float offset) { - finiFadeInt(); + finiFadeOutInt(); lockStream(); @@ -96,7 +104,7 @@ void AudioStream::play(const std::string &filename, && _pitch == current.pitch && (sState == ALStream::Playing || sState == ALStream::Paused)) { - setBaseVolume(_volume); + setVolume(Base, _volume); current.volume = _volume; unlockStream(); return; @@ -132,9 +140,15 @@ void AudioStream::play(const std::string &filename, break; } - setBaseVolume(_volume); + setVolume(Base, _volume); stream.setPitch(_pitch); + if (offset > 0) + { + setVolume(FadeIn, 0); + startFadeIn(); + } + current.filename = filename; current.volume = _volume; current.pitch = _pitch; @@ -149,7 +163,7 @@ void AudioStream::play(const std::string &filename, void AudioStream::stop() { - finiFadeInt(); + finiFadeOutInt(); lockStream(); @@ -190,18 +204,19 @@ void AudioStream::fadeOut(int duration) if (fade.thread) { - fade.reqFini = true; + fade.reqFini.set(); SDL_WaitThread(fade.thread, 0); fade.thread = 0; } - fade.active = true; + fade.active.set(); fade.msStep = (1.0) / duration; - fade.reqFini = false; - fade.reqTerm = false; + fade.reqFini.clear(); + fade.reqTerm.clear(); fade.startTicks = SDL_GetTicks(); - fade.thread = SDL_CreateThread(fadeThreadFun, fade.threadName.c_str(), this); + fade.thread = createSDLThread + (this, fade.threadName); unlockStream(); } @@ -219,16 +234,15 @@ void AudioStream::unlockStream() SDL_UnlockMutex(streamMut); } -void AudioStream::setFadeVolume(float value) +void AudioStream::setVolume(VolumeType type, float value) { - fadeVolume = value; + volumes[type] = value; updateVolume(); } -void AudioStream::setExtVolume1(float value) +float AudioStream::getVolume(VolumeType type) { - extVolume = value; - updateVolume(); + return volumes[type]; } float AudioStream::playingOffset() @@ -236,28 +250,47 @@ float AudioStream::playingOffset() return stream.queryOffset(); } -void AudioStream::finiFadeInt() -{ - if (!fade.thread) - return; - - fade.reqFini = true; - SDL_WaitThread(fade.thread, 0); - fade.thread = 0; -} - void AudioStream::updateVolume() { - stream.setVolume(baseVolume * fadeVolume * extVolume); + float vol = 1.0; + + for (size_t i = 0; i < VolumeTypeCount; ++i) + vol *= volumes[i]; + + stream.setVolume(vol); } -void AudioStream::setBaseVolume(float value) +void AudioStream::finiFadeOutInt() { - baseVolume = value; - updateVolume(); + if (fade.thread) + { + fade.reqFini.set(); + SDL_WaitThread(fade.thread, 0); + fade.thread = 0; + } + + if (fadeIn.thread) + { + fadeIn.rqFini.set(); + SDL_WaitThread(fadeIn.thread, 0); + fadeIn.thread = 0; + } } -void AudioStream::fadeThread() +void AudioStream::startFadeIn() +{ + /* Previous fadein should always be terminated in play() */ + assert(!fadeIn.thread); + + fadeIn.rqFini.clear(); + fadeIn.rqTerm.clear(); + fadeIn.startTicks = SDL_GetTicks(); + + fadeIn.thread = createSDLThread + (this, fadeIn.threadName); +} + +void AudioStream::fadeOutThread() { while (true) { @@ -273,31 +306,59 @@ void AudioStream::fadeThread() ALStream::State state = stream.queryState(); if (state != ALStream::Playing - || resVol < 0 - || fade.reqFini) + || resVol < 0 + || fade.reqFini) { if (state != ALStream::Paused) stream.stop(); - setFadeVolume(1.0); + setVolume(FadeOut, 1.0); unlockStream(); break; } - setFadeVolume(resVol); + setVolume(FadeOut, resVol); unlockStream(); SDL_Delay(AUDIO_SLEEP); } - fade.active = false; + fade.active.clear(); } -int AudioStream::fadeThreadFun(void *self) +void AudioStream::fadeInThread() { - static_cast(self)->fadeThread(); + while (true) + { + if (fadeIn.rqTerm) + break; - return 0; + lockStream(); + + /* Fade in duration is always 1 second */ + uint32_t cur = SDL_GetTicks() - fadeIn.startTicks; + float prog = cur / 1000.0; + + ALStream::State state = stream.queryState(); + + if (state != ALStream::Playing + || prog >= 1.0 + || fadeIn.rqFini) + { + setVolume(FadeIn, 1.0); + unlockStream(); + + break; + } + + /* Quadratic increase (not really the same as + * in RMVXA, but close enough) */ + setVolume(FadeIn, prog*prog); + + unlockStream(); + + SDL_Delay(AUDIO_SLEEP); + } } diff --git a/src/audiostream.h b/src/audiostream.h index 79a2509..d968af3 100644 --- a/src/audiostream.h +++ b/src/audiostream.h @@ -24,12 +24,10 @@ #include "al-util.h" #include "alstream.h" +#include "sdl-util.h" #include -struct SDL_mutex; -struct SDL_Thread; - struct AudioStream { struct @@ -39,17 +37,21 @@ struct AudioStream float pitch; } current; - /* Volume set with 'play()' */ - float baseVolume; - - /* Volume set by external threads, + /* Volumes set by external threads, * such as for fade-in/out. - * Multiplied with intVolume for final - * playback volume. - * fadeVolume: used by fade-out thread. - * extVolume: used by MeWatch. */ - float fadeVolume; - float extVolume; + * Multiplied together for final + * playback volume. Used with setVolume(). + * Base is set by play(). + * External is used by MeWatch */ + enum VolumeType + { + Base = 0, + FadeOut, + FadeIn, + External, + + VolumeTypeCount + }; /* Note that 'extPaused' and 'noResumeStop' are * effectively only used with the AudioStream @@ -76,18 +78,19 @@ struct AudioStream ALStream stream; SDL_mutex *streamMut; + /* Fade out */ struct { - /* Fade is in progress */ - bool active; + /* Fade out is in progress */ + AtomicFlag active; /* Request fade thread to finish and * cleanup (like it normally would) */ - bool reqFini; + AtomicFlag reqFini; /* Request fade thread to terminate * immediately */ - bool reqTerm; + AtomicFlag reqTerm; SDL_Thread *thread; std::string threadName; @@ -100,6 +103,18 @@ struct AudioStream uint32_t startTicks; } fade; + /* Fade in */ + struct + { + AtomicFlag rqFini; + AtomicFlag rqTerm; + + SDL_Thread *thread; + std::string threadName; + + uint32_t startTicks; + } fadeIn; + AudioStream(ALStream::LoopMode loopMode, const std::string &threadId); ~AudioStream(); @@ -117,19 +132,20 @@ struct AudioStream void lockStream(); void unlockStream(); - void setFadeVolume(float value); - void setExtVolume1(float value); + void setVolume(VolumeType type, float value); + float getVolume(VolumeType type); float playingOffset(); private: - void finiFadeInt(); - + float volumes[VolumeTypeCount]; void updateVolume(); - void setBaseVolume(float value); - void fadeThread(); - static int fadeThreadFun(void *); + void finiFadeOutInt(); + void startFadeIn(); + + void fadeOutThread(); + void fadeInThread(); }; #endif // AUDIOSTREAM_H diff --git a/src/eventthread.h b/src/eventthread.h index 23402c5..013f60b 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -24,47 +24,20 @@ #include "config.h" #include "etc-internal.h" +#include "sdl-util.h" #include #include #include #include -#include #include #include struct RGSSThreadData; -struct SDL_Thread; struct SDL_Window; -struct AtomicFlag -{ - AtomicFlag() - { - clear(); - } - - void set() - { - SDL_AtomicSet(&atom, 1); - } - - void clear() - { - SDL_AtomicSet(&atom, 0); - } - - operator bool() const - { - return SDL_AtomicGet(&atom); - } - -private: - mutable SDL_atomic_t atom; -}; - class EventThread { public: diff --git a/src/sdl-util.h b/src/sdl-util.h new file mode 100644 index 0000000..ba02046 --- /dev/null +++ b/src/sdl-util.h @@ -0,0 +1,48 @@ +#ifndef SDLUTIL_H +#define SDLUTIL_H + +#include +#include + +#include + +struct AtomicFlag +{ + AtomicFlag() + { + clear(); + } + + void set() + { + SDL_AtomicSet(&atom, 1); + } + + void clear() + { + SDL_AtomicSet(&atom, 0); + } + + operator bool() const + { + return SDL_AtomicGet(&atom); + } + +private: + mutable SDL_atomic_t atom; +}; + +template +int __sdlThreadFun(void *obj) +{ + (static_cast(obj)->*func)(); + return 0; +} + +template +SDL_Thread *createSDLThread(C *obj, const std::string &name = std::string()) +{ + return SDL_CreateThread(__sdlThreadFun, name.c_str(), obj); +} + +#endif // SDLUTIL_H From 5ea964eee8f5052f33c3a1b5c1e652fc24e2869b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Tue, 30 Sep 2014 14:17:33 +0200 Subject: [PATCH 038/239] CMakeLists.txt: Link against libiconv on OSX --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85e58e3..60ea1fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,6 +368,7 @@ if(APPLE) list(APPEND PLATFORM_LIBRARIES ${CARBON_LIBRARY} ${IOKIT_LIBRARY} + "-liconv" ) endif() From fa911b80182582eaeb2fd375553b4c8aa181ed6b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Wed, 1 Oct 2014 04:48:23 +0200 Subject: [PATCH 039/239] gl-fun: Don't rely on SDL_opengl.h for function type definitions --- src/gl-fun.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gl-fun.h b/src/gl-fun.h index e555c99..bae8dc3 100644 --- a/src/gl-fun.h +++ b/src/gl-fun.h @@ -59,9 +59,6 @@ typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRY * _GLDEBUGPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void *userParam); typedef void (APIENTRYP _PFNGLDEBUGMESSAGECALLBACKPROC) (_GLDEBUGPROC callback, const void *userParam); -#ifdef GLES2_HEADER -#define GL_NUM_EXTENSIONS 0x821D - /* Buffer object */ typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers); @@ -101,8 +98,6 @@ typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint); typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer); /* Framebuffer object */ -#define GL_READ_FRAMEBUFFER 0x8CA8 -#define GL_DRAW_FRAMEBUFFER 0x8CA9 typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers); typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint* framebuffers); typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); @@ -113,6 +108,11 @@ typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLi typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays); typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint* arrays); typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array); + +#ifdef GLES2_HEADER +#define GL_NUM_EXTENSIONS 0x821D +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 #endif #define GL_20_FUN \ From 7b65977eb951a015b2c400917c018ff2ad64b3b0 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Wed, 1 Oct 2014 06:29:20 +0200 Subject: [PATCH 040/239] Silence "uninitialized" warnings --- binding-mri/binding-util.h | 2 +- binding-mruby/binding-util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/binding-mri/binding-util.h b/binding-mri/binding-util.h index 6deac5d..d895f07 100644 --- a/binding-mri/binding-util.h +++ b/binding-mri/binding-util.h @@ -349,7 +349,7 @@ rb_check_argc(int actual, int expected) { \ RB_UNUSED_PARAM; \ Klass *k = getPrivateData(self); \ - type value; \ + type value = 0; \ GUARD_EXC( value = k->get##PropName(); ) \ return value_fun(value); \ } \ diff --git a/binding-mruby/binding-util.h b/binding-mruby/binding-util.h index 5883e43..5dd5cd7 100644 --- a/binding-mruby/binding-util.h +++ b/binding-mruby/binding-util.h @@ -195,7 +195,7 @@ defineClass(mrb_state *mrb, const char *name) MRB_METHOD(Klass##Get##PropName) \ { \ Klass *k = getPrivateData(mrb, self); \ - mrb_type value; \ + mrb_type value = 0; \ GUARD_EXC( value = k->get##PropName(); ) \ return mrb_##conv_t##_value(value); \ } \ From 95cda4035eed5ad5260bd050f20fb70e31ed75fa Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Wed, 1 Oct 2014 19:19:25 +0200 Subject: [PATCH 041/239] fluid-fun: Fix fluidsynth soname on OSX --- src/fluid-fun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fluid-fun.cpp b/src/fluid-fun.cpp index 4b8a751..845a8c4 100644 --- a/src/fluid-fun.cpp +++ b/src/fluid-fun.cpp @@ -13,7 +13,7 @@ #ifdef __LINUX__ #define FLUID_LIB "libfluidsynth.so.1" #elif __MACOSX__ -#define FLUID_LIB "libfluidsynth.dylib.1" +#define FLUID_LIB "libfluidsynth.1.dylib" #elif __WINDOWS__ #define FLUID_LIB "fluidsynth.dll" #else From db78e5537199634ed96a260e608d9b1496177758 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Thu, 2 Oct 2014 16:41:53 +0200 Subject: [PATCH 042/239] TileAtlasVX: Clamp blit src rect to tileset bitmap size --- src/tileatlasvx.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp index 711675c..45fab3a 100644 --- a/src/tileatlasvx.cpp +++ b/src/tileatlasvx.cpp @@ -297,7 +297,9 @@ void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) for (size_t i = 0; i < blits##part##N; ++i) \ {\ IntRect src = blits##part[i].src; \ - src = IntRect(src.x*32, src.y*32, src.w*32, src.h*32); \ + int w = std::min(bm->width(), src.w*32); \ + int h = std::min(bm->height(), src.h*32); \ + src = IntRect(src.x*32, src.y*32, w, h); \ Vec2i dst = blits##part[i].dst; \ dst = Vec2i(dst.x*32, dst.y*32); \ GLMeta::blitRectangle(src, dst); \ From df73045d81f7155f5bef935302b323b017be24d8 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 3 Oct 2014 06:51:39 +0200 Subject: [PATCH 043/239] TileAtlasVX: Followup fix Use rectangle intersection to correctly clip source rectangles with origin != (0,0). --- src/etc-internal.h | 17 ++++++++++------- src/tileatlasvx.cpp | 23 ++++++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/etc-internal.h b/src/etc-internal.h index da40cb7..2d3e547 100644 --- a/src/etc-internal.h +++ b/src/etc-internal.h @@ -93,17 +93,20 @@ struct Vec2i } }; -struct IntRect +struct IntRect : SDL_Rect { - int x, y, w, h; - IntRect() - : x(0), y(0), w(0), h(0) - {} + { + x = y = w = h = 0; + } IntRect(int x, int y, int w, int h) - : x(x), y(y), w(w), h(h) - {} + { + this->x = x; + this->y = y; + this->w = w; + this->h = h; + } bool operator==(const IntRect &other) const { diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp index 45fab3a..7a5f48c 100644 --- a/src/tileatlasvx.cpp +++ b/src/tileatlasvx.cpp @@ -270,6 +270,19 @@ createShadowSet() return surf; } +static void doBlit(Bitmap *bm, const IntRect &src, const Vec2i &dst) +{ + /* Translate tile to pixel units */ + IntRect _src(src.x*32, src.y*32, src.w*32, src.h*32); + Vec2i _dst(dst.x*32, dst.y*32); + IntRect bmr(0, 0, bm->width(), bm->height()); + + if (!SDL_IntersectRect(&_src, &bmr, &_src)) + return; + + GLMeta::blitRectangle(_src, _dst); +} + void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) { assert(tf.width == ATLASVX_W && tf.height == ATLASVX_H); @@ -296,13 +309,9 @@ void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) GLMeta::blitSource(bm->getGLTypes()); \ for (size_t i = 0; i < blits##part##N; ++i) \ {\ - IntRect src = blits##part[i].src; \ - int w = std::min(bm->width(), src.w*32); \ - int h = std::min(bm->height(), src.h*32); \ - src = IntRect(src.x*32, src.y*32, w, h); \ - Vec2i dst = blits##part[i].dst; \ - dst = Vec2i(dst.x*32, dst.y*32); \ - GLMeta::blitRectangle(src, dst); \ + const IntRect &src = blits##part[i].src; \ + const Vec2i &dst = blits##part[i].dst; \ + doBlit(bm, src, dst); \ } \ } From 55a2cf562ea2fe784a03cfe08144e9107d515468 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 3 Oct 2014 06:51:39 +0200 Subject: [PATCH 044/239] TileAtlasVX: Followup fix Use rectangle intersection to correctly clip source rectangles with origin != (0,0). --- src/etc-internal.h | 17 ++++++++++------- src/tileatlasvx.cpp | 24 +++++++++++++++++------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/etc-internal.h b/src/etc-internal.h index da40cb7..2d3e547 100644 --- a/src/etc-internal.h +++ b/src/etc-internal.h @@ -93,17 +93,20 @@ struct Vec2i } }; -struct IntRect +struct IntRect : SDL_Rect { - int x, y, w, h; - IntRect() - : x(0), y(0), w(0), h(0) - {} + { + x = y = w = h = 0; + } IntRect(int x, int y, int w, int h) - : x(x), y(y), w(w), h(h) - {} + { + this->x = x; + this->y = y; + this->w = w; + this->h = h; + } bool operator==(const IntRect &other) const { diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp index 45fab3a..079d30a 100644 --- a/src/tileatlasvx.cpp +++ b/src/tileatlasvx.cpp @@ -270,6 +270,20 @@ createShadowSet() return surf; } +static void doBlit(Bitmap *bm, const IntRect &src, const Vec2i &dst) +{ + /* Translate tile to pixel units */ + IntRect _src(src.x*32, src.y*32, src.w*32, src.h*32); + Vec2i _dst(dst.x*32, dst.y*32); + IntRect bmr(0, 0, bm->width(), bm->height()); + + /* Drop blit if source rect lies outside bitmap rect */ + if (!SDL_IntersectRect(&_src, &bmr, &_src)) + return; + + GLMeta::blitRectangle(_src, _dst); +} + void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) { assert(tf.width == ATLASVX_W && tf.height == ATLASVX_H); @@ -296,13 +310,9 @@ void build(TEXFBO &tf, Bitmap *bitmaps[BM_COUNT]) GLMeta::blitSource(bm->getGLTypes()); \ for (size_t i = 0; i < blits##part##N; ++i) \ {\ - IntRect src = blits##part[i].src; \ - int w = std::min(bm->width(), src.w*32); \ - int h = std::min(bm->height(), src.h*32); \ - src = IntRect(src.x*32, src.y*32, w, h); \ - Vec2i dst = blits##part[i].dst; \ - dst = Vec2i(dst.x*32, dst.y*32); \ - GLMeta::blitRectangle(src, dst); \ + const IntRect &src = blits##part[i].src; \ + const Vec2i &dst = blits##part[i].dst; \ + doBlit(bm, src, dst); \ } \ } From c1d89e4f8d31a55578714589178d81834a6ca84b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 3 Oct 2014 20:15:52 +0200 Subject: [PATCH 045/239] CMakeLists.txt: Bump default MRI version to 2.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60ea1fd..aa274df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -276,7 +276,7 @@ source_group("Embedded Source" FILES ${EMBEDDED_INPUT} ${EMBEDDED_SOURCE}) ## Setup binding source ## if (BINDING STREQUAL "MRI") - set(MRIVERSION "2.0" CACHE STRING "Version of MRI to link with") + set(MRIVERSION "2.1" CACHE STRING "Version of MRI to link with") pkg_check_modules(MRI REQUIRED ruby-${MRIVERSION}) list(APPEND DEFINES BINDING_MRI From 0c08fc2d16c03bceb42d30ba77668cf4083fabfa Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Mon, 6 Oct 2014 21:10:19 +0200 Subject: [PATCH 046/239] gl-fun.h: Fix function type signature --- src/gl-fun.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gl-fun.h b/src/gl-fun.h index bae8dc3..42cd4d7 100644 --- a/src/gl-fun.h +++ b/src/gl-fun.h @@ -69,7 +69,7 @@ typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, /* Shader */ typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); -typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths); +typedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths); typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param); From 1b7ed5ed780d35e9381fd36bc34eb298fe997733 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Thu, 9 Oct 2014 18:53:24 +0200 Subject: [PATCH 047/239] Font: Fix default 'shadow' value for RGSS1 --- src/font.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/font.cpp b/src/font.cpp index e4ddcd9..6a04316 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -387,8 +387,8 @@ void Font::initDefaultDynAttribs() void Font::initDefaults() { - FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false); - FontPrivate::defaultShadow = (rgssVer >= 3 ? false : true ); + FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false); + FontPrivate::defaultShadow = (rgssVer == 2 ? true : false); } _TTF_Font *Font::getSdlFont() From 520162f36a0ff188b5b3db89d095c0660ad562f2 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Thu, 9 Oct 2014 19:02:29 +0200 Subject: [PATCH 048/239] Use safe way to get at a vector's data pointer &std::vector[0] is not guaranteed to not throw if the vector is empty. Better safe than sorry. --- binding-mruby/mrb-ext/rwmem.cpp | 2 +- src/global-ibo.h | 2 +- src/quadarray.h | 4 ++-- src/tileatlasvx.cpp | 2 +- src/tilemap.cpp | 6 +++--- src/tilemapvx.cpp | 4 ++-- src/util.h | 13 +++++++++++++ src/windowvx.cpp | 6 +++--- 8 files changed, 26 insertions(+), 13 deletions(-) diff --git a/binding-mruby/mrb-ext/rwmem.cpp b/binding-mruby/mrb-ext/rwmem.cpp index 7245ffd..1c83061 100644 --- a/binding-mruby/mrb-ext/rwmem.cpp +++ b/binding-mruby/mrb-ext/rwmem.cpp @@ -101,7 +101,7 @@ int RWMemGetData(SDL_RWops *ops, void *buffer) ByteVec *v = getRWPrivate(ops); if (buffer) - memcpy(buffer, &(*v)[0], v->size()); + memcpy(buffer, dataPtr(*v), v->size()); return v->size(); } diff --git a/src/global-ibo.h b/src/global-ibo.h index 77ff555..c8beaf3 100644 --- a/src/global-ibo.h +++ b/src/global-ibo.h @@ -67,7 +67,7 @@ struct GlobalIBO } IBO::bind(ibo); - IBO::uploadData(buffer.size() * sizeof(index_t), &buffer[0]); + IBO::uploadData(buffer.size() * sizeof(index_t), dataPtr(buffer)); IBO::unbind(); } }; diff --git a/src/quadarray.h b/src/quadarray.h index f4037ed..8751739 100644 --- a/src/quadarray.h +++ b/src/quadarray.h @@ -86,7 +86,7 @@ struct QuadArray { /* New data exceeds already allocated size. * Reallocate VBO. */ - VBO::uploadData(size, &vertices[0], GL_DYNAMIC_DRAW); + VBO::uploadData(size, dataPtr(vertices), GL_DYNAMIC_DRAW); vboSize = size; shState->ensureQuadIBO(quadCount); @@ -94,7 +94,7 @@ struct QuadArray else { /* New data fits in allocated size */ - VBO::uploadSubData(0, size, &vertices[0]); + VBO::uploadSubData(0, size, dataPtr(vertices)); } VBO::unbind(); diff --git a/src/tileatlasvx.cpp b/src/tileatlasvx.cpp index 7a5f48c..5af8060 100644 --- a/src/tileatlasvx.cpp +++ b/src/tileatlasvx.cpp @@ -265,7 +265,7 @@ createShadowSet() /* Fill rects with half opacity black */ uint32_t color = (0x80808080 & am); - SDL_FillRects(surf, &rects[0], rects.size(), color); + SDL_FillRects(surf, dataPtr(rects), rects.size(), color); return surf; } diff --git a/src/tilemap.cpp b/src/tilemap.cpp index 9878275..ac50c70 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -766,7 +766,7 @@ struct TilemapPrivate VBO::bind(tiles.vbo); VBO::allocEmpty(quadDataSize(quadCount)); - VBO::uploadSubData(0, quadDataSize(groundQuadCount), &groundVert[0]); + VBO::uploadSubData(0, quadDataSize(groundQuadCount), dataPtr(groundVert)); for (size_t i = 0; i < zlayersMax; ++i) { @@ -774,7 +774,7 @@ struct TilemapPrivate continue; VBO::uploadSubData(quadDataSize(zlayerBases[i]), - quadDataSize(zlayerSize(i)), &zlayerVert[i][0]); + quadDataSize(zlayerSize(i)), dataPtr(zlayerVert[i])); } VBO::unbind(); @@ -855,7 +855,7 @@ struct TilemapPrivate return; VBO::bind(flash.vbo); - VBO::uploadData(sizeof(CVertex) * vertices.size(), &vertices[0]); + VBO::uploadData(sizeof(CVertex) * vertices.size(), dataPtr(vertices)); VBO::unbind(); /* Ensure global IBO size */ diff --git a/src/tilemapvx.cpp b/src/tilemapvx.cpp index bbd925d..d45e82d 100644 --- a/src/tilemapvx.cpp +++ b/src/tilemapvx.cpp @@ -236,8 +236,8 @@ struct TilemapVXPrivate : public ViewportElement, TileAtlasVX::Reader allocQuads = totalQuads; } - VBO::uploadSubData(0, quadBytes(groundQuads), &groundVert[0]); - VBO::uploadSubData(quadBytes(groundQuads), quadBytes(aboveQuads), &aboveVert[0]); + VBO::uploadSubData(0, quadBytes(groundQuads), dataPtr(groundVert)); + VBO::uploadSubData(quadBytes(groundQuads), quadBytes(aboveQuads), dataPtr(aboveVert)); VBO::unbind(); diff --git a/src/util.h b/src/util.h index 8009a26..2a48ef4 100644 --- a/src/util.h +++ b/src/util.h @@ -25,6 +25,7 @@ #include #include #include +#include static inline int wrapRange(int value, int min, int max) @@ -101,6 +102,18 @@ inline bool contains(const C &c, const V &v) return std::find(c.begin(), c.end(), v) != c.end(); } +template +inline const C *dataPtr(const std::vector &v) +{ + return v.empty() ? (C*)0 : &v[0]; +} + +template +inline C *dataPtr(std::vector &v) +{ + return v.empty() ? (C*)0 : &v[0]; +} + #define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0])) #define elementsN(obj) const size_t obj##N = ARRAY_SIZE(obj) diff --git a/src/windowvx.cpp b/src/windowvx.cpp index cc6d193..0b01a6e 100644 --- a/src/windowvx.cpp +++ b/src/windowvx.cpp @@ -374,7 +374,7 @@ struct WindowVXPrivate base.vert.resize(count); - Vertex *vert = &base.vert.vertices[0]; + Vertex *vert = dataPtr(base.vert.vertices); size_t i = 0; /* Stretched background */ @@ -518,7 +518,7 @@ struct WindowVXPrivate }; size_t i = 0; - Vertex *vert = &ctrlVert.vertices[0]; + Vertex *vert = dataPtr(ctrlVert.vertices); if (!nullOrDisposed(contents) && arrowsVisible) { @@ -600,7 +600,7 @@ struct WindowVXPrivate quads += 1; cursorVert.resize(quads); - Vertex *vert = &cursorVert.vertices[0]; + Vertex *vert = dataPtr(cursorVert.vertices); size_t i = 0; i += Quad::setTexPosRect(&vert[i*4], src.corners.tl, cornerPos.tl); From af145c3a0157455351c6e09c589aa724089af56c Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sat, 11 Oct 2014 15:32:35 +0200 Subject: [PATCH 049/239] mkxp.pro: Make MRI version a qmake config option Example: qmake MRIVERSION=2.2 --- README.md | 2 +- mkxp.pro | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f4ba120..ac0e8f5 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ By default, mkxp switches into the directory where its binary is contained and t To auto detect the encoding of the game title in `Game.ini` and auto convert it to UTF-8, build with `CONFIG+=INI_ENCODING`. Requires iconv implementation and libguess. If the encoding is wrongly detected, you can set the "titleLanguage" hint in mkxp.conf. -**MRI-Binding**: pkg-config will look for `ruby-2.1.pc`, but you can modify mkxp.pro to use 2.0 instead. This is the default binding, so no arguments to qmake needed (`BINDING=MRI` to be explicit). +**MRI-Binding**: pkg-config will look for `ruby-2.1.pc`, but you can override the version with `MRIVERSION=2.2` ('2.2' being an example). This is the default binding, so no arguments to qmake needed (`BINDING=MRI` to be explicit). **MRuby-Binding**: place the "mruby" folder into the project folder and build it first. Add `BINDING=MRUBY` to qmake's arguments. diff --git a/mkxp.pro b/mkxp.pro index 0adb918..8e522c9 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -267,7 +267,11 @@ BINDING_MRUBY { } BINDING_MRI { - PKGCONFIG += ruby-2.1 + isEmpty(MRIVERSION) { + MRIVERSION = 2.1 + } + + PKGCONFIG += ruby-$$MRIVERSION DEFINES += BINDING_MRI # EMBED2 = binding-mri/module_rpg.rb From dd73db2e9da46162130afc52d1e9856de623c824 Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Sat, 25 Jan 2014 09:24:55 +0100 Subject: [PATCH 050/239] Introduce F1 menu to reconfigure key bindings at runtime --- CMakeLists.txt | 4 + mkxp.conf.sample | 13 + mkxp.pro | 4 + src/config.cpp | 18 + src/config.h | 7 + src/eventthread.cpp | 45 +- src/eventthread.h | 57 ++- src/font.cpp | 7 + src/font.h | 2 + src/input.cpp | 225 ++++----- src/input.h | 3 +- src/keybindings.cpp | 311 ++++++++++++ src/keybindings.h | 108 ++++ src/main.cpp | 10 +- src/settingsmenu.cpp | 1112 ++++++++++++++++++++++++++++++++++++++++++ src/settingsmenu.h | 46 ++ src/sharedstate.cpp | 1 + 17 files changed, 1837 insertions(+), 136 deletions(-) create mode 100644 src/keybindings.cpp create mode 100644 src/keybindings.h create mode 100644 src/settingsmenu.cpp create mode 100644 src/settingsmenu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index aa274df..5f3457d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,8 @@ set(MAIN_HEADERS src/gl-util.h src/util.h src/config.h + src/settingsmenu.h + src/keybindings.h src/tileatlas.h src/sharedstate.h src/al-util.h @@ -180,6 +182,8 @@ set(MAIN_SOURCE src/debuglogger.cpp src/etc.cpp src/config.cpp + src/settingsmenu.cpp + src/keybindings.cpp src/tileatlas.cpp src/sharedstate.cpp src/gl-fun.cpp diff --git a/mkxp.conf.sample b/mkxp.conf.sample index 2f119f4..2122fab 100644 --- a/mkxp.conf.sample +++ b/mkxp.conf.sample @@ -111,6 +111,19 @@ # allowSymlinks=false +# Organisation / company and application / game +# name to build the directory path where mkxp +# will store game specific data (eg. key bindings). +# If not specified, mkxp will save to a common +# directory shared by all games. Note that these +# are TWO individual config entries, and both need +# to be defined for this to take effect. +# (default: none) +# +# dataPathOrg=mycompany +# dataPathApp=mygame + + # Set the game window icon to 'path/to/icon.png' # (default: none) # diff --git a/mkxp.pro b/mkxp.pro index 8e522c9..5d17087 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -114,6 +114,8 @@ HEADERS += \ src/gl-util.h \ src/util.h \ src/config.h \ + src/settingsmenu.h \ + src/keybindings.h \ src/tileatlas.h \ src/sharedstate.h \ src/al-util.h \ @@ -158,6 +160,8 @@ SOURCES += \ src/debuglogger.cpp \ src/etc.cpp \ src/config.cpp \ + src/settingsmenu.cpp \ + src/keybindings.cpp \ src/tileatlas.cpp \ src/sharedstate.cpp \ src/gl-fun.cpp \ diff --git a/src/config.cpp b/src/config.cpp index 62d0676..160e66b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -25,6 +25,8 @@ #include #include +#include + #include #include @@ -118,6 +120,15 @@ static bool validUtf8(const char *string) return true; } +static std::string prefPath(const char *org, const char *app) +{ + char *path = SDL_GetPrefPath(org, app); + std::string str(path); + SDL_free(path); + + return str; +} + typedef std::vector StringVec; namespace po = boost::program_options; @@ -167,6 +178,8 @@ void Config::read(int argc, char *argv[]) PO_DESC(anyAltToggleFS, bool) \ PO_DESC(enableReset, bool) \ PO_DESC(allowSymlinks, bool) \ + PO_DESC(dataPathOrg, std::string) \ + PO_DESC(dataPathApp, std::string) \ PO_DESC(iconPath, std::string) \ PO_DESC(titleLanguage, std::string) \ PO_DESC(midi.soundFont, std::string) \ @@ -243,6 +256,11 @@ void Config::read(int argc, char *argv[]) rgssVersion = clamp(rgssVersion, 0, 3); SE.sourceCount = clamp(SE.sourceCount, 1, 64); + + if (!dataPathOrg.empty() && !dataPathApp.empty()) + customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str()); + + commonDataPath = prefPath(".", "mkxp"); } static std::string baseName(const std::string &path) diff --git a/src/config.h b/src/config.h index 78d75f7..e7eb357 100644 --- a/src/config.h +++ b/src/config.h @@ -51,6 +51,9 @@ struct Config bool allowSymlinks; bool pathCache; + std::string dataPathOrg; + std::string dataPathApp; + std::string iconPath; std::string titleLanguage; @@ -82,6 +85,10 @@ struct Config std::string title; } game; + /* Internal */ + std::string customDataPath; + std::string commonDataPath; + Config(); void read(int argc, char *argv[]); diff --git a/src/eventthread.cpp b/src/eventthread.cpp index fec1e5b..6678772 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -29,6 +29,7 @@ #include "sharedstate.h" #include "graphics.h" +#include "settingsmenu.h" #include "debugwriter.h" #include @@ -37,7 +38,7 @@ bool EventThread::keyStates[] = { false }; EventThread::JoyState EventThread::joyState = { - 0, 0, { false } + { 0 }, { false } }; EventThread::MouseState EventThread::mouseState = @@ -108,6 +109,8 @@ void EventThread::process(RGSSThreadData &rtData) bool resetting = false; + SettingsMenu *sMenu = 0; + while (true) { if (!SDL_WaitEvent(&event)) @@ -116,6 +119,19 @@ void EventThread::process(RGSSThreadData &rtData) break; } + if (sMenu && sMenu->onEvent(event)) + { + if (sMenu->destroyReq()) + { + delete sMenu; + sMenu = 0; + + updateCursorState(cursorInWindow && windowFocused); + } + + continue; + } + switch (event.type) { case SDL_WINDOWEVENT : @@ -129,14 +145,14 @@ void EventThread::process(RGSSThreadData &rtData) case SDL_WINDOWEVENT_ENTER : cursorInWindow = true; mouseState.inWindow = true; - updateCursorState(cursorInWindow && windowFocused); + updateCursorState(cursorInWindow && windowFocused && !sMenu); break; case SDL_WINDOWEVENT_LEAVE : cursorInWindow = false; mouseState.inWindow = false; - updateCursorState(cursorInWindow && windowFocused); + updateCursorState(cursorInWindow && windowFocused && !sMenu); break; @@ -147,13 +163,13 @@ void EventThread::process(RGSSThreadData &rtData) case SDL_WINDOWEVENT_FOCUS_GAINED : windowFocused = true; - updateCursorState(cursorInWindow && windowFocused); + updateCursorState(cursorInWindow && windowFocused && !sMenu); break; case SDL_WINDOWEVENT_FOCUS_LOST : windowFocused = false; - updateCursorState(cursorInWindow && windowFocused); + updateCursorState(cursorInWindow && windowFocused && !sMenu); resetInputStates(); break; @@ -181,6 +197,17 @@ void EventThread::process(RGSSThreadData &rtData) break; } + if (event.key.keysym.scancode == SDL_SCANCODE_F1) + { + if (!sMenu) + { + sMenu = new SettingsMenu(rtData); + updateCursorState(false); + } + + sMenu->raise(); + } + if (event.key.keysym.scancode == SDL_SCANCODE_F2) { if (!fps.displaying) @@ -248,11 +275,7 @@ void EventThread::process(RGSSThreadData &rtData) break; case SDL_JOYAXISMOTION : - if (event.jaxis.axis == 0) - joyState.xAxis = event.jaxis.value; - else - joyState.yAxis = event.jaxis.value; - + joyState.axis[event.jaxis.axis] = event.jaxis.value; break; case SDL_JOYDEVICEADDED : @@ -333,6 +356,8 @@ void EventThread::process(RGSSThreadData &rtData) if (SDL_JoystickGetAttached(js)) SDL_JoystickClose(js); + + delete sMenu; } void EventThread::cleanup() diff --git a/src/eventthread.h b/src/eventthread.h index 013f60b..ec5e8bb 100644 --- a/src/eventthread.h +++ b/src/eventthread.h @@ -25,6 +25,7 @@ #include "config.h" #include "etc-internal.h" #include "sdl-util.h" +#include "keybindings.h" #include #include @@ -45,10 +46,8 @@ public: struct JoyState { - int xAxis; - int yAxis; - - bool buttons[16]; + int axis[256]; + bool buttons[256]; }; static JoyState joyState; @@ -155,6 +154,55 @@ struct WindowSizeNotify } }; +struct BindingNotify +{ + BindingNotify() + { + mut = SDL_CreateMutex(); + } + ~BindingNotify() + { + SDL_DestroyMutex(mut); + } + + bool poll(BDescVec &out) const + { + if (!changed) + return false; + + SDL_LockMutex(mut); + + out = data; + changed.clear(); + + SDL_UnlockMutex(mut); + + return true; + } + + void get(BDescVec &out) const + { + SDL_LockMutex(mut); + out = data; + SDL_UnlockMutex(mut); + } + + void post(const BDescVec &d) + { + SDL_LockMutex(mut); + + changed.set(); + data = d; + + SDL_UnlockMutex(mut); + } + +private: + SDL_mutex *mut; + BDescVec data; + mutable AtomicFlag changed; +}; + struct RGSSThreadData { /* Main thread sets this to request RGSS thread to terminate */ @@ -171,6 +219,7 @@ struct RGSSThreadData EventThread *ethread; WindowSizeNotify windowSizeMsg; + BindingNotify bindingUpdateMsg; const char *argv0; diff --git a/src/font.cpp b/src/font.cpp index 6a04316..ea8c736 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -195,6 +195,13 @@ bool SharedFontState::fontPresent(std::string family) return !(set.regular.empty() && set.other.empty()); } +_TTF_Font *SharedFontState::openBundled(int size) +{ + SDL_RWops *ops = openBundledFont(); + + return TTF_OpenFontRW(ops, 1, size); +} + struct FontPrivate { diff --git a/src/font.h b/src/font.h index 9320600..a37c935 100644 --- a/src/font.h +++ b/src/font.h @@ -49,6 +49,8 @@ public: bool fontPresent(std::string family); + static _TTF_Font *openBundled(int size); + private: SharedFontStatePrivate *p; }; diff --git a/src/input.cpp b/src/input.cpp index fd53698..1cae58a 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -22,6 +22,7 @@ #include "input.h" #include "sharedstate.h" #include "eventthread.h" +#include "keybindings.h" #include "exception.h" #include "util.h" @@ -30,6 +31,7 @@ #include #include +#include #define BUTTON_CODE_COUNT 24 @@ -52,12 +54,6 @@ struct KbBindingData Input::ButtonCode target; }; -struct JsBindingData -{ - int source; - Input::ButtonCode target; -}; - struct Binding { Binding(Input::ButtonCode target = Input::None) @@ -82,6 +78,15 @@ struct KbBinding : public Binding bool sourceActive() const { + /* Special case aliases */ + if (source == SDL_SCANCODE_LSHIFT) + return EventThread::keyStates[source] + || EventThread::keyStates[SDL_SCANCODE_RSHIFT]; + + if (source == SDL_SCANCODE_RETURN) + return EventThread::keyStates[source] + || EventThread::keyStates[SDL_SCANCODE_KP_ENTER]; + return EventThread::keyStates[source]; } @@ -100,11 +105,6 @@ struct JsButtonBinding : public Binding { JsButtonBinding() {} - JsButtonBinding(const JsBindingData &data) - : Binding(data.target), - source(data.source) - {} - bool sourceActive() const { return EventThread::joyState.buttons[source]; @@ -115,7 +115,7 @@ struct JsButtonBinding : public Binding return true; } - int source; + uint8_t source; }; /* Joystick axis binding */ @@ -123,17 +123,22 @@ struct JsAxisBinding : public Binding { JsAxisBinding() {} - JsAxisBinding(int *source, - int compareValue, + JsAxisBinding(uint8_t source, + AxisDir dir, Input::ButtonCode target) : Binding(target), source(source), - compareValue(compareValue) + dir(dir) {} bool sourceActive() const { - return (*source == compareValue); + int val = EventThread::joyState.axis[source]; + + if (dir == Negative) + return val < -JAXIS_THRESHOLD; + else /* dir == Positive */ + return val > JAXIS_THRESHOLD; } bool sourceRepeatable() const @@ -141,8 +146,8 @@ struct JsAxisBinding : public Binding return true; } - int *source; - int compareValue; + uint8_t source; + AxisDir dir; }; /* Mouse button binding */ @@ -172,10 +177,6 @@ struct MsBinding : public Binding /* Not rebindable */ static const KbBindingData staticKbBindings[] = { - { SDL_SCANCODE_LEFT, Input::Left }, - { SDL_SCANCODE_RIGHT, Input::Right }, - { SDL_SCANCODE_UP, Input::Up }, - { SDL_SCANCODE_DOWN, Input::Down }, { SDL_SCANCODE_LSHIFT, Input::Shift }, { SDL_SCANCODE_RSHIFT, Input::Shift }, { SDL_SCANCODE_LCTRL, Input::Ctrl }, @@ -191,61 +192,6 @@ static const KbBindingData staticKbBindings[] = static elementsN(staticKbBindings); -/* Rebindable */ -static const KbBindingData defaultKbBindings[] = -{ - { SDL_SCANCODE_SPACE, Input::C }, - { SDL_SCANCODE_RETURN, Input::C }, - { SDL_SCANCODE_KP_ENTER, Input::C }, /* Treated as alias of RETURN */ - { SDL_SCANCODE_ESCAPE, Input::B }, - { SDL_SCANCODE_KP_0, Input::B }, - { SDL_SCANCODE_LSHIFT, Input::A }, - { SDL_SCANCODE_RSHIFT, Input::A }, - { SDL_SCANCODE_X, Input::B }, - { SDL_SCANCODE_B, Input::None }, - { SDL_SCANCODE_D, Input::Z }, - { SDL_SCANCODE_Q, Input::L }, - { SDL_SCANCODE_W, Input::R }, - { SDL_SCANCODE_V, Input::None }, - { SDL_SCANCODE_A, Input::X }, - { SDL_SCANCODE_S, Input::Y } -}; - -/* RGSS1 */ -static const KbBindingData defaultKbBindings1[] = -{ - { SDL_SCANCODE_Z, Input::A }, - { SDL_SCANCODE_C, Input::C }, -}; - -/* RGSS2 and higher */ -static const KbBindingData defaultKbBindings2[] = -{ - { SDL_SCANCODE_Z, Input::C }, - { SDL_SCANCODE_C, Input::None }, -}; - -static elementsN(defaultKbBindings); -static elementsN(defaultKbBindings1); -static elementsN(defaultKbBindings2); - -/* Rebindable */ -static const JsBindingData defaultJsBindings[] = -{ - { 0, Input::A }, - { 1, Input::B }, - { 2, Input::C }, - { 3, Input::X }, - { 4, Input::Y }, - { 5, Input::Z }, - { 6, Input::L }, - { 7, Input::R }, - { 8, Input::None }, - { 9, Input::None } -}; - -static elementsN(defaultJsBindings); - /* Maps ButtonCode enum values to indices * in the button state array */ static const int mapToIndex[] = @@ -292,6 +238,7 @@ static const Input::ButtonCode otherDirs[4][3] = struct InputPrivate { + std::vector kbStatBindings; std::vector kbBindings; std::vector jsABindings; std::vector jsBBindings; @@ -320,12 +267,14 @@ struct InputPrivate } dir8Data; - InputPrivate() + InputPrivate(const RGSSThreadData &rtData) { - initKbBindings(); - initJsBindings(); + initStaticKbBindings(); initMsBindings(); + /* Main thread should have these posted by now */ + checkBindingChange(rtData); + states = stateArray; statesOld = stateArray + BUTTON_CODE_COUNT; @@ -378,51 +327,90 @@ struct InputPrivate memset(states, 0, size); } - void initKbBindings() + void checkBindingChange(const RGSSThreadData &rtData) { - kbBindings.clear(); + BDescVec d; - for (size_t i = 0; i < staticKbBindingsN; ++i) - kbBindings.push_back(KbBinding(staticKbBindings[i])); + if (!rtData.bindingUpdateMsg.poll(d)) + return; - for (size_t i = 0; i < defaultKbBindingsN; ++i) - kbBindings.push_back(KbBinding(defaultKbBindings[i])); - - if (rgssVer == 1) - for (size_t i = 0; i < defaultKbBindings1N; ++i) - kbBindings.push_back(KbBinding(defaultKbBindings1[i])); - else - for (size_t i = 0; i < defaultKbBindings2N; ++i) - kbBindings.push_back(KbBinding(defaultKbBindings2[i])); - - /* Add to binging array */ - for (size_t i = 0; i < kbBindings.size(); ++i) - bindings.push_back(&kbBindings[i]); + applyBindingDesc(d); } - void initJsBindings() + template + void appendBindings(std::vector &bind) { - /* Create axis bindings */ - jsABindings.resize(4); + for (size_t i = 0; i < bind.size(); ++i) + bindings.push_back(&bind[i]); + } - size_t i = 0; - jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, 0x7FFF, Input::Right); - jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, -0x8000, Input::Left); - jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, 0x7FFF, Input::Down); - jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, -0x8000, Input::Up); + void applyBindingDesc(const BDescVec &d) + { + kbBindings.clear(); + jsABindings.clear(); + jsBBindings.clear(); - /* Create button bindings */ - jsBBindings.resize(defaultJsBindingsN); + for (size_t i = 0; i < d.size(); ++i) + { + const BindingDesc &desc = d[i]; + const SourceDesc &src = desc.src; - for (size_t i = 0; i < defaultJsBindingsN; ++i) - jsBBindings[i] = JsButtonBinding(defaultJsBindings[i]); + if (desc.target == Input::None) + continue; - /* Add to binging array */ - for (size_t i = 0; i < jsABindings.size(); ++i) - bindings.push_back(&jsABindings[i]); + switch (desc.src.type) + { + case Invalid : + break; + case Key : + { + KbBinding bind; + bind.source = src.d.scan; + bind.target = desc.target; + kbBindings.push_back(bind); - for (size_t i = 0; i < jsBBindings.size(); ++i) - bindings.push_back(&jsBBindings[i]); + break; + } + case JAxis : + { + JsAxisBinding bind; + bind.source = src.d.ja.axis; + bind.dir = src.d.ja.dir; + bind.target = desc.target; + jsABindings.push_back(bind); + + break; + } + case JButton : + { + JsButtonBinding bind; + bind.source = src.d.jb; + bind.target = desc.target; + jsBBindings.push_back(bind); + + break; + } + default : + assert(!"unreachable"); + } + } + + bindings.clear(); + + appendBindings(kbStatBindings); + appendBindings(msBindings); + + appendBindings(kbBindings); + appendBindings(jsABindings); + appendBindings(jsBBindings); + } + + void initStaticKbBindings() + { + kbStatBindings.clear(); + + for (size_t i = 0; i < staticKbBindingsN; ++i) + kbStatBindings.push_back(KbBinding(staticKbBindings[i])); } void initMsBindings() @@ -433,10 +421,6 @@ struct InputPrivate msBindings[i++] = MsBinding(SDL_BUTTON_LEFT, Input::MouseLeft); msBindings[i++] = MsBinding(SDL_BUTTON_MIDDLE, Input::MouseMiddle); msBindings[i++] = MsBinding(SDL_BUTTON_RIGHT, Input::MouseRight); - - /* Add to binding array */ - for (size_t i = 0; i < msBindings.size(); ++i) - bindings.push_back(&msBindings[i]); } void pollBindings(Input::ButtonCode &repeatCand) @@ -564,14 +548,15 @@ struct InputPrivate }; -Input::Input() +Input::Input(const RGSSThreadData &rtData) { - p = new InputPrivate; + p = new InputPrivate(rtData); } void Input::update() { shState->checkShutdown(); + p->checkBindingChange(shState->rtData()); p->swapBuffers(); p->clearBuffer(); diff --git a/src/input.h b/src/input.h index 2a4e501..5448338 100644 --- a/src/input.h +++ b/src/input.h @@ -23,6 +23,7 @@ #define INPUT_H struct InputPrivate; +struct RGSSThreadData; class Input { @@ -59,7 +60,7 @@ public: int mouseY(); private: - Input(); + Input(const RGSSThreadData &rtData); ~Input(); friend struct SharedStatePrivate; diff --git a/src/keybindings.cpp b/src/keybindings.cpp new file mode 100644 index 0000000..a867b79 --- /dev/null +++ b/src/keybindings.cpp @@ -0,0 +1,311 @@ +/* +** keybindings.cpp +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with mkxp. If not, see . +*/ + +#include "keybindings.h" + +#include "config.h" +#include "util.h" + +#include + +struct KbBindingData +{ + SDL_Scancode source; + Input::ButtonCode target; + + void add(BDescVec &d) const + { + SourceDesc src; + src.type = Key; + src.d.scan = source; + + BindingDesc desc; + desc.src = src; + desc.target = target; + + d.push_back(desc); + } +}; + +struct JsBindingData +{ + int source; + Input::ButtonCode target; + + void add(BDescVec &d) const + { + SourceDesc src; + src.type = JButton; + src.d.jb = source; + + BindingDesc desc; + desc.src = src; + desc.target = target; + + d.push_back(desc); + } +}; + +/* Common */ +static const KbBindingData defaultKbBindings[] = +{ + { SDL_SCANCODE_LEFT, Input::Left }, + { SDL_SCANCODE_RIGHT, Input::Right }, + { SDL_SCANCODE_UP, Input::Up }, + { SDL_SCANCODE_DOWN, Input::Down }, + { SDL_SCANCODE_SPACE, Input::C }, + { SDL_SCANCODE_RETURN, Input::C }, + { SDL_SCANCODE_ESCAPE, Input::B }, + { SDL_SCANCODE_KP_0, Input::B }, + { SDL_SCANCODE_LSHIFT, Input::A }, + { SDL_SCANCODE_X, Input::B }, + { SDL_SCANCODE_D, Input::Z }, + { SDL_SCANCODE_Q, Input::L }, + { SDL_SCANCODE_W, Input::R }, + { SDL_SCANCODE_A, Input::X }, + { SDL_SCANCODE_S, Input::Y } +}; + +/* RGSS1 */ +static const KbBindingData defaultKbBindings1[] = +{ + { SDL_SCANCODE_Z, Input::A }, + { SDL_SCANCODE_C, Input::C }, +}; + +/* RGSS2 and higher */ +static const KbBindingData defaultKbBindings2[] = +{ + { SDL_SCANCODE_Z, Input::C } +}; + +static elementsN(defaultKbBindings); +static elementsN(defaultKbBindings1); +static elementsN(defaultKbBindings2); + +static const JsBindingData defaultJsBindings[] = +{ + { 0, Input::A }, + { 1, Input::B }, + { 2, Input::C }, + { 3, Input::X }, + { 4, Input::Y }, + { 5, Input::Z }, + { 6, Input::L }, + { 7, Input::R } +}; + +static elementsN(defaultJsBindings); + +static void addAxisBinding(BDescVec &d, uint8_t axis, AxisDir dir, Input::ButtonCode target) +{ + SourceDesc src; + src.type = JAxis; + src.d.ja.axis = axis; + src.d.ja.dir = dir; + + BindingDesc desc; + desc.src = src; + desc.target = target; + + d.push_back(desc); +} + +BDescVec genDefaultBindings(const Config &conf) +{ + BDescVec d; + + for (size_t i = 0; i < defaultKbBindingsN; ++i) + defaultKbBindings[i].add(d); + + if (conf.rgssVersion == 1) + for (size_t i = 0; i < defaultKbBindings1N; ++i) + defaultKbBindings1[i].add(d); + else + for (size_t i = 0; i < defaultKbBindings2N; ++i) + defaultKbBindings2[i].add(d); + + for (size_t i = 0; i < defaultJsBindingsN; ++i) + defaultJsBindings[i].add(d); + + addAxisBinding(d, 0, Negative, Input::Left ); + addAxisBinding(d, 0, Positive, Input::Right); + addAxisBinding(d, 1, Negative, Input::Up ); + addAxisBinding(d, 1, Positive, Input::Down ); + + return d; +} + +#define FORMAT_VER 1 + +struct Header +{ + uint32_t formVer; + uint32_t rgssVer; + uint32_t count; +}; + +static void buildPath(const std::string &dir, uint32_t rgssVersion, + char *out, size_t outSize) +{ + snprintf(out, outSize, "%s/keybindings.mkxp%u", dir.c_str(), rgssVersion); +} + +static bool writeBindings(const BDescVec &d, const std::string &dir, + uint32_t rgssVersion) +{ + if (dir.empty()) + return false; + + char path[1024]; + buildPath(dir, rgssVersion, path, sizeof(path)); + + FILE *f = fopen(path, "w"); + + if (!f) + return false; + + Header hd; + hd.formVer = FORMAT_VER; + hd.rgssVer = rgssVersion; + hd.count = d.size(); + + if (fwrite(&hd, sizeof(hd), 1, f) < 1) + { + fclose(f); + return false; + } + + if (fwrite(&d[0], sizeof(d[0]), hd.count, f) < hd.count) + { + fclose(f); + return false; + } + + fclose(f); + return true; +} + +void storeBindings(const BDescVec &d, const Config &conf) +{ + if (writeBindings(d, conf.customDataPath, conf.rgssVersion)) + return; + + writeBindings(d, conf.commonDataPath, conf.rgssVersion); +} + +#define READ(ptr, size, n, f) if (fread(ptr, size, n, f) < n) return false + +static bool verifyDesc(const BindingDesc &desc) +{ + const Input::ButtonCode codes[] = + { + Input::None, + Input::Down, Input::Left, Input::Right, Input::Up, + Input::A, Input::B, Input::C, + Input::X, Input::Y, Input::Z, + Input::L, Input::R, + Input::Shift, Input::Ctrl, Input::Alt, + Input::F5, Input::F6, Input::F7, Input::F8, Input::F9 + }; + + elementsN(codes); + size_t i; + + for (i = 0; i < codesN; ++i) + if (desc.target == codes[i]) + break; + + if (i == codesN) + return false; + + const SourceDesc &src = desc.src; + + switch (src.type) + { + case Invalid: + return true; + case Key: + return src.d.scan < SDL_NUM_SCANCODES; + case JButton: + return true; + case JAxis: + return src.d.ja.dir == Negative || src.d.ja.dir == Positive; + default: + return false; + } +} + +static bool readBindings(BDescVec &out, const std::string &dir, + uint32_t rgssVersion) +{ + if (dir.empty()) + return false; + + char path[1024]; + buildPath(dir, rgssVersion, path, sizeof(path)); + + FILE *f = fopen(path, "r"); + + if (!f) + return false; + + Header hd; + if (fread(&hd, sizeof(hd), 1, f) < 1) + { + fclose(f); + return false; + } + + if (hd.formVer != FORMAT_VER) + return false; + if (hd.rgssVer != rgssVersion) + return false; + /* Arbitrary max value */ + if (hd.count > 1024) + return false; + + out.resize(hd.count); + if (fread(&out[0], sizeof(out[0]), hd.count, f) < hd.count) + { + fclose(f); + return false; + } + + for (size_t i = 0; i < hd.count; ++i) + if (!verifyDesc(out[i])) + return false; + + return true; +} + +BDescVec loadBindings(const Config &conf) +{ + BDescVec d; + + if (readBindings(d, conf.customDataPath, conf.rgssVersion)) + return d; + + if (readBindings(d, conf.commonDataPath, conf.rgssVersion)) + return d; + + return genDefaultBindings(conf); +} diff --git a/src/keybindings.h b/src/keybindings.h new file mode 100644 index 0000000..9bd6c43 --- /dev/null +++ b/src/keybindings.h @@ -0,0 +1,108 @@ +/* +** keybindings.h +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with mkxp. If not, see . +*/ + +#ifndef KEYBINDINGS_H +#define KEYBINDINGS_H + +#include "input.h" + +#include +#include +#include +#include + +enum AxisDir +{ + Negative, + Positive +}; + +enum SourceType +{ + Invalid, + Key, + JButton, + JAxis +}; + +struct SourceDesc +{ + SourceType type; + + union Data + { + /* Keyboard scancode */ + SDL_Scancode scan; + /* Joystick button index */ + uint8_t jb; + struct + { + /* Joystick axis index */ + uint8_t axis; + /* Joystick axis direction */ + AxisDir dir; + } ja; + } d; + + bool operator==(const SourceDesc &o) const + { + if (type != o.type) + return false; + + switch (type) + { + case Invalid: + return true; + case Key: + return d.scan == o.d.scan; + case JButton: + return d.jb == o.d.jb; + case JAxis: + return (d.ja.axis == o.d.ja.axis) && (d.ja.dir == o.d.ja.dir); + default: + assert(!"unreachable"); + return false; + } + } + + bool operator!=(const SourceDesc &o) const + { + return !(*this == o); + } +}; + +#define JAXIS_THRESHOLD 0x4000 + +struct BindingDesc +{ + SourceDesc src; + Input::ButtonCode target; +}; + +typedef std::vector BDescVec; +struct Config; + +BDescVec genDefaultBindings(const Config &conf); + +void storeBindings(const BDescVec &d, const Config &conf); +BDescVec loadBindings(const Config &conf); + +#endif // KEYBINDINGS_H diff --git a/src/main.cpp b/src/main.cpp index ae3def8..8c840ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -238,7 +238,7 @@ int main(int argc, char *argv[]) SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0"); SDL_Window *win; - Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; + Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS; if (conf.winResizable) winFlags |= SDL_WINDOW_RESIZABLE; @@ -268,6 +268,9 @@ int main(int argc, char *argv[]) EventThread eventThread; RGSSThreadData rtData(&eventThread, argv[0], win, conf); + /* Load and post key bindings */ + rtData.bindingUpdateMsg.post(loadBindings(conf)); + /* Start RGSS thread */ SDL_Thread *rgssThread = SDL_CreateThread(rgssThreadFun, "rgss", &rtData); @@ -310,6 +313,11 @@ int main(int argc, char *argv[]) /* Clean up any remainin events */ eventThread.cleanup(); + /* Store key bindings */ + BDescVec keyBinds; + rtData.bindingUpdateMsg.get(keyBinds); + storeBindings(keyBinds, rtData.config); + Debug() << "Shutting down."; SDL_DestroyWindow(win); diff --git a/src/settingsmenu.cpp b/src/settingsmenu.cpp new file mode 100644 index 0000000..99bfe51 --- /dev/null +++ b/src/settingsmenu.cpp @@ -0,0 +1,1112 @@ +/* +** settingsmenu.cpp +** +** This file is part of mkxp. +** +** Copyright (C) 2014 Jonas Kulla +** +** mkxp is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** mkxp is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with mkxp. If not, see . +*/ + +#include "settingsmenu.h" + +#include +#include +#include +#include +#include + +#include "keybindings.h" +#include "eventthread.h" +#include "font.h" +#include "input.h" +#include "etc-internal.h" +#include "util.h" + +#include +#include + +const Vec2i winSize(540, 356); + +const uint8_t cBgNorm = 50; +const uint8_t cBgDark = 20; +const uint8_t cLine = 0; +const uint8_t cText = 255; + +const uint8_t frameWidth = 4; +const uint8_t fontSize = 15; + +static bool pointInRect(const SDL_Rect &r, int x, int y) +{ + return (x >= r.x && x <= r.x+r.w && y >= r.y && y <= r.y+r.h); +} + +typedef SettingsMenuPrivate SMP; + +#define BTN_STRING(btn) { Input:: btn, #btn } +struct VButton +{ + Input::ButtonCode code; + const char *str; +} static const vButtons[] = +{ + BTN_STRING(Up), + BTN_STRING(Down), + BTN_STRING(L), + BTN_STRING(Left), + BTN_STRING(Right), + BTN_STRING(R), + BTN_STRING(A), + BTN_STRING(B), + BTN_STRING(C), + BTN_STRING(X), + BTN_STRING(Y), + BTN_STRING(Z) +}; + +static elementsN(vButtons); + +/* Human readable string representation */ +std::string sourceDescString(const SourceDesc &src) +{ + char buf[128]; + + switch (src.type) + { + case Invalid: + return std::string(); + + case Key: + { + if (src.d.scan == SDL_SCANCODE_LSHIFT) + return "Shift"; + + SDL_Keycode key = SDL_GetKeyFromScancode(src.d.scan); + const char *str = SDL_GetKeyName(key); + + if (*str == '\0') + return "Unknown key"; + else + return str; + } + case JButton: + snprintf(buf, sizeof(buf), "JS %d", src.d.jb); + return buf; + + case JAxis: + snprintf(buf, sizeof(buf), "Axis %d%c", + src.d.ja.axis, src.d.ja.dir == Negative ? '-' : '+'); + return buf; + } + + assert(!"unreachable"); + return ""; +} + +struct Widget +{ + /* Widgets have a static size and position, + * defined at creation */ + Widget(SMP *p, const IntRect &rect); + + /* Public methods take coordinates in global + * window coordinates */ + bool hit(int x, int y); + void draw(SDL_Surface *surf); + void motion(int x, int y); + void leave(); + void click(int x, int y, uint8_t button); + +protected: + SMP *p; + IntRect rect; + + /* Protected abstract methods are called with + * widget-local coordinates */ + virtual void drawHandler(SDL_Surface *surf) = 0; + virtual void motionHandler(int x, int y) = 0; + virtual void leaveHandler() = 0; + virtual void clickHandler(int x, int y, uint8_t button) = 0; +}; + +struct BindingWidget : Widget +{ + VButton vb; + /* Source slots */ + SourceDesc src[4]; + /* Flag indicating whether a slot source is used + * for multiple button targets (red indicator) */ + bool dupFlag[4]; + + BindingWidget(int vbIndex, SMP *p, const IntRect &rect) + : Widget(p, rect), + vb(vButtons[vbIndex]), + hoveredCell(-1) + {} + + void appendBindings(BDescVec &d) const; + +protected: + int hoveredCell; + void setHoveredCell(int cell); + /* Get the slot cell index that contains (x,y), + * or -1 if none */ + int cellIndex(int x, int y) const; + + void drawHandler(SDL_Surface *surf); + void motionHandler(int x, int y); + void leaveHandler(); + void clickHandler(int x, int y, uint8_t button); +}; + +struct Button : Widget +{ + typedef void (SMP::*Callback)(); + + const char *str; + Callback cb; + + Button(SMP *p, const IntRect &rect, + const char *str, Callback cb) + : Widget(p, rect), + str(str), cb(cb), hovered(false) + {} + +protected: + bool hovered; + + void setHovered(bool val); + + void drawHandler(SDL_Surface *surf); + void motionHandler(int, int); + void leaveHandler(); + void clickHandler(int, int, uint8_t button); +}; + +struct Label : Widget +{ + const char *str; + SDL_Color c; + + Label() : Widget(0, IntRect()) {} + + Label(SMP *p, const IntRect &rect, + const char *str, uint8_t r, uint8_t g, uint8_t b) + : Widget(p, rect), + str(str) + { + c.r = r; + c.g = g; + c.b = b; + c.a = 255; + } + + void setVisible(bool val); + +protected: + bool visible; + + void drawHandler(SDL_Surface *surf); + void motionHandler(int, int) {} + void leaveHandler() {} + void clickHandler(int, int, uint8_t) {} +}; + +enum State +{ + Idle, + AwaitingInput +}; + +enum Justification +{ + Left, + Center +}; + +struct SettingsMenuPrivate +{ + State state; + + /* Necessary to decide which window gets to + * process joystick events */ + bool hasFocus; + + /* Tell the outer EventThread to destroy us */ + bool destroyReq; + + /* Offset added for all draw calls */ + Vec2i drawOff; + + SDL_Window *window; + SDL_Surface *winSurf; + uint32_t winID; + + TTF_Font *font; + SDL_PixelFormat *rgb; + + RGSSThreadData &rtData; + + std::vector bWidgets; + std::vector