Merge branch 'dev'
This commit is contained in:
commit
58d86039d5
|
@ -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`.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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, ...);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
5
mkxp.pro
5
mkxp.pro
|
@ -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 \
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -366,6 +366,7 @@ struct SDLSoundSource : ALDataSource
|
||||||
|
|
||||||
~SDLSoundSource()
|
~SDLSoundSource()
|
||||||
{
|
{
|
||||||
|
/* This also closes 'srcOps' */
|
||||||
Sound_FreeSample(sample);
|
Sound_FreeSample(sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
|
|
||||||
~Debug()
|
~Debug()
|
||||||
{
|
{
|
||||||
std::clog << buf.str() << "\n";
|
std::clog << buf.str() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
flashAlpha = flashColor.w;
|
flashAlpha = flashColor.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update()
|
virtual void update()
|
||||||
{
|
{
|
||||||
if (!flashing)
|
if (!flashing)
|
||||||
return;
|
return;
|
||||||
|
|
174
src/font.cpp
174
src/font.cpp
|
@ -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
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
// FIXME Find out how font path resolution is done in VX/Ace
|
/* 'Regular' style */
|
||||||
std::string nameKey(filename);
|
std::string regular;
|
||||||
strToLower(nameKey);
|
|
||||||
strReplace(nameKey, ' ', '_');
|
|
||||||
|
|
||||||
bool useBundled = false;
|
/* Any other styles (used in case no 'Regular' exists) */
|
||||||
std::string path = std::string("Fonts/") + nameKey;
|
std::string other;
|
||||||
if (!shState->fileSystem().exists(path.c_str(), FileSystem::Font))
|
};
|
||||||
|
|
||||||
|
struct SharedFontStatePrivate
|
||||||
{
|
{
|
||||||
/* Use the same name key for the bundled font
|
/* Maps: font family name, To: substituted family name,
|
||||||
* even when it resulted from multiple different
|
* as specified via configuration file / arguments */
|
||||||
* font name requests. The space at the front is
|
BoostHash<std::string, std::string> subs;
|
||||||
* to prevent collisions (spaces are normally
|
|
||||||
* replaced with '_' */
|
/* Maps: font family name, To: set of physical
|
||||||
useBundled = true;
|
* font filenames located in "Fonts/" */
|
||||||
nameKey = " bundled";
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FontKey key(nameKey, size);
|
SharedFontState::~SharedFontState()
|
||||||
|
{
|
||||||
|
BoostHash<FontKey, TTF_Font*>::const_iterator iter;
|
||||||
|
for (iter = p->pool.cbegin(); iter != p->pool.cend(); ++iter)
|
||||||
|
TTF_CloseFont(iter->second);
|
||||||
|
|
||||||
TTF_Font *font = p->hash.value(key, 0);
|
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)
|
||||||
|
{
|
||||||
|
/* Check for substitutions */
|
||||||
|
if (p->subs.contains(family))
|
||||||
|
family = p->subs[family];
|
||||||
|
|
||||||
|
/* Find out if the font asset exists */
|
||||||
|
const FontSet &req = p->sets[family];
|
||||||
|
|
||||||
|
if (req.regular.empty() && req.other.empty())
|
||||||
|
{
|
||||||
|
/* Doesn't exist; use built-in font */
|
||||||
|
family = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
FontKey key(family, size);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
40
src/font.h
40
src/font.h
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -93,9 +93,6 @@ struct PlanePrivate
|
||||||
updateQuadSource();
|
updateQuadSource();
|
||||||
quadSourceDirty = false;
|
quadSourceDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitmap)
|
|
||||||
bitmap->flush();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
133
src/quadarray.h
133
src/quadarray.h
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
195
src/sprite.cpp
195
src/sprite.cpp
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
15
src/sprite.h
15
src/sprite.h
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue