Merge branch 'dev'

This commit is contained in:
Jonas Kulla 2014-04-17 08:19:24 +02:00
commit 58d86039d5
46 changed files with 1121 additions and 632 deletions

View File

@ -44,7 +44,7 @@ This binding only exists for testing purposes and does nothing (the engine quits
* pixman * pixman
* zlib (only ruby bindings) * zlib (only ruby bindings)
mkxp employs Qt's qmake build system, so you'll need to install that beforehand. mkxp employs Qt's qmake build system, so you'll need to install that beforehand. Alternatively, you can build with cmake (FIXME: add cmake instructions).
qmake will use pkg-config to locate the respective include/library paths. If you installed any dependencies into non-standard prefixes, make sure to adjust your `PKG_CONFIG_PATH` variable accordingly. qmake will use pkg-config to locate the respective include/library paths. If you installed any dependencies into non-standard prefixes, make sure to adjust your `PKG_CONFIG_PATH` variable accordingly.
@ -89,5 +89,5 @@ If a requested font is not found, no error is generated. Instead, a built-in fon
To alleviate possible porting of heavily Win32API reliant scripts, I have added certain functionality that you won't find in the RGSS spec. Currently this amounts to the following: To alleviate possible porting of heavily Win32API reliant scripts, I have added certain functionality that you won't find in the RGSS spec. Currently this amounts to the following:
* The `Input.press?` family of functions accepts three additional button constants: `::MOUSELEFT`, `::MOUSEMIDDLE` and `::MOUSERIGHT` for the respective mouse buttons. * The `Input.press?` family of functions accepts three additional button constants: `::MOUSELEFT`, `::MOUSEMIDDLE` and `::MOUSERIGHT` for the respective mouse buttons.
* The `Input` module has two additional functions, `#mouse_x` and `#mouse_y` to query the mouse pointer position relative to the game window. * The `Input` module has two additional functions, `#mouse_x` and `#mouse_y` to query the mouse pointer position relative to the game screen.
* The `Graphics` module has two additional properties: `fullscreen` represents the current fullscreen mode (`true` = fullscreen, `false` = windowed), `show_cursor` hides the system cursor inside the game window when `false`. * The `Graphics` module has two additional properties: `fullscreen` represents the current fullscreen mode (`true` = fullscreen, `false` = windowed), `show_cursor` hides the system cursor inside the game window when `false`.

View File

@ -88,8 +88,13 @@ static void mriBindingInit()
fileIntBindingInit(); fileIntBindingInit();
#ifdef RGSS3
_rb_define_module_function(rb_mKernel, "msgbox", mriPrint);
_rb_define_module_function(rb_mKernel, "msgbox_p", mriP);
#else
_rb_define_module_function(rb_mKernel, "print", mriPrint); _rb_define_module_function(rb_mKernel, "print", mriPrint);
_rb_define_module_function(rb_mKernel, "p", mriP); _rb_define_module_function(rb_mKernel, "p", mriP);
#endif
rb_eval_string(module_rpg); rb_eval_string(module_rpg);

View File

@ -237,6 +237,24 @@ rb_get_args(int argc, VALUE *argv, const char *format, ...)
break; break;
} }
case 'n' :
{
if (argI >= argc)
break;
ID *sym = va_arg(ap, ID*);
VALUE symVal = *arg++;
if (!SYMBOL_P(symVal))
rb_raise(rb_eTypeError, "Argument %d: Expected symbol", argI);
*sym = SYM2ID(symVal);
++argI;
break;
}
case '|' : case '|' :
opt = true; opt = true;
break; break;

View File

@ -131,7 +131,7 @@ wrapNilProperty(VALUE self, const char *iv)
rb_iv_set(self, iv, Qnil); rb_iv_set(self, iv, Qnil);
} }
/* Implemented: oSszfib| */ /* Implemented: oSszfibn| */
int int
rb_get_args(int argc, VALUE *argv, const char *format, ...); rb_get_args(int argc, VALUE *argv, const char *format, ...);

View File

@ -52,12 +52,14 @@ RB_METHOD(bitmapInitialize)
setPrivateData(self, b); setPrivateData(self, b);
/* Wrap properties */ /* Wrap properties */
Font *font = new Font(); VALUE fontKlass = rb_const_get(rb_cObject, rb_intern("Font"));
b->setFont(font); VALUE fontObj = rb_obj_alloc(fontKlass);
font->setColor(new Color(*font->getColor())); rb_obj_call_init(fontObj, 0, 0);
VALUE fontProp = wrapProperty(self, font, "font", FontType); Font *font = getPrivateData<Font>(fontObj);
wrapProperty(fontProp, font->getColor(), "color", ColorType); b->setFont(font);
rb_iv_set(self, "font", fontObj);
return self; return self;
} }
@ -202,7 +204,7 @@ RB_METHOD(bitmapGetPixel)
return Qnil; return Qnil;
) )
Vec4 value; Color value;
GUARD_EXC( value = b->getPixel(x, y); ); GUARD_EXC( value = b->getPixel(x, y); );
Color *color = new Color(value); Color *color = new Color(value);
@ -223,7 +225,7 @@ RB_METHOD(bitmapSetPixel)
color = getPrivateDataCheck<Color>(colorObj, ColorType); color = getPrivateDataCheck<Color>(colorObj, ColorType);
GUARD_EXC( b->setPixel(x, y, color->norm); ); GUARD_EXC( b->setPixel(x, y, *color); );
return self; return self;
} }

View File

@ -23,6 +23,9 @@
#include "binding-util.h" #include "binding-util.h"
#include "binding-types.h" #include "binding-types.h"
#include "exception.h" #include "exception.h"
#include "sharedstate.h"
#include <string.h>
DEF_TYPE(Font); DEF_TYPE(Font);
@ -36,14 +39,16 @@ RB_METHOD(fontDoesExist)
return rb_bool_new(Font::doesExist(name)); return rb_bool_new(Font::doesExist(name));
} }
RB_METHOD(FontSetName);
RB_METHOD(fontInitialize) RB_METHOD(fontInitialize)
{ {
const char *name = 0; VALUE name = Qnil;
int size = 0; int size = 0;
rb_get_args(argc, argv, "|zi", &name, &size RB_ARG_END); rb_get_args(argc, argv, "|oi", &name, &size RB_ARG_END);
Font *f = new Font(name, size); Font *f = new Font(0, size);
setPrivateData(self, f); setPrivateData(self, f);
@ -51,6 +56,13 @@ RB_METHOD(fontInitialize)
f->setColor(new Color(*f->getColor())); f->setColor(new Color(*f->getColor()));
wrapProperty(self, f->getColor(), "color", ColorType); wrapProperty(self, f->getColor(), "color", ColorType);
if (NIL_P(name))
name = rb_iv_get(rb_obj_class(self), "default_name");
/* Going over the 'name=' function automatically causes
* a possbile name array to be re-verified for existing fonts */
FontSetName(1, &name, self);
return self; return self;
} }
@ -77,21 +89,63 @@ RB_METHOD(FontGetName)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
Font *f = getPrivateData<Font>(self); return rb_iv_get(self, "name");
}
return rb_str_new_cstr(f->getName()); static void
fontSetNameHelper(VALUE self, int argc, VALUE *argv,
const char *nameIv, char *outBuf, size_t outLen)
{
rb_check_argc(argc, 1);
VALUE arg = argv[0];
int type = rb_type(arg);
// Fixme: in RGSS3, specifying "" (and only that) as font name results in
// no text being drawn (everything else is substituted with Arial I think)
strncpy(outBuf, "", outLen);
if (type == RUBY_T_STRING)
{
strncpy(outBuf, RSTRING_PTR(arg), outLen);
}
else if (type == RUBY_T_ARRAY)
{
for (long i = 0; i < RARRAY_LEN(arg); ++i)
{
VALUE str = rb_ary_entry(arg, i);
/* Non-string objects are tolerated (ignored) */
if (rb_type(str) != RUBY_T_STRING)
continue;
const char *family = RSTRING_PTR(str);
/* We only set the core Font object's name attribute
* to the actually existing font name */
if (!shState->fontState().fontPresent(family))
continue;
strncpy(outBuf, family, outLen);
}
}
/* RMXP doesn't even care if the argument type is
* something other than string/array. Whatever... */
rb_iv_set(self, nameIv, arg);
} }
RB_METHOD(FontSetName) RB_METHOD(FontSetName)
{ {
Font *f = getPrivateData<Font>(self); Font *f = getPrivateData<Font>(self);
VALUE name; char result[256];
rb_get_args(argc, argv, "S", &name RB_ARG_END); fontSetNameHelper(self, argc, argv, "default_name",
result, sizeof(result));
f->setName(RSTRING_PTR(name)); f->setName(result);
return name; return argv[0];
} }
#undef DEF_PROP_CHK_DISP #undef DEF_PROP_CHK_DISP
@ -124,18 +178,19 @@ DEF_KLASS_PROP(Font, bool, DefaultItalic, "b", rb_bool_new)
RB_METHOD(FontGetDefaultName) RB_METHOD(FontGetDefaultName)
{ {
RB_UNUSED_PARAM; RB_UNUSED_PARAM;
return rb_str_new_cstr(Font::getDefaultName());
return rb_iv_get(self, "default_name");
} }
RB_METHOD(FontSetDefaultName) RB_METHOD(FontSetDefaultName)
{ {
RB_UNUSED_PARAM; char result[256];
VALUE nameObj; fontSetNameHelper(self, argc, argv, "default_name",
rb_get_args(argc, argv, "S", &nameObj RB_ARG_END); result, sizeof(result));
Font::setDefaultName(RSTRING_PTR(nameObj)); Font::setDefaultName(result);
return nameObj; return argv[0];
} }
RB_METHOD(FontGetDefaultColor) RB_METHOD(FontGetDefaultColor)
@ -174,6 +229,7 @@ fontBindingInit()
Font::setDefaultColor(new Color(*Font::getDefaultColor())); Font::setDefaultColor(new Color(*Font::getDefaultColor()));
wrapProperty(klass, Font::getDefaultColor(), "default_color", ColorType); wrapProperty(klass, Font::getDefaultColor(), "default_color", ColorType);
rb_iv_set(klass, "default_name", rb_str_new_cstr(Font::getDefaultName()));
INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name"); INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name");
INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size"); INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size");

View File

@ -99,6 +99,24 @@ RB_METHOD(graphicsFrameReset)
DEF_GRA_PROP_I(FrameRate) DEF_GRA_PROP_I(FrameRate)
DEF_GRA_PROP_I(FrameCount) DEF_GRA_PROP_I(FrameCount)
#ifdef RGSS2
RB_METHOD(graphicsWidth)
{
RB_UNUSED_PARAM;
return rb_fix_new(shState->graphics().width());
}
RB_METHOD(graphicsHeight)
{
RB_UNUSED_PARAM;
return rb_fix_new(shState->graphics().height());
}
#endif
DEF_GRA_PROP_B(Fullscreen) DEF_GRA_PROP_B(Fullscreen)
DEF_GRA_PROP_B(ShowCursor) DEF_GRA_PROP_B(ShowCursor)
@ -120,6 +138,11 @@ void graphicsBindingInit()
INIT_GRA_PROP_BIND( FrameRate, "frame_rate" ); INIT_GRA_PROP_BIND( FrameRate, "frame_rate" );
INIT_GRA_PROP_BIND( FrameCount, "frame_count" ); INIT_GRA_PROP_BIND( FrameCount, "frame_count" );
#ifdef RGSS2
_rb_define_module_function(module, "width", graphicsWidth);
_rb_define_module_function(module, "height", graphicsHeight);
#endif
INIT_GRA_PROP_BIND( Fullscreen, "fullscreen" ); INIT_GRA_PROP_BIND( Fullscreen, "fullscreen" );
INIT_GRA_PROP_BIND( ShowCursor, "show_cursor" ); INIT_GRA_PROP_BIND( ShowCursor, "show_cursor" );
} }

View File

@ -33,40 +33,45 @@ RB_METHOD(inputUpdate)
return Qnil; return Qnil;
} }
static int getButtonArg(VALUE self, int argc, VALUE *argv)
{
int num;
#ifdef RGSS3
ID sym;
rb_get_args(argc, argv, "n", &sym RB_ARG_END);
if (rb_const_defined(self, sym))
num = FIX2INT(rb_const_get(self, sym));
else
num = 0;
#else
(void) self;
rb_get_args(argc, argv, "i", &num RB_ARG_END);
#endif
return num;
}
RB_METHOD(inputPress) RB_METHOD(inputPress)
{ {
RB_UNUSED_PARAM; int num = getButtonArg(self, argc, argv);
int num; return rb_bool_new(shState->input().isPressed(num));
rb_get_args(argc, argv, "i", &num RB_ARG_END);
Input::ButtonCode bc = (Input::ButtonCode) num;
return rb_bool_new(shState->input().isPressed(bc));
} }
RB_METHOD(inputTrigger) RB_METHOD(inputTrigger)
{ {
RB_UNUSED_PARAM; int num = getButtonArg(self, argc, argv);
int num; return rb_bool_new(shState->input().isTriggered(num));
rb_get_args(argc, argv, "i", &num RB_ARG_END);
Input::ButtonCode bc = (Input::ButtonCode) num;
return rb_bool_new(shState->input().isTriggered(bc));
} }
RB_METHOD(inputRepeat) RB_METHOD(inputRepeat)
{ {
RB_UNUSED_PARAM; int num = getButtonArg(self, argc, argv);
int num; return rb_bool_new(shState->input().isRepeated(num));
rb_get_args(argc, argv, "i", &num RB_ARG_END);
Input::ButtonCode bc = (Input::ButtonCode) num;
return rb_bool_new(shState->input().isRepeated(bc));
} }
RB_METHOD(inputDir4) RB_METHOD(inputDir4)

View File

@ -69,6 +69,39 @@ DEF_PROP_F(Sprite, Angle)
DEF_PROP_B(Sprite, Mirror) DEF_PROP_B(Sprite, Mirror)
#ifdef RGSS2
RB_METHOD(spriteWidth)
{
RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self);
int value;
GUARD_EXC( value = s->getWidth(); )
return rb_fix_new(value);
}
RB_METHOD(spriteHeight)
{
RB_UNUSED_PARAM;
Sprite *s = getPrivateData<Sprite>(self);
int value;
GUARD_EXC( value = s->getHeight(); )
return rb_fix_new(value);
}
DEF_PROP_I(Sprite, WaveAmp)
DEF_PROP_I(Sprite, WaveLength)
DEF_PROP_I(Sprite, WaveSpeed)
DEF_PROP_F(Sprite, WavePhase)
#endif
void void
spriteBindingInit() spriteBindingInit()
{ {
@ -98,4 +131,14 @@ spriteBindingInit()
INIT_PROP_BIND( Sprite, BlendType, "blend_type" ); INIT_PROP_BIND( Sprite, BlendType, "blend_type" );
INIT_PROP_BIND( Sprite, Color, "color" ); INIT_PROP_BIND( Sprite, Color, "color" );
INIT_PROP_BIND( Sprite, Tone, "tone" ); INIT_PROP_BIND( Sprite, Tone, "tone" );
#ifdef RGSS2
_rb_define_method(klass, "width", spriteWidth);
_rb_define_method(klass, "height", spriteHeight);
INIT_PROP_BIND( Sprite, WaveAmp, "wave_amp" );
INIT_PROP_BIND( Sprite, WaveLength, "wave_length" );
INIT_PROP_BIND( Sprite, WaveSpeed, "wave_speed" );
INIT_PROP_BIND( Sprite, WavePhase, "wave_phase" );
#endif
} }

View File

@ -194,7 +194,7 @@ MRB_METHOD(bitmapGetPixel)
return mrb_nil_value(); return mrb_nil_value();
) )
Vec4 value; Color value;
GUARD_EXC( value = b->getPixel(x, y); ) GUARD_EXC( value = b->getPixel(x, y); )
Color *color = new Color(value); Color *color = new Color(value);
@ -215,7 +215,7 @@ MRB_METHOD(bitmapSetPixel)
color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType); color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
GUARD_EXC( b->setPixel(x, y, color->norm); ) GUARD_EXC( b->setPixel(x, y, *color); )
return mrb_nil_value(); return mrb_nil_value();
} }

View File

@ -24,22 +24,22 @@
#include "binding-types.h" #include "binding-types.h"
#include "serializable-binding.h" #include "serializable-binding.h"
#define ATTR_RW(Type, attr, arg_type, mrb_val, arg_t_s) \ #define ATTR_RW(Type, Attr, arg_type, mrb_val, arg_t_s) \
MRB_METHOD(Type##Get_##attr) \ MRB_METHOD(Type##Get##Attr) \
{ \ { \
Type *p = getPrivateData<Type>(mrb, self); \ Type *p = getPrivateData<Type>(mrb, self); \
\ \
return mrb_##mrb_val##_value(p->attr); \ return mrb_##mrb_val##_value(p->get##Attr()); \
} \ } \
\ \
MRB_METHOD(Type##Set_##attr) \ MRB_METHOD(Type##Set##Attr) \
{ \ { \
Type *p = getPrivateData<Type>(mrb, self); \ Type *p = getPrivateData<Type>(mrb, self); \
\ \
arg_type arg; \ arg_type arg; \
mrb_get_args(mrb, arg_t_s, &arg); \ mrb_get_args(mrb, arg_t_s, &arg); \
\ \
p->attr = arg; \ p->set##Attr(arg); \
UPDATE_F \ UPDATE_F \
\ \
return mrb_##mrb_val##_value(arg); \ return mrb_##mrb_val##_value(arg); \
@ -64,22 +64,22 @@
#define ATTR_INT_RW(Type, attr) ATTR_RW(Type, attr, mrb_int, fixnum, "i") #define ATTR_INT_RW(Type, attr) ATTR_RW(Type, attr, mrb_int, fixnum, "i")
#define UPDATE_F p->updateInternal(); #define UPDATE_F p->updateInternal();
ATTR_FLOAT_RW(Color, red) ATTR_FLOAT_RW(Color, Red)
ATTR_FLOAT_RW(Color, green) ATTR_FLOAT_RW(Color, Green)
ATTR_FLOAT_RW(Color, blue) ATTR_FLOAT_RW(Color, Blue)
ATTR_FLOAT_RW(Color, alpha) ATTR_FLOAT_RW(Color, Alpha)
ATTR_FLOAT_RW(Tone, red) ATTR_FLOAT_RW(Tone, Red)
ATTR_FLOAT_RW(Tone, green) ATTR_FLOAT_RW(Tone, Green)
ATTR_FLOAT_RW(Tone, blue) ATTR_FLOAT_RW(Tone, Blue)
ATTR_FLOAT_RW(Tone, gray) ATTR_FLOAT_RW(Tone, Gray)
#undef UPDATE_F #undef UPDATE_F
#define UPDATE_F #define UPDATE_F
ATTR_INT_RW(Rect, x) ATTR_INT_RW(Rect, X)
ATTR_INT_RW(Rect, y) ATTR_INT_RW(Rect, Y)
ATTR_INT_RW(Rect, width) ATTR_INT_RW(Rect, Width)
ATTR_INT_RW(Rect, height) ATTR_INT_RW(Rect, Height)
EQUAL_FUN(Color) EQUAL_FUN(Color)
EQUAL_FUN(Tone) EQUAL_FUN(Tone)
@ -163,15 +163,9 @@ CLONE_FUN(Tone)
CLONE_FUN(Color) CLONE_FUN(Color)
CLONE_FUN(Rect) CLONE_FUN(Rect)
#define MRB_ATTR_R(Class, attr) mrb_define_method(mrb, klass, #attr, Class##Get_##attr, MRB_ARGS_NONE()) #define MRB_ATTR_R(Class, Attr, sym) mrb_define_method(mrb, klass, sym, Class##Get##Attr, MRB_ARGS_NONE())
#define MRB_ATTR_W(Class, attr) mrb_define_method(mrb, klass, #attr "=", Class##Set_##attr, MRB_ARGS_REQ(1)) #define MRB_ATTR_W(Class, Attr, sym) mrb_define_method(mrb, klass, sym "=", Class##Set##Attr, MRB_ARGS_REQ(1))
#define MRB_ATTR_RW(Class, attr) { MRB_ATTR_R(Class, attr); MRB_ATTR_W(Class, attr); } #define MRB_ATTR_RW(Class, Attr, sym) { MRB_ATTR_R(Class, Attr, sym); MRB_ATTR_W(Class, Attr, sym); }
#define MRB_ATTR_RW_A(Class, attr, alias) \
{ \
mrb_define_method(mrb, klass, #alias, Class##Get_##attr, MRB_ARGS_NONE()); \
mrb_define_method(mrb, klass, #alias "=", Class##Set_##attr, MRB_ARGS_REQ(1)); \
}
#define INIT_BIND(Klass) \ #define INIT_BIND(Klass) \
{ \ { \
@ -191,21 +185,21 @@ void etcBindingInit(mrb_state *mrb)
RClass *klass; RClass *klass;
INIT_BIND(Color); INIT_BIND(Color);
MRB_ATTR_RW(Color, red); MRB_ATTR_RW(Color, Red, "red" );
MRB_ATTR_RW(Color, green); MRB_ATTR_RW(Color, Green, "green");
MRB_ATTR_RW(Color, blue); MRB_ATTR_RW(Color, Blue, "blue" );
MRB_ATTR_RW(Color, alpha); MRB_ATTR_RW(Color, Alpha, "alpha");
INIT_BIND(Tone); INIT_BIND(Tone);
MRB_ATTR_RW(Tone, red); MRB_ATTR_RW(Tone, Red, "red" );
MRB_ATTR_RW(Tone, green); MRB_ATTR_RW(Tone, Green, "green");
MRB_ATTR_RW(Tone, blue); MRB_ATTR_RW(Tone, Blue, "blue" );
MRB_ATTR_RW(Tone, gray); MRB_ATTR_RW(Tone, Gray, "gray" );
INIT_BIND(Rect); INIT_BIND(Rect);
MRB_ATTR_RW(Rect, x); MRB_ATTR_RW(Rect, X, "x" );
MRB_ATTR_RW(Rect, y); MRB_ATTR_RW(Rect, Y, "y" );
MRB_ATTR_RW(Rect, width); MRB_ATTR_RW(Rect, Width, "width" );
MRB_ATTR_RW(Rect, height); MRB_ATTR_RW(Rect, Height, "height");
mrb_define_method(mrb, klass, "empty", RectEmpty, MRB_ARGS_NONE()); mrb_define_method(mrb, klass, "empty", RectEmpty, MRB_ARGS_NONE());
} }

View File

@ -33,34 +33,44 @@ MRB_FUNCTION(inputUpdate)
return mrb_nil_value(); return mrb_nil_value();
} }
MRB_FUNCTION(inputPress) static mrb_int getButtonArg(mrb_state *mrb, mrb_value self)
{ {
mrb_int num; mrb_int num;
#ifdef RGSS3
mrb_sym sym;
mrb_get_args(mrb, "n", &sym);
if (mrb_const_defined(mrb, self, sym))
num = mrb_fixnum(mrb_const_get(mrb, self, sym));
else
num = 0;
#else
mrb_get_args(mrb, "i", &num); mrb_get_args(mrb, "i", &num);
#endif
Input::ButtonCode bc = (Input::ButtonCode) num; return num;
return mrb_bool_value(shState->input().isPressed(bc));
} }
MRB_FUNCTION(inputTrigger) MRB_METHOD(inputPress)
{ {
mrb_int num; mrb_int num = getButtonArg(mrb, self);
mrb_get_args(mrb, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num; return mrb_bool_value(shState->input().isPressed(num));
return mrb_bool_value(shState->input().isTriggered(bc));
} }
MRB_FUNCTION(inputRepeat) MRB_METHOD(inputTrigger)
{ {
mrb_int num; mrb_int num = getButtonArg(mrb, self);
mrb_get_args(mrb, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num; return mrb_bool_value(shState->input().isTriggered(num));
}
return mrb_bool_value(shState->input().isRepeated(bc)); MRB_METHOD(inputRepeat)
{
mrb_int num = getButtonArg(mrb, self);
return mrb_bool_value(shState->input().isRepeated(num));
} }
MRB_FUNCTION(inputDir4) MRB_FUNCTION(inputDir4)

View File

@ -68,6 +68,35 @@ DEF_PROP_F(Sprite, Angle)
DEF_PROP_B(Sprite, Mirror) DEF_PROP_B(Sprite, Mirror)
#ifdef RGSS2
MRB_METHOD(spriteWidth)
{
Sprite *s = getPrivateData<Sprite>(mrb, self);
int value;
GUARD_EXC( value = s->getWidth(); )
return mrb_fixnum_value(value);
}
MRB_METHOD(spriteHeight)
{
Sprite *s = getPrivateData<Sprite>(mrb, self);
int value;
GUARD_EXC( value = s->getHeight(); )
return mrb_fixnum_value(value);
}
DEF_PROP_I(Sprite, WaveAmp)
DEF_PROP_I(Sprite, WaveLength)
DEF_PROP_I(Sprite, WaveSpeed)
DEF_PROP_F(Sprite, WavePhase)
#endif
void void
spriteBindingInit(mrb_state *mrb) spriteBindingInit(mrb_state *mrb)
{ {
@ -95,5 +124,15 @@ spriteBindingInit(mrb_state *mrb)
INIT_PROP_BIND( Sprite, Color, "color" ); INIT_PROP_BIND( Sprite, Color, "color" );
INIT_PROP_BIND( Sprite, Tone, "tone" ); INIT_PROP_BIND( Sprite, Tone, "tone" );
#ifdef RGSS2
mrb_define_method(mrb, klass, "width", spriteWidth, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "height", spriteHeight, MRB_ARGS_NONE());
INIT_PROP_BIND( Sprite, WaveAmp, "wave_amp" );
INIT_PROP_BIND( Sprite, WaveLength, "wave_length" );
INIT_PROP_BIND( Sprite, WaveSpeed, "wave_speed" );
INIT_PROP_BIND( Sprite, WavePhase, "wave_phase" );
#endif
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE()); mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
} }

View File

@ -119,3 +119,18 @@
# (default: disabled) # (default: disabled)
# #
# useScriptNames=false # useScriptNames=false
# Font substitutions allow drop-in replacements of fonts
# to be used without changing the RGSS scripts,
# eg. providing 'Open Sans' when the game thinkgs it's
# using 'Arial'. Font family to be substituted and
# replacement family are separated by one sole '>'.
# Be careful not to include any spaces.
# This is not connected to the built-in font, which is
# always used when a non-existing font family is
# requested by RGSS.
# (default: none)
#
# fontSub=Arial>Open Sans
# fontSub=Times New Roman>Liberation Serif

View File

@ -44,6 +44,11 @@ RGSS2 {
DEFINES += RGSS2 DEFINES += RGSS2
} }
# Requires RGSS2
RGSS3 {
DEFINES += RGSS3
}
unix { unix {
CONFIG += link_pkgconfig CONFIG += link_pkgconfig
PKGCONFIG += sigc++-2.0 glew pixman-1 zlib physfs \ PKGCONFIG += sigc++-2.0 glew pixman-1 zlib physfs \

View File

@ -20,18 +20,14 @@ void main()
vec4 resFrag; vec4 resFrag;
float ab = opacity; float co1 = srcFrag.a * opacity;
float as = srcFrag.a; float co2 = dstFrag.a * (1.0 - co1);
float ad = dstFrag.a; resFrag.a = co1 + co2;
float at = ab*as; if (resFrag.a == 0.0)
resFrag.a = at + ad - ad*at;
// Sigh...
if (ad == 0.0)
resFrag.rgb = srcFrag.rgb; resFrag.rgb = srcFrag.rgb;
else else
resFrag.rgb = as*srcFrag.rgb + (1.0-at) * ad * dstFrag.rgb; resFrag.rgb = (co1*srcFrag.rgb + co2*dstFrag.rgb) / resFrag.a;
gl_FragColor = resFrag; gl_FragColor = resFrag;
} }

View File

@ -23,6 +23,7 @@
#define ALUTIL_H #define ALUTIL_H
#include <al.h> #include <al.h>
#include <alc.h>
#include <alext.h> #include <alext.h>
namespace AL namespace AL

View File

@ -366,6 +366,7 @@ struct SDLSoundSource : ALDataSource
~SDLSoundSource() ~SDLSoundSource()
{ {
/* This also closes 'srcOps' */
Sound_FreeSample(sample); Sound_FreeSample(sample);
} }

View File

@ -55,10 +55,6 @@ struct BitmapPrivate
{ {
TEXFBO gl; TEXFBO gl;
/* 'setPixel()' calls are cached and executed
* in batches on 'flush()' */
PointArray pointArray;
Font *font; Font *font;
/* "Mega surfaces" are a hack to allow Tilesets to be used /* "Mega surfaces" are a hack to allow Tilesets to be used
@ -154,32 +150,9 @@ struct BitmapPrivate
glState.blendMode.pop(); glState.blendMode.pop();
} }
void flushPoints()
{
if (pointArray.count() == 0)
return;
SimpleColorShader &shader = shState->shaders().simpleColor;
shader.bind();
shader.setTranslation(Vec2i());
bindFBO();
pushSetViewport(shader);
glState.blendMode.pushSet(BlendNone);
pointArray.commit();
pointArray.draw();
pointArray.reset();
glState.blendMode.pop();
popViewport();
}
void fillRect(const IntRect &rect, void fillRect(const IntRect &rect,
const Vec4 &color) const Vec4 &color)
{ {
flushPoints();
bindFBO(); bindFBO();
glState.scissorTest.pushSet(true); glState.scissorTest.pushSet(true);
@ -271,7 +244,6 @@ Bitmap::Bitmap(const Bitmap &other)
p->gl = shState->texPool().request(other.width(), other.height()); p->gl = shState->texPool().request(other.width(), other.height());
other.flush();
blt(0, 0, other, rect()); blt(0, 0, other, rect());
} }
@ -368,8 +340,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
if (opacity == 255 && !p->touchesTaintedArea(destRect)) if (opacity == 255 && !p->touchesTaintedArea(destRect))
{ {
/* Fast blit */ /* Fast blit */
flush();
FBO::bind(source.p->gl.fbo, FBO::Read); FBO::bind(source.p->gl.fbo, FBO::Read);
FBO::bind(p->gl.fbo, FBO::Draw); FBO::bind(p->gl.fbo, FBO::Draw);
@ -379,8 +349,6 @@ void Bitmap::stretchBlt(const IntRect &destRect,
else else
{ {
/* Fragment pipeline */ /* Fragment pipeline */
flush();
float normOpacity = (float) opacity / 255.0f; float normOpacity = (float) opacity / 255.0f;
TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h); TEXFBO &gpTex = shState->gpTexFBO(destRect.w, destRect.h);
@ -461,8 +429,6 @@ void Bitmap::gradientFillRect(const IntRect &rect,
GUARD_MEGA; GUARD_MEGA;
flush();
SimpleColorShader &shader = shState->shaders().simpleColor; SimpleColorShader &shader = shState->shaders().simpleColor;
shader.bind(); shader.bind();
shader.setTranslation(Vec2i()); shader.setTranslation(Vec2i());
@ -520,8 +486,6 @@ void Bitmap::blur()
GUARD_MEGA; GUARD_MEGA;
flush();
Quad &quad = shState->gpQuad(); Quad &quad = shState->gpQuad();
FloatRect rect(0, 0, width(), height()); FloatRect rect(0, 0, width(), height());
quad.setTexPosRect(rect, rect); quad.setTexPosRect(rect, rect);
@ -567,8 +531,6 @@ void Bitmap::radialBlur(int angle, int divisions)
GUARD_MEGA; GUARD_MEGA;
flush();
angle = clamp<int>(angle, 0, 359); angle = clamp<int>(angle, 0, 359);
divisions = clamp<int>(divisions, 2, 100); divisions = clamp<int>(divisions, 2, 100);
@ -666,9 +628,6 @@ void Bitmap::clear()
GUARD_MEGA; GUARD_MEGA;
/* Any queued points won't be visible after this anyway */
p->pointArray.reset();
p->bindFBO(); p->bindFBO();
glState.clearColor.pushSet(Vec4()); glState.clearColor.pushSet(Vec4());
@ -682,7 +641,7 @@ void Bitmap::clear()
modified(); modified();
} }
Vec4 Bitmap::getPixel(int x, int y) const Color Bitmap::getPixel(int x, int y) const
{ {
GUARD_DISPOSED; GUARD_DISPOSED;
@ -691,24 +650,34 @@ Vec4 Bitmap::getPixel(int x, int y) const
if (x < 0 || y < 0 || x >= width() || y >= height()) if (x < 0 || y < 0 || x >= width() || y >= height())
return Vec4(); return Vec4();
flush();
FBO::bind(p->gl.fbo, FBO::Read); FBO::bind(p->gl.fbo, FBO::Read);
glState.viewport.pushSet(IntRect(0, 0, width(), height())); glState.viewport.pushSet(IntRect(0, 0, width(), height()));
Vec4 pixel = FBO::getPixel(x, y);
uint8_t pixel[4];
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
glState.viewport.pop(); glState.viewport.pop();
return pixel; return Color(pixel[0], pixel[1], pixel[2], pixel[3]);
} }
void Bitmap::setPixel(int x, int y, const Vec4 &color) void Bitmap::setPixel(int x, int y, const Color &color)
{ {
GUARD_DISPOSED; GUARD_DISPOSED;
GUARD_MEGA; GUARD_MEGA;
p->pointArray.append(Vec2(x+.5, y+.5), color); uint8_t pixel[] =
{
(uint8_t) clamp<double>(color.red, 0, 255),
(uint8_t) clamp<double>(color.green, 0, 255),
(uint8_t) clamp<double>(color.blue, 0, 255),
(uint8_t) clamp<double>(color.alpha, 0, 255)
};
TEX::bind(p->gl.tex);
TEX::uploadSubImage(x, y, 1, 1, &pixel, GL_RGBA);
p->addTaintedArea(IntRect(x, y, 1, 1)); p->addTaintedArea(IntRect(x, y, 1, 1));
@ -724,8 +693,6 @@ void Bitmap::hueChange(int hue)
if ((hue % 360) == 0) if ((hue % 360) == 0)
return; return;
flush();
TEXFBO newTex = shState->texPool().request(width(), height()); TEXFBO newTex = shState->texPool().request(width(), height());
FloatRect texRect(rect()); FloatRect texRect(rect());
@ -748,8 +715,6 @@ void Bitmap::hueChange(int hue)
p->blitQuad(quad); p->blitQuad(quad);
shader.unbind();
p->popViewport(); p->popViewport();
TEX::unbind(); TEX::unbind();
@ -779,8 +744,6 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
if (str[0] == ' ' && str[1] == '\0') if (str[0] == ' ' && str[1] == '\0')
return; return;
flush();
TTF_Font *font = p->font->getSdlFont(); TTF_Font *font = p->font->getSdlFont();
Color *fontColor = p->font->getColor(); Color *fontColor = p->font->getColor();
@ -1011,17 +974,6 @@ IntRect Bitmap::textSize(const char *str)
DEF_ATTR_SIMPLE(Bitmap, Font, Font*, p->font) DEF_ATTR_SIMPLE(Bitmap, Font, Font*, p->font)
void Bitmap::flush() const
{
if (isDisposed())
return;
if (p->megaSurface)
return;
p->flushPoints();
}
TEXFBO &Bitmap::getGLTypes() TEXFBO &Bitmap::getGLTypes()
{ {
return p->gl; return p->gl;

View File

@ -81,8 +81,8 @@ public:
void clear(); void clear();
Vec4 getPixel(int x, int y) const; Color getPixel(int x, int y) const;
void setPixel(int x, int y, const Vec4 &color); void setPixel(int x, int y, const Color &color);
void hueChange(int hue); void hueChange(int hue);
@ -105,9 +105,6 @@ public:
DECL_ATTR(Font, Font*) DECL_ATTR(Font, Font*)
/* <internal> */ /* <internal> */
/* Warning: Flushing might change the current
* FBO binding (so don't call it during 'draw()' routines */
void flush() const;
TEXFBO &getGLTypes(); TEXFBO &getGLTypes();
SDL_Surface *megaSurface() const; SDL_Surface *megaSurface() const;
void ensureNonMega() const; void ensureNonMega() const;

View File

@ -35,7 +35,6 @@ namespace po = boost::program_options;
Config::Config() Config::Config()
: debugMode(false), : debugMode(false),
screenshots(false),
winResizable(false), winResizable(false),
fullscreen(false), fullscreen(false),
fixedAspectRatio(true), fixedAspectRatio(true),
@ -57,7 +56,6 @@ void Config::read(int argc, char *argv[])
{ {
#define PO_DESC_ALL \ #define PO_DESC_ALL \
PO_DESC(debugMode, bool) \ PO_DESC(debugMode, bool) \
PO_DESC(screenshots, bool) \
PO_DESC(winResizable, bool) \ PO_DESC(winResizable, bool) \
PO_DESC(fullscreen, bool) \ PO_DESC(fullscreen, bool) \
PO_DESC(fixedAspectRatio, bool) \ PO_DESC(fixedAspectRatio, bool) \
@ -85,6 +83,7 @@ void Config::read(int argc, char *argv[])
podesc.add_options() podesc.add_options()
PO_DESC_ALL PO_DESC_ALL
("RTP", po::value<StringVec>()->composing()) ("RTP", po::value<StringVec>()->composing())
("fontSub", po::value<StringVec>()->composing())
; ;
po::variables_map vm; po::variables_map vm;
@ -117,6 +116,8 @@ void Config::read(int argc, char *argv[])
GUARD_ALL( rtps = vm["RTP"].as<StringVec>(); ); GUARD_ALL( rtps = vm["RTP"].as<StringVec>(); );
GUARD_ALL( fontSubs = vm["fontSub"].as<StringVec>(); );
#undef PO_DESC #undef PO_DESC
#undef PO_DESC_ALL #undef PO_DESC_ALL
} }

View File

@ -28,7 +28,6 @@
struct Config struct Config
{ {
bool debugMode; bool debugMode;
bool screenshots;
bool winResizable; bool winResizable;
bool fullscreen; bool fullscreen;
@ -56,6 +55,8 @@ struct Config
std::string customScript; std::string customScript;
std::vector<std::string> rtps; std::vector<std::string> rtps;
std::vector<std::string> fontSubs;
/* Game INI contents */ /* Game INI contents */
struct { struct {
std::string scripts; std::string scripts;

View File

@ -46,7 +46,7 @@ public:
~Debug() ~Debug()
{ {
std::clog << buf.str() << "\n"; std::clog << buf.str() << std::endl;
} }
private: private:

View File

@ -209,9 +209,6 @@ void EventThread::process(RGSSThreadData &rtData)
break; break;
} }
if (event.key.keysym.scancode == SDL_SCANCODE_F3 && rtData.config.screenshots)
rtData.rqScreenshot = true;
keyStates[event.key.keysym.scancode] = true; keyStates[event.key.keysym.scancode] = true;
break; break;

View File

@ -178,8 +178,6 @@ struct RGSSThreadData
std::string rgssErrorMsg; std::string rgssErrorMsg;
volatile bool rqScreenshot;
RGSSThreadData(EventThread *ethread, RGSSThreadData(EventThread *ethread,
const char *argv0, const char *argv0,
SDL_Window *window, SDL_Window *window,
@ -190,8 +188,7 @@ struct RGSSThreadData
argv0(argv0), argv0(argv0),
window(window), window(window),
sizeResoRatio(1, 1), sizeResoRatio(1, 1),
config(newconf), config(newconf)
rqScreenshot(false)
{} {}
}; };

View File

@ -21,6 +21,7 @@
#include "filesystem.h" #include "filesystem.h"
#include "font.h"
#include "util.h" #include "util.h"
#include "exception.h" #include "exception.h"
#include "boost-hash.h" #include "boost-hash.h"
@ -297,8 +298,12 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
/* Check header */ /* Check header */
uint32_t header1, header2; uint32_t header1, header2;
readUint32(io, header1);
readUint32(io, header2); if (!readUint32(io, header1))
return 0;
if (!readUint32(io, header2))
return 0;
if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2) if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2)
return 0; return 0;
@ -494,23 +499,115 @@ static const PHYSFS_Archiver RGSS_Archiver =
RGSS_closeArchive RGSS_closeArchive
}; };
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
{
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
}
static Sint64 SDL_RWopsSize(SDL_RWops *ops)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
return PHYSFS_fileLength(f);
}
static Sint64 SDL_RWopsSeek(SDL_RWops *ops, int64_t offset, int whence)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
int64_t base;
switch (whence)
{
default:
case RW_SEEK_SET :
base = 0;
break;
case RW_SEEK_CUR :
base = PHYSFS_tell(f);
break;
case RW_SEEK_END :
base = PHYSFS_fileLength(f);
break;
}
int result = PHYSFS_seek(f, base + offset);
return (result != 0) ? PHYSFS_tell(f) : -1;
}
static size_t SDL_RWopsRead(SDL_RWops *ops, void *buffer, size_t size, size_t maxnum)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_readBytes(f, buffer, size*maxnum);
return (result != -1) ? (result / size) : 0;
}
static size_t SDL_RWopsWrite(SDL_RWops *ops, const void *buffer, size_t size, size_t num)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_writeBytes(f, buffer, size*num);
return (result != -1) ? (result / size) : 0;
}
static int SDL_RWopsClose(SDL_RWops *ops)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
int result = PHYSFS_close(f);
f = 0;
return (result != 0) ? 0 : -1;
}
static int SDL_RWopsCloseFree(SDL_RWops *ops)
{
int result = SDL_RWopsClose(ops);
SDL_FreeRW(ops);
return result;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
struct FileSystemPrivate struct FileSystemPrivate
{ {
/* All keys are lower case */ /* Maps: lower case filename, To: actual (mixed case) filename.
* This is for compatibility with games that take Windows'
* case insensitivity for granted */
BoostHash<std::string, std::string> pathCache; BoostHash<std::string, std::string> pathCache;
bool havePathCache;
std::vector<std::string> extensions[FileSystem::Undefined+1]; std::vector<std::string> extensions[FileSystem::Undefined+1];
// FIXME Need to find a better way to do this..
char pathBuffer[512];
bool havePathCache;
/* Attempt to locate an extension string in a filename. /* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the * Either a pointer into the input string pointing at the
* extension, or null is returned */ * extension, or null is returned */
const char *findExt(const char *filename) const char *findExt(const char *filename)
{ {
int len; size_t len;
for (len = strlen(filename); len > 0; --len) for (len = strlen(filename); len > 0; --len)
{ {
@ -524,110 +621,147 @@ struct FileSystemPrivate
return 0; return 0;
} }
const char *completeFileName(const char *filename, /* Complete filename via regular physfs lookup */
bool completeFilenameReg(const char *filename,
FileSystem::FileType type, FileSystem::FileType type,
char *outBuffer,
size_t outN,
const char **foundExt) const char **foundExt)
{ {
if (!havePathCache) /* Try supplementing extensions to find an existing path */
const std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i)
{ {
const char *ext = extList[i].c_str();
snprintf(outBuffer, outN, "%s.%s", filename, ext);
if (PHYSFS_exists(outBuffer))
{
if (foundExt)
*foundExt = ext;
return true;
}
}
/* Doing the check without supplemented extension
* fits the usage pattern of RMXP games */
if (PHYSFS_exists(filename)) if (PHYSFS_exists(filename))
{ {
strncpy(outBuffer, filename, outN);
if (foundExt) if (foundExt)
*foundExt = findExt(filename); *foundExt = findExt(filename);
return filename; return true;
} }
return false;
}
/* Complete filename via path cache */
bool completeFilenamePC(const char *filename,
FileSystem::FileType type,
char *outBuffer,
size_t outN,
const char **foundExt)
{
size_t i;
char lowCase[512];
for (i = 0; i < sizeof(lowCase)-1 && filename[i]; ++i)
lowCase[i] = tolower(filename[i]);
lowCase[i] = '\0';
std::string key;
const std::vector<std::string> &extList = extensions[type]; const std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i) for (size_t i = 0; i < extList.size(); ++i)
{ {
const char *ext = extList[i].c_str(); const char *ext = extList[i].c_str();
snprintf(pathBuffer, sizeof(pathBuffer), "%s.%s", filename, ext); snprintf(outBuffer, outN, "%s.%s", lowCase, ext);
key = outBuffer;
if (PHYSFS_exists(pathBuffer)) if (pathCache.contains(key))
{ {
strncpy(outBuffer, pathCache[key].c_str(), outN);
if (foundExt) if (foundExt)
*foundExt = ext; *foundExt = ext;
return pathBuffer; return true;
} }
} }
// Is this even necessary? key = lowCase;
if (foundExt)
*foundExt = 0;
return 0;
}
char buff[512];
size_t i;
for (i = 0; i < sizeof(buff) && filename[i]; ++i)
buff[i] = tolower(filename[i]);
buff[i] = '\0';
std::string key(buff);
/* If the path was already complete,
* we are done at this point */
if (pathCache.contains(key)) if (pathCache.contains(key))
{ {
/* The extension might already be included here, strncpy(outBuffer, pathCache[key].c_str(), outN);
* so try to find it */
if (foundExt) if (foundExt)
*foundExt = findExt(filename); *foundExt = findExt(filename);
return pathCache[key].c_str(); return true;
} }
char buff2[512]; return false;
}
/* Try supplementing extensions /* Try to complete 'filename' with file extensions
* to find an existing path */ * based on 'type'. If no combination could be found,
if (type != FileSystem::Undefined) * returns false, and 'foundExt' is untouched */
bool completeFileName(const char *filename,
FileSystem::FileType type,
char *outBuffer,
size_t outN,
const char **foundExt)
{ {
std::vector<std::string> &extList = extensions[type]; if (havePathCache)
for (size_t i = 0; i < extList.size(); ++i) return completeFilenamePC(filename, type, outBuffer, outN, foundExt);
{ else
const char *ext = extList[i].c_str(); return completeFilenameReg(filename, type, outBuffer, outN, foundExt);
snprintf(buff2, sizeof(buff2), "%s.%s", buff, ext);
key = buff2;
if (pathCache.contains(key))
{
if (foundExt)
*foundExt = ext;
return pathCache[key].c_str();
}
}
} }
if (foundExt) PHYSFS_File *openReadHandle(const char *filename,
*foundExt = 0;
return 0;
}
PHYSFS_File *openReadInt(const char *filename,
FileSystem::FileType type, FileSystem::FileType type,
const char **foundExt) const char **foundExt)
{ {
const char *foundName = completeFileName(filename, type, foundExt); char found[512];
if (!foundName) if (!completeFileName(filename, type, found, sizeof(found), foundExt))
throw Exception(Exception::NoFileError, "%s", filename); throw Exception(Exception::NoFileError, "%s", filename);
PHYSFS_File *handle = PHYSFS_openRead(foundName); PHYSFS_File *handle = PHYSFS_openRead(found);
if (!handle) if (!handle)
throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError()); throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError());
return handle; return handle;
} }
void initReadOps(PHYSFS_File *handle,
SDL_RWops &ops,
bool freeOnClose)
{
ops.size = SDL_RWopsSize;
ops.seek = SDL_RWopsSeek;
ops.read = SDL_RWopsRead;
ops.write = SDL_RWopsWrite;
if (freeOnClose)
ops.close = SDL_RWopsCloseFree;
else
ops.close = SDL_RWopsClose;
ops.type = SDL_RWOPS_PHYSFS;
ops.hidden.unknown.data1 = handle;
}
}; };
FileSystem::FileSystem(const char *argv0, FileSystem::FileSystem(const char *argv0,
@ -724,123 +858,83 @@ void FileSystem::createPathCache()
p->havePathCache = true; p->havePathCache = true;
} }
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops) static void strToLower(std::string &str)
{ {
return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1); for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
} }
static Sint64 SDL_RWopsSize(SDL_RWops *ops) struct FontSetsCBData
{ {
PHYSFS_File *f = sdlPHYS(ops); FileSystemPrivate *p;
SharedFontState *sfs;
};
if (!f) static void fontSetEnumCB(void *data, const char *,
return -1; const char *fname)
{
FontSetsCBData *d = static_cast<FontSetsCBData*>(data);
FileSystemPrivate *p = d->p;
return PHYSFS_fileLength(f); /* Only consider filenames with font extensions */
const char *ext = p->findExt(fname);
if (!ext)
return;
std::string lower(ext);
strToLower(lower);
if (!contains(p->extensions[FileSystem::Font], lower))
return;
std::string filename("Fonts/");
filename += fname;
PHYSFS_File *handle = PHYSFS_openRead(filename.c_str());
if (!handle)
return;
SDL_RWops ops;
p->initReadOps(handle, ops, false);
d->sfs->initFontSetCB(ops, filename);
SDL_RWclose(&ops);
} }
static Sint64 SDL_RWopsSeek(SDL_RWops *ops, int64_t offset, int whence) void FileSystem::initFontSets(SharedFontState &sfs)
{ {
PHYSFS_File *f = sdlPHYS(ops); FontSetsCBData d = { p, &sfs };
if (!f) PHYSFS_enumerateFilesCallback("Fonts", fontSetEnumCB, &d);
return -1;
int64_t base;
switch (whence)
{
default:
case RW_SEEK_SET :
base = 0;
break;
case RW_SEEK_CUR :
base = PHYSFS_tell(f);
break;
case RW_SEEK_END :
base = PHYSFS_fileLength(f);
break;
}
int result = PHYSFS_seek(f, base + offset);
return (result != 0) ? PHYSFS_tell(f) : -1;
} }
static size_t SDL_RWopsRead(SDL_RWops *ops, void *buffer, size_t size, size_t maxnum)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_readBytes(f, buffer, size*maxnum);
return (result != -1) ? (result / size) : 0;
}
static size_t SDL_RWopsWrite(SDL_RWops *ops, const void *buffer, size_t size, size_t num)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return 0;
PHYSFS_sint64 result = PHYSFS_writeBytes(f, buffer, size*num);
return (result != -1) ? (result / size) : 0;
}
static int SDL_RWopsClose(SDL_RWops *ops)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
int result = PHYSFS_close(f);
f = 0;
return (result != 0) ? 0 : -1;
}
static int SDL_RWopsCloseFree(SDL_RWops *ops)
{
int result = SDL_RWopsClose(ops);
SDL_FreeRW(ops);
return result;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
void FileSystem::openRead(SDL_RWops &ops, void FileSystem::openRead(SDL_RWops &ops,
const char *filename, const char *filename,
FileType type, FileType type,
bool freeOnClose, bool freeOnClose,
const char **foundExt) const char **foundExt)
{ {
PHYSFS_File *handle = p->openReadInt(filename, type, foundExt); PHYSFS_File *handle = p->openReadHandle(filename, type, foundExt);
ops.size = SDL_RWopsSize; p->initReadOps(handle, ops, freeOnClose);
ops.seek = SDL_RWopsSeek; }
ops.read = SDL_RWopsRead;
ops.write = SDL_RWopsWrite;
if (freeOnClose) void FileSystem::openReadRaw(SDL_RWops &ops,
ops.close = SDL_RWopsCloseFree; const char *filename,
else bool freeOnClose)
ops.close = SDL_RWopsClose; {
PHYSFS_File *handle = PHYSFS_openRead(filename);
assert(handle);
ops.type = SDL_RWOPS_PHYSFS; p->initReadOps(handle, ops, freeOnClose);
ops.hidden.unknown.data1 = handle;
} }
bool FileSystem::exists(const char *filename, FileType type) bool FileSystem::exists(const char *filename, FileType type)
{ {
const char *foundName = p->completeFileName(filename, type, 0); char found[512];
return (foundName != 0); return p->completeFileName(filename, type, found, sizeof(found), 0);
} }

View File

@ -25,6 +25,7 @@
#include <SDL_rwops.h> #include <SDL_rwops.h>
struct FileSystemPrivate; struct FileSystemPrivate;
class SharedFontState;
class FileSystem class FileSystem
{ {
@ -35,9 +36,13 @@ public:
void addPath(const char *path); void addPath(const char *path);
/* Call this after the last 'addPath()' */ /* Call these after the last 'addPath()' */
void createPathCache(); void createPathCache();
/* Scans "Fonts/" and creates inventory of
* available font assets */
void initFontSets(SharedFontState &sfs);
/* For extension supplementing */ /* For extension supplementing */
enum FileType enum FileType
{ {
@ -53,6 +58,11 @@ public:
bool freeOnClose = false, bool freeOnClose = false,
const char **foundExt = 0); const char **foundExt = 0);
/* Circumvents extension supplementing */
void openReadRaw(SDL_RWops &ops,
const char *filename,
bool freeOnClose = false);
bool exists(const char *filename, bool exists(const char *filename,
FileType type = Undefined); FileType type = Undefined);

View File

@ -55,7 +55,7 @@ public:
flashAlpha = flashColor.w; flashAlpha = flashColor.w;
} }
void update() virtual void update()
{ {
if (!flashing) if (!flashing)
return; return;

View File

@ -26,6 +26,7 @@
#include "exception.h" #include "exception.h"
#include "boost-hash.h" #include "boost-hash.h"
#include "util.h" #include "util.h"
#include "config.h"
#include <string> #include <string>
#include <utility> #include <utility>
@ -45,88 +46,151 @@
typedef std::pair<std::string, int> FontKey; typedef std::pair<std::string, int> FontKey;
static void strToLower(std::string &str)
{
for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
}
struct FontPoolPrivate
{
BoostHash<FontKey, TTF_Font*> hash;
};
FontPool::FontPool()
{
p = new FontPoolPrivate;
}
FontPool::~FontPool()
{
BoostHash<FontKey, TTF_Font*>::const_iterator iter;
for (iter = p->hash.cbegin(); iter != p->hash.cend(); ++iter)
TTF_CloseFont(iter->second);
delete p;
}
static SDL_RWops *openBundledFont() static SDL_RWops *openBundledFont()
{ {
return SDL_RWFromConstMem(BNDL_F_D(BUNDLED_FONT), BNDL_F_L(BUNDLED_FONT)); return SDL_RWFromConstMem(BNDL_F_D(BUNDLED_FONT), BNDL_F_L(BUNDLED_FONT));
} }
_TTF_Font *FontPool::request(const char *filename, struct FontSet
{
/* 'Regular' style */
std::string regular;
/* Any other styles (used in case no 'Regular' exists) */
std::string other;
};
struct SharedFontStatePrivate
{
/* Maps: font family name, To: substituted family name,
* as specified via configuration file / arguments */
BoostHash<std::string, std::string> subs;
/* Maps: font family name, To: set of physical
* font filenames located in "Fonts/" */
BoostHash<std::string, FontSet> sets;
/* Pool of already opened fonts; once opened, they are reused
* and never closed until the termination of the program */
BoostHash<FontKey, TTF_Font*> pool;
};
SharedFontState::SharedFontState(const Config &conf)
{
p = new SharedFontStatePrivate;
/* Parse font substitutions */
for (size_t i = 0; i < conf.fontSubs.size(); ++i)
{
const std::string &raw = conf.fontSubs[i];
size_t sepPos = raw.find_first_of('>');
if (sepPos == std::string::npos)
continue;
std::string from = raw.substr(0, sepPos);
std::string to = raw.substr(sepPos+1);
p->subs.insert(from, to);
}
}
SharedFontState::~SharedFontState()
{
BoostHash<FontKey, TTF_Font*>::const_iterator iter;
for (iter = p->pool.cbegin(); iter != p->pool.cend(); ++iter)
TTF_CloseFont(iter->second);
delete p;
}
void SharedFontState::initFontSetCB(SDL_RWops &ops,
const std::string &filename)
{
TTF_Font *font = TTF_OpenFontRW(&ops, 0, 0);
if (!font)
return;
std::string family = TTF_FontFaceFamilyName(font);
std::string style = TTF_FontFaceStyleName(font);
TTF_CloseFont(font);
FontSet &set = p->sets[family];
if (style == "Regular")
set.regular = filename;
else
set.other = filename;
}
_TTF_Font *SharedFontState::getFont(std::string family,
int size) int size)
{ {
// FIXME Find out how font path resolution is done in VX/Ace /* Check for substitutions */
std::string nameKey(filename); if (p->subs.contains(family))
strToLower(nameKey); family = p->subs[family];
strReplace(nameKey, ' ', '_');
bool useBundled = false; /* Find out if the font asset exists */
std::string path = std::string("Fonts/") + nameKey; const FontSet &req = p->sets[family];
if (!shState->fileSystem().exists(path.c_str(), FileSystem::Font))
if (req.regular.empty() && req.other.empty())
{ {
/* Use the same name key for the bundled font /* Doesn't exist; use built-in font */
* even when it resulted from multiple different family = "";
* font name requests. The space at the front is
* to prevent collisions (spaces are normally
* replaced with '_' */
useBundled = true;
nameKey = " bundled";
} }
FontKey key(nameKey, size); FontKey key(family, size);
TTF_Font *font = p->hash.value(key, 0); TTF_Font *font = p->pool.value(key);
if (font) if (font)
return font; return font;
/* Not in hash, open */ /* Not in pool; open new handle */
SDL_RWops *ops; SDL_RWops *ops;
if (useBundled) if (family.empty())
{ {
/* Built-in font */
ops = openBundledFont(); ops = openBundledFont();
} }
else else
{ {
/* Use 'other' path as alternative in case
* we have no 'regular' styled font asset */
const char *path = !req.regular.empty()
? req.regular.c_str() : req.other.c_str();
ops = SDL_AllocRW(); ops = SDL_AllocRW();
shState->fileSystem().openRead(*ops, path.c_str(), FileSystem::Font, true); shState->fileSystem().openReadRaw(*ops, path, true);
} }
// FIXME 0.9 is guesswork at this point // FIXME 0.9 is guesswork at this point
font = TTF_OpenFontRW(ops, 1, (float) size * .90); // float gamma = (96.0/45.0)*(5.0/14.0)*(size-5);
// font = TTF_OpenFontRW(ops, 1, gamma /** .90*/);
font = TTF_OpenFontRW(ops, 1, size* .90);
if (!font) if (!font)
throw Exception(Exception::SDLError, "SDL: %s", SDL_GetError()); throw Exception(Exception::SDLError, "%s", SDL_GetError());
p->hash.insert(key, font); p->pool.insert(key, font);
return font; return font;
} }
bool SharedFontState::fontPresent(std::string family)
{
/* Check for substitutions */
if (p->subs.contains(family))
family = p->subs[family];
const FontSet &set = p->sets[family];
return !(set.regular.empty() && set.other.empty());
}
struct FontPrivate struct FontPrivate
{ {
@ -173,7 +237,7 @@ struct FontPrivate
{} {}
}; };
std::string FontPrivate::defaultName = "MS PGothic"; std::string FontPrivate::defaultName = "Arial";
int FontPrivate::defaultSize = 22; int FontPrivate::defaultSize = 22;
bool FontPrivate::defaultBold = false; bool FontPrivate::defaultBold = false;
bool FontPrivate::defaultItalic = false; bool FontPrivate::defaultItalic = false;
@ -183,9 +247,7 @@ Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
bool Font::doesExist(const char *name) bool Font::doesExist(const char *name)
{ {
std::string path = std::string("Fonts/") + std::string(name); return shState->fontState().fontPresent(name);
return shState->fileSystem().exists(path.c_str(), FileSystem::Font);
} }
Font::Font(const char *name, Font::Font(const char *name,
@ -223,6 +285,10 @@ void Font::setSize(int value)
if (p->size == value) if (p->size == value)
return; return;
/* Catch illegal values (according to RMXP) */
if (value < 6 || value > 96)
throw Exception(Exception::ArgumentError, "%s", "bad value for size");
p->size = value; p->size = value;
p->sdlFont = 0; p->sdlFont = 0;
} }
@ -253,7 +319,7 @@ void Font::setDefaultName(const char *value)
_TTF_Font *Font::getSdlFont() _TTF_Font *Font::getSdlFont()
{ {
if (!p->sdlFont) if (!p->sdlFont)
p->sdlFont = shState->fontPool().request(p->name.c_str(), p->sdlFont = shState->fontState().getFont(p->name.c_str(),
p->size); p->size);
int style = TTF_STYLE_NORMAL; int style = TTF_STYLE_NORMAL;

View File

@ -25,22 +25,50 @@
#include "etc.h" #include "etc.h"
#include "util.h" #include "util.h"
struct SDL_RWops;
struct _TTF_Font; struct _TTF_Font;
struct FontPoolPrivate; struct Config;
class FontPool struct SharedFontStatePrivate;
class SharedFontState
{ {
public: public:
FontPool(); SharedFontState(const Config &conf);
~FontPool(); ~SharedFontState();
_TTF_Font *request(const char *filename, /* Called from FileSystem during font cache initialization
* (when "Fonts/" is scanned for available assets).
* 'ops' is an opened handle to a possible font file,
* 'filename' is the corresponding path */
void initFontSetCB(SDL_RWops &ops,
const std::string &filename);
_TTF_Font *getFont(std::string family,
int size); int size);
bool fontPresent(std::string family);
private: private:
FontPoolPrivate *p; SharedFontStatePrivate *p;
}; };
/* Concerning Font::name/defaultName :
* In RGSS, this is not actually a string; any type of
* object is accepted, however anything but strings and
* arrays is ignored (and text drawing turns blank).
* Single strings are interpreted as font family names,
* and directly passed to the underlying C++ object;
* arrays however are searched for the first string
* object corresponding to a valid font family name,
* and rendering is done with that. In mkxp, we pass
* this first valid font family as the 'name' attribute
* back to the C++ object on assignment and object
* creation (in case Font.default_name is also an array).
* Invalid parameters (things other than strings or
* arrays not containing any valid family name) are
* passed back as "". */
struct FontPrivate; struct FontPrivate;
class Font class Font

View File

@ -216,15 +216,6 @@ namespace FBO
blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH, mode); blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH, mode);
} }
inline Vec4 getPixel(int x, int y)
{
Vec4 pixel;
glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &pixel.x);
return pixel;
}
inline void clear() inline void clear()
{ {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);

View File

@ -20,6 +20,7 @@
*/ */
#include "glstate.h" #include "glstate.h"
#include "shader.h"
#include "etc.h" #include "etc.h"
#include <glew.h> #include <glew.h>
@ -95,6 +96,11 @@ void GLViewport::apply(const IntRect &value)
glViewport(value.x, value.y, value.w, value.h); glViewport(value.x, value.y, value.w, value.h);
} }
void GLProgram::apply(const unsigned int &value)
{
glUseProgram(value);
}
GLState::Caps::Caps() GLState::Caps::Caps()
{ {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
@ -110,4 +116,5 @@ GLState::GLState()
scissorTest.init(false); scissorTest.init(false);
scissorBox.init(IntRect(0, 0, 640, 480)); scissorBox.init(IntRect(0, 0, 640, 480));
texture2D.init(true); texture2D.init(true);
program.init(0);
} }

View File

@ -99,6 +99,11 @@ class GLViewport : public GLProperty<IntRect>
void apply(const IntRect &value); void apply(const IntRect &value);
}; };
class GLProgram : public GLProperty<unsigned int> /* GLuint */
{
void apply(const unsigned int &value);
};
class GLState class GLState
{ {
@ -109,6 +114,7 @@ public:
GLTexture2D texture2D; GLTexture2D texture2D;
GLBlendMode blendMode; GLBlendMode blendMode;
GLViewport viewport; GLViewport viewport;
GLProgram program;
struct Caps struct Caps
{ {

View File

@ -191,7 +191,6 @@ public:
screenQuad.draw(); screenQuad.draw();
glState.blendMode.pop(); glState.blendMode.pop();
shader.unbind();
} }
#ifdef RGSS2 #ifdef RGSS2
@ -508,44 +507,6 @@ struct GraphicsPrivate
swapGLBuffer(); swapGLBuffer();
} }
void writeScreenshot(const char *filename)
{
int bpp;
uint32_t rm, gm, bm, am;
SDL_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ABGR8888, &bpp, &rm, &gm, &bm, &am);
/* Discard alpha channel because it might have bogus values */
SDL_Surface *screenshot =
SDL_CreateRGBSurface(0, scRes.x, scRes.y, bpp, rm, gm, bm, 0);
screen.getPP().bindLastBuffer();
glReadPixels(0, 0, scRes.x, scRes.y, GL_RGBA, GL_UNSIGNED_BYTE, screenshot->pixels);
IMG_SavePNG(screenshot, filename);
SDL_FreeSurface(screenshot);
}
void checkScreenshotRq()
{
if (!threadData->rqScreenshot)
return;
threadData->rqScreenshot = false;
struct timeval tv;
gettimeofday(&tv, 0);
struct tm tm = *localtime(&tv.tv_sec);
char filename[32];
snprintf(filename, sizeof(filename), "%d%02d%02d-%02d%02d%02d.png",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
writeScreenshot(filename);
}
}; };
Graphics::Graphics(RGSSThreadData *data) Graphics::Graphics(RGSSThreadData *data)
@ -569,8 +530,6 @@ void Graphics::update()
// p->cpuTimer->endTiming(); // p->cpuTimer->endTiming();
// p->gpuTimer->startTiming(); // p->gpuTimer->startTiming();
p->checkScreenshotRq();
if (p->frozen) if (p->frozen)
return; return;

View File

@ -93,9 +93,6 @@ struct PlanePrivate
updateQuadSource(); updateQuadSource();
quadSourceDirty = false; quadSourceDirty = false;
} }
if (bitmap)
bitmap->flush();
} }
}; };

View File

@ -34,17 +34,41 @@
typedef uint32_t index_t; typedef uint32_t index_t;
#define _GL_INDEX_TYPE GL_UNSIGNED_INT #define _GL_INDEX_TYPE GL_UNSIGNED_INT
struct ColorQuadArray /* A small hack to get mutable QuadArray constructors */
inline void initBufferBindings(Vertex *)
{ {
std::vector<Vertex> vertices; glEnableVertexAttribArray(Shader::Color);
glEnableVertexAttribArray(Shader::Position);
glEnableVertexAttribArray(Shader::TexCoord);
glVertexAttribPointer(Shader::Color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::colorOffset());
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::posOffset());
glVertexAttribPointer(Shader::TexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::texPosOffset());
}
inline void initBufferBindings(SVertex *)
{
glEnableVertexAttribArray(Shader::Position);
glEnableVertexAttribArray(Shader::TexCoord);
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), SVertex::posOffset());
glVertexAttribPointer(Shader::TexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), SVertex::texPosOffset());
}
template<class VertexType>
struct QuadArray
{
std::vector<VertexType> vertices;
VBO::ID vbo; VBO::ID vbo;
VAO::ID vao; VAO::ID vao;
int quadCount; int quadCount;
GLsizeiptr vboSize;
ColorQuadArray() QuadArray()
: quadCount(0) : quadCount(0),
vboSize(-1)
{ {
vbo = VBO::gen(); vbo = VBO::gen();
vao = VAO::gen(); vao = VAO::gen();
@ -53,20 +77,16 @@ struct ColorQuadArray
VBO::bind(vbo); VBO::bind(vbo);
shState->bindQuadIBO(); shState->bindQuadIBO();
glEnableVertexAttribArray(Shader::Color); /* Call correct implementation here via overloading */
glEnableVertexAttribArray(Shader::Position); VertexType *dummy = 0;
glEnableVertexAttribArray(Shader::TexCoord); initBufferBindings(dummy);
glVertexAttribPointer(Shader::Color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::colorOffset());
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::posOffset());
glVertexAttribPointer(Shader::TexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::texPosOffset());
VAO::unbind(); VAO::unbind();
IBO::unbind(); IBO::unbind();
VBO::unbind(); VBO::unbind();
} }
~ColorQuadArray() ~QuadArray()
{ {
VBO::del(vbo); VBO::del(vbo);
VAO::del(vao); VAO::del(vao);
@ -78,16 +98,37 @@ struct ColorQuadArray
quadCount = size; quadCount = size;
} }
void clear()
{
vertices.clear();
quadCount = 0;
}
/* This needs to be called after the final 'append()' call /* This needs to be called after the final 'append()' call
* and previous to the first 'draw()' call. */ * and previous to the first 'draw()' call. */
void commit() void commit()
{ {
VBO::bind(vbo); VBO::bind(vbo);
VBO::uploadData(vertices.size() * sizeof(Vertex), &vertices[0], GL_DYNAMIC_DRAW);
VBO::unbind(); GLsizeiptr size = vertices.size() * sizeof(VertexType);
if (size > vboSize)
{
/* New data exceeds already allocated size.
* Reallocate VBO. */
VBO::uploadData(size, &vertices[0], GL_DYNAMIC_DRAW);
vboSize = size;
shState->ensureQuadIBO(quadCount); shState->ensureQuadIBO(quadCount);
} }
else
{
/* New data fits in allocated size */
VBO::uploadSubData(0, size, &vertices[0]);
}
VBO::unbind();
}
void draw(size_t offset, size_t count) void draw(size_t offset, size_t count)
{ {
@ -110,67 +151,7 @@ struct ColorQuadArray
} }
}; };
struct PointArray typedef QuadArray<Vertex> ColorQuadArray;
{ typedef QuadArray<SVertex> SimpleQuadArray;
std::vector<Vertex> vertices;
VBO::ID vbo;
VAO::ID vao;
PointArray()
{
vbo = VBO::gen();
vao = VAO::gen();
VAO::bind(vao);
VBO::bind(vbo);
glEnableVertexAttribArray(Shader::Color);
glEnableVertexAttribArray(Shader::Position);
glVertexAttribPointer(Shader::Color, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::colorOffset());
glVertexAttribPointer(Shader::Position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), Vertex::posOffset());
VAO::unbind();
VBO::unbind();
}
~PointArray()
{
VBO::del(vbo);
VAO::del(vao);
}
void append(const Vec2 &pos, const Vec4 &color)
{
Vertex vert;
vert.pos = pos;
vert.color = color;
vertices.push_back(vert);
}
void commit()
{
VBO::bind(vbo);
VBO::uploadData(vertices.size() * sizeof(Vertex), &vertices[0]);
VBO::unbind();
}
void reset()
{
vertices.clear();
}
void draw()
{
VAO::bind(vao);
glDrawArrays(GL_POINTS, 0, count());
VAO::unbind();
}
int count()
{
return vertices.size();
}
};
#endif // QUADARRAY_H #endif // QUADARRAY_H

View File

@ -99,13 +99,13 @@ Shader::~Shader()
void Shader::bind() void Shader::bind()
{ {
glUseProgram(program); glState.program.set(program);
} }
void Shader::unbind() void Shader::unbind()
{ {
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glUseProgram(0); glState.program.set(0);
} }
void Shader::init(const unsigned char *vert, int vertSize, void Shader::init(const unsigned char *vert, int vertSize,

View File

@ -67,8 +67,8 @@ struct SharedStatePrivate
ShaderSet shaders; ShaderSet shaders;
TexPool texPool; TexPool texPool;
FontPool fontPool;
SharedFontState fontState;
Font *defaultFont; Font *defaultFont;
TEX::ID globalTex; TEX::ID globalTex;
@ -90,6 +90,7 @@ struct SharedStatePrivate
rtData(*threadData), rtData(*threadData),
config(threadData->config), config(threadData->config),
graphics(threadData), graphics(threadData),
fontState(threadData->config),
stampCounter(0) stampCounter(0)
{ {
if (!config.gameFolder.empty()) if (!config.gameFolder.empty())
@ -121,6 +122,8 @@ struct SharedStatePrivate
if (config.pathCache) if (config.pathCache)
fileSystem.createPathCache(); fileSystem.createPathCache();
fileSystem.initFontSets(fontState);
globalTexW = 128; globalTexW = 128;
globalTexH = 64; globalTexH = 64;
@ -206,8 +209,8 @@ GSATT(Audio&, audio)
GSATT(GLState&, _glState) GSATT(GLState&, _glState)
GSATT(ShaderSet&, shaders) GSATT(ShaderSet&, shaders)
GSATT(TexPool&, texPool) GSATT(TexPool&, texPool)
GSATT(FontPool&, fontPool)
GSATT(Quad&, gpQuad) GSATT(Quad&, gpQuad)
GSATT(SharedFontState&, fontState)
void SharedState::setBindingData(void *data) void SharedState::setBindingData(void *data)
{ {

View File

@ -43,8 +43,8 @@ class Input;
class Audio; class Audio;
class GLState; class GLState;
class TexPool; class TexPool;
class FontPool;
class Font; class Font;
class SharedFontState;
struct GlobalIBO; struct GlobalIBO;
struct Config; struct Config;
struct Vec2i; struct Vec2i;
@ -74,8 +74,8 @@ struct SharedState
ShaderSet &shaders(); ShaderSet &shaders();
TexPool &texPool(); TexPool &texPool();
FontPool &fontPool();
SharedFontState &fontState();
Font &defaultFont(); Font &defaultFont();
sigc::signal<void> prepareDraw; sigc::signal<void> prepareDraw;

View File

@ -32,6 +32,9 @@
#include "transform.h" #include "transform.h"
#include "shader.h" #include "shader.h"
#include "glstate.h" #include "glstate.h"
#include "quadarray.h"
#include <math.h>
#include <SDL_rect.h> #include <SDL_rect.h>
@ -63,6 +66,22 @@ struct SpritePrivate
Color *color; Color *color;
Tone *tone; Tone *tone;
#ifdef RGSS2
struct
{
int amp;
int length;
int speed;
float phase;
/* Wave effect is active (amp != 0) */
bool active;
/* qArray needs updating */
bool dirty;
SimpleQuadArray qArray;
} wave;
#endif
EtcTemps tmp; EtcTemps tmp;
sigc::connection prepareCon; sigc::connection prepareCon;
@ -87,6 +106,13 @@ struct SpritePrivate
prepareCon = shState->prepareDraw.connect prepareCon = shState->prepareDraw.connect
(sigc::mem_fun(this, &SpritePrivate::prepare)); (sigc::mem_fun(this, &SpritePrivate::prepare));
#ifdef RGSS2
wave.amp = 0;
wave.length = 180;
wave.speed = 360;
wave.phase = 0.0;
#endif
} }
~SpritePrivate() ~SpritePrivate()
@ -117,6 +143,10 @@ struct SpritePrivate
quad.setPosRect(IntRect(0, 0, srcRect->width, srcRect->height)); quad.setPosRect(IntRect(0, 0, srcRect->width, srcRect->height));
recomputeBushDepth(); recomputeBushDepth();
#ifdef RGSS2
wave.dirty = true;
#endif
} }
void updateSrcRectCon() void updateSrcRectCon()
@ -141,6 +171,16 @@ struct SpritePrivate
if (!opacity) if (!opacity)
return; return;
#ifdef RGSS2
if (wave.active)
{
/* Don't do expensive wave bounding box
* calculations */
isVisible = true;
return;
}
#endif
/* Compare sprite bounding box against the scene */ /* Compare sprite bounding box against the scene */
/* If sprite is zoomed/rotated, just opt out for now /* If sprite is zoomed/rotated, just opt out for now
@ -161,10 +201,101 @@ struct SpritePrivate
isVisible = SDL_HasIntersection(&self, &sceneRect); isVisible = SDL_HasIntersection(&self, &sceneRect);
} }
#ifdef RGSS2
void emitWaveChunk(SVertex *&vert, float phase, int width,
float zoomY, int chunkY, int chunkLength)
{
float wavePos = phase + (chunkY / (float) wave.length) * M_PI * 2;
float chunkX = sin(wavePos) * wave.amp;
FloatRect tex(0, chunkY / zoomY, width, chunkLength / zoomY);
FloatRect pos = tex;
pos.x = chunkX;
Quad::setTexPosRect(vert, tex, pos);
vert += 4;
}
void updateWave()
{
if (!bitmap)
return;
if (wave.amp == 0)
{
wave.active = false;
return;
}
wave.active = true;
int width = srcRect->width;
int height = srcRect->height;
float zoomY = trans.getScale().y;
if (wave.amp < -(width / 2))
{
wave.qArray.resize(0);
wave.qArray.commit();
return;
}
/* RMVX does this, and I have no fucking clue why */
if (wave.amp < 0)
{
wave.qArray.resize(1);
int x = -wave.amp;
int w = width - x * 2;
FloatRect tex(x, srcRect->y, w, srcRect->height);
Quad::setTexPosRect(&wave.qArray.vertices[0], tex, tex);
wave.qArray.commit();
return;
}
/* The length of the sprite as it appears on screen */
int visibleLength = height * zoomY;
/* First chunk length (aligned to 8 pixel boundary */
int firstLength = ((int) trans.getPosition().y) % 8;
/* Amount of full 8 pixel chunks in the middle */
int chunks = (visibleLength - firstLength) / 8;
/* Final chunk length */
int lastLength = (visibleLength - firstLength) % 8;
wave.qArray.resize(!!firstLength + chunks + !!lastLength);
SVertex *vert = &wave.qArray.vertices[0];
float phase = (wave.phase * M_PI) / 180.f;
if (firstLength > 0)
emitWaveChunk(vert, phase, width, zoomY, 0, firstLength);
for (int i = 0; i < chunks; ++i)
emitWaveChunk(vert, phase, width, zoomY, firstLength + i * 8, 8);
if (lastLength > 0)
emitWaveChunk(vert, phase, width, zoomY, firstLength + chunks * 8, lastLength);
wave.qArray.commit();
}
#endif
void prepare() void prepare()
{ {
if (bitmap) #ifdef RGSS2
bitmap->flush(); if (wave.dirty)
{
updateWave();
wave.dirty = false;
}
#endif
updateVisibility(); updateVisibility();
} }
@ -196,14 +327,21 @@ DEF_ATTR_RD_SIMPLE(Sprite, Angle, float, p->trans.getRotation())
DEF_ATTR_RD_SIMPLE(Sprite, Mirror, bool, p->mirrored) DEF_ATTR_RD_SIMPLE(Sprite, Mirror, bool, p->mirrored)
DEF_ATTR_RD_SIMPLE(Sprite, BushDepth, int, p->bushDepth) DEF_ATTR_RD_SIMPLE(Sprite, BushDepth, int, p->bushDepth)
DEF_ATTR_RD_SIMPLE(Sprite, BlendType, int, p->blendType) DEF_ATTR_RD_SIMPLE(Sprite, BlendType, int, p->blendType)
DEF_ATTR_RD_SIMPLE(Sprite, Width, int, p->srcRect->width)
DEF_ATTR_RD_SIMPLE(Sprite, Height, int, p->srcRect->height)
DEF_ATTR_SIMPLE(Sprite, BushOpacity, int, p->bushOpacity) DEF_ATTR_SIMPLE(Sprite, BushOpacity, int, p->bushOpacity)
DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity) DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity)
DEF_ATTR_SIMPLE(Sprite, Color, Color*, p->color) DEF_ATTR_SIMPLE(Sprite, Color, Color*, p->color)
DEF_ATTR_SIMPLE(Sprite, Tone, Tone*, p->tone) DEF_ATTR_SIMPLE(Sprite, Tone, Tone*, p->tone)
#ifdef RGSS2
DEF_ATTR_RD_SIMPLE(Sprite, Width, int, p->srcRect->width)
DEF_ATTR_RD_SIMPLE(Sprite, Height, int, p->srcRect->height)
DEF_ATTR_RD_SIMPLE(Sprite, WaveAmp, int, p->wave.amp)
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)
#endif
void Sprite::setBitmap(Bitmap *bitmap) void Sprite::setBitmap(Bitmap *bitmap)
{ {
GUARD_DISPOSED GUARD_DISPOSED
@ -221,6 +359,10 @@ void Sprite::setBitmap(Bitmap *bitmap)
*p->srcRect = bitmap->rect(); *p->srcRect = bitmap->rect();
p->onSrcRectChange(); p->onSrcRectChange();
p->quad.setPosRect(p->srcRect->toFloatRect()); p->quad.setPosRect(p->srcRect->toFloatRect());
#ifdef RGSS2
p->wave.dirty = true;
#endif
} }
void Sprite::setSrcRect(Rect *rect) void Sprite::setSrcRect(Rect *rect)
@ -255,6 +397,10 @@ void Sprite::setY(int value)
return; return;
p->trans.setPosition(Vec2(getX(), value)); p->trans.setPosition(Vec2(getX(), value));
#ifdef RGSS2
p->wave.dirty = true;
#endif
} }
void Sprite::setOX(int value) void Sprite::setOX(int value)
@ -296,6 +442,10 @@ void Sprite::setZoomY(float value)
p->trans.setScale(Vec2(getZoomX(), value)); p->trans.setScale(Vec2(getZoomX(), value));
p->recomputeBushDepth(); p->recomputeBushDepth();
#ifdef RGSS2
p->wave.dirty = true;
#endif
} }
void Sprite::setAngle(float value) void Sprite::setAngle(float value)
@ -349,6 +499,36 @@ void Sprite::setBlendType(int type)
} }
} }
#ifdef RGSS2
#define DEF_WAVE_SETTER(Name, name, type) \
void Sprite::setWave##Name(type value) \
{ \
GUARD_DISPOSED; \
if (p->wave.name == value) \
return; \
p->wave.name = value; \
p->wave.dirty = true; \
}
DEF_WAVE_SETTER(Amp, amp, int)
DEF_WAVE_SETTER(Length, length, int)
DEF_WAVE_SETTER(Speed, speed, int)
DEF_WAVE_SETTER(Phase, phase, float)
#undef DEF_WAVE_SETTER
/* Flashable */
void Sprite::update()
{
Flashable::update();
p->wave.phase += p->wave.speed / 180;
p->wave.dirty = true;
}
#endif
/* Disposable */ /* Disposable */
void Sprite::releaseResources() void Sprite::releaseResources()
{ {
@ -410,7 +590,14 @@ void Sprite::draw()
p->bitmap->bindTex(*base); p->bitmap->bindTex(*base);
#ifdef RGSS2
if (p->wave.active)
p->wave.qArray.draw();
else
p->quad.draw(); p->quad.draw();
#else
p->quad.draw();
#endif
glState.blendMode.pop(); glState.blendMode.pop();
} }

View File

@ -41,9 +41,6 @@ public:
Sprite(Viewport *viewport = 0); Sprite(Viewport *viewport = 0);
~Sprite(); ~Sprite();
int getWidth() const;
int getHeight() const;
DECL_ATTR( Bitmap, Bitmap* ) DECL_ATTR( Bitmap, Bitmap* )
DECL_ATTR( SrcRect, Rect* ) DECL_ATTR( SrcRect, Rect* )
DECL_ATTR( X, int ) DECL_ATTR( X, int )
@ -61,6 +58,18 @@ public:
DECL_ATTR( Color, Color* ) DECL_ATTR( Color, Color* )
DECL_ATTR( Tone, Tone* ) DECL_ATTR( Tone, Tone* )
#ifdef RGSS2
int getWidth() const;
int getHeight() const;
DECL_ATTR( WaveAmp, int )
DECL_ATTR( WaveLength, int )
DECL_ATTR( WaveSpeed, int )
DECL_ATTR( WavePhase, float )
void update();
#endif
private: private:
SpritePrivate *p; SpritePrivate *p;

View File

@ -21,8 +21,6 @@
#include "tileatlas.h" #include "tileatlas.h"
#include <list>
namespace TileAtlas namespace TileAtlas
{ {
@ -37,8 +35,7 @@ struct Column
{} {}
}; };
// FIXME: this can be optimized to a vector typedef std::vector<Column> ColumnVec;
typedef std::list<Column> ColumnList;
/* Autotile area width */ /* Autotile area width */
static const int atAreaW = 96*4; static const int atAreaW = 96*4;
@ -79,9 +76,10 @@ Vec2i minSize(int tilesetH, int maxAtlasSize)
return Vec2i(-1, -1); return Vec2i(-1, -1);
} }
static ColumnList calcSrcCols(int tilesetH) static ColumnVec calcSrcCols(int tilesetH)
{ {
ColumnList cols; ColumnVec cols;
cols.reserve(2);
cols.push_back(Column(0, 0, tilesetH)); cols.push_back(Column(0, 0, tilesetH));
cols.push_back(Column(tsLaneW, 0, tilesetH)); cols.push_back(Column(tsLaneW, 0, tilesetH));
@ -89,9 +87,10 @@ static ColumnList calcSrcCols(int tilesetH)
return cols; return cols;
} }
static ColumnList calcDstCols(int atlasW, int atlasH) static ColumnVec calcDstCols(int atlasW, int atlasH)
{ {
ColumnList cols; ColumnVec cols;
cols.reserve(3);
/* Columns below the autotile area */ /* Columns below the autotile area */
const int underAt = atlasH - atAreaH; const int underAt = atlasH - atAreaH;
@ -110,19 +109,21 @@ static ColumnList calcDstCols(int atlasW, int atlasH)
return cols; return cols;
} }
static BlitList calcBlitsInt(ColumnList &srcCols, ColumnList &dstCols) static BlitVec calcBlitsInt(ColumnVec &srcCols, ColumnVec &dstCols)
{ {
BlitList blits; BlitVec blits;
while (!srcCols.empty()) /* Using signed indices here is safer, as we
{ * might decrement dstI while it is zero. */
Column srcCol = srcCols.front(); int dstI = 0;
srcCols.pop_front();
while (!dstCols.empty() && srcCol.h > 0) for (size_t srcI = 0; srcI < srcCols.size(); ++srcI)
{ {
Column dstCol = dstCols.front(); Column &srcCol = srcCols[srcI];
dstCols.pop_front();
for (; dstI < (int) dstCols.size() && srcCol.h > 0; ++dstI)
{
Column &dstCol = dstCols[dstI];
if (srcCol.h > dstCol.h) if (srcCol.h > dstCol.h)
{ {
@ -141,7 +142,10 @@ static BlitList calcBlitsInt(ColumnList &srcCols, ColumnList &dstCols)
dstCol.y += srcCol.h; dstCol.y += srcCol.h;
dstCol.h -= srcCol.h; dstCol.h -= srcCol.h;
dstCols.push_front(dstCol);
/* Queue this column up again for processing */
--dstI;
srcCol.h = 0; srcCol.h = 0;
} }
else else
@ -156,10 +160,10 @@ static BlitList calcBlitsInt(ColumnList &srcCols, ColumnList &dstCols)
return blits; return blits;
} }
BlitList calcBlits(int tilesetH, const Vec2i &atlasSize) BlitVec calcBlits(int tilesetH, const Vec2i &atlasSize)
{ {
ColumnList srcCols = calcSrcCols(tilesetH); ColumnVec srcCols = calcSrcCols(tilesetH);
ColumnList dstCols = calcDstCols(atlasSize.x, atlasSize.y); ColumnVec dstCols = calcDstCols(atlasSize.x, atlasSize.y);
return calcBlitsInt(srcCols, dstCols); return calcBlitsInt(srcCols, dstCols);
} }

View File

@ -46,16 +46,17 @@ struct Blit
{} {}
}; };
typedef std::vector<Blit> BlitList; typedef std::vector<Blit> BlitVec;
/* Calculates the minimum atlas size required to hold /* Calculates the minimum atlas size required to hold
* a tileset of height 'tilesetH'. If the required dimensions * a tileset of height 'tilesetH'. If the required dimensions
* exceed 'maxAtlasSize', Vec2i(-1, -1) is returned. */ * exceed 'maxAtlasSize', Vec2i(-1, -1) is returned. */
Vec2i minSize(int tilesetH, int maxAtlasSize); Vec2i minSize(int tilesetH, int maxAtlasSize);
/* Calculates a series of blits necessary to fill dstRows /* Calculates a series of blits necessary to fill an atlas
* with srcRows without wasting any space */ * of size 'atlasSize' with a tileset of height 'tilesetH'.
BlitList calcBlits(int tilesetH, const Vec2i &atlasSize); * Usually fed results from 'minSize()'. */
BlitVec calcBlits(int tilesetH, const Vec2i &atlasSize);
/* Translates a tile coordinate (not pixel!) to a physical /* Translates a tile coordinate (not pixel!) to a physical
* pixel coordinate in the atlas */ * pixel coordinate in the atlas */

View File

@ -48,13 +48,6 @@ extern const StaticRect autotileRects[];
typedef std::vector<SVertex> SVVector; typedef std::vector<SVertex> SVVector;
typedef struct { SVVector v[4]; } TileVBuffer; typedef struct { SVVector v[4]; } TileVBuffer;
/* Check if [C]ontainer contains [V]alue */
template<typename C, typename V>
inline bool contains(const C &c, const V &v)
{
return std::find(c.begin(), c.end(), v) != c.end();
}
static const int tilesetW = 8 * 32; static const int tilesetW = 8 * 32;
static const int autotileW = 3 * 32; static const int autotileW = 3 * 32;
static const int autotileH = 4 * 32; static const int autotileH = 4 * 32;
@ -511,8 +504,6 @@ struct TilemapPrivate
usableATs.push_back(i); usableATs.push_back(i);
autotiles[i]->flush();
if (autotiles[i]->width() > autotileW) if (autotiles[i]->width() > autotileW)
animatedATs.push_back(i); animatedATs.push_back(i);
} }
@ -623,14 +614,9 @@ struct TilemapPrivate
/* Assembles atlas from tileset and autotile bitmaps */ /* Assembles atlas from tileset and autotile bitmaps */
void buildAtlas() void buildAtlas()
{ {
tileset->flush();
updateAutotileInfo(); updateAutotileInfo();
for (size_t i = 0; i < atlas.usableATs.size(); ++i) TileAtlas::BlitVec blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
autotiles[atlas.usableATs[i]]->flush();
TileAtlas::BlitList blits = TileAtlas::calcBlits(atlas.efTilesetH, atlas.size);
/* Clear atlas */ /* Clear atlas */
FBO::bind(atlas.gl.fbo, FBO::Draw); FBO::bind(atlas.gl.fbo, FBO::Draw);

View File

@ -24,6 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <algorithm>
static inline int static inline int
wrapRange(int value, int min, int max) wrapRange(int value, int min, int max)
@ -93,6 +94,13 @@ inline void strReplace(std::string &str,
str[i] = after; str[i] = after;
} }
/* Check if [C]ontainer contains [V]alue */
template<typename C, typename V>
inline bool contains(const C &c, const V &v)
{
return std::find(c.begin(), c.end(), v) != c.end();
}
#define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0])) #define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0]))
#define elementsN(obj) const int obj##N = ARRAY_SIZE(obj) #define elementsN(obj) const int obj##N = ARRAY_SIZE(obj)

View File

@ -508,12 +508,6 @@ struct WindowPrivate
{ {
bool updateBaseQuadArray = false; bool updateBaseQuadArray = false;
if (windowskin)
windowskin->flush();
if (contents)
contents->flush();
if (baseVertDirty) if (baseVertDirty)
{ {
buildBaseVert(); buildBaseVert();