Initial commit

This commit is contained in:
Jonas Kulla 2013-09-01 16:27:21 +02:00
commit ff25887f41
119 changed files with 24901 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.o
*.pro.*
*.bak
*.frag.xxd
*.ttf.xxd
mkxp

85
README.md Normal file
View File

@ -0,0 +1,85 @@
# mkxp
mkxp is a project that seeks to provide a fully open source implementation of the RGSS (Ruby Game Scripting System) interface used in the popular game creation software "RPG Maker XP" (trademark by Enterbrain, Inc.), with focus on Linux. The goal is to be able to run games created with the above software natively without changing a single file.
## Bindings
Bindings provide the interpreted language environment to run game scripts in. As of right now, they are compiled directly into the executable. Currently there are three bindings:
### MRI
Website: https://www.ruby-lang.org/en/
Matz's Ruby Interpreter, also called CRuby, is the most widely deployed version of ruby. If you're interested in running games created with RPG Maker XP, this is the one you should go for. MRI 1.8 is what was used in RPG Maker XP, however, this binding is written against 2.0 (the latest version). For games utilizing only the default scripts provided by Enterbrain, this binding works quite well so far. Note that there are language and syntax differences between 1.8 and 2.0, so some user created scripts may not work correctly.
For a list of differences, see:
http://stackoverflow.com/questions/21574/what-is-the-difference-between-ruby-1-8-and-ruby-1-9
To select this backend, run `qmake BINDING=BINDING_MRI`
### mruby (Lightweight Ruby)
Website: https://github.com/mruby/mruby
mruby is a new endeavor by Matz and others to create a more lightweight, spec-adhering, embeddable Ruby implementation. You can think of it as a Ruby version of Lua.
Due to heavy differences between mruby and MRI as well as lacking modules, running RPG Maker games with this backend will most likely not work correctly. It is provided as experimental code. You can eg. write your own ruby scripts and run them with this backend.
Some extensions to the standard classes/modules are provided taking the RPG Maker XP helpfile as a quasi "standard". These include Marshal, File, FileTest and Time.
To select this backend, run `qmake BINDING=BINDING_MRUBY`
### null
This backend only exists for testing purposes and does nothing (the engine quits immediately).
To select this backend, run `qmake BINDING=BINDING_NULL`
## Dependencies
* QtCore 4.8
* libsigc++
* PhysFS
* glew
* SDL2
* SDL2_image
* SDL2_ttf
* sfml-system 2.0
* sfml-audio 2.0
(If no version specified, assume latest)
### MRI binding:
Place a recent version of ruby in the project folder and build it.
### mruby binding:
Place a recent version of mruby in the project folder and build it.
To run mkxp, you should have a graphics card capable of at least **OpenGL 3.0**
## Building
mkxp employs Qt's qmake build system, so you'll need to install that beforehand. After cloning mkxp, run one of the above qmake calls, or simply `qmake` to select the default backend (currently MRI), then `make`.
## Configuration
mkxp reads configuration data from the file "mkxp.conf" contained in the current directory. The format is ini-style.
* "gameFolder": Specifies where mkxp will look for the game scripts. Default is the current directory.
* "customScript": Specifies a raw ruby script file to be run instead of an RPG Maker game, residing in "gameFolder".
* "RTPs": Specifies a list of space separated paths to RTPs to be used. (See next section)
Most other entries are self explanatory.
## RTPs
As of right now, mkxp doesn't support midi files, so to use the default RTPs provided by Enterbrain you will have to convert all midi tracks (those in BGM and ME) to ogg or wav. Make sure that the file names match up, ie. "foobar.mid" should be converted to "foobar.ogg".
## Fonts
In the RMXP version of RGSS, fonts are loaded directly from system specific search paths (meaning they must be installed to be available to games). Because this whole thing is a giant platform-dependent headache, I decided to implement the behavior Enterbrain thankfully added in VX Ace: loading fonts will automatically search a folder called "Fonts", which obeys the default searchpath behavior (ie. it can be located directly in the game folder, or an RTP).
If a requested font is not found, no error is generated. Instead, a built-in font is used (currently "Liberation Sans").
## What doesn't work
* Audio formats other than ogg/wav (this might change in the future)
* Audio "pitch" parameter
* The Win32API ruby class (for obvious reasons)
* Loading Bitmaps with sizes greater than the OpenGL texture size limit (around 8192 on modern cards)

BIN
assets/liberation.ttf Normal file

Binary file not shown.

View File

@ -0,0 +1,88 @@
/*
** audio-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "audio.h"
#include "globalstate.h"
#include "binding-util.h"
#include "exception.h"
#define DEF_PLAY_STOP(entity) \
RB_METHOD(audio_##entity##Play) \
{ \
RB_UNUSED_PARAM; \
const char *filename; \
int volume = 100; \
int pitch = 100; \
rb_get_args(argc, argv, "z|ii", &filename, &volume, &pitch); \
GUARD_EXC( gState->audio().entity##Play(filename, volume, pitch); ) \
return Qnil; \
} \
RB_METHOD(audio_##entity##Stop) \
{ \
RB_UNUSED_PARAM; \
gState->audio().entity##Stop(); \
return Qnil; \
}
#define DEF_FADE(entity) \
RB_METHOD(audio_##entity##Fade) \
{ \
RB_UNUSED_PARAM; \
int time; \
rb_get_args(argc, argv, "i", &time); \
gState->audio().bgmFade(time); \
return Qnil; \
}
#define DEF_PLAY_STOP_FADE(entity) \
DEF_PLAY_STOP(entity) \
DEF_FADE(entity)
DEF_PLAY_STOP_FADE( bgm )
DEF_PLAY_STOP_FADE( bgs )
DEF_PLAY_STOP_FADE( me )
DEF_PLAY_STOP( se )
#define BIND_PLAY_STOP(entity) \
_rb_define_module_function(module, #entity "_play", audio_##entity##Play); \
_rb_define_module_function(module, #entity "_stop", audio_##entity##Stop);
#define BIND_FADE(entity) \
_rb_define_module_function(module, #entity "_fade", audio_##entity##Fade);
#define BIND_PLAY_STOP_FADE(entity) \
BIND_PLAY_STOP(entity) \
BIND_FADE(entity)
void
audioBindingInit()
{
VALUE module = rb_define_module("Audio");
BIND_PLAY_STOP_FADE( bgm )
BIND_PLAY_STOP_FADE( bgs )
BIND_PLAY_STOP_FADE( me )
BIND_PLAY_STOP( se )
}

313
binding-mri/binding-mri.cpp Normal file
View File

@ -0,0 +1,313 @@
/*
** binding-mri.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "binding.h"
#include "binding-util.h"
#include "globalstate.h"
#include "eventthread.h"
#include "filesystem.h"
#include "./ruby/include/ruby.h"
#include "zlib.h"
#include <QFile>
#include <QByteArray>
#include <QDebug>
extern const char module_rpg[];
static void mriBindingExecute();
static void mriBindingTerminate();
ScriptBinding scriptBindingImpl =
{
mriBindingExecute,
mriBindingTerminate
};
ScriptBinding *scriptBinding = &scriptBindingImpl;
void tableBindingInit();
void etcBindingInit();
void fontBindingInit();
void bitmapBindingInit();
void spriteBindingInit();
void viewportBindingInit();
void planeBindingInit();
void windowBindingInit();
void tilemapBindingInit();
void inputBindingInit();
void audioBindingInit();
void graphicsBindingInit();
void fileIntBindingInit();
static VALUE mriPrint(int, VALUE*, VALUE);
static VALUE mriP(int, VALUE*, VALUE);
static void mriBindingInit()
{
tableBindingInit();
etcBindingInit();
fontBindingInit();
bitmapBindingInit();
spriteBindingInit();
viewportBindingInit();
planeBindingInit();
windowBindingInit();
tilemapBindingInit();
inputBindingInit();
audioBindingInit();
graphicsBindingInit();
fileIntBindingInit();
_rb_define_module_function(rb_mKernel, "print", mriPrint);
_rb_define_module_function(rb_mKernel, "p", mriP);
rb_eval_string(module_rpg);
rb_define_global_const("MKXP", Qtrue);
}
static void
showMsg(const QByteArray &msg)
{
gState->eThread().showMessageBox(msg.constData());
}
static void printP(int argc, VALUE *argv,
const char *convMethod, const char *sep)
{
VALUE dispString = rb_str_buf_new(128);
ID conv = rb_intern(convMethod);
for (int i = 0; i < argc; ++i)
{
VALUE str = rb_funcall(argv[i], conv, 0);
rb_str_buf_append(dispString, str);
if (i < argc)
rb_str_buf_cat2(dispString, sep);
}
showMsg(RSTRING_PTR(dispString));
rb_str_free(dispString);
}
RB_METHOD(mriPrint)
{
RB_UNUSED_PARAM;
printP(argc, argv, "to_s", "");
return Qnil;
}
RB_METHOD(mriP)
{
RB_UNUSED_PARAM;
printP(argc, argv, "inspect", "\n");
return Qnil;
}
static void runCustomScript(const char *filename)
{
QFile scriptFile(filename);
if (!scriptFile.open(QFile::ReadOnly))
{
showMsg(QByteArray("Unable to open '") + filename + "'");
return;
}
QByteArray scriptData = scriptFile.readAll();
scriptFile.close();
rb_eval_string_protect(scriptData.constData(), 0);
}
VALUE kernelLoadDataInt(const char *filename);
struct Script
{
QByteArray name;
QByteArray encData;
uint32_t unknown;
QByteArray decData;
};
static void runRMXPScripts()
{
const QByteArray &scriptPack = gState->rtData().config.game.scripts;
if (!gState->fileSystem().exists(scriptPack.constData()))
{
showMsg("Unable to open '" + scriptPack + "'");
return;
}
VALUE scriptArray = kernelLoadDataInt(scriptPack.constData());
if (rb_type(scriptArray) != RUBY_T_ARRAY)
{
showMsg("Failed to read script data");
return;
}
int scriptCount = RARRAY_LEN(scriptArray);
QByteArray decodeBuffer;
decodeBuffer.resize(0x1000);
QVector<Script> encScripts(scriptCount);
for (int i = 0; i < scriptCount; ++i)
{
VALUE script = rb_ary_entry(scriptArray, i);
if (rb_type(script) != RUBY_T_ARRAY)
{
continue;
}
VALUE scriptUnknown = rb_ary_entry(script, 0);
VALUE scriptName = rb_ary_entry(script, 1);
VALUE scriptString = rb_ary_entry(script, 2);
Script &sc = encScripts[i];
sc.name = RSTRING_PTR(scriptName);
sc.encData = QByteArray(RSTRING_PTR(scriptString), RSTRING_LEN(scriptString));
sc.unknown = FIX2UINT(scriptUnknown);
}
for (int i = 0; i < scriptCount; ++i)
{
Script &sc = encScripts[i];
int result = Z_OK;
ulong bufferLen;
while (true)
{
unsigned char *bufferPtr =
reinterpret_cast<unsigned char*>(const_cast<char*>(decodeBuffer.constData()));
const unsigned char *sourcePtr =
reinterpret_cast<const unsigned char*>(sc.encData.constData());
bufferLen = decodeBuffer.length();
result = uncompress(bufferPtr, &bufferLen,
sourcePtr, sc.encData.length());
bufferPtr[bufferLen] = '\0';
if (result != Z_BUF_ERROR)
break;
decodeBuffer.resize(decodeBuffer.size()*2);
}
if (result != Z_OK)
{
static char buffer[256];
snprintf(buffer, sizeof(buffer), "Error decoding script %d: '%s'",
i, sc.name.constData());
showMsg(buffer);
break;
}
// QFile file(QString("/home/Ancurio/programming/C++/mkxp/dump/%1.rb").arg(i, 3, 10, QChar('0')));
// if (file.open(QFile::WriteOnly))
// file.write(decodeBuffer.constData(), bufferLen);
sc.decData = QByteArray(decodeBuffer.constData(), bufferLen);
ruby_script(sc.name.constData());
rb_gc_start();
qDebug() << "Executing script:" << QString("%1").arg(i, 3, 10, QChar('0'));
/* Execute code */
rb_eval_string_protect(decodeBuffer.constData(), 0);
VALUE exc = rb_gv_get("$!");
if (rb_type(exc) != RUBY_T_NIL)
break;
}
// QFile file("/home/Ancurio/programming/C++/mkxp/dump/index");
// if (file.open(QFile::WriteOnly))
// {
// for (int i = 0; i < encScripts.size(); ++i)
// {
// const Script &sc = encScripts[i];
// file.write(sc.name);
// }
// }
}
static void mriBindingExecute()
{
ruby_setup();
RbData rbData;
gState->setBindingData(&rbData);
mriBindingInit();
QByteArray &customScript = gState->rtData().config.customScript;
if (!customScript.isEmpty())
runCustomScript(customScript.constData());
else
runRMXPScripts();
VALUE exc = rb_gv_get("$!");
if (rb_type(exc) != RUBY_T_NIL && !rb_eql(rb_obj_class(exc), rb_eSystemExit))
{
qDebug() << "Had exception:" << rb_class2name(rb_obj_class(exc));
VALUE bt = rb_funcall(exc, rb_intern("backtrace"), 0);
rb_p(bt);
VALUE msg = rb_funcall(exc, rb_intern("message"), 0);
if (RSTRING_LEN(msg) < 256)
showMsg(RSTRING_PTR(msg));
else
qDebug() << (RSTRING_PTR(msg));
}
ruby_cleanup(0);
gState->rtData().rqTermAck = true;
}
static void mriBindingTerminate()
{
rb_raise(rb_eSystemExit, " ");
}

View File

@ -0,0 +1,40 @@
/*
** binding-types.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BINDINGTYPES_H
#define BINDINGTYPES_H
#include "binding-util.h"
DECL_TYPE(Table);
DECL_TYPE(Rect);
DECL_TYPE(Color);
DECL_TYPE(Tone);
DECL_TYPE(Font);
DECL_TYPE(Bitmap);
DECL_TYPE(Sprite);
DECL_TYPE(Plane);
DECL_TYPE(Viewport);
DECL_TYPE(Tilemap);
DECL_TYPE(Window);
#endif // BINDINGTYPES_H

View File

@ -0,0 +1,306 @@
/*
** binding-util.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "binding-util.h"
#include "globalstate.h"
#include "exception.h"
#include "util.h"
#include <stdarg.h>
#include <QDebug>
void initType(rb_data_type_struct &type,
const char *name,
void (*freeInst)(void *))
{
type.wrap_struct_name = name;
type.function.dmark = 0;
type.function.dsize = 0;
type.function.dfree = freeInst;
type.function.reserved[0] =
type.function.reserved[1] = 0;
type.parent = 0;
}
RbData *getRbData()
{
return static_cast<RbData*>(gState->bindingData());
}
//enum RbException
//{
// RGSS = 0,
// PHYSFS,
// SDL,
// ErrnoENOENT,
// IOError,
// TypeError,
// ArgumentError,
// RbExceptionsMax
//};
struct
{
RbException id;
const char *name;
} static customExc[] =
{
{ RGSS, "RGSSError" },
{ PHYSFS, "PHYSFSError" },
{ SDL, "SDLError" }
};
RbData::RbData()
{
for (size_t i = 0; i < ARRAY_SIZE(customExc); ++i)
exc[customExc[i].id] = rb_define_class(customExc[i].name, rb_eException);
exc[ErrnoENOENT] = rb_const_get(rb_const_get(rb_cObject, rb_intern("Errno")), rb_intern("ENOENT"));
exc[IOError] = rb_eIOError;
exc[TypeError] = rb_eTypeError;
exc[ArgumentError] = rb_eArgError;
}
RbData::~RbData()
{
}
/* Indexed with Exception::Type */
static const RbException excToRbExc[] =
{
RGSS, /* RGSSError */
ErrnoENOENT, /* NoFileError */
IOError,
TypeError,
ArgumentError,
PHYSFS, /* PHYSFSError */
SDL /* SDLError */
};
void raiseRbExc(const Exception &exc)
{
RbData *data = getRbData();
VALUE excClass = data->exc[excToRbExc[exc.type]];
static char buffer[512];
exc.snprintf(buffer, sizeof(buffer));
rb_raise(excClass, buffer);
}
int
rb_get_args(int argc, VALUE *argv, const char *format, ...)
{
char c;
VALUE *arg = argv;
va_list ap;
bool opt = false;
int argI = 0;
va_start(ap, format);
while ((c = *format++))
{
switch (c)
{
case '|' :
break;
default:
// FIXME print num of needed args vs provided
if (argc <= argI && !opt)
rb_raise(rb_eArgError, "wrong number of arguments");
break;
}
if (argI >= argc)
break;
switch (c)
{
case 'o' :
{
if (argI >= argc)
break;
VALUE *obj = va_arg(ap, VALUE*);
*obj = *arg++;
++argI;
break;
}
case 'S' :
{
if (argI >= argc)
break;
VALUE *str = va_arg(ap, VALUE*);
VALUE tmp = *arg;
if (!rb_type(tmp) == RUBY_T_STRING)
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*str = tmp;
++argI;
break;
}
case 's' :
{
if (argI >= argc)
break;
const char **s = va_arg(ap, const char**);
int *len = va_arg(ap, int*);
VALUE tmp = *arg;
if (!rb_type(tmp) == RUBY_T_STRING)
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*s = RSTRING_PTR(tmp);
*len = RSTRING_LEN(tmp);
++argI;
break;
}
case 'z' :
{
if (argI >= argc)
break;
const char **s = va_arg(ap, const char**);
VALUE tmp = *arg++;
if (!rb_type(tmp) == RUBY_T_STRING)
rb_raise(rb_eTypeError, "Argument %d: Expected string", argI);
*s = RSTRING_PTR(tmp);
++argI;
break;
}
case 'f' :
{
if (argI >= argc)
break;
double *f = va_arg(ap, double*);
VALUE fVal = *arg++;
switch (rb_type(fVal))
{
case RUBY_T_FLOAT :
*f = rb_float_value(fVal);
break;
case RUBY_T_FIXNUM :
*f = rb_fix2int(fVal);
break;
default:
rb_raise(rb_eTypeError, "Argument %d: Expected float", argI);
}
++argI;
break;
}
case 'i' :
{
if (argI >= argc)
break;
int *i = va_arg(ap, int*);
VALUE iVal = *arg++;
switch (rb_type(iVal))
{
case RUBY_T_FLOAT :
// FIXME check int range?
*i = rb_num2long(iVal);
break;
case RUBY_T_FIXNUM :
*i = rb_fix2int(iVal);
break;
default:
rb_raise(rb_eTypeError, "Argument %d: Expected fixnum", argI);
}
++argI;
break;
}
case 'b' :
{
if (argI >= argc)
break;
bool *b = va_arg(ap, bool*);
VALUE bVal = *arg++;
switch (rb_type(bVal))
{
case RUBY_T_TRUE :
*b = true;
break;
case RUBY_T_FALSE :
case RUBY_T_NIL :
*b = false;
break;
default:
rb_raise(rb_eTypeError, "Argument %d: Expected bool", argI);
}
++argI;
break;
}
case '|' :
opt = true;
break;
default:
rb_raise(rb_eFatal, "invalid argument specifier %c", c);
}
}
// FIXME print num of needed args vs provided
if (!c && argc > argI)
rb_raise(rb_eArgError, "wrong number of arguments");
va_end(ap);
return argI;
}

297
binding-mri/binding-util.h Normal file
View File

@ -0,0 +1,297 @@
/*
** binding-util.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BINDING_UTIL_H
#define BINDING_UTIL_H
#include "./ruby/ruby.h"
#define PRIV_IV "priv"
enum RbException
{
RGSS = 0,
PHYSFS,
SDL,
ErrnoENOENT,
IOError,
TypeError,
ArgumentError,
RbExceptionsMax
};
struct RbData
{
VALUE exc[RbExceptionsMax];
RbData();
~RbData();
};
RbData *getRbData();
struct Exception;
void
raiseRbExc(const Exception &exc);
#define DECL_TYPE(Klass) \
extern rb_data_type_struct Klass##Type
#define DEF_TYPE(Klass) \
rb_data_type_struct Klass##Type
void initType(rb_data_type_struct &type,
const char *name,
void (*freeInst)(void*));
template<class C>
static inline void freeInstance(void *inst)
{
delete static_cast<C*>(inst);
}
#define INIT_TYPE(Klass) initType(Klass##Type, #Klass, freeInstance<Klass>)
template<class C>
static inline C *
getPrivateData(VALUE self)
{
VALUE priv = rb_iv_get(self, PRIV_IV);
return static_cast<C*>(RTYPEDDATA_DATA(priv));
}
template<class C>
static inline C *
getPrivateDataCheck(VALUE self, const rb_data_type_struct &type)
{
VALUE priv = rb_iv_get(self, PRIV_IV);
void *obj = rb_check_typeddata(priv, &type);
return static_cast<C*>(obj);
}
static inline void
setPrivateData(VALUE self, void *p, const rb_data_type_struct &type)
{
VALUE priv = rb_data_typed_object_alloc(rb_cData, p, &type);
rb_iv_set(self, PRIV_IV, priv);
}
inline VALUE
wrapObject(void *p, const rb_data_type_struct &type)
{
VALUE klass = rb_const_get(rb_cObject, rb_intern(type.wrap_struct_name));
VALUE obj = rb_obj_alloc(klass);
setPrivateData(obj, p, type);
return obj;
}
inline VALUE
wrapProperty(VALUE self, void *prop, const char *iv,
const rb_data_type_struct &type)
{
VALUE propObj = wrapObject(prop, type);
rb_iv_set(self, iv, propObj);
return propObj;
}
inline void
wrapNilProperty(VALUE self, const char *iv)
{
rb_iv_set(self, iv, Qnil);
}
/* Implemented: oSszfib| */
int
rb_get_args(int argc, VALUE *argv, const char *format, ...);
typedef VALUE (*RubyMethod)(int argc, VALUE *argv, VALUE self);
static inline void
_rb_define_method(VALUE klass, const char *name, RubyMethod func)
{
rb_define_method(klass, name, RUBY_METHOD_FUNC(func), -1);
}
static inline void
rb_define_class_method(VALUE klass, const char *name, RubyMethod func)
{
rb_define_singleton_method(klass, name, RUBY_METHOD_FUNC(func), -1);
}
static inline void
_rb_define_module_function(VALUE module, const char *name, RubyMethod func)
{
rb_define_module_function(module, name, RUBY_METHOD_FUNC(func), -1);
}
template<class C>
static inline VALUE
objectLoad(int argc, VALUE *argv, VALUE self, rb_data_type_struct &type)
{
const char *data;
int dataLen;
rb_get_args(argc, argv, "s", &data, &dataLen);
VALUE obj = rb_obj_alloc(self);
C *c = C::deserialize(data, dataLen);
setPrivateData(obj, c, type);
return obj;
}
static inline VALUE
rb_bool_new(bool value)
{
return value ? Qtrue : Qfalse;
}
#define RB_METHOD(name) \
static VALUE name(int argc, VALUE *argv, VALUE self)
#define RB_UNUSED_PARAM \
{ (void) argc; (void) argv; (void) self; }
#define MARSH_LOAD_FUN(Typ) \
RB_METHOD(Typ##Load) \
{ \
return objectLoad<Typ>(argc, argv, self, Typ##Type); \
}
#define CLONE_FUNC(Klass) \
static mrb_value \
Klass##Clone(mrb_state *mrb, mrb_value self) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); \
mrb_value dupObj = mrb_obj_clone(mrb, self); \
Klass *dupK = new Klass(*k); \
setPrivateData(mrb, dupObj, dupK, Klass##Type); \
return dupObj; \
}
#define CLONE_FUN(Klass) \
RB_METHOD(Klass##Clone) \
{ \
RB_UNUSED_PARAM \
Klass *k = getPrivateData<Klass>(self); \
VALUE dupObj = rb_obj_clone(self); \
Klass *dupK = new Klass(*k); \
setPrivateData(dupObj, dupK, Klass##Type); \
return dupObj; \
}
/* If we're not binding a disposable class,
* we want to #undef DEF_PROP_CHK_DISP */
#define DEF_PROP_CHK_DISP \
checkDisposed(k, DISP_CLASS_NAME);
#define DEF_PROP_OBJ(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) \
{ \
RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); (void) k; \
DEF_PROP_CHK_DISP \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) \
{ \
Klass *k = getPrivateData<Klass>(self); \
VALUE propObj; \
PropKlass *prop; \
rb_get_args(argc, argv, "o", &propObj); \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC( k->set##PropName(prop); ) \
rb_iv_set(self, prop_iv, propObj); \
return propObj; \
}
/* Object property with allowed NIL */
#define DEF_PROP_OBJ_NIL(Klass, PropKlass, PropName, prop_iv) \
RB_METHOD(Klass##Get##PropName) \
{ \
RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); (void) k; \
DEF_PROP_CHK_DISP \
return rb_iv_get(self, prop_iv); \
} \
RB_METHOD(Klass##Set##PropName) \
{ \
RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \
VALUE propObj; \
PropKlass *prop; \
rb_get_args(argc, argv, "o", &propObj); \
if (rb_type(propObj) == RUBY_T_NIL) \
prop = 0; \
else \
prop = getPrivateDataCheck<PropKlass>(propObj, PropKlass##Type); \
GUARD_EXC( k->set##PropName(prop); ) \
rb_iv_set(self, prop_iv, propObj); \
return propObj; \
}
#define DEF_PROP(Klass, type, PropName, param_t_s, value_fun) \
RB_METHOD(Klass##Get##PropName) \
{ \
RB_UNUSED_PARAM; \
Klass *k = getPrivateData<Klass>(self); \
DEF_PROP_CHK_DISP \
return value_fun(k->get##PropName()); \
} \
RB_METHOD(Klass##Set##PropName) \
{ \
Klass *k = getPrivateData<Klass>(self); \
type value; \
rb_get_args(argc, argv, param_t_s, &value); \
GUARD_EXC( k->set##PropName(value); ) \
return value_fun(value); \
}
#define DEF_PROP_I(Klass, PropName) \
DEF_PROP(Klass, int, PropName, "i", rb_fix_new)
#define DEF_PROP_F(Klass, PropName) \
DEF_PROP(Klass, double, PropName, "f", rb_float_new)
#define DEF_PROP_B(Klass, PropName) \
DEF_PROP(Klass, bool, PropName, "b", rb_bool_new)
#define INIT_PROP_BIND(Klass, PropName, prop_name_s) \
{ \
_rb_define_method(klass, prop_name_s, Klass##Get##PropName); \
_rb_define_method(klass, prop_name_s "=", Klass##Set##PropName); \
}
#define GUARD_EXC(exp) \
{ try { exp } catch (const Exception &exc) { raiseRbExc(exc); } }
#endif // BINDING_UTIL_H

View File

@ -0,0 +1,324 @@
/*
** bitmap-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bitmap.h"
#include "font.h"
#include "exception.h"
#include "disposable-binding.h"
#include "binding-util.h"
#include "binding-types.h"
#include <QDebug>
#define DISP_CLASS_NAME "bitmap"
DEF_TYPE(Bitmap);
RB_METHOD(bitmapInitialize)
{
Bitmap *b = 0;
if (argc == 1)
{
char *filename;
rb_get_args(argc, argv, "z", &filename);
GUARD_EXC( b = new Bitmap(filename); )
}
else
{
int width, height;
rb_get_args(argc, argv, "ii", &width, &height);
b = new Bitmap(width, height);
}
setPrivateData(self, b, BitmapType);
/* Wrap properties */
Font *font = new Font();
b->setFont(font);
font->setColor(new Color(*font->getColor()));
VALUE fontProp = wrapProperty(self, font, "font", FontType);
wrapProperty(fontProp, font->getColor(), "color", ColorType);
return self;
}
RB_METHOD(bitmapWidth)
{
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0;
GUARD_EXC( value = b->width(); );
return INT2FIX(value);
}
RB_METHOD(bitmapHeight)
{
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
int value = 0;
GUARD_EXC( value = b->height(); );
return INT2FIX(value);
}
RB_METHOD(bitmapRect)
{
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
IntRect rect;
GUARD_EXC( rect = b->rect(); );
Rect *r = new Rect(rect);
return wrapObject(r, RectType);
}
RB_METHOD(bitmapBlt)
{
Bitmap *b = getPrivateData<Bitmap>(self);
int x, y;
VALUE srcObj;
VALUE srcRectObj;
int opacity = 255;
Bitmap *src;
Rect *srcRect;
rb_get_args(argc, argv, "iioo|i", &x, &y, &srcObj, &srcRectObj, &opacity);
src = getPrivateDataCheck<Bitmap>(srcObj, BitmapType);
srcRect = getPrivateDataCheck<Rect>(srcRectObj, RectType);
GUARD_EXC( b->blt(x, y, *src, srcRect->toIntRect(), opacity); );
return self;
}
RB_METHOD(bitmapStretchBlt)
{
Bitmap *b = getPrivateData<Bitmap>(self);
VALUE destRectObj;
VALUE srcObj;
VALUE srcRectObj;
int opacity = 255;
Bitmap *src;
Rect *destRect, *srcRect;
rb_get_args(argc, argv, "ooo|i", &destRectObj, &srcObj, &srcRectObj);
src = getPrivateDataCheck<Bitmap>(srcObj, BitmapType);
destRect = getPrivateDataCheck<Rect>(destRectObj, RectType);
srcRect = getPrivateDataCheck<Rect>(srcRectObj, RectType);
GUARD_EXC( b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(), opacity); );
return self;
}
RB_METHOD(bitmapFillRect)
{
Bitmap *b = getPrivateData<Bitmap>(self);
VALUE colorObj;
Color *color;
if (argc == 2)
{
VALUE rectObj;
Rect *rect;
rb_get_args(argc, argv, "oo", &rectObj, &colorObj);
rect = getPrivateDataCheck<Rect>(rectObj, RectType);
color = getPrivateDataCheck<Color>(colorObj, ColorType);
GUARD_EXC( b->fillRect(rect->toIntRect(), color->norm); );
}
else
{
int x, y, width, height;
rb_get_args(argc, argv, "iiiio", &x, &y, &width, &height, &colorObj);
color = getPrivateDataCheck<Color>(colorObj, ColorType);
GUARD_EXC( b->fillRect(x, y, width, height, color->norm); );
}
return self;
}
RB_METHOD(bitmapClear)
{
RB_UNUSED_PARAM;
Bitmap *b = getPrivateData<Bitmap>(self);
GUARD_EXC( b->clear(); )
return self;
}
RB_METHOD(bitmapGetPixel)
{
Bitmap *b = getPrivateData<Bitmap>(self);
int x, y;
rb_get_args(argc, argv, "ii", &x, &y);
GUARD_EXC(
if (x < 0 || y < 0 || x >= b->width() || y >= b->height())
return Qnil;
)
Vec4 value;
GUARD_EXC( value = b->getPixel(x, y); );
Color *color = new Color(value);
return wrapObject(color, ColorType);
}
RB_METHOD(bitmapSetPixel)
{
Bitmap *b = getPrivateData<Bitmap>(self);
int x, y;
VALUE colorObj;
Color *color;
rb_get_args(argc, argv, "iio", &x, &y, &colorObj);
color = getPrivateDataCheck<Color>(colorObj, ColorType);
GUARD_EXC( b->setPixel(x, y, color->norm); );
return self;
}
RB_METHOD(bitmapHueChange)
{
Bitmap *b = getPrivateData<Bitmap>(self);
int hue;
rb_get_args(argc, argv, "i", &hue);
GUARD_EXC( b->hueChange(hue); );
return self;
}
RB_METHOD(bitmapDrawText)
{
Bitmap *b = getPrivateData<Bitmap>(self);
const char *str;
int align = Bitmap::Left;
if (argc == 2 || argc == 3)
{
VALUE rectObj;
Rect *rect;
rb_get_args(argc, argv, "oz|i", &rectObj, &str, &align);
rect = getPrivateDataCheck<Rect>(rectObj, RectType);
GUARD_EXC( b->drawText(rect->toIntRect(), str, align); );
}
else
{
int x, y, width, height;
rb_get_args(argc, argv, "iiiiz|i", &x, &y, &width, &height, &str, &align);
GUARD_EXC( b->drawText(x, y, width, height, str, align); );
}
return self;
}
RB_METHOD(bitmapTextSize)
{
Bitmap *b = getPrivateData<Bitmap>(self);
const char *str;
rb_get_args(argc, argv, "z", &str);
IntRect value;
GUARD_EXC( value = b->textSize(str); );
Rect *rect = new Rect(value);
return wrapObject(rect, RectType);
}
DEF_PROP_OBJ(Bitmap, Font, Font, "font")
CLONE_FUN(Bitmap)
void
bitmapBindingInit()
{
INIT_TYPE(Bitmap);
VALUE klass = rb_define_class("Bitmap", rb_cObject);
disposableBindingInit<Bitmap>(klass);
_rb_define_method(klass, "initialize", bitmapInitialize);
_rb_define_method(klass, "width", bitmapWidth);
_rb_define_method(klass, "height", bitmapHeight);
_rb_define_method(klass, "rect", bitmapRect);
_rb_define_method(klass, "blt", bitmapBlt);
_rb_define_method(klass, "stretch_blt", bitmapStretchBlt);
_rb_define_method(klass, "fill_rect", bitmapFillRect);
_rb_define_method(klass, "clear", bitmapClear);
_rb_define_method(klass, "get_pixel", bitmapGetPixel);
_rb_define_method(klass, "set_pixel", bitmapSetPixel);
_rb_define_method(klass, "hue_change", bitmapHueChange);
_rb_define_method(klass, "draw_text", bitmapDrawText);
_rb_define_method(klass, "text_size", bitmapTextSize);
INIT_PROP_BIND(Bitmap, Font, "font");
_rb_define_method(klass, "clone", BitmapClone);
}

View File

@ -0,0 +1,65 @@
/*
** disposable-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DISPOSABLEBINDING_H
#define DISPOSABLEBINDING_H
#include "disposable.h"
#include "binding-util.h"
template<class C>
RB_METHOD(disposableDispose)
{
RB_UNUSED_PARAM;
Disposable *d = getPrivateData<C>(self);
d->dispose();
return Qnil;
}
template<class C>
RB_METHOD(disposableIsDisposed)
{
RB_UNUSED_PARAM;
Disposable *d = getPrivateData<C>(self);
return rb_bool_new(d->isDisposed());
}
template<class C>
static void disposableBindingInit(VALUE klass)
{
_rb_define_method(klass, "dispose", disposableDispose<C>);
_rb_define_method(klass, "disposed?", disposableIsDisposed<C>);
}
inline void checkDisposed(Disposable *d, const char *klassName)
{
RbData *data = getRbData(); (void) data;
if (d->isDisposed())
rb_raise(getRbData()->exc[RGSS], "disposed %s", klassName);
}
#endif // DISPOSABLEBINDING_H

204
binding-mri/etc-binding.cpp Normal file
View File

@ -0,0 +1,204 @@
/*
** etc-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "etc.h"
#include "binding-util.h"
#include "serializable-binding.h"
#include <QDebug>
DEF_TYPE(Color);
DEF_TYPE(Tone);
DEF_TYPE(Rect);
#define ATTR_RW(Klass, Attr, arg_type, arg_t_s, value_fun) \
RB_METHOD(Klass##Get##Attr) \
{ \
RB_UNUSED_PARAM \
Klass *p = getPrivateData<Klass>(self); \
return value_fun(p->get##Attr()); \
} \
RB_METHOD(Klass##Set##Attr) \
{ \
Klass *p = getPrivateData<Klass>(self); \
arg_type arg; \
rb_get_args(argc, argv, arg_t_s, &arg); \
p->set##Attr(arg); \
return *argv; \
}
#define ATTR_DOUBLE_RW(Klass, Attr) ATTR_RW(Klass, Attr, double, "f", rb_float_new)
#define ATTR_INT_RW(Klass, Attr) ATTR_RW(Klass, Attr, int, "i", rb_fix_new)
ATTR_DOUBLE_RW(Color, Red)
ATTR_DOUBLE_RW(Color, Green)
ATTR_DOUBLE_RW(Color, Blue)
ATTR_DOUBLE_RW(Color, Alpha)
ATTR_DOUBLE_RW(Tone, Red)
ATTR_DOUBLE_RW(Tone, Green)
ATTR_DOUBLE_RW(Tone, Blue)
ATTR_DOUBLE_RW(Tone, Gray)
ATTR_INT_RW(Rect, X)
ATTR_INT_RW(Rect, Y)
ATTR_INT_RW(Rect, Width)
ATTR_INT_RW(Rect, Height)
#define EQUAL_FUN(Klass) \
RB_METHOD(Klass##Equal) \
{ \
Klass *p = getPrivateData<Klass>(self); \
VALUE otherObj; \
Klass *other; \
rb_get_args(argc, argv, "o", &otherObj); \
other = getPrivateDataCheck<Klass>(otherObj, Klass##Type); \
return rb_bool_new(*p == *other); \
}
EQUAL_FUN(Color)
EQUAL_FUN(Tone)
EQUAL_FUN(Rect)
#define INIT_FUN(Klass, param_type, param_t_s, last_param_def) \
RB_METHOD(Klass##Initialize) \
{ \
param_type p1, p2, p3, p4 = last_param_def; \
rb_get_args(argc, argv, param_t_s, &p1, &p2, &p3, &p4); \
Klass *k = new Klass(p1, p2, p3, p4); \
setPrivateData(self, k, Klass##Type); \
return self; \
}
INIT_FUN(Color, double, "fff|f", 255)
INIT_FUN(Tone, double, "fff|f", 0)
INIT_FUN(Rect, int, "iiii", 0)
#define SET_FUN(Klass, param_type, param_t_s, last_param_def) \
RB_METHOD(Klass##Set) \
{ \
param_type p1, p2, p3, p4 = last_param_def; \
rb_get_args(argc, argv, param_t_s, &p1, &p2, &p3, &p4); \
Klass *k = getPrivateData<Klass>(self); \
k->set(p1, p2, p3, p4); \
return self; \
}
SET_FUN(Color, double, "fff|f", 255)
SET_FUN(Tone, double, "fff|f", 0)
SET_FUN(Rect, int, "iiii", 0)
RB_METHOD(rectEmpty)
{
RB_UNUSED_PARAM;
Rect *r = getPrivateData<Rect>(self);
r->empty();
return self;
}
RB_METHOD(ColorStringify)
{
RB_UNUSED_PARAM;
Color *c = getPrivateData<Color>(self);
return rb_sprintf("(%f, %f, %f, %f)",
c->red, c->green, c->blue, c->alpha);
}
RB_METHOD(ToneStringify)
{
RB_UNUSED_PARAM;
Tone *t = getPrivateData<Tone>(self);
return rb_sprintf("(%f, %f, %f, %f)",
t->red, t->green, t->blue, t->gray);
}
RB_METHOD(RectStringify)
{
RB_UNUSED_PARAM;
Rect *r = getPrivateData<Rect>(self);
return rb_sprintf("(%d, %d, %d, %d)",
r->x, r->y, r->width, r->height);
}
MARSH_LOAD_FUN(Color)
MARSH_LOAD_FUN(Tone)
MARSH_LOAD_FUN(Rect)
CLONE_FUN(Tone)
CLONE_FUN(Color)
CLONE_FUN(Rect)
#define INIT_BIND(Klass) \
{ \
INIT_TYPE(Klass); \
klass = rb_define_class(#Klass, rb_cObject); \
rb_define_class_method(klass, "_load", Klass##Load); \
serializableBindingInit<Klass>(klass); \
_rb_define_method(klass, "initialize", Klass##Initialize); \
_rb_define_method(klass, "set", Klass##Set); \
_rb_define_method(klass, "clone", Klass##Clone); \
_rb_define_method(klass, "==", Klass##Equal); \
_rb_define_method(klass, "to_s", Klass##Stringify); \
_rb_define_method(klass, "inspect", Klass##Stringify); \
}
#define MRB_ATTR_R(Class, attr) mrb_define_method(mrb, klass, #attr, 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_RW(Class, attr) { MRB_ATTR_R(Class, attr); MRB_ATTR_W(Class, attr); }
#define RB_ATTR_R(Klass, Attr, attr) _rb_define_method(klass, #attr, Klass##Get##Attr)
#define RB_ATTR_W(Klass, Attr, attr) _rb_define_method(klass, #attr "=", Klass##Set##Attr)
#define RB_ATTR_RW(Klass, Attr, attr) \
{ RB_ATTR_R(Klass, Attr, attr); RB_ATTR_W(Klass, Attr, attr); }
void
etcBindingInit()
{
VALUE klass;
INIT_BIND(Color);
RB_ATTR_RW(Color, Red, red);
RB_ATTR_RW(Color, Green, green);
RB_ATTR_RW(Color, Blue, blue);
RB_ATTR_RW(Color, Alpha, alpha);
INIT_BIND(Tone);
RB_ATTR_RW(Tone, Red, red);
RB_ATTR_RW(Tone, Green, green);
RB_ATTR_RW(Tone, Blue, blue);
RB_ATTR_RW(Tone, Gray, gray);
INIT_BIND(Rect);
RB_ATTR_RW(Rect, X, x);
RB_ATTR_RW(Rect, Y, y);
RB_ATTR_RW(Rect, Width, width);
RB_ATTR_RW(Rect, Height, height);
_rb_define_method(klass, "empty", rectEmpty);
}

View File

@ -0,0 +1,173 @@
/*
** filesystem-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "binding-util.h"
#include "globalstate.h"
#include "filesystem.h"
#include <QDebug>
DEF_TYPE(FileInt);
static VALUE
fileIntForPath(const char *path)
{
SDL_RWops *ops = SDL_AllocRW();
gState->fileSystem().openRead(*ops, path);
VALUE klass = rb_const_get(rb_cObject, rb_intern("FileInt"));
VALUE obj = rb_obj_alloc(klass);
setPrivateData(obj, ops, FileIntType);
return obj;
}
RB_METHOD(fileIntRead)
{
int length = -1;
rb_get_args(argc, argv, "i", &length);
SDL_RWops *ops = getPrivateData<SDL_RWops>(self);
if (length == -1)
{
Sint64 cur = SDL_RWtell(ops);
Sint64 end = SDL_RWseek(ops, 0, SEEK_END);
length = end - cur;
SDL_RWseek(ops, cur, SEEK_SET);
}
if (length == 0)
return Qnil;
VALUE data = rb_str_new(0, length);
SDL_RWread(ops, RSTRING_PTR(data), 1, length);
return data;
}
RB_METHOD(fileIntClose)
{
RB_UNUSED_PARAM;
SDL_RWops *ops = getPrivateData<SDL_RWops>(self);
SDL_RWclose(ops);
return Qnil;
}
RB_METHOD(fileIntGetByte)
{
RB_UNUSED_PARAM;
SDL_RWops *ops = getPrivateData<SDL_RWops>(self);
unsigned char byte;
size_t result = SDL_RWread(ops, &byte, 1, 1);
return (result == 1) ? rb_fix_new(byte) : Qnil;
}
RB_METHOD(fileIntBinmode)
{
RB_UNUSED_PARAM;
return Qnil;
}
static void
fileIntFreeInstance(void *inst)
{
SDL_RWops *ops = static_cast<SDL_RWops*>(inst);
SDL_RWclose(ops);
SDL_FreeRW(ops);
}
VALUE
kernelLoadDataInt(const char *filename)
{
rb_gc_start();
VALUE port = fileIntForPath(filename);
VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal"));
VALUE result = rb_funcall(marsh, rb_intern("load"), 1, port);
rb_funcall(port, rb_intern("close"), 0);
return result;
}
RB_METHOD(kernelLoadData)
{
RB_UNUSED_PARAM;
const char *filename;
rb_get_args(argc, argv, "z", &filename);
return kernelLoadDataInt(filename);
}
RB_METHOD(kernelSaveData)
{
RB_UNUSED_PARAM;
VALUE obj;
VALUE filename;
rb_get_args(argc, argv, "oS", &obj, &filename);
VALUE file = rb_funcall(rb_cFile, rb_intern("open"), 2, filename, rb_str_new_cstr("w"));
VALUE marsh = rb_const_get(rb_cObject, rb_intern("Marshal"));
rb_funcall(marsh, rb_intern("dump"), 2, obj, file);
rb_funcall(file, rb_intern("close"), 0);
return Qnil;
}
void
fileIntBindingInit()
{
initType(FileIntType, "FileInt", fileIntFreeInstance);
VALUE klass = rb_define_class("FileInt", rb_cIO);
_rb_define_method(klass, "read", fileIntRead);
// _rb_define_method(klass, "eof?", fileIntIsEof);
// _rb_define_method(klass, "pos", fileIntGetPos);
// _rb_define_method(klass, "pos=", fileIntSetPos);
_rb_define_method(klass, "getbyte", fileIntGetByte);
_rb_define_method(klass, "binmode", fileIntBinmode);
_rb_define_method(klass, "close", fileIntClose);
_rb_define_module_function(rb_mKernel, "load_data", kernelLoadData);
_rb_define_module_function(rb_mKernel, "save_data", kernelSaveData);
}

View File

@ -0,0 +1,73 @@
/*
** flashable-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FLASHABLEBINDING_H
#define FLASHABLEBINDING_H
#include "flashable.h"
#include "binding-util.h"
#include "binding-types.h"
template<class C>
RB_METHOD(flashableFlash)
{
Flashable *f = getPrivateData<C>(self);
VALUE colorObj;
int duration;
Color *color;
rb_get_args(argc, argv, "oi", &colorObj, &duration);
if (rb_type(colorObj) == RUBY_T_NIL)
{
f->flash(0, duration);
return Qnil;
}
color = getPrivateDataCheck<Color>(colorObj, ColorType);
f->flash(&color->norm, duration);
return Qnil;
}
template<class C>
RB_METHOD(flashableUpdate)
{
RB_UNUSED_PARAM;
Flashable *f = getPrivateData<C>(self);
f->update();
return Qnil;
}
template<class C>
static void flashableBindingInit(VALUE klass)
{
_rb_define_method(klass, "flash", flashableFlash<C>);
_rb_define_method(klass, "update", flashableUpdate<C>);
}
#endif // FLASHABLEBINDING_H

View File

@ -0,0 +1,173 @@
/*
** font-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "font.h"
#include "binding-util.h"
#include "binding-types.h"
#include "exception.h"
DEF_TYPE(Font);
RB_METHOD(fontDoesExist)
{
RB_UNUSED_PARAM;
const char *name;
rb_get_args(argc, argv, "z", &name);
return rb_bool_new(Font::doesExist(name));
}
RB_METHOD(fontInitialize)
{
const char *name = 0;
int size = 0;
rb_get_args(argc, argv, "|zi", &name, &size);
Font *f = new Font(name, size);
setPrivateData(self, f, FontType);
/* Wrap property objects */
f->setColor(new Color(*f->getColor()));
wrapProperty(self, f->getColor(), "color", ColorType);
return self;
}
RB_METHOD(FontGetName)
{
RB_UNUSED_PARAM;
Font *f = getPrivateData<Font>(self);
return rb_str_new_cstr(f->getName());
}
RB_METHOD(FontSetName)
{
Font *f = getPrivateData<Font>(self);
VALUE name;
rb_get_args(argc, argv, "S", &name);
f->setName(RSTRING_PTR(name));
return name;
}
#undef DEF_PROP_CHK_DISP
#define DEF_PROP_CHK_DISP
DEF_PROP_I(Font, Size)
DEF_PROP_B(Font, Bold)
DEF_PROP_B(Font, Italic)
DEF_PROP_OBJ(Font, Color, Color, "color")
#define DEF_KLASS_PROP(Klass, type, PropName, param_t_s, value_fun) \
RB_METHOD(Klass##Get##PropName) \
{ \
RB_UNUSED_PARAM; \
return value_fun(Klass::get##PropName()); \
} \
RB_METHOD(Klass##Set##PropName) \
{ \
RB_UNUSED_PARAM; \
type value; \
rb_get_args(argc, argv, param_t_s, &value); \
Klass::set##PropName(value); \
return value_fun(value); \
}
DEF_KLASS_PROP(Font, int, DefaultSize, "i", rb_fix_new)
DEF_KLASS_PROP(Font, bool, DefaultBold, "b", rb_bool_new)
DEF_KLASS_PROP(Font, bool, DefaultItalic, "b", rb_bool_new)
RB_METHOD(FontGetDefaultName)
{
RB_UNUSED_PARAM;
return rb_str_new_cstr(Font::getDefaultName());
}
RB_METHOD(FontSetDefaultName)
{
RB_UNUSED_PARAM;
VALUE nameObj;
rb_get_args(argc, argv, "S", &nameObj);
Font::setDefaultName(RSTRING_PTR(nameObj));
return nameObj;
}
RB_METHOD(FontGetDefaultColor)
{
RB_UNUSED_PARAM;
return rb_iv_get(self, "default_color");
}
RB_METHOD(FontSetDefaultColor)
{
VALUE colorObj;
rb_get_args(argc, argv, "o", &colorObj);
Color *c = getPrivateDataCheck<Color>(colorObj, ColorType);
Font::setDefaultColor(c);
rb_iv_set(self, "default_color", colorObj);
return colorObj;
}
#define INIT_KLASS_PROP_BIND(Klass, PropName, prop_name_s) \
{ \
rb_define_class_method(klass, prop_name_s, Klass##Get##PropName); \
rb_define_class_method(klass, prop_name_s "=", Klass##Set##PropName); \
}
void
fontBindingInit()
{
INIT_TYPE(Font);
VALUE klass = rb_define_class("Font", rb_cObject);
Font::setDefaultColor(new Color(*Font::getDefaultColor()));
wrapProperty(klass, Font::getDefaultColor(), "default_color", ColorType);
INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name");
INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size");
INIT_KLASS_PROP_BIND(Font, DefaultBold, "default_bold");
INIT_KLASS_PROP_BIND(Font, DefaultItalic, "default_italic");
INIT_KLASS_PROP_BIND(Font, DefaultColor, "default_color");
rb_define_class_method(klass, "exist?", fontDoesExist);
_rb_define_method(klass, "initialize", fontInitialize);
INIT_PROP_BIND(Font, Name, "name");
INIT_PROP_BIND(Font, Size, "size");
INIT_PROP_BIND(Font, Bold, "bold");
INIT_PROP_BIND(Font, Italic, "italic");
INIT_PROP_BIND(Font, Color, "color");
}

View File

@ -0,0 +1,124 @@
/*
** graphics-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics.h"
#include "globalstate.h"
#include "binding-util.h"
#include "exception.h"
RB_METHOD(graphicsUpdate)
{
RB_UNUSED_PARAM;
gState->graphics().update();
return Qnil;
}
RB_METHOD(graphicsFreeze)
{
RB_UNUSED_PARAM;
gState->graphics().freeze();
return Qnil;
}
RB_METHOD(graphicsTransition)
{
RB_UNUSED_PARAM;
int duration = 8;
const char *filename = 0;
int vague = 40;
rb_get_args(argc, argv, "|izi", &duration, &filename, &vague);
GUARD_EXC( gState->graphics().transition(duration, filename, vague); )
return Qnil;
}
RB_METHOD(graphicsFrameReset)
{
RB_UNUSED_PARAM;
gState->graphics().frameReset();
return Qnil;
}
#define DEF_GRA_PROP_I(PropName) \
RB_METHOD(graphics##Get##PropName) \
{ \
RB_UNUSED_PARAM; \
return rb_fix_new(gState->graphics().get##PropName()); \
} \
RB_METHOD(graphics##Set##PropName) \
{ \
RB_UNUSED_PARAM; \
int value; \
rb_get_args(argc, argv, "i", &value); \
gState->graphics().set##PropName(value); \
return rb_fix_new(value); \
}
DEF_GRA_PROP_I(FrameRate)
DEF_GRA_PROP_I(FrameCount)
RB_METHOD(graphicsGetFullscreen)
{
RB_UNUSED_PARAM;
return rb_bool_new(gState->graphics().getFullscreen());
}
RB_METHOD(graphicsSetFullscreen)
{
RB_UNUSED_PARAM;
bool mode;
rb_get_args(argc, argv, "b", &mode);
gState->graphics().setFullscreen(mode);
return rb_bool_new(mode);
}
#define INIT_GRA_PROP_BIND(PropName, prop_name_s) \
{ \
_rb_define_module_function(module, prop_name_s, graphics##Get##PropName); \
_rb_define_module_function(module, prop_name_s "=", graphics##Set##PropName); \
}
void graphicsBindingInit()
{
VALUE module = rb_define_module("Graphics");
_rb_define_module_function(module, "update", graphicsUpdate);
_rb_define_module_function(module, "freeze", graphicsFreeze);
_rb_define_module_function(module, "transition", graphicsTransition);
_rb_define_module_function(module, "frame_reset", graphicsFrameReset);
INIT_GRA_PROP_BIND( FrameRate, "frame_rate" );
INIT_GRA_PROP_BIND( FrameCount, "frame_count" );
INIT_GRA_PROP_BIND( Fullscreen, "fullscreen" );
}

View File

@ -0,0 +1,146 @@
/*
** input-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "input.h"
#include "globalstate.h"
#include "exception.h"
#include "binding-util.h"
RB_METHOD(inputUpdate)
{
RB_UNUSED_PARAM;
gState->input().update();
return Qnil;
}
RB_METHOD(inputPress)
{
RB_UNUSED_PARAM;
int num;
rb_get_args(argc, argv, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num;
return rb_bool_new(gState->input().isPressed(bc));
}
RB_METHOD(inputTrigger)
{
RB_UNUSED_PARAM;
int num;
rb_get_args(argc, argv, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num;
return rb_bool_new(gState->input().isTriggered(bc));
}
RB_METHOD(inputRepeat)
{
RB_UNUSED_PARAM;
int num;
rb_get_args(argc, argv, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num;
return rb_bool_new(gState->input().isRepeated(bc));
}
RB_METHOD(inputDir4)
{
RB_UNUSED_PARAM;
return rb_fix_new(gState->input().dir4Value());
}
RB_METHOD(inputDir8)
{
RB_UNUSED_PARAM;
return rb_fix_new(gState->input().dir8Value());
}
/* Non-standard extensions */
RB_METHOD(inputMouseX)
{
RB_UNUSED_PARAM;
return rb_fix_new(gState->input().mouseX());
}
RB_METHOD(inputMouseY)
{
RB_UNUSED_PARAM;
return rb_fix_new(gState->input().mouseY());
}
#define DEF_CONST_I(name, value) \
rb_const_set(module, rb_intern(name), rb_fix_new(value))
void
inputBindingInit()
{
VALUE module = rb_define_module("Input");
_rb_define_module_function(module, "update", inputUpdate);
_rb_define_module_function(module, "press?", inputPress);
_rb_define_module_function(module, "trigger?", inputTrigger);
_rb_define_module_function(module, "repeat?", inputRepeat);
_rb_define_module_function(module, "dir4", inputDir4);
_rb_define_module_function(module, "dir8", inputDir8);
DEF_CONST_I("DOWN", Input::Down );
DEF_CONST_I("LEFT", Input::Left );
DEF_CONST_I("RIGHT", Input::Right);
DEF_CONST_I("UP", Input::Up );
DEF_CONST_I("A", Input::A );
DEF_CONST_I("B", Input::B );
DEF_CONST_I("C", Input::C );
DEF_CONST_I("X", Input::X );
DEF_CONST_I("Y", Input::Y );
DEF_CONST_I("Z", Input::Z );
DEF_CONST_I("L", Input::L );
DEF_CONST_I("R", Input::R );
DEF_CONST_I("SHIFT", Input::Shift);
DEF_CONST_I("CTRL", Input::Ctrl );
DEF_CONST_I("ALT", Input::Alt );
DEF_CONST_I("F5", Input::F5 );
DEF_CONST_I("F6", Input::F6 );
DEF_CONST_I("F7", Input::F7 );
DEF_CONST_I("F8", Input::F8 );
DEF_CONST_I("F9", Input::F9 );
_rb_define_module_function(module, "mouse_x", inputMouseX);
_rb_define_module_function(module, "mouse_y", inputMouseY);
DEF_CONST_I("MOUSELEFT", Input::MouseLeft );
DEF_CONST_I("MOUSEMIDDLE", Input::MouseMiddle);
DEF_CONST_I("MOUSERIGHT", Input::MouseRight );
}

View File

@ -0,0 +1 @@
#include "module_rpg.rb.xxd"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
/*
** plane-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "plane.h"
#include "disposable-binding.h"
#include "viewportelement-binding.h"
#include "binding-util.h"
#include "binding-types.h"
DEF_TYPE(Plane);
RB_METHOD(planeInitialize)
{
Plane *p = viewportElementInitialize<Plane>(argc, argv, self);
setPrivateData(self, p, PlaneType);
p->setColor(new Color);
p->setTone(new Tone);
wrapNilProperty(self, "bitmap");
wrapProperty(self, p->getColor(), "color", ColorType);
wrapProperty(self, p->getTone(), "tone", ToneType);
return self;
}
#define DISP_CLASS_NAME "plane"
DEF_PROP_OBJ(Plane, Bitmap, Bitmap, "bitmap")
DEF_PROP_OBJ(Plane, Color, Color, "color")
DEF_PROP_OBJ(Plane, Tone, Tone, "tone")
DEF_PROP_I(Plane, OX)
DEF_PROP_I(Plane, OY)
DEF_PROP_I(Plane, Opacity)
DEF_PROP_I(Plane, BlendType)
DEF_PROP_F(Plane, ZoomX)
DEF_PROP_F(Plane, ZoomY)
void
planeBindingInit()
{
INIT_TYPE(Plane);
VALUE klass = rb_define_class("Plane", rb_cObject);
disposableBindingInit<Plane> (klass);
viewportElementBindingInit<Plane>(klass);
_rb_define_method(klass, "initialize", planeInitialize);
INIT_PROP_BIND( Plane, Bitmap, "bitmap" );
INIT_PROP_BIND( Plane, OX, "ox" );
INIT_PROP_BIND( Plane, OY, "oy" );
INIT_PROP_BIND( Plane, ZoomX, "zoom_x" );
INIT_PROP_BIND( Plane, ZoomY, "zoom_y" );
INIT_PROP_BIND( Plane, Opacity, "opacity" );
INIT_PROP_BIND( Plane, BlendType, "blend_type" );
INIT_PROP_BIND( Plane, Color, "color" );
INIT_PROP_BIND( Plane, Tone, "tone" );
}

View File

@ -0,0 +1,90 @@
/*
** sceneelement-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCENEELEMENTBINDING_H
#define SCENEELEMENTBINDING_H
#include "scene.h"
#include "binding-util.h"
template<class C>
RB_METHOD(sceneElementGetZ)
{
RB_UNUSED_PARAM;
SceneElement *se = getPrivateData<C>(self);
int value = 0;
GUARD_EXC( value = se->getZ(); );
return rb_fix_new(value);
}
template<class C>
RB_METHOD(sceneElementSetZ)
{
SceneElement *se = getPrivateData<C>(self);
int z;
rb_get_args(argc, argv, "i", &z);
GUARD_EXC( se->setZ(z); );
return rb_fix_new(z);
}
template<class C>
RB_METHOD(sceneElementGetVisible)
{
RB_UNUSED_PARAM;
SceneElement *se = getPrivateData<C>(self);
bool value = false;
GUARD_EXC( value = se->getVisible(); );
return rb_bool_new(value);
}
template<class C>
RB_METHOD(sceneElementSetVisible)
{
SceneElement *se = getPrivateData<C>(self);
bool visible;
rb_get_args(argc, argv, "b", &visible);
GUARD_EXC( se->setVisible(visible); );
return rb_bool_new(visible);
}
template<class C>
void
sceneElementBindingInit(VALUE klass)
{
_rb_define_method(klass, "z", sceneElementGetZ<C>);
_rb_define_method(klass, "z=", sceneElementSetZ<C>);
_rb_define_method(klass, "visible", sceneElementGetVisible<C>);
_rb_define_method(klass, "visible=", sceneElementSetVisible<C>);
}
#endif // SCENEELEMENTBINDING_H

View File

@ -0,0 +1,51 @@
/*
** serializable-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERIALIZABLEBINDING_H
#define SERIALIZABLEBINDING_H
#include "serializable.h"
#include "binding-util.h"
#include "exception.h"
template<class C>
static VALUE
serializableDump(int, VALUE *, VALUE self)
{
Serializable *s = getPrivateData<C>(self);
int dataSize = s->serialSize();
VALUE data = rb_str_new(0, dataSize);
GUARD_EXC( s->serialize(RSTRING_PTR(data)); );
return data;
}
template<class C>
void
serializableBindingInit(VALUE klass)
{
_rb_define_method(klass, "_dump", serializableDump<C>);
}
#endif // SERIALIZABLEBINDING_H

View File

@ -0,0 +1,100 @@
/*
** sprite-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sprite.h"
#include "disposable-binding.h"
#include "flashable-binding.h"
#include "sceneelement-binding.h"
#include "viewportelement-binding.h"
#include "binding-util.h"
#include "binding-types.h"
DEF_TYPE(Sprite);
RB_METHOD(spriteInitialize)
{
Sprite *s = viewportElementInitialize<Sprite>(argc, argv, self);
setPrivateData(self, s, SpriteType);
/* Wrap property objects */
s->setSrcRect(new Rect);
s->setColor(new Color);
s->setTone(new Tone);
wrapNilProperty(self, "bitmap");
wrapProperty(self, s->getSrcRect(), "src_rect", RectType);
wrapProperty(self, s->getColor(), "color", ColorType);
wrapProperty(self, s->getTone(), "tone", ToneType);
return self;
}
#define DISP_CLASS_NAME "sprite"
DEF_PROP_OBJ_NIL(Sprite, Bitmap, Bitmap, "bitmap")
DEF_PROP_OBJ(Sprite, Rect, SrcRect, "src_rect")
DEF_PROP_OBJ(Sprite, Color, Color, "color")
DEF_PROP_OBJ(Sprite, Tone, Tone, "tone")
DEF_PROP_I(Sprite, X)
DEF_PROP_I(Sprite, Y)
DEF_PROP_I(Sprite, OX)
DEF_PROP_I(Sprite, OY)
DEF_PROP_I(Sprite, BushDepth)
DEF_PROP_I(Sprite, Opacity)
DEF_PROP_I(Sprite, BlendType)
DEF_PROP_F(Sprite, ZoomX)
DEF_PROP_F(Sprite, ZoomY)
DEF_PROP_F(Sprite, Angle)
DEF_PROP_B(Sprite, Mirror)
void
spriteBindingInit()
{
INIT_TYPE(Sprite);
VALUE klass = rb_define_class("Sprite", rb_cObject);
disposableBindingInit <Sprite>(klass);
flashableBindingInit <Sprite>(klass);
viewportElementBindingInit<Sprite>(klass);
_rb_define_method(klass, "initialize", spriteInitialize);
INIT_PROP_BIND( Sprite, Bitmap, "bitmap" );
INIT_PROP_BIND( Sprite, SrcRect, "src_rect" );
INIT_PROP_BIND( Sprite, X, "x" );
INIT_PROP_BIND( Sprite, Y, "y" );
INIT_PROP_BIND( Sprite, OX, "ox" );
INIT_PROP_BIND( Sprite, OY, "oy" );
INIT_PROP_BIND( Sprite, ZoomX, "zoom_x" );
INIT_PROP_BIND( Sprite, ZoomY, "zoom_y" );
INIT_PROP_BIND( Sprite, Angle, "angle" );
INIT_PROP_BIND( Sprite, Mirror, "mirror" );
INIT_PROP_BIND( Sprite, BushDepth, "bush_depth" );
INIT_PROP_BIND( Sprite, Opacity, "opacity" );
INIT_PROP_BIND( Sprite, BlendType, "blend_type" );
INIT_PROP_BIND( Sprite, Color, "color" );
INIT_PROP_BIND( Sprite, Tone, "tone" );
}

View File

@ -0,0 +1,162 @@
/*
** table-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "table.h"
#include "binding-util.h"
#include "serializable-binding.h"
DEF_TYPE(Table);
RB_METHOD(tableInitialize)
{
int x, y, z;
x = y = z = 1;
rb_get_args(argc, argv, "i|ii", &x, &y, &z);
Table *t = new Table(x, y, z);
setPrivateData(self, t, TableType);
return self;
}
RB_METHOD(tableResize)
{
Table *t = getPrivateData<Table>(self);
switch (argc)
{
default:
case 1:
t->resize(rb_fix2int(argv[0]));
return Qnil;
case 2:
t->resize(rb_fix2int(argv[0]),
rb_fix2int(argv[1]));
return Qnil;
case 3:
t->resize(rb_fix2int(argv[0]),
rb_fix2int(argv[1]),
rb_fix2int(argv[2]));
return Qnil;
}
}
#define TABLE_SIZE(d, D) \
RB_METHOD(table##D##Size) \
{ \
RB_UNUSED_PARAM \
Table *t = getPrivateData<Table>(self); \
return rb_int2inum(t->d##Size()); \
}
TABLE_SIZE(x, X)
TABLE_SIZE(y, Y)
TABLE_SIZE(z, Z)
RB_METHOD(tableGetAt)
{
Table *t = getPrivateData<Table>(self);
int x, y, z;
x = y = z = 0;
x = rb_num2int(argv[0]);
if (argc > 1)
y = rb_num2int(argv[1]);
if (argc > 2)
z = rb_num2int(argv[2]);
if (argc > 3)
rb_raise(rb_eArgError, "wrong number of arguments");
if (x < 0 || x >= t->xSize()
|| y < 0 || y >= t->ySize()
|| z < 0 || z >= t->zSize())
{
return Qnil;
}
int result = t->get(x, y, z);
return rb_int2inum(result);
}
RB_METHOD(tableSetAt)
{
Table *t = getPrivateData<Table>(self);
int x, y, z, value;
x = y = z = 0;
if (argc < 2)
rb_raise(rb_eArgError, "wrong number of arguments");
switch (argc)
{
default:
case 2 :
x = rb_fix2int(argv[0]);
value = rb_fix2int(argv[1]);
break;
case 3 :
x = rb_fix2int(argv[0]);
y = rb_fix2int(argv[1]);
value = rb_fix2int(argv[2]);
break;
case 4 :
x = rb_fix2int(argv[0]);
y = rb_fix2int(argv[1]);
z = rb_fix2int(argv[2]);
value = rb_fix2int(argv[3]);
break;
}
t->set(value, x, y, z);
return rb_int2inum(value);
}
MARSH_LOAD_FUN(Table)
void
tableBindingInit()
{
INIT_TYPE(Table);
VALUE klass = rb_define_class("Table", rb_cObject);
serializableBindingInit<Table>(klass);
rb_define_class_method(klass, "_load", TableLoad);
_rb_define_method(klass, "initialize", tableInitialize);
_rb_define_method(klass, "resize", tableResize);
_rb_define_method(klass, "xsize", tableXSize);
_rb_define_method(klass, "ysize", tableYSize);
_rb_define_method(klass, "zsize", tableZSize);
_rb_define_method(klass, "[]", tableGetAt);
_rb_define_method(klass, "[]=", tableSetAt);
}

View File

@ -0,0 +1,160 @@
/*
** tilemap-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tilemap.h"
#include "viewport.h"
#include "bitmap.h"
#include "table.h"
#include "disposable-binding.h"
#include "binding-util.h"
#include "binding-types.h"
static rb_data_type_struct TilemapAutotilesType;
RB_METHOD(tilemapAutotilesSet)
{
Tilemap::Autotiles *a = getPrivateData<Tilemap::Autotiles>(self);
int i;
VALUE bitmapObj;
rb_get_args(argc, argv, "io", &i, &bitmapObj);
Bitmap *bitmap = getPrivateDataCheck<Bitmap>(bitmapObj, BitmapType);
a->set(i, bitmap);
VALUE ary = rb_iv_get(self, "array");
rb_ary_store(ary, i, bitmapObj);
return self;
}
RB_METHOD(tilemapAutotilesGet)
{
int i;
rb_get_args (argc, argv, "i", &i);
if (i < 0 || i > 6)
return Qnil;
VALUE ary = rb_iv_get(self, "array");
return rb_ary_entry(ary, i);
}
DEF_TYPE(Tilemap);
RB_METHOD(tilemapInitialize)
{
Tilemap *t;
/* Get parameters */
VALUE viewportObj = Qnil;
Viewport *viewport = 0;
rb_get_args(argc, argv, "|o", &viewportObj);
if (rb_type(viewportObj) != RUBY_T_NIL)
viewport = getPrivateDataCheck<Viewport>(viewportObj, ViewportType);
/* Construct object */
t = new Tilemap(viewport);
setPrivateData(self, t, TilemapType);
rb_iv_set(self, "viewport", viewportObj);
wrapProperty(self, &t->getAutotiles(), "autotiles", TilemapAutotilesType);
VALUE autotilesObj = rb_iv_get(self, "autotiles");
VALUE ary = rb_ary_new2(7);
for (int i = 0; i < 7; ++i)
rb_ary_push(ary, Qnil);
rb_iv_set(autotilesObj, "array", ary);
return self;
}
RB_METHOD(tilemapGetAutotiles)
{
RB_UNUSED_PARAM;
return rb_iv_get(self, "autotiles");
}
RB_METHOD(tilemapUpdate)
{
RB_UNUSED_PARAM;
Tilemap *t = getPrivateData<Tilemap>(self);
t->update();
return Qnil;
}
#define DISP_CLASS_NAME "tilemap"
DEF_PROP_OBJ(Tilemap, Viewport, Viewport, "viewport")
DEF_PROP_OBJ(Tilemap, Bitmap, Tileset, "tileset")
DEF_PROP_OBJ(Tilemap, Table, MapData, "map_data")
DEF_PROP_OBJ(Tilemap, Table, FlashData, "flash_data")
DEF_PROP_OBJ(Tilemap, Table, Priorities, "priorities")
DEF_PROP_B(Tilemap, Visible)
DEF_PROP_I(Tilemap, OX)
DEF_PROP_I(Tilemap, OY)
void
tilemapBindingInit()
{
initType(TilemapAutotilesType, "TilemapAutotiles", 0);
VALUE klass = rb_define_class("TilemapAutotiles", rb_cObject);
_rb_define_method(klass, "[]=", tilemapAutotilesSet);
_rb_define_method(klass, "[]", tilemapAutotilesGet);
INIT_TYPE(Tilemap);
klass = rb_define_class("Tilemap", rb_cObject);
disposableBindingInit<Tilemap>(klass);
_rb_define_method(klass, "initialize", tilemapInitialize);
_rb_define_method(klass, "autotiles", tilemapGetAutotiles);
_rb_define_method(klass, "update", tilemapUpdate);
INIT_PROP_BIND( Tilemap, Viewport, "viewport" );
INIT_PROP_BIND( Tilemap, Tileset, "tileset" );
INIT_PROP_BIND( Tilemap, MapData, "map_data" );
INIT_PROP_BIND( Tilemap, FlashData, "flash_data" );
INIT_PROP_BIND( Tilemap, Priorities, "priorities" );
INIT_PROP_BIND( Tilemap, Visible, "visible" );
INIT_PROP_BIND( Tilemap, OX, "ox" );
INIT_PROP_BIND( Tilemap, OY, "oy" );
}

View File

@ -0,0 +1,100 @@
/*
** viewport-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "viewport.h"
#include "disposable-binding.h"
#include "flashable-binding.h"
#include "sceneelement-binding.h"
#include "binding-util.h"
#include "binding-types.h"
DEF_TYPE(Viewport);
RB_METHOD(viewportInitialize)
{
Viewport *v;
if (argc == 1)
{
/* The rect arg is only used to init the viewport,
* and does NOT replace its 'rect' property */
VALUE rectObj;
Rect *rect;
rb_get_args(argc, argv, "o", &rectObj);
rect = getPrivateDataCheck<Rect>(rectObj, RectType);
v = new Viewport(rect);
}
else
{
int x, y, width, height;
rb_get_args(argc, argv, "iiii", &x, &y, &width, &height);
v = new Viewport(x, y, width, height);
}
setPrivateData(self, v, ViewportType);
/* Wrap property objects */
v->setRect(new Rect(*v->getRect()));
v->setColor(new Color);
v->setTone(new Tone);
wrapProperty(self, v->getRect(), "rect", RectType);
wrapProperty(self, v->getColor(), "color", ColorType);
wrapProperty(self, v->getTone(), "tone", ToneType);
return self;
}
#define DISP_CLASS_NAME "viewport"
DEF_PROP_OBJ(Viewport, Rect, Rect, "rect")
DEF_PROP_OBJ(Viewport, Color, Color, "color")
DEF_PROP_OBJ(Viewport, Tone, Tone, "tone")
DEF_PROP_I(Viewport, OX)
DEF_PROP_I(Viewport, OY)
void
viewportBindingInit()
{
INIT_TYPE(Viewport);
VALUE klass = rb_define_class("Viewport", rb_cObject);
disposableBindingInit <Viewport>(klass);
flashableBindingInit <Viewport>(klass);
sceneElementBindingInit<Viewport>(klass);
_rb_define_method(klass, "initialize", viewportInitialize);
INIT_PROP_BIND( Viewport, Rect, "rect" );
INIT_PROP_BIND( Viewport, OX, "ox" );
INIT_PROP_BIND( Viewport, OY, "oy" );
INIT_PROP_BIND( Viewport, Color, "color" );
INIT_PROP_BIND( Viewport, Tone, "tone" );
}

View File

@ -0,0 +1,74 @@
/*
** viewportelement-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VIEWPORTELEMENTBINDING_H
#define VIEWPORTELEMENTBINDING_H
#include "viewport.h"
#include "binding-util.h"
#include "binding-types.h"
#include "sceneelement-binding.h"
template<class C>
RB_METHOD(viewportElementGetViewport)
{
RB_UNUSED_PARAM;
ViewportElement *ve = getPrivateData<C>(self);
GUARD_EXC( ve->aboutToAccess(); );
return rb_iv_get(self, "viewport");
}
template<class C>
static C *
viewportElementInitialize(int argc, VALUE *argv, VALUE self)
{
/* Get parameters */
VALUE viewportObj = Qnil;
Viewport *viewport = 0;
rb_get_args(argc, argv, "|o", &viewportObj);
if (rb_type(viewportObj) != RUBY_T_NIL)
viewport = getPrivateDataCheck<Viewport>(viewportObj, ViewportType);
/* Construct object */
C *ve = new C(viewport);
/* Set property objects */
rb_iv_set(self, "viewport", viewportObj);
return ve;
}
template<class C>
void
viewportElementBindingInit(VALUE klass)
{
sceneElementBindingInit<C>(klass);
_rb_define_method(klass, "viewport", viewportElementGetViewport<C>);
}
#endif // VIEWPORTELEMENTBINDING_H

View File

@ -0,0 +1,103 @@
/*
** window-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "window.h"
#include "disposable-binding.h"
#include "viewportelement-binding.h"
#include "binding-util.h"
DEF_TYPE(Window);
RB_METHOD(windowInitialize)
{
Window *w = viewportElementInitialize<Window>(argc, argv, self);
setPrivateData(self, w, WindowType);
w->setCursorRect(new Rect);
wrapNilProperty(self, "windowskin");
wrapNilProperty(self, "contents");
wrapProperty(self, w->getCursorRect(), "cursor_rect", RectType);
return self;
}
RB_METHOD(windowUpdate)
{
RB_UNUSED_PARAM;
Window *w = getPrivateData<Window>(self);
w->update();
return Qnil;
}
#define DISP_CLASS_NAME "window"
DEF_PROP_OBJ_NIL(Window, Bitmap, Windowskin, "windowskin")
DEF_PROP_OBJ_NIL(Window, Bitmap, Contents, "contents")
DEF_PROP_OBJ(Window, Rect, CursorRect, "cursor_rect")
DEF_PROP_B(Window, Stretch)
DEF_PROP_B(Window, Active)
DEF_PROP_B(Window, Pause)
DEF_PROP_I(Window, X)
DEF_PROP_I(Window, Y)
DEF_PROP_I(Window, Width)
DEF_PROP_I(Window, Height)
DEF_PROP_I(Window, OX)
DEF_PROP_I(Window, OY)
DEF_PROP_I(Window, Opacity)
DEF_PROP_I(Window, BackOpacity)
DEF_PROP_I(Window, ContentsOpacity)
void
windowBindingInit()
{
INIT_TYPE(Window);
VALUE klass = rb_define_class("Window", rb_cObject);
disposableBindingInit <Window>(klass);
viewportElementBindingInit<Window>(klass);
_rb_define_method(klass, "initialize", windowInitialize);
_rb_define_method(klass, "update", windowUpdate);
INIT_PROP_BIND( Window, Windowskin, "windowskin" );
INIT_PROP_BIND( Window, Contents, "contents" );
INIT_PROP_BIND( Window, Stretch, "stretch" );
INIT_PROP_BIND( Window, CursorRect, "cursor_rect" );
INIT_PROP_BIND( Window, Active, "active" );
INIT_PROP_BIND( Window, Pause, "pause" );
INIT_PROP_BIND( Window, X, "x" );
INIT_PROP_BIND( Window, Y, "y" );
INIT_PROP_BIND( Window, Width, "width" );
INIT_PROP_BIND( Window, Height, "height" );
INIT_PROP_BIND( Window, OX, "ox" );
INIT_PROP_BIND( Window, OY, "oy" );
INIT_PROP_BIND( Window, Opacity, "opacity" );
INIT_PROP_BIND( Window, BackOpacity, "back_opacity" );
INIT_PROP_BIND( Window, ContentsOpacity, "contents_opacity" );
}

View File

@ -0,0 +1,88 @@
/*
** audio-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "audio.h"
#include "globalstate.h"
#include "binding-util.h"
#include "exception.h"
#define DEF_PLAY_STOP(entity) \
MRB_METHOD(audio_##entity##Play) \
{ \
MRB_UNUSED_PARAM; \
char *filename; \
mrb_int volume = 100; \
mrb_int pitch = 100; \
mrb_get_args(mrb, "z|ii", &filename, &volume, &pitch); \
GUARD_EXC( gState->audio().entity##Play(filename, volume, pitch); ) \
return mrb_nil_value(); \
} \
MRB_METHOD(audio_##entity##Stop) \
{ \
MRB_UNUSED_PARAM; \
gState->audio().entity##Stop(); \
return mrb_nil_value(); \
}
#define DEF_FADE(entity) \
MRB_METHOD(audio_##entity##Fade) \
{ \
MRB_UNUSED_PARAM; \
mrb_int time; \
mrb_get_args(mrb, "i", &time); \
gState->audio().entity##Fade(time); \
return mrb_nil_value(); \
}
#define DEF_PLAY_STOP_FADE(entity) \
DEF_PLAY_STOP(entity) \
DEF_FADE(entity)
DEF_PLAY_STOP_FADE( bgm )
DEF_PLAY_STOP_FADE( bgs )
DEF_PLAY_STOP_FADE( me )
DEF_PLAY_STOP( se )
#define BIND_PLAY_STOP(entity) \
mrb_define_module_function(mrb, module, #entity "_play", audio_##entity##Play, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2)); \
mrb_define_module_function(mrb, module, #entity "_stop", audio_##entity##Stop, MRB_ARGS_NONE());
#define BIND_FADE(entity) \
mrb_define_module_function(mrb, module, #entity "_fade", audio_##entity##Fade, MRB_ARGS_REQ(1));
#define BIND_PLAY_STOP_FADE(entity) \
BIND_PLAY_STOP(entity) \
BIND_FADE(entity)
void
audioBindingInit(mrb_state *mrb)
{
RClass *module = mrb_define_module(mrb, "Audio");
BIND_PLAY_STOP_FADE( bgm )
BIND_PLAY_STOP_FADE( bgs )
BIND_PLAY_STOP_FADE( me )
BIND_PLAY_STOP( se )
}

View File

@ -0,0 +1,356 @@
/*
** binding-mruby.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "binding.h"
#include "mruby.h"
#include "mruby/string.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/irep.h"
#include "mruby/compile.h"
#include "mruby/proc.h"
#include "binding-util.h"
#include "stdio.h"
#include "zlib.h"
#include "SDL2/SDL_messagebox.h"
#include "SDL2/SDL_rwops.h"
#include "SDL2/SDL_timer.h"
#include "globalstate.h"
#include "texpool.h"
#include "eventthread.h"
#include "filesystem.h"
#include "binding-types.h"
#include "mrb-ext/marshal.h"
void mrbBindingExecute();
void mrbBindingTerminate();
ScriptBinding scriptBindingImpl =
{
mrbBindingExecute,
mrbBindingTerminate
};
ScriptBinding *scriptBinding = &scriptBindingImpl;
void fileBindingInit(mrb_state *);
void timeBindingInit(mrb_state *);
void marshalBindingInit(mrb_state *);
void kernelBindingInit(mrb_state *);
void tableBindingInit(mrb_state *);
void etcBindingInit(mrb_state *);
void fontBindingInit(mrb_state *);
void bitmapBindingInit(mrb_state *);
void spriteBindingInit(mrb_state *);
void planeBindingInit(mrb_state *);
void viewportBindingInit(mrb_state *);
void windowBindingInit(mrb_state *);
void tilemapBindingInit(mrb_state *);
void inputBindingInit(mrb_state *);
void audioBindingInit(mrb_state *);
void graphicsBindingInit(mrb_state *);
/* From module_rpg.c */
extern const uint8_t mrbModuleRPG[];
static void mrbBindingInit(mrb_state *mrb)
{
int arena = mrb_gc_arena_save(mrb);
/* Init standard classes */
fileBindingInit(mrb);
timeBindingInit(mrb);
marshalBindingInit(mrb);
kernelBindingInit(mrb);
/* Init RGSS classes */
tableBindingInit(mrb);
etcBindingInit(mrb);
fontBindingInit(mrb);
bitmapBindingInit(mrb);
spriteBindingInit(mrb);
planeBindingInit(mrb);
viewportBindingInit(mrb);
windowBindingInit(mrb);
tilemapBindingInit(mrb);
/* Init RGSS modules */
inputBindingInit(mrb);
audioBindingInit(mrb);
graphicsBindingInit(mrb);
/* Load RPG module */
mrb_load_irep(mrb, mrbModuleRPG);
mrb_define_global_const(mrb, "MKXP", mrb_true_value());
mrb_gc_arena_restore(mrb, arena);
}
static mrb_value
mkxpTimeOp(mrb_state *mrb, mrb_value)
{
const char *opName;
mrb_value block;
mrb_get_args(mrb, "z&", &opName, &block);
Uint64 start = SDL_GetPerformanceCounter();
mrb_yield(mrb, block, mrb_nil_value());
Uint64 diff = SDL_GetPerformanceCounter() - start;
double sec = (double) diff / SDL_GetPerformanceFrequency();
float ms = sec * 1000;
printf("<%s> [%f ms]\n", opName, ms);
fflush(stdout);
return mrb_nil_value();
}
static mrb_value
mkxpEvalBlock(mrb_state *mrb, mrb_value)
{
mrb_value block;
mrb_get_args(mrb, "&", &block);
// mrb_yield_argv(mrb, block, 0, 0);
mrb_run(mrb, mrb_proc_ptr(block), mrb_obj_value(mrb->top_self));
if (mrb->exc)
{
qDebug() << "Got exc!" << mrb_class_name(mrb, mrb_class(mrb, mrb_obj_value(mrb->exc)));
}
return mrb_nil_value();
}
static const char *
mrbValueString(mrb_value value)
{
return mrb_string_p(value) ? RSTRING_PTR(value) : 0;
}
static void
showExcMessageBox(mrb_state *mrb, mrb_value exc)
{
/* Display actual exception in a message box */
mrb_value mesg = mrb_funcall(mrb, exc, "message", 0);
mrb_value line = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "line", 4));
mrb_value file = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "file", 4));
const char *excClass = mrb_class_name(mrb, mrb_class(mrb, exc));
char msgBoxText[512];
snprintf(msgBoxText, 512, "Script '%s' line %d: %s occured.\n\n%s",
mrbValueString(file), mrb_fixnum(line), excClass, mrbValueString(mesg));
gState->eThread().showMessageBox(msgBoxText, SDL_MESSAGEBOX_ERROR);
}
static void
checkException(mrb_state *mrb)
{
if (!mrb->exc)
return;
mrb_value exc = mrb_obj_value(mrb->exc);
MrbData &mrbData = *getMrbData(mrb);
/* Check if an actual exception occured, or just a shutdown was called */
if (mrb_obj_class(mrb, exc) != mrbData.exc[Shutdown])
showExcMessageBox(mrb, exc);
}
static void
showError(const QByteArray &msg)
{
gState->eThread().showMessageBox(msg.constData());
}
static void
runCustomScript(mrb_state *mrb, mrbc_context *ctx, const char *filename)
{
/* Execute custom script */
FILE *f = fopen(filename, "r");
if (!f)
{
static char buffer[256];
snprintf(buffer, sizeof(buffer), "Unable to open script '%s'", filename);
showError(buffer);
return;
}
ctx->filename = strdup(filename);
ctx->lineno = 1;
/* Run code */
mrb_load_file_cxt(mrb, f, ctx);
free(ctx->filename);
fclose(f);
}
static void
runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
{
const QByteArray &scriptLoc = gState->rtData().config.game.scripts;
if (!gState->fileSystem().exists(scriptLoc.constData()))
{
showError("Unable to open '" + scriptLoc + "'");
return;
}
/* We use a secondary util state to unmarshal the scripts */
mrb_state *scriptMrb = mrb_open();
SDL_RWops ops;
gState->fileSystem().openRead(ops, scriptLoc.constData());
mrb_value scriptArray = marshalLoadInt(scriptMrb, &ops);
SDL_RWclose(&ops);
if (!mrb_array_p(scriptArray))
{
showError("Failed to read script data");
mrb_close(scriptMrb);
return;
}
int scriptCount = mrb_ary_len(scriptMrb, scriptArray);
QByteArray decodeBuffer;
decodeBuffer.resize(0x1000);
for (int i = 0; i < scriptCount; ++i)
{
mrb_value script = mrb_ary_entry(scriptArray, i);
mrb_value scriptChksum = mrb_ary_entry(script, 0);
mrb_value scriptName = mrb_ary_entry(script, 1);
mrb_value scriptString = mrb_ary_entry(script, 2);
(void) scriptChksum;
int result = Z_OK;
ulong bufferLen;
while (true)
{
unsigned char *bufferPtr =
reinterpret_cast<unsigned char*>(const_cast<char*>(decodeBuffer.constData()));
unsigned char *sourcePtr =
reinterpret_cast<unsigned char*>(RSTRING_PTR(scriptString));
bufferLen = decodeBuffer.length();
result = uncompress(bufferPtr, &bufferLen,
sourcePtr, RSTRING_LEN(scriptString));
bufferPtr[bufferLen] = '\0';
if (result != Z_BUF_ERROR)
break;
decodeBuffer.resize(decodeBuffer.size()*2);
}
if (result != Z_OK)
{
static char buffer[256];
snprintf(buffer, sizeof(buffer), "Error decoding script %d: '%s'",
i, RSTRING_PTR(scriptName));
showError(buffer);
break;
}
ctx->filename = RSTRING_PTR(scriptName);
ctx->lineno = 1;
int ai = mrb_gc_arena_save(mrb);
/* Execute code */
mrb_load_nstring_cxt(mrb, decodeBuffer.constData(), bufferLen, ctx);
mrb_gc_arena_restore(mrb, ai);
if (mrb->exc)
break;
}
mrb_close(scriptMrb);
}
void mrbBindingExecute()
{
mrb_state *mrb = mrb_open();
gState->setBindingData(mrb);
MrbData mrbData(mrb);
mrb->ud = &mrbData;
RClass *mkxpMod = mrb_define_module(mrb, "MKXP");
mrb_define_module_function(mrb, mkxpMod, "time_op", mkxpTimeOp, MRB_ARGS_REQ(1) | MRB_ARGS_BLOCK());
mrb_define_module_function(mrb, mkxpMod, "eval_block", mkxpEvalBlock, MRB_ARGS_BLOCK());
mrbBindingInit(mrb);
mrbc_context *ctx = mrbc_context_new(mrb);
ctx->capture_errors = 1;
QByteArray &customScript = gState->rtData().config.customScript;
if (!customScript.isEmpty())
runCustomScript(mrb, ctx, customScript.constData());
else
runRMXPScripts(mrb, ctx);
checkException(mrb);
gState->rtData().rqTermAck = true;
gState->texPool().disable();
mrbc_context_free(mrb, ctx);
mrb_close(mrb);
}
void mrbBindingTerminate()
{
mrb_state *mrb = static_cast<mrb_state*>(gState->bindingData());
MrbData *data = static_cast<MrbData*>(mrb->ud);
mrb_raise(mrb, data->exc[Shutdown], "");
}

View File

@ -0,0 +1,40 @@
/*
** binding-types.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BINDINGTYPES_H
#define BINDINGTYPES_H
#include "binding-util.h"
DECL_TYPE(Table);
DECL_TYPE(Rect);
DECL_TYPE(Color);
DECL_TYPE(Tone);
DECL_TYPE(Font);
DECL_TYPE(Bitmap);
DECL_TYPE(Sprite);
DECL_TYPE(Plane);
DECL_TYPE(Viewport);
DECL_TYPE(Tilemap);
DECL_TYPE(Window);
#endif // BINDINGTYPES_H

View File

@ -0,0 +1,167 @@
/*
** binding-util.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "binding-util.h"
#include "util.h"
#include "exception.h"
#define SYMD(symbol) { CS##symbol, #symbol }
struct
{
CommonSymbol ind;
const char *str;
} static const symData[] =
{
SYMD(priv_iv),
SYMD(font),
SYMD(viewport),
SYMD(bitmap),
SYMD(color),
SYMD(tone),
SYMD(rect),
SYMD(src_rect),
SYMD(tileset),
SYMD(autotiles),
SYMD(map_data),
SYMD(flash_data),
SYMD(priorities),
SYMD(windowskin),
SYMD(contents),
SYMD(cursor_rect),
SYMD(path),
SYMD(array),
SYMD(default_color)
};
static elementsN(symData);
struct MrbExcData
{
MrbException ind;
const char *str;
};
static const MrbExcData excData[] =
{
{ Shutdown, "SystemExit" },
{ RGSS, "RGSSError" },
{ PHYSFS, "PHYSFSError" },
{ SDL, "SDLError" },
{ IO, "IOError" }
};
static elementsN(excData);
#define ENO(id) { Errno##id, #id }
static const MrbExcData enoExcData[] =
{
ENO(E2BIG),
ENO(EACCES),
ENO(EAGAIN),
ENO(EBADF),
ENO(ECHILD),
ENO(EDEADLOCK),
ENO(EDOM),
ENO(EEXIST),
ENO(EINVAL),
ENO(EMFILE),
ENO(ENOENT),
ENO(ENOEXEC),
ENO(ENOMEM),
ENO(ENOSPC),
ENO(ERANGE),
ENO(EXDEV)
};
static elementsN(enoExcData);
MrbData::MrbData(mrb_state *mrb)
{
int arena = mrb_gc_arena_save(mrb);
for (int i = 0; i < excDataN; ++i)
exc[excData[i].ind] = mrb_define_class(mrb, excData[i].str, mrb->eException_class);
RClass *errnoMod = mrb_define_module(mrb, "Errno");
for (int i = 0; i < enoExcDataN; ++i)
exc[enoExcData[i].ind] =
mrb_define_class_under(mrb, errnoMod, enoExcData[i].str, mrb->eStandardError_class);
exc[TypeError] = mrb_class_get(mrb, "TypeError");
exc[ArgumentError] = mrb_class_get(mrb, "ArgumentError");
for (int i = 0; i < symDataN; ++i)
symbols[symData[i].ind] = mrb_intern(mrb, symData[i].str);
mrb_gc_arena_restore(mrb, arena);
}
//enum Type
//{
// RGSSError,
// NoFileError,
// IOError,
// /* Already defined by ruby */
// TypeError,
// ArgumentError,
// /* New types introduced in mkxp */
// PHYSFSError,
// SDLError
//};
/* Indexed with Exception::Type */
static const MrbException excToMrbExc[] =
{
RGSS, /* RGSSError */
ErrnoENOENT, /* NoFileError */
IO,
TypeError,
ArgumentError,
PHYSFS, /* PHYSFSError */
SDL, /* SDLError */
};
void raiseMrbExc(mrb_state *mrb, const Exception &exc)
{
MrbData *data = getMrbData(mrb);
RClass *excClass = data->exc[excToMrbExc[exc.type]];
static char buffer[512];
exc.snprintf(buffer, sizeof(buffer));
mrb_raise(mrb, excClass, buffer);
}
MRB_METHOD_PUB(inspectObject)
{
mrb_value priv = mrb_obj_iv_get(mrb, mrb_obj_ptr(self), getSym(mrb, CSpriv_iv));
static char buffer[64];
sprintf(buffer, "#<%s:%p>", DATA_TYPE(priv)->struct_name, DATA_PTR(priv));
return mrb_str_new_cstr(mrb, buffer);
}

View File

@ -0,0 +1,387 @@
/*
** binding-util.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BINDINGUTIL_H
#define BINDINGUTIL_H
#include "mruby.h"
#include "mruby/data.h"
#include "mruby/variable.h"
#include "mruby/class.h"
#include <stdio.h>
enum CommonSymbol
{
CSpriv_iv = 0, /* private data */
/* From here on out all symbols
* have implicit '@' prefix */
CSfont,
CSviewport,
CSbitmap,
CScolor,
CStone,
CSrect,
CSsrc_rect,
CStileset,
CSautotiles,
CSmap_data,
CSflash_data,
CSpriorities,
CSwindowskin,
CScontents,
CScursor_rect,
CSpath,
CSarray,
CSdefault_color,
CommonSymbolsMax
};
enum MrbException
{
Shutdown = 0,
RGSS,
PHYSFS,
SDL,
ErrnoE2BIG,
ErrnoEACCES,
ErrnoEAGAIN,
ErrnoEBADF,
ErrnoECHILD,
ErrnoEDEADLOCK,
ErrnoEDOM,
ErrnoEEXIST,
ErrnoEINVAL,
ErrnoEMFILE,
ErrnoENOENT,
ErrnoENOEXEC,
ErrnoENOMEM,
ErrnoENOSPC,
ErrnoERANGE,
ErrnoEXDEV,
IO,
TypeError,
ArgumentError,
MrbExceptionsMax
};
struct MrbData
{
RClass *exc[MrbExceptionsMax];
/* I'll leave the usage of these syms to later,
* so I can measure how much of a speed difference they make */
mrb_sym symbols[CommonSymbolsMax];
MrbData(mrb_state *mrb);
};
struct Exception;
void
raiseMrbExc(mrb_state *mrb, const Exception &exc);
inline MrbData*
getMrbData(mrb_state *mrb)
{
return static_cast<MrbData*>(mrb->ud);
}
#define GUARD_EXC(exp) \
{ try { exp } catch (Exception &exc) { raiseMrbExc(mrb, exc); } }
#define DECL_TYPE(_Type) \
extern const mrb_data_type _Type##Type
#define DEF_TYPE(_Type) \
extern const mrb_data_type _Type##Type = \
{ \
#_Type, \
freeInstance<_Type> \
}
#define MRB_METHOD_PUB(name) \
mrb_value name(mrb_state *mrb, mrb_value self)
#define MRB_METHOD(name) static MRB_METHOD_PUB(name)
#define MRB_UNUSED_PARAM \
{ (void) mrb; (void) self; }
/* If we're not binding a disposable class,
* we want to #undef DEF_PROP_CHK_DISP */
#define DEF_PROP_CHK_DISP \
checkDisposed(mrb, k, DISP_CLASS_NAME);
#define DEF_PROP_OBJ(Klass, PropKlass, PropName, prop_iv) \
MRB_METHOD(Klass##Get##PropName) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); (void) k; \
DEF_PROP_CHK_DISP \
return getProperty(mrb, self, prop_iv); \
} \
MRB_METHOD(Klass##Set##PropName) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); \
mrb_value propObj; \
PropKlass *prop; \
mrb_get_args(mrb, "o", &propObj); \
prop = getPrivateDataCheck<PropKlass>(mrb, propObj, PropKlass##Type); \
GUARD_EXC( k->set##PropName(prop); ) \
setProperty(mrb, self, prop_iv, propObj); \
return propObj; \
}
/* Object property with allowed NIL */
#define DEF_PROP_OBJ_NIL(Klass, PropKlass, PropName, prop_iv) \
MRB_METHOD(Klass##Get##PropName) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); (void) k; \
DEF_PROP_CHK_DISP \
return getProperty(mrb, self, prop_iv); \
} \
MRB_METHOD(Klass##Set##PropName) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); \
mrb_value propObj; \
PropKlass *prop; \
mrb_get_args(mrb, "o", &propObj); \
if (mrb_nil_p(propObj)) \
prop = 0; \
else \
prop = getPrivateDataCheck<PropKlass>(mrb, propObj, PropKlass##Type); \
GUARD_EXC( k->set##PropName(prop); ) \
setProperty(mrb, self, prop_iv, propObj); \
return mrb_nil_value(); \
}
#define DEF_PROP(Klass, mrb_type, PropName, arg_type, conv_t) \
MRB_METHOD(Klass##Get##PropName) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); \
DEF_PROP_CHK_DISP \
return mrb_##conv_t##_value(k->get##PropName()); \
} \
MRB_METHOD(Klass##Set##PropName) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); \
mrb_type value; \
mrb_get_args(mrb, arg_type, &value); \
GUARD_EXC( k->set##PropName(value); ) \
return mrb_##conv_t##_value(value); \
}
#define DEF_PROP_I(Klass, PropName) \
DEF_PROP(Klass, mrb_int, PropName, "i", fixnum)
#define DEF_PROP_F(Klass, PropName) \
DEF_PROP(Klass, mrb_float, PropName, "f", _float)
#define DEF_PROP_B(Klass, PropName) \
DEF_PROP(Klass, mrb_bool, PropName, "b", bool)
#define CLONE_FUN(Klass) \
MRB_METHOD(Klass##Clone) \
{ \
Klass *k = getPrivateData<Klass>(mrb, self); \
mrb_value dupObj = mrb_obj_clone(mrb, self); \
Klass *dupK = new Klass(*k); \
setPrivateData(mrb, dupObj, dupK, Klass##Type); \
return dupObj; \
}
#define MARSH_LOAD_FUN(Klass) \
MRB_METHOD(Klass##Load) \
{ \
return objectLoad<Klass>(mrb, self, Klass##Type); \
}
#define INIT_PROP_BIND(Klass, PropName, prop_name_s) \
{ \
mrb_define_method(mrb, klass, prop_name_s, Klass##Get##PropName, MRB_ARGS_NONE()); \
mrb_define_method(mrb, klass, prop_name_s "=", Klass##Set##PropName, MRB_ARGS_REQ(1)); \
}
static inline mrb_value
mrb__float_value(mrb_float f)
{
mrb_value v;
MRB_SET_VALUE(v, MRB_TT_FLOAT, value.f, f);
return v;
}
inline mrb_sym
getSym(mrb_state *mrb, CommonSymbol sym)
{
return getMrbData(mrb)->symbols[sym];
}
template<typename T>
inline T *
getPrivateData(mrb_state *mrb, mrb_value self)
{
mrb_value priv = mrb_obj_iv_get(mrb,
mrb_obj_ptr(self),
getSym(mrb, CSpriv_iv));
return static_cast<T*>(DATA_PTR(priv));
}
template<typename T>
inline T *
getPrivateDataCheck(mrb_state *mrb, mrb_value obj, const mrb_data_type &type)
{
static const char mesg[] = "wrong argument type %S (expected %S)";
if (mrb_type(obj) != MRB_TT_OBJECT)
mrb_raisef(mrb, E_TYPE_ERROR, mesg,
mrb_str_new_cstr(mrb, (mrb_class_name(mrb, mrb_class(mrb, obj)))),
mrb_str_new_cstr(mrb, type.struct_name));
RObject *objP = mrb_obj_ptr(obj);
if (!mrb_obj_iv_defined(mrb, objP, getSym(mrb, CSpriv_iv)))
mrb_raisef(mrb, E_TYPE_ERROR, mesg,
mrb_str_new_cstr(mrb, (mrb_class_name(mrb, mrb_class(mrb, obj)))),
mrb_str_new_cstr(mrb, type.struct_name));
mrb_value priv = mrb_obj_iv_get(mrb, objP, getSym(mrb, CSpriv_iv));
void *p = mrb_check_datatype(mrb, priv, &type);
return static_cast<T*>(p);
}
inline void
setPrivateData(mrb_state *mrb, mrb_value self, void *p, const mrb_data_type &type)
{
RData *data =
mrb_data_object_alloc(mrb,
mrb_obj_class(mrb, self),
p,
&type);
mrb_obj_iv_set(mrb,
mrb_obj_ptr(self),
getSym(mrb, CSpriv_iv),
mrb_obj_value(data));
}
inline mrb_value
wrapObject(mrb_state *mrb, void *p, const mrb_data_type &type)
{
RClass *c = mrb_class_get(mrb, type.struct_name);
RObject *o = (RObject*) mrb_obj_alloc(mrb, MRB_TT_OBJECT, c);
mrb_value obj = mrb_obj_value(o);
setPrivateData(mrb, obj, p, type);
return obj;
}
inline void
wrapProperty(mrb_state *mrb, mrb_value self,
void *prop, CommonSymbol iv, const mrb_data_type &type)
{
mrb_value propObj = wrapObject(mrb, prop, type);
mrb_obj_iv_set(mrb,
mrb_obj_ptr(self),
getSym(mrb, iv),
propObj);
}
inline void
wrapNilProperty(mrb_state *mrb, mrb_value self, CommonSymbol iv)
{
mrb_obj_iv_set(mrb,
mrb_obj_ptr(self),
getSym(mrb, iv),
mrb_nil_value());
}
inline mrb_value
getProperty(mrb_state *mrb, mrb_value self, CommonSymbol iv)
{
return mrb_obj_iv_get(mrb,
mrb_obj_ptr(self),
getSym(mrb, iv));
}
inline void
setProperty(mrb_state *mrb, mrb_value self,
CommonSymbol iv, mrb_value propObject)
{
mrb_obj_iv_set(mrb,
mrb_obj_ptr(self),
getSym(mrb, iv),
propObject);
}
template<typename T>
void
freeInstance(mrb_state *, void *instance)
{
delete static_cast<T*>(instance);
}
inline mrb_value
mrb_bool_value(bool value)
{
return value ? mrb_true_value() : mrb_false_value();
}
inline bool
_mrb_bool(mrb_value o)
{
return mrb_test(o);
}
template<class C>
inline mrb_value
objectLoad(mrb_state *mrb, mrb_value self, const mrb_data_type &type)
{
RClass *klass = mrb_class_ptr(self);
char *data;
int data_len;
mrb_get_args(mrb, "s", &data, &data_len);
RObject *obj = (RObject*) mrb_obj_alloc(mrb, MRB_TT_OBJECT, klass);
mrb_value obj_value = mrb_obj_value(obj);
C *c = C::deserialize(data, data_len);
setPrivateData(mrb, obj_value, c, type);
return obj_value;
}
MRB_METHOD_PUB(inspectObject);
#endif // BINDINGUTIL_H

View File

@ -0,0 +1,340 @@
/*
** bitmap-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bitmap.h"
#include "font.h"
#include "exception.h"
#include "disposable-binding.h"
#include "binding-util.h"
#include "binding-types.h"
#include <QDebug>
#define DISP_CLASS_NAME "bitmap"
DEF_TYPE(Bitmap);
MRB_METHOD(bitmapInitialize)
{
Bitmap *b = 0;
if (mrb->c->ci->argc == 1)
{
char *filename;
mrb_get_args(mrb, "z", &filename);
GUARD_EXC( b = new Bitmap(filename); )
}
else
{
mrb_int width, height;
mrb_get_args(mrb, "ii", &width, &height);
b = new Bitmap(width, height);
}
setPrivateData(mrb, self, b, BitmapType);
/* Wrap properties */
Font *font = new Font();
b->setFont(font);
font->setColor(new Color(*font->getColor()));
wrapProperty(mrb, self, font, CSfont, FontType);
wrapProperty(mrb, getProperty(mrb, self, CSfont), font->getColor(), CScolor, ColorType);
return self;
}
MRB_METHOD(bitmapWidth)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_int value = 0;
GUARD_EXC( value = b->width(); )
return mrb_fixnum_value(value);
}
MRB_METHOD(bitmapHeight)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_int value = 0;
GUARD_EXC( value = b->height(); )
return mrb_fixnum_value(value);
}
MRB_METHOD(bitmapRect)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
IntRect rect;
GUARD_EXC( rect = b->rect(); )
Rect *r = new Rect(rect);
return wrapObject(mrb, r, RectType);
}
MRB_METHOD(bitmapBlt)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_int x, y;
mrb_value srcObj;
mrb_value srcRectObj;
mrb_int opacity = 255;
Bitmap *src;
Rect *srcRect;
mrb_get_args(mrb, "iioo|i", &x, &y, &srcObj, &srcRectObj, &opacity);
src = getPrivateDataCheck<Bitmap>(mrb, srcObj, BitmapType);
srcRect = getPrivateDataCheck<Rect>(mrb, srcRectObj, RectType);
GUARD_EXC( b->blt(x, y, *src, srcRect->toIntRect(), opacity); )
return mrb_nil_value();
}
MRB_METHOD(bitmapStretchBlt)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_value destRectObj;
mrb_value srcObj;
mrb_value srcRectObj;
mrb_int opacity = 255;
Bitmap *src;
Rect *destRect, *srcRect;
mrb_get_args(mrb, "ooo|i", &destRectObj, &srcObj, &srcRectObj);
src = getPrivateDataCheck<Bitmap>(mrb, srcObj, BitmapType);
destRect = getPrivateDataCheck<Rect>(mrb, destRectObj, RectType);
srcRect = getPrivateDataCheck<Rect>(mrb, srcRectObj, RectType);
GUARD_EXC( b->stretchBlt(destRect->toIntRect(), *src, srcRect->toIntRect(), opacity); )
return mrb_nil_value();
}
MRB_METHOD(bitmapFillRect)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_value colorObj;
Color *color;
if (mrb->c->ci->argc == 2)
{
mrb_value rectObj;
Rect *rect;
mrb_get_args(mrb, "oo", &rectObj, &colorObj);
rect = getPrivateDataCheck<Rect>(mrb, rectObj, RectType);
color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
GUARD_EXC( b->fillRect(rect->toIntRect(), color->norm); )
}
else
{
mrb_int x, y, width, height;
mrb_get_args(mrb, "iiiio", &x, &y, &width, &height, &colorObj);
color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
GUARD_EXC( b->fillRect(x, y, width, height, color->norm); )
}
return mrb_nil_value();
}
MRB_METHOD(bitmapClear)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
GUARD_EXC( b->clear(); )
return mrb_nil_value();
}
MRB_METHOD(bitmapGetPixel)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_int x, y;
mrb_get_args(mrb, "ii", &x, &y);
GUARD_EXC(
if (x < 0 || y < 0 || x >= b->width() || y >= b->height())
return mrb_nil_value();
)
Vec4 value;
GUARD_EXC( value = b->getPixel(x, y); )
Color *color = new Color(value);
return wrapObject(mrb, color, ColorType);
}
MRB_METHOD(bitmapSetPixel)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_int x, y;
mrb_value colorObj;
Color *color;
mrb_get_args(mrb, "iio", &x, &y, &colorObj);
color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
GUARD_EXC( b->setPixel(x, y, color->norm); )
return mrb_nil_value();
}
MRB_METHOD(bitmapHueChange)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_int hue;
mrb_get_args(mrb, "i", &hue);
GUARD_EXC( b->hueChange(hue); )
return mrb_nil_value();
}
MRB_METHOD(bitmapDrawText)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
char *str;
mrb_int align = Bitmap::Left;
int argc = mrb->c->ci->argc;
if (argc == 2 || argc == 3)
{
mrb_value rectObj;
Rect *rect;
mrb_get_args(mrb, "oz|i", &rectObj, &str, &align);
rect = getPrivateDataCheck<Rect>(mrb, rectObj, RectType);
GUARD_EXC( b->drawText(rect->toIntRect(), str, align); )
}
else
{
mrb_int x, y, width, height;
mrb_get_args(mrb, "iiiiz|i", &x, &y, &width, &height, &str, &align);
GUARD_EXC( b->drawText(x, y, width, height, str, align); )
}
return mrb_nil_value();
}
MRB_METHOD(bitmapTextSize)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
char *str;
mrb_get_args(mrb, "z", &str);
IntRect value;
GUARD_EXC( value = b->textSize(str); )
Rect *rect = new Rect(value);
return wrapObject(mrb, rect, RectType);
}
MRB_METHOD(bitmapGetFont)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
checkDisposed(mrb, b, "bitmap");
return getProperty(mrb, self, CSfont);
}
MRB_METHOD(bitmapSetFont)
{
Bitmap *b = getPrivateData<Bitmap>(mrb, self);
mrb_value fontObj;
Font *font;
mrb_get_args(mrb, "o", &fontObj);
font = getPrivateDataCheck<Font>(mrb, fontObj, FontType);
GUARD_EXC( b->setFont(font); )
setProperty(mrb, self, CSfont, fontObj);
return mrb_nil_value();
}
CLONE_FUN(Bitmap)
void
bitmapBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Bitmap", 0);
disposableBindingInit<Bitmap>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", bitmapInitialize, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1));
mrb_define_method(mrb, klass, "width", bitmapWidth, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "height", bitmapHeight, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "rect", bitmapRect, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "blt", bitmapBlt, MRB_ARGS_REQ(4) | MRB_ARGS_OPT(1));
mrb_define_method(mrb, klass, "stretch_blt", bitmapStretchBlt, MRB_ARGS_REQ(3) | MRB_ARGS_OPT(1));
mrb_define_method(mrb, klass, "fill_rect", bitmapFillRect, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(2));
mrb_define_method(mrb, klass, "clear", bitmapClear, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "get_pixel", bitmapGetPixel, MRB_ARGS_REQ(2));
mrb_define_method(mrb, klass, "set_pixel", bitmapSetPixel, MRB_ARGS_REQ(3));
mrb_define_method(mrb, klass, "hue_change", bitmapHueChange, MRB_ARGS_REQ(1));
mrb_define_method(mrb, klass, "draw_text", bitmapDrawText, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(4));
mrb_define_method(mrb, klass, "text_size", bitmapTextSize, MRB_ARGS_REQ(1));
mrb_define_method(mrb, klass, "font", bitmapGetFont, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "font=", bitmapSetFont, MRB_ARGS_REQ(1));
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "clone", BitmapClone, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,62 @@
/*
** disposable-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DISPOSABLEBINDING_H
#define DISPOSABLEBINDING_H
#include "disposable.h"
#include "binding-util.h"
template<class C>
MRB_METHOD(disposableDispose)
{
Disposable *d = getPrivateData<C>(mrb, self);
d->dispose();
return mrb_nil_value();
}
template<class C>
MRB_METHOD(disposableDisposed)
{
Disposable *d = getPrivateData<C>(mrb, self);
return mrb_bool_value(d->isDisposed());
}
template<class C>
static void disposableBindingInit(mrb_state *mrb, RClass *klass)
{
mrb_define_method(mrb, klass, "dispose", disposableDispose<C>, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "disposed?", disposableDisposed<C>, MRB_ARGS_NONE());
}
inline void checkDisposed(mrb_state *mrb, Disposable *d, const char *klassName)
{
MrbData *data = getMrbData(mrb);
if (d->isDisposed())
mrb_raisef(mrb, data->exc[RGSS], "disposed %S",
mrb_str_new_static(mrb, klassName, strlen(klassName)));
}
#endif // DISPOSABLEBINDING_H

View File

@ -0,0 +1,214 @@
/*
** etc-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "etc.h"
#include "binding-util.h"
#include "binding-types.h"
#include "serializable-binding.h"
#include "mruby/class.h"
#include <QDebug>
#define ATTR_RW(Type, attr, arg_type, mrb_val, arg_t_s) \
MRB_METHOD(Type##Get_##attr) \
{ \
Type *p = getPrivateData<Type>(mrb, self); \
\
return mrb_##mrb_val##_value(p->attr); \
} \
\
MRB_METHOD(Type##Set_##attr) \
{ \
Type *p = getPrivateData<Type>(mrb, self); \
\
arg_type arg; \
mrb_get_args(mrb, arg_t_s, &arg); \
\
p->attr = arg; \
UPDATE_F \
\
return mrb_##mrb_val##_value(arg); \
}
#define EQUAL_FUN(Typ) \
MRB_METHOD(Typ##Equal) \
{ \
Typ *p = getPrivateData<Typ>(mrb, self); \
mrb_value otherObj; \
Typ *other; \
mrb_get_args(mrb, "o", &otherObj); \
RClass *klass = mrb_obj_class(mrb, self); \
RClass *otherKlass = mrb_obj_class(mrb, otherObj); \
if (klass != otherKlass) \
return mrb_false_value(); \
other = getPrivateDataCheck<Typ>(mrb, otherObj, Typ##Type); \
return mrb_bool_value(*p == *other); \
}
#define ATTR_FLOAT_RW(Type, attr) ATTR_RW(Type, attr, mrb_float, _float, "f")
#define ATTR_INT_RW(Type, attr) ATTR_RW(Type, attr, mrb_int, fixnum, "i")
#define UPDATE_F p->updateInternal();
ATTR_FLOAT_RW(Color, red)
ATTR_FLOAT_RW(Color, green)
ATTR_FLOAT_RW(Color, blue)
ATTR_FLOAT_RW(Color, alpha)
ATTR_FLOAT_RW(Tone, red)
ATTR_FLOAT_RW(Tone, green)
ATTR_FLOAT_RW(Tone, blue)
ATTR_FLOAT_RW(Tone, gray)
#undef UPDATE_F
#define UPDATE_F
ATTR_INT_RW(Rect, x)
ATTR_INT_RW(Rect, y)
ATTR_INT_RW(Rect, width)
ATTR_INT_RW(Rect, height)
EQUAL_FUN(Color)
EQUAL_FUN(Tone)
EQUAL_FUN(Rect)
DEF_TYPE(Color);
DEF_TYPE(Tone);
DEF_TYPE(Rect);
#define INIT_FUN(Klass, param_type, param_t_s, last_param_def) \
MRB_METHOD(Klass##Initialize) \
{ \
param_type p1, p2, p3, p4 = last_param_def; \
mrb_get_args(mrb, param_t_s, &p1, &p2, &p3, &p4); \
Klass *k = new Klass(p1, p2, p3, p4); \
setPrivateData(mrb, self, k, Klass##Type); \
return self; \
}
INIT_FUN(Color, mrb_float, "fff|f", 255)
INIT_FUN(Tone, mrb_float, "fff|f", 0)
INIT_FUN(Rect, mrb_int, "iiii", 0)
#define SET_FUN(Klass, param_type, param_t_s, last_param_def) \
MRB_METHOD(Klass##Set) \
{ \
param_type p1, p2, p3, p4 = last_param_def; \
mrb_get_args(mrb, param_t_s, &p1, &p2, &p3, &p4); \
Klass *k = getPrivateData<Klass>(mrb, self); \
k->set(p1, p2, p3, p4); \
return self; \
}
SET_FUN(Color, mrb_float, "fff|f", 255)
SET_FUN(Tone, mrb_float, "fff|f", 0)
SET_FUN(Rect, mrb_int, "iiii", 0)
MRB_METHOD(RectEmpty)
{
Rect *r = getPrivateData<Rect>(mrb, self);
r->empty();
return mrb_nil_value();
}
static char buffer[64];
MRB_METHOD(ColorStringify)
{
Color *c = getPrivateData<Color>(mrb, self);
sprintf(buffer, "(%f, %f, %f, %f)", c->red, c->green, c->blue, c->alpha);
return mrb_str_new_cstr(mrb, buffer);
}
MRB_METHOD(ToneStringify)
{
Tone *t = getPrivateData<Tone>(mrb, self);
sprintf(buffer, "(%f, %f, %f, %f)", t->red, t->green, t->blue, t->gray);
return mrb_str_new_cstr(mrb, buffer);
}
MRB_METHOD(RectStringify)
{
Rect *r = getPrivateData<Rect>(mrb, self);
sprintf(buffer, "(%d, %d, %d, %d)", r->x, r->y, r->width, r->height);
return mrb_str_new_cstr(mrb, buffer);
}
MARSH_LOAD_FUN(Color)
MARSH_LOAD_FUN(Tone)
MARSH_LOAD_FUN(Rect)
CLONE_FUN(Tone)
CLONE_FUN(Color)
CLONE_FUN(Rect)
#define MRB_ATTR_R(Class, attr) mrb_define_method(mrb, klass, #attr, 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_RW(Class, attr) { MRB_ATTR_R(Class, attr); MRB_ATTR_W(Class, attr); }
#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) \
{ \
klass = mrb_define_class(mrb, #Klass, 0); \
mrb_define_class_method(mrb, klass, "_load", Klass##Load, MRB_ARGS_REQ(1)); \
serializableBindingInit<Klass>(mrb, klass); \
mrb_define_method(mrb, klass, "initialize", Klass##Initialize, MRB_ARGS_REQ(3) | MRB_ARGS_OPT(1)); \
mrb_define_method(mrb, klass, "set", Klass##Set, MRB_ARGS_REQ(3) | MRB_ARGS_OPT(1)); \
mrb_define_method(mrb, klass, "clone", Klass##Clone, MRB_ARGS_NONE()); \
mrb_define_method(mrb, klass, "==", Klass##Equal, MRB_ARGS_REQ(1)); \
mrb_define_method(mrb, klass, "to_s", Klass##Stringify, MRB_ARGS_NONE()); \
mrb_define_method(mrb, klass, "inspect", Klass##Stringify, MRB_ARGS_NONE()); \
}
void etcBindingInit(mrb_state *mrb)
{
RClass *klass;
INIT_BIND(Color);
MRB_ATTR_RW(Color, red);
MRB_ATTR_RW(Color, green);
MRB_ATTR_RW(Color, blue);
MRB_ATTR_RW(Color, alpha);
INIT_BIND(Tone);
MRB_ATTR_RW(Tone, red);
MRB_ATTR_RW(Tone, green);
MRB_ATTR_RW(Tone, blue);
MRB_ATTR_RW(Tone, gray);
INIT_BIND(Rect);
MRB_ATTR_RW(Rect, x);
MRB_ATTR_RW(Rect, y);
MRB_ATTR_RW(Rect, width);
MRB_ATTR_RW(Rect, height);
mrb_define_method(mrb, klass, "empty", RectEmpty, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,71 @@
/*
** flashable-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FLASHABLEBINDING_H
#define FLASHABLEBINDING_H
#include "flashable.h"
#include "binding-util.h"
#include "binding-types.h"
template<class C>
MRB_METHOD(flashableFlash)
{
Flashable *f = getPrivateData<C>(mrb, self);
mrb_value colorObj;
mrb_int duration;
Color *color;
mrb_get_args(mrb, "oi", &colorObj, &duration);
if (mrb_nil_p(colorObj))
{
f->flash(0, duration);
return mrb_nil_value();
}
color = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
f->flash(&color->norm, duration);
return mrb_nil_value();
}
template<class C>
MRB_METHOD(flashableUpdate)
{
Flashable *f = getPrivateData<C>(mrb, self);
f->update();
return mrb_nil_value();
}
template<class C>
static void flashableBindingInit(mrb_state *mrb, RClass *klass)
{
mrb_define_method(mrb, klass, "flash", flashableFlash<C>, MRB_ARGS_REQ(2));
mrb_define_method(mrb, klass, "update", flashableUpdate<C>, MRB_ARGS_NONE());
}
#endif // FLASHABLEBINDING_H

View File

@ -0,0 +1,173 @@
/*
** font-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "font.h"
#include "binding-util.h"
#include "binding-types.h"
#include "exception.h"
#include "mruby/string.h"
DEF_TYPE(Font);
MRB_METHOD(fontDoesExist)
{
MRB_UNUSED_PARAM;
const char *name;
mrb_get_args(mrb, "z", &name);
return mrb_bool_value(Font::doesExist(name));
}
MRB_METHOD(fontInitialize)
{
char *name = 0;
mrb_int size = 0;
mrb_get_args(mrb, "|zi", &name, &size);
Font *f = new Font(name, size);
setPrivateData(mrb, self, f, FontType);
/* Wrap property objects */
f->setColor(new Color(*f->getColor()));
wrapProperty(mrb, self, f->getColor(), CScolor, ColorType);
return self;
}
MRB_METHOD(FontGetName)
{
Font *f = getPrivateData<Font>(mrb, self);
return mrb_str_new_cstr(mrb, f->getName());
}
MRB_METHOD(FontSetName)
{
Font *f = getPrivateData<Font>(mrb, self);
mrb_value name;
mrb_get_args(mrb, "S", &name);
f->setName(RSTRING_PTR(name));
return name;
}
#undef DEF_PROP_CHK_DISP
#define DEF_PROP_CHK_DISP
DEF_PROP_I(Font, Size)
DEF_PROP_B(Font, Bold)
DEF_PROP_B(Font, Italic)
DEF_PROP_OBJ(Font, Color, Color, CScolor)
#define DEF_KLASS_PROP(Klass, mrb_type, PropName, arg_type, conv_t) \
static mrb_value \
Klass##Get##PropName(mrb_state *, mrb_value) \
{ \
return mrb_##conv_t##_value(Klass::get##PropName()); \
} \
static mrb_value \
Klass##Set##PropName(mrb_state *mrb, mrb_value) \
{ \
mrb_type value; \
mrb_get_args(mrb, arg_type, &value); \
Klass::set##PropName(value); \
return mrb_##conv_t##_value(value); \
}
DEF_KLASS_PROP(Font, mrb_int, DefaultSize, "i", fixnum)
DEF_KLASS_PROP(Font, mrb_bool, DefaultBold, "b", bool)
DEF_KLASS_PROP(Font, mrb_bool, DefaultItalic, "b", bool)
MRB_METHOD(FontGetDefaultName)
{
MRB_UNUSED_PARAM;
return mrb_str_new_cstr(mrb, Font::getDefaultName());
}
MRB_METHOD(FontSetDefaultName)
{
MRB_UNUSED_PARAM;
mrb_value nameObj;
mrb_get_args(mrb, "S", &nameObj);
Font::setDefaultName(RSTRING_PTR(nameObj));
return nameObj;
}
MRB_METHOD(FontGetDefaultColor)
{
return getProperty(mrb, self, CSdefault_color);
}
MRB_METHOD(FontSetDefaultColor)
{
mrb_value colorObj;
mrb_get_args(mrb, "o", &colorObj);
Color *c = getPrivateDataCheck<Color>(mrb, colorObj, ColorType);
Font::setDefaultColor(c);
setProperty(mrb, self, CSdefault_color, colorObj);
return colorObj;
}
#define INIT_KLASS_PROP_BIND(Klass, PropName, prop_name_s) \
{ \
mrb_define_class_method(mrb, klass, prop_name_s, Klass##Get##PropName, MRB_ARGS_NONE()); \
mrb_define_class_method(mrb, klass, prop_name_s "=", Klass##Set##PropName, MRB_ARGS_REQ(1)); \
}
void
fontBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Font", 0);
Font::setDefaultColor(new Color(*Font::getDefaultColor()));
wrapProperty(mrb, mrb_obj_value(klass), Font::getDefaultColor(), CSdefault_color, ColorType);
mrb_define_class_method(mrb, klass, "exist?", fontDoesExist, MRB_ARGS_REQ(1));
INIT_KLASS_PROP_BIND(Font, DefaultName, "default_name");
INIT_KLASS_PROP_BIND(Font, DefaultSize, "default_size");
INIT_KLASS_PROP_BIND(Font, DefaultBold, "default_bold");
INIT_KLASS_PROP_BIND(Font, DefaultItalic, "default_italic");
INIT_KLASS_PROP_BIND(Font, DefaultColor, "default_color");
mrb_define_method(mrb, klass, "initialize", fontInitialize, MRB_ARGS_OPT(2));
INIT_PROP_BIND(Font, Name, "name");
INIT_PROP_BIND(Font, Size, "size");
INIT_PROP_BIND(Font, Bold, "bold");
INIT_PROP_BIND(Font, Italic, "italic");
INIT_PROP_BIND(Font, Color, "color");
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,126 @@
/*
** graphics-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics.h"
#include "globalstate.h"
#include "mruby.h"
#include "binding-util.h"
#include "exception.h"
MRB_METHOD(graphicsUpdate)
{
MRB_UNUSED_PARAM;
gState->graphics().update();
return mrb_nil_value();
}
MRB_METHOD(graphicsFreeze)
{
MRB_UNUSED_PARAM;
gState->graphics().freeze();
return mrb_nil_value();
}
MRB_METHOD(graphicsTransition)
{
MRB_UNUSED_PARAM;
mrb_int duration = 8;
const char *filename = 0;
mrb_int vague = 40;
mrb_get_args(mrb, "|izi", &duration, &filename, &vague);
GUARD_EXC( gState->graphics().transition(duration, filename, vague); )
return mrb_nil_value();
}
MRB_METHOD(graphicsFrameReset)
{
MRB_UNUSED_PARAM;
gState->graphics().frameReset();
return mrb_nil_value();
}
#define DEF_GRA_PROP_I(PropName) \
MRB_METHOD(graphics##Get##PropName) \
{ \
MRB_UNUSED_PARAM; \
return mrb_fixnum_value(gState->graphics().get##PropName()); \
} \
MRB_METHOD(graphics##Set##PropName) \
{ \
MRB_UNUSED_PARAM; \
mrb_int value; \
mrb_get_args(mrb, "i", &value); \
gState->graphics().set##PropName(value); \
return mrb_nil_value(); \
}
DEF_GRA_PROP_I(FrameRate)
DEF_GRA_PROP_I(FrameCount)
MRB_METHOD(graphicsGetFullscreen)
{
MRB_UNUSED_PARAM;
return mrb_bool_value(gState->graphics().getFullscreen());
}
MRB_METHOD(graphicsSetFullscreen)
{
MRB_UNUSED_PARAM;
mrb_bool mode;
mrb_get_args(mrb, "b", &mode);
gState->graphics().setFullscreen(mode);
return mrb_bool_value(mode);
}
#define INIT_GRA_PROP_BIND(PropName, prop_name_s) \
{ \
mrb_define_module_function(mrb, module, prop_name_s, graphics##Get##PropName, MRB_ARGS_NONE()); \
mrb_define_module_function(mrb, module, prop_name_s "=", graphics##Set##PropName, MRB_ARGS_REQ(1)); \
}
void graphicsBindingInit(mrb_state *mrb)
{
RClass *module = mrb_define_module(mrb, "Graphics");
mrb_define_module_function(mrb, module, "update", graphicsUpdate, MRB_ARGS_NONE());
mrb_define_module_function(mrb, module, "freeze", graphicsFreeze, MRB_ARGS_NONE());
mrb_define_module_function(mrb, module, "transition", graphicsTransition, MRB_ARGS_OPT(3));
mrb_define_module_function(mrb, module, "frame_reset", graphicsFrameReset, MRB_ARGS_NONE());
INIT_GRA_PROP_BIND( FrameRate, "frame_rate" );
INIT_GRA_PROP_BIND( FrameCount, "frame_count" );
INIT_GRA_PROP_BIND( Fullscreen, "fullscreen" );
}

View File

@ -0,0 +1,146 @@
/*
** input-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "input.h"
#include "globalstate.h"
#include "exception.h"
#include "binding-util.h"
MRB_METHOD(inputUpdate)
{
MRB_UNUSED_PARAM;
gState->input().update();
return mrb_nil_value();
}
MRB_METHOD(inputPress)
{
MRB_UNUSED_PARAM;
mrb_int num;
mrb_get_args(mrb, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num;
return mrb_bool_value(gState->input().isPressed(bc));
}
MRB_METHOD(inputTrigger)
{
MRB_UNUSED_PARAM;
mrb_int num;
mrb_get_args(mrb, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num;
return mrb_bool_value(gState->input().isTriggered(bc));
}
MRB_METHOD(inputRepeat)
{
MRB_UNUSED_PARAM;
mrb_int num;
mrb_get_args(mrb, "i", &num);
Input::ButtonCode bc = (Input::ButtonCode) num;
return mrb_bool_value(gState->input().isRepeated(bc));
}
MRB_METHOD(inputDir4)
{
MRB_UNUSED_PARAM;
return mrb_fixnum_value(gState->input().dir4Value());
}
MRB_METHOD(inputDir8)
{
MRB_UNUSED_PARAM;
return mrb_fixnum_value(gState->input().dir8Value());
}
/* Non-standard extensions */
MRB_METHOD(inputMouseX)
{
MRB_UNUSED_PARAM;
return mrb_fixnum_value(gState->input().mouseX());
}
MRB_METHOD(inputMouseY)
{
MRB_UNUSED_PARAM;
return mrb_fixnum_value(gState->input().mouseY());
}
#define DEF_CONST_I(name, value) \
mrb_const_set(mrb, mrb_obj_value(module), mrb_intern(mrb, name), mrb_fixnum_value(value))
void
inputBindingInit(mrb_state *mrb)
{
RClass *module = mrb_define_module(mrb, "Input");
mrb_define_module_function(mrb, module, "update", inputUpdate, MRB_ARGS_NONE());
mrb_define_module_function(mrb, module, "press?", inputPress, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, module, "trigger?", inputTrigger, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, module, "repeat?", inputRepeat, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, module, "dir4", inputDir4, MRB_ARGS_NONE());
mrb_define_module_function(mrb, module, "dir8", inputDir8, MRB_ARGS_NONE());
DEF_CONST_I("DOWN", Input::Down );
DEF_CONST_I("LEFT", Input::Left );
DEF_CONST_I("RIGHT", Input::Right);
DEF_CONST_I("UP", Input::Up );
DEF_CONST_I("A", Input::A );
DEF_CONST_I("B", Input::B );
DEF_CONST_I("C", Input::C );
DEF_CONST_I("X", Input::X );
DEF_CONST_I("Y", Input::Y );
DEF_CONST_I("Z", Input::Z );
DEF_CONST_I("L", Input::L );
DEF_CONST_I("R", Input::R );
DEF_CONST_I("SHIFT", Input::Shift);
DEF_CONST_I("CTRL", Input::Ctrl );
DEF_CONST_I("ALT", Input::Alt );
DEF_CONST_I("F5", Input::F5 );
DEF_CONST_I("F6", Input::F6 );
DEF_CONST_I("F7", Input::F7 );
DEF_CONST_I("F8", Input::F8 );
DEF_CONST_I("F9", Input::F9 );
mrb_define_module_function(mrb, module, "mouse_x", inputMouseX, MRB_ARGS_NONE());
mrb_define_module_function(mrb, module, "mouse_y", inputMouseY, MRB_ARGS_NONE());
DEF_CONST_I("MOUSELEFT", Input::MouseLeft );
DEF_CONST_I("MOUSEMIDDLE", Input::MouseMiddle);
DEF_CONST_I("MOUSERIGHT", Input::MouseRight );
}

2368
binding-mruby/module_rpg.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
/*
** plane-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "plane.h"
#include "disposable-binding.h"
#include "viewportelement-binding.h"
#include "binding-util.h"
#include "binding-types.h"
DEF_TYPE(Plane);
MRB_METHOD(planeInitialize)
{
Plane *p = viewportElementInitialize<Plane>(mrb, self);
setPrivateData(mrb, self, p, PlaneType);
p->setColor(new Color);
p->setTone(new Tone);
wrapNilProperty(mrb, self, CSbitmap);
wrapProperty(mrb, self, p->getColor(), CScolor, ColorType);
wrapProperty(mrb, self, p->getTone(), CStone, ToneType);
return self;
}
#define DISP_CLASS_NAME "plane"
DEF_PROP_OBJ(Plane, Bitmap, Bitmap, CSbitmap)
DEF_PROP_OBJ(Plane, Color, Color, CScolor)
DEF_PROP_OBJ(Plane, Tone, Tone, CStone)
DEF_PROP_I(Plane, OX)
DEF_PROP_I(Plane, OY)
DEF_PROP_I(Plane, Opacity)
DEF_PROP_I(Plane, BlendType)
DEF_PROP_F(Plane, ZoomX)
DEF_PROP_F(Plane, ZoomY)
void
planeBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Plane", 0);
disposableBindingInit<Plane> (mrb, klass);
viewportElementBindingInit<Plane>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", planeInitialize, MRB_ARGS_OPT(1));
INIT_PROP_BIND( Plane, Bitmap, "bitmap" );
INIT_PROP_BIND( Plane, OX, "ox" );
INIT_PROP_BIND( Plane, OY, "oy" );
INIT_PROP_BIND( Plane, ZoomX, "zoom_x" );
INIT_PROP_BIND( Plane, ZoomY, "zoom_y" );
INIT_PROP_BIND( Plane, Opacity, "opacity" );
INIT_PROP_BIND( Plane, BlendType, "blend_type" );
INIT_PROP_BIND( Plane, Color, "color" );
INIT_PROP_BIND( Plane, Tone, "tone" );
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,90 @@
/*
** sceneelement-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCENEELEMENTBINDING_H
#define SCENEELEMENTBINDING_H
#include "scene.h"
#include "binding-util.h"
template<class C>
MRB_METHOD(sceneElementGetZ)
{
SceneElement *se = getPrivateData<C>(mrb, self);
mrb_int value = 0;
GUARD_EXC( value = se->getZ(); )
return mrb_fixnum_value(value);
}
template<class C>
MRB_METHOD(sceneElementSetZ)
{
SceneElement *se = getPrivateData<C>(mrb, self);
mrb_int z;
mrb_get_args(mrb, "i", &z);
GUARD_EXC( se->setZ(z); )
return mrb_nil_value();
}
template<class C>
MRB_METHOD(sceneElementGetVisible)
{
SceneElement *se = getPrivateData<C>(mrb, self);
bool value = false;
GUARD_EXC( value = se->getVisible(); )
return mrb_bool_value(value);
}
template<class C>
MRB_METHOD(sceneElementSetVisible)
{
SceneElement *se = getPrivateData<C>(mrb, self);
mrb_value visibleObj;
bool visible;
mrb_get_args(mrb, "o", &visibleObj);
visible = mrb_test(visibleObj);
GUARD_EXC( se->setVisible(visible); )
return mrb_nil_value();
}
template<class C>
void
sceneElementBindingInit(mrb_state *mrb, RClass *klass)
{
mrb_define_method(mrb, klass, "z", sceneElementGetZ<C>, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "z=", sceneElementSetZ<C>, MRB_ARGS_REQ(1));
mrb_define_method(mrb, klass, "visible", sceneElementGetVisible<C>, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "visible=", sceneElementSetVisible<C>, MRB_ARGS_REQ(1));
}
#endif // SCENEELEMENTBINDING_H

View File

@ -0,0 +1,51 @@
/*
** serializable-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERIALIZABLEBINDING_H
#define SERIALIZABLEBINDING_H
#include "serializable.h"
#include "binding-util.h"
#include "mruby/string.h"
template<class C>
MRB_METHOD(serializableDump)
{
Serializable *s = getPrivateData<C>(mrb, self);
int dataSize = s->serialSize();
mrb_value data = mrb_str_new(mrb, 0, dataSize);
s->serialize(RSTRING_PTR(data));
return data;
}
template<class C>
void
serializableBindingInit(mrb_state *mrb, RClass *klass)
{
mrb_define_method(mrb, klass, "_dump", serializableDump<C>, MRB_ARGS_NONE());
}
#endif // SERIALIZABLEBINDING_H

View File

@ -0,0 +1,99 @@
/*
** sprite-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "sprite.h"
#include "disposable-binding.h"
#include "flashable-binding.h"
#include "sceneelement-binding.h"
#include "viewportelement-binding.h"
#include "binding-util.h"
DEF_TYPE(Sprite);
MRB_METHOD(spriteInitialize)
{
Sprite *s = viewportElementInitialize<Sprite>(mrb, self);
setPrivateData(mrb, self, s, SpriteType);
/* Wrap property objects */
s->setSrcRect(new Rect);
s->setColor(new Color);
s->setTone(new Tone);
wrapNilProperty(mrb, self, CSbitmap);
wrapProperty(mrb, self, s->getSrcRect(), CSsrc_rect, RectType);
wrapProperty(mrb, self, s->getColor(), CScolor, ColorType);
wrapProperty(mrb, self, s->getTone(), CStone, ToneType);
return self;
}
#define DISP_CLASS_NAME "sprite"
DEF_PROP_OBJ_NIL(Sprite, Bitmap, Bitmap, CSbitmap)
DEF_PROP_OBJ(Sprite, Rect, SrcRect, CSsrc_rect)
DEF_PROP_OBJ(Sprite, Color, Color, CScolor)
DEF_PROP_OBJ(Sprite, Tone, Tone, CStone)
DEF_PROP_I(Sprite, X)
DEF_PROP_I(Sprite, Y)
DEF_PROP_I(Sprite, OX)
DEF_PROP_I(Sprite, OY)
DEF_PROP_I(Sprite, BushDepth)
DEF_PROP_I(Sprite, Opacity)
DEF_PROP_I(Sprite, BlendType)
DEF_PROP_F(Sprite, ZoomX)
DEF_PROP_F(Sprite, ZoomY)
DEF_PROP_F(Sprite, Angle)
DEF_PROP_B(Sprite, Mirror)
void
spriteBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Sprite", 0);
disposableBindingInit <Sprite>(mrb, klass);
flashableBindingInit <Sprite>(mrb, klass);
viewportElementBindingInit<Sprite>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", spriteInitialize, MRB_ARGS_OPT(1));
INIT_PROP_BIND( Sprite, Bitmap, "bitmap" );
INIT_PROP_BIND( Sprite, SrcRect, "src_rect" );
INIT_PROP_BIND( Sprite, X, "x" );
INIT_PROP_BIND( Sprite, Y, "y" );
INIT_PROP_BIND( Sprite, OX, "ox" );
INIT_PROP_BIND( Sprite, OY, "oy" );
INIT_PROP_BIND( Sprite, ZoomX, "zoom_x" );
INIT_PROP_BIND( Sprite, ZoomY, "zoom_y" );
INIT_PROP_BIND( Sprite, Angle, "angle" );
INIT_PROP_BIND( Sprite, Mirror, "mirror" );
INIT_PROP_BIND( Sprite, BushDepth, "bush_depth" );
INIT_PROP_BIND( Sprite, Opacity, "opacity" );
INIT_PROP_BIND( Sprite, BlendType, "blend_type" );
INIT_PROP_BIND( Sprite, Color, "color" );
INIT_PROP_BIND( Sprite, Tone, "tone" );
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,163 @@
/*
** table-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "table.h"
#include "binding-util.h"
#include "binding-types.h"
#include "serializable-binding.h"
#include "mruby.h"
#include <QDebug>
DEF_TYPE(Table);
MRB_METHOD(tableInitialize)
{
mrb_int x, y, z;
x = y = z = 1;
mrb_get_args(mrb, "i|ii", &x, &y, &z);
Table *t = new Table(x, y, z);
setPrivateData(mrb, self, t, TableType);
return self;
}
#define TABLE_SIZE(d, D) \
MRB_METHOD(table##D##Size) \
{ \
Table *t = getPrivateData<Table>(mrb, self); \
return mrb_fixnum_value((mrb_int)t->d##Size()); \
}
TABLE_SIZE(x, X)
TABLE_SIZE(y, Y)
TABLE_SIZE(z, Z)
MRB_METHOD(tableResize)
{
Table *t = getPrivateData<Table>(mrb, self);
mrb_int x, y, z;
mrb_get_args(mrb, "i|ii", &x, &y, &z);
switch (mrb->c->ci->argc)
{
default:
case 1:
t->resize(x);
return mrb_nil_value();
case 2:
t->resize(x, y);
return mrb_nil_value();
case 3:
t->resize(x, y, z);
return mrb_nil_value();
}
}
MRB_METHOD(tableGetAt)
{
Table *t = getPrivateData<Table>(mrb, self);
mrb_int x, y, z;
x = y = z = 0;
mrb_get_args(mrb, "i|ii", &x, &y, &z);
if (x < 0 || x >= t->xSize()
|| y < 0 || y >= t->ySize()
|| z < 0 || z >= t->zSize())
{
return mrb_nil_value();
}
mrb_int result = t->get(x, y, z);
return mrb_fixnum_value(result);
}
#define fix(x) mrb_fixnum(x)
MRB_METHOD(tableSetAt)
{
Table *t = getPrivateData<Table>(mrb, self);
int argc;
mrb_value* argv;
mrb_int x, y, z, value;
x = y = z = 0;
mrb_get_args(mrb, "*", &argv, &argc);
if (argc < 2)
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
switch (argc)
{
default:
case 2 :
x = fix(argv[0]);
value = fix(argv[1]);
break;
case 3 :
x = fix(argv[0]);
y = fix(argv[1]);
value = fix(argv[2]);
break;
case 4 :
x = fix(argv[0]);
y = fix(argv[1]);
z = fix(argv[2]);
value = fix(argv[3]);
break;
}
t->set(value, x, y, z);
return mrb_fixnum_value(value);
}
MARSH_LOAD_FUN(Table)
void
tableBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Table", 0);
mrb_define_class_method(mrb, klass, "_load", TableLoad, MRB_ARGS_REQ(1));
serializableBindingInit<Table>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", tableInitialize, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2));
mrb_define_method(mrb, klass, "resize", tableResize, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2));
mrb_define_method(mrb, klass, "xsize", tableXSize, MRB_ARGS_NONE() );
mrb_define_method(mrb, klass, "ysize", tableYSize, MRB_ARGS_NONE() );
mrb_define_method(mrb, klass, "zsize", tableZSize, MRB_ARGS_NONE() );
mrb_define_method(mrb, klass, "[]", tableGetAt, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(2));
mrb_define_method(mrb, klass, "[]=", tableSetAt, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(2));
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,161 @@
/*
** tilemap-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tilemap.h"
#include "viewport.h"
#include "bitmap.h"
#include "table.h"
#include "disposable-binding.h"
#include "binding-util.h"
#include "binding-types.h"
#include "mruby/array.h"
static const mrb_data_type TilemapAutotilesType =
{
"TilemapAutotiles",
0
};
MRB_METHOD(tilemapAutotilesSet)
{
Tilemap::Autotiles *a = getPrivateData<Tilemap::Autotiles>(mrb, self);
mrb_int i;
mrb_value bitmapObj;
mrb_get_args(mrb, "io", &i, &bitmapObj);
Bitmap *bitmap = getPrivateDataCheck<Bitmap>(mrb, bitmapObj, BitmapType);
a->set(i, bitmap);
mrb_value ary = mrb_iv_get(mrb, self, getMrbData(mrb)->symbols[CSarray]);
mrb_ary_set(mrb, ary, i, bitmapObj);
return self;
}
MRB_METHOD(tilemapAutotilesGet)
{
mrb_int i;
mrb_get_args (mrb, "i", &i);
if (i < 0 || i > 6)
return mrb_nil_value();
mrb_value ary = mrb_iv_get(mrb, self, getMrbData(mrb)->symbols[CSarray]);
return mrb_ary_entry(ary, i);
}
DEF_TYPE(Tilemap);
MRB_METHOD(tilemapInitialize)
{
Tilemap *t;
/* Get parameters */
mrb_value viewportObj = mrb_nil_value();
Viewport *viewport = 0;
mrb_get_args(mrb, "|o", &viewportObj);
if (!mrb_nil_p(viewportObj))
viewport = getPrivateDataCheck<Viewport>(mrb, viewportObj, ViewportType);
/* Construct object */
t = new Tilemap(viewport);
setPrivateData(mrb, self, t, TilemapType);
setProperty(mrb, self, CSviewport, viewportObj);
wrapProperty(mrb, self, &t->getAutotiles(), CSautotiles, TilemapAutotilesType);
mrb_value autotilesObj = mrb_iv_get(mrb, self, getMrbData(mrb)->symbols[CSautotiles]);
mrb_value ary = mrb_ary_new_capa(mrb, 7);
for (int i = 0; i < 7; ++i)
mrb_ary_push(mrb, ary, mrb_nil_value());
mrb_iv_set(mrb, autotilesObj, getMrbData(mrb)->symbols[CSarray], ary);
return self;
}
MRB_METHOD(tilemapGetAutotiles)
{
return getProperty(mrb, self, CSautotiles);
}
MRB_METHOD(tilemapUpdate)
{
Tilemap *t = getPrivateData<Tilemap>(mrb, self);
t->update();
return mrb_nil_value();
}
#define DISP_CLASS_NAME "tilemap"
DEF_PROP_OBJ(Tilemap, Viewport, Viewport, CSviewport)
DEF_PROP_OBJ(Tilemap, Bitmap, Tileset, CStileset)
DEF_PROP_OBJ(Tilemap, Table, MapData, CSmap_data)
DEF_PROP_OBJ(Tilemap, Table, FlashData, CSflash_data)
DEF_PROP_OBJ(Tilemap, Table, Priorities, CSpriorities)
DEF_PROP_B(Tilemap, Visible)
DEF_PROP_I(Tilemap, OX)
DEF_PROP_I(Tilemap, OY)
void
tilemapBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "TilemapAutotiles", 0);
mrb_define_method(mrb, klass, "[]=", tilemapAutotilesSet, MRB_ARGS_REQ(2));
mrb_define_method(mrb, klass, "[]", tilemapAutotilesGet, MRB_ARGS_REQ(1));
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
klass = mrb_define_class(mrb, "Tilemap", 0);
disposableBindingInit<Tilemap>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", tilemapInitialize, MRB_ARGS_OPT(1));
mrb_define_method(mrb, klass, "autotiles", tilemapGetAutotiles, MRB_ARGS_NONE());
mrb_define_method(mrb, klass, "update", tilemapUpdate, MRB_ARGS_NONE());
INIT_PROP_BIND( Tilemap, Viewport, "viewport" );
INIT_PROP_BIND( Tilemap, Tileset, "tileset" );
INIT_PROP_BIND( Tilemap, MapData, "map_data" );
INIT_PROP_BIND( Tilemap, FlashData, "flash_data" );
INIT_PROP_BIND( Tilemap, Priorities, "priorities" );
INIT_PROP_BIND( Tilemap, Visible, "visible" );
INIT_PROP_BIND( Tilemap, OX, "ox" );
INIT_PROP_BIND( Tilemap, OY, "oy" );
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,99 @@
/*
** viewport-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "viewport.h"
#include "disposable-binding.h"
#include "flashable-binding.h"
#include "sceneelement-binding.h"
#include "binding-util.h"
#include "binding-types.h"
DEF_TYPE(Viewport);
MRB_METHOD(viewportInitialize)
{
Viewport *v;
if (mrb->c->ci->argc == 1)
{
/* The rect arg is only used to init the viewport,
* and does NOT replace its 'rect' property */
mrb_value rectObj;
Rect *rect;
mrb_get_args(mrb, "o", &rectObj);
rect = getPrivateDataCheck<Rect>(mrb, rectObj, RectType);
v = new Viewport(rect);
}
else
{
mrb_int x, y, width, height;
mrb_get_args(mrb, "iiii", &x, &y, &width, &height);
v = new Viewport(x, y, width, height);
}
setPrivateData(mrb, self, v, ViewportType);
/* Wrap property objects */
v->setRect(new Rect(*v->getRect()));
v->setColor(new Color);
v->setTone(new Tone);
wrapProperty(mrb, self, v->getRect(), CSrect, RectType);
wrapProperty(mrb, self, v->getColor(), CScolor, ColorType);
wrapProperty(mrb, self, v->getTone(), CStone, ToneType);
return self;
}
#define DISP_CLASS_NAME "viewport"
DEF_PROP_OBJ(Viewport, Rect, Rect, CSrect)
DEF_PROP_OBJ(Viewport, Color, Color, CScolor)
DEF_PROP_OBJ(Viewport, Tone, Tone, CStone)
DEF_PROP_I(Viewport, OX)
DEF_PROP_I(Viewport, OY)
void
viewportBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Viewport", 0);
disposableBindingInit <Viewport>(mrb, klass);
flashableBindingInit <Viewport>(mrb, klass);
sceneElementBindingInit<Viewport>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", viewportInitialize, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(3));
INIT_PROP_BIND( Viewport, Rect, "rect" );
INIT_PROP_BIND( Viewport, OX, "ox" );
INIT_PROP_BIND( Viewport, OY, "oy" );
INIT_PROP_BIND( Viewport, Color, "color" );
INIT_PROP_BIND( Viewport, Tone, "tone" );
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,72 @@
/*
** viewportelement-binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VIEWPORTELEMENTBINDING_H
#define VIEWPORTELEMENTBINDING_H
#include "viewport.h"
#include "binding-util.h"
#include "binding-types.h"
#include "sceneelement-binding.h"
template<class C>
MRB_METHOD(viewportElementGetViewport)
{
ViewportElement *ve = getPrivateData<C>(mrb, self);
GUARD_EXC( ve->aboutToAccess(); )
return getProperty(mrb, self, CSviewport);
}
template<class C>
static C *
viewportElementInitialize(mrb_state *mrb, mrb_value self)
{
/* Get parameters */
mrb_value viewportObj = mrb_nil_value();
Viewport *viewport = 0;
mrb_get_args(mrb, "|o", &viewportObj);
if (!mrb_nil_p(viewportObj))
viewport = getPrivateDataCheck<Viewport>(mrb, viewportObj, ViewportType);
/* Construct object */
C *ve = new C(viewport);
/* Set property objects */
setProperty(mrb, self, CSviewport, viewportObj);
return ve;
}
template<class C>
void
viewportElementBindingInit(mrb_state *mrb, RClass *klass)
{
sceneElementBindingInit<C>(mrb, klass);
mrb_define_method(mrb, klass, "viewport", viewportElementGetViewport<C>, MRB_ARGS_NONE());
}
#endif // VIEWPORTELEMENTBINDING_H

View File

@ -0,0 +1,101 @@
/*
** window-binding.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "window.h"
#include "disposable-binding.h"
#include "viewportelement-binding.h"
#include "binding-util.h"
DEF_TYPE(Window);
MRB_METHOD(windowInitialize)
{
Window *w = viewportElementInitialize<Window>(mrb, self);
setPrivateData(mrb, self, w, WindowType);
w->setCursorRect(new Rect);
wrapNilProperty(mrb, self, CSwindowskin);
wrapNilProperty(mrb, self, CScontents);
wrapProperty(mrb, self, w->getCursorRect(), CScursor_rect, RectType);
return self;
}
MRB_METHOD(windowUpdate)
{
Window *w = getPrivateData<Window>(mrb, self);
w->update();
return mrb_nil_value();
}
#define DISP_CLASS_NAME "window"
DEF_PROP_OBJ_NIL(Window, Bitmap, Windowskin, CSwindowskin)
DEF_PROP_OBJ_NIL(Window, Bitmap, Contents, CScontents)
DEF_PROP_OBJ(Window, Rect, CursorRect, CScursor_rect)
DEF_PROP_B(Window, Stretch)
DEF_PROP_B(Window, Active)
DEF_PROP_B(Window, Pause)
DEF_PROP_I(Window, X)
DEF_PROP_I(Window, Y)
DEF_PROP_I(Window, Width)
DEF_PROP_I(Window, Height)
DEF_PROP_I(Window, OX)
DEF_PROP_I(Window, OY)
DEF_PROP_I(Window, Opacity)
DEF_PROP_I(Window, BackOpacity)
DEF_PROP_I(Window, ContentsOpacity)
void
windowBindingInit(mrb_state *mrb)
{
RClass *klass = mrb_define_class(mrb, "Window", 0);
disposableBindingInit <Window>(mrb, klass);
viewportElementBindingInit<Window>(mrb, klass);
mrb_define_method(mrb, klass, "initialize", windowInitialize, MRB_ARGS_REQ(1));
mrb_define_method(mrb, klass, "update", windowUpdate, MRB_ARGS_NONE());
INIT_PROP_BIND( Window, Windowskin, "windowskin" );
INIT_PROP_BIND( Window, Contents, "contents" );
INIT_PROP_BIND( Window, Stretch, "stretch" );
INIT_PROP_BIND( Window, CursorRect, "cursor_rect" );
INIT_PROP_BIND( Window, Active, "active" );
INIT_PROP_BIND( Window, Pause, "pause" );
INIT_PROP_BIND( Window, X, "x" );
INIT_PROP_BIND( Window, Y, "y" );
INIT_PROP_BIND( Window, Width, "width" );
INIT_PROP_BIND( Window, Height, "height" );
INIT_PROP_BIND( Window, OX, "ox" );
INIT_PROP_BIND( Window, OY, "oy" );
INIT_PROP_BIND( Window, Opacity, "opacity" );
INIT_PROP_BIND( Window, BackOpacity, "back_opacity" );
INIT_PROP_BIND( Window, ContentsOpacity, "contents_opacity" );
mrb_define_method(mrb, klass, "inspect", inspectObject, MRB_ARGS_NONE());
}

View File

@ -0,0 +1,45 @@
/*
** binding-null.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "binding.h"
#include "globalstate.h"
#include "eventthread.h"
#include <QDebug>
static void nullBindingExecute()
{
qDebug() << "The null binding doesn't do anything, so we're done!";
gState->rtData().rqTermAck = true;
}
static void nullBindingTerminate()
{
}
ScriptBinding scriptBindingImpl =
{
nullBindingExecute,
nullBindingTerminate
};
ScriptBinding *scriptBinding = &scriptBindingImpl;

11
mkxp.conf Normal file
View File

@ -0,0 +1,11 @@
[General]
debugMode=true
winResizable=true
fullscreen=false
vsync=true
defScreenW=640
defScreenH=480
solidFonts=false
gameFolder=.
customScript=
RTPs=/home/Ancurio/Public/RGSS-RTP

192
mkxp.pro Normal file
View File

@ -0,0 +1,192 @@
TEMPLATE = app
QT = core
TARGET = mkxp
DEPENDPATH += src shader assets
INCLUDEPATH += . src SFML/include libsigc++
isEmpty(BINDING) {
BINDING = BINDING_MRI
}
CONFIG += $$BINDING
unix {
CONFIG += link_pkgconfig
PKGCONFIG += sigc++-2.0 sdl2 SDL2_image SDL2_ttf sfml-audio
LIBS += -lGLEW -lphysfs -lz
}
# 'slots' keyword fucks with libsigc++
DEFINES += QT_NO_KEYWORDS
# Input
HEADERS += \
src/quadarray.h \
src/audio.h \
src/binding.h \
src/bitmap.h \
src/disposable.h \
src/etc.h \
src/etc-internal.h \
src/eventthread.h \
src/flashable.h \
src/font.h \
src/globalstate.h \
src/input.h \
src/plane.h \
src/scene.h \
src/sprite.h \
src/table.h \
src/texpool.h \
src/tilequad.h \
src/transform.h \
src/viewport.h \
src/window.h \
src/serializable.h \
src/shader.h \
src/glstate.h \
src/quad.h \
src/tilemap.h \
src/graphics.h \
src/debuglogger.h \
src/global-ibo.h \
src/exception.h \
src/filesystem.h \
src/serial-util.h \
src/intrulist.h \
src/binding.h \
src/gl-util.h \
src/util.h \
src/config.h
SOURCES += \
src/main.cpp \
src/audio.cpp \
src/bitmap.cpp \
src/eventthread.cpp \
src/filesystem.cpp \
src/font.cpp \
src/globalstate.cpp \
src/input.cpp \
src/plane.cpp \
src/scene.cpp \
src/sprite.cpp \
src/table.cpp \
src/tilequad.cpp \
src/viewport.cpp \
src/window.cpp \
src/texpool.cpp \
src/shader.cpp \
src/glstate.cpp \
src/tilemap.cpp \
src/autotiles.cpp \
src/graphics.cpp \
src/debuglogger.cpp \
src/etc.cpp \
src/config.cpp
EMBED = shader/transSimple.frag \
shader/trans.frag \
shader/hue.frag \
shader/sprite.frag \
shader/bitmapBlit.frag \
assets/liberation.ttf
# xxd
xxd.output = ${QMAKE_FILE_NAME}.xxd
xxd.commands = xxd -i ${QMAKE_FILE_NAME} > ${QMAKE_FILE_OUT}
xxd.depends = $$EMBED
xxd.input = EMBED
xxd.variable_out = HEADERS
QMAKE_EXTRA_COMPILERS += xxd
BINDING_NULL {
SOURCES += binding-null/binding-null.cpp
}
BINDING_MRUBY {
LIBS += mruby/build/host/lib/libmruby.a
INCLUDEPATH += mruby/include
DEPENDPATH += mruby/include
DEFINES += BINDING_MRUBY
HEADERS += \
binding-mruby/binding-util.h \
binding-mruby/disposable-binding.h \
binding-mruby/flashable-binding.h \
binding-mruby/binding-types.h \
binding-mruby/sceneelement-binding.h \
binding-mruby/viewportelement-binding.h \
binding-mruby/serializable-binding.h \
binding-mruby/mrb-ext/file.h \
binding-mruby/mrb-ext/rwmem.h \
binding-mruby/mrb-ext/marshal.h
SOURCES += \
binding-mruby/binding-mruby.cpp \
binding-mruby/binding-util.cpp \
binding-mruby/window-binding.cpp \
binding-mruby/bitmap-binding.cpp \
binding-mruby/sprite-binding.cpp \
binding-mruby/font-binding.cpp \
binding-mruby/viewport-binding.cpp \
binding-mruby/plane-binding.cpp \
binding-mruby/audio-binding.cpp \
binding-mruby/tilemap-binding.cpp \
binding-mruby/etc-binding.cpp \
binding-mruby/graphics-binding.cpp \
binding-mruby/input-binding.cpp \
binding-mruby/table-binding.cpp \
binding-mruby/module_rpg.c \
binding-mruby/mrb-ext/file.cpp \
binding-mruby/mrb-ext/marshal.cpp \
binding-mruby/mrb-ext/rwmem.cpp \
binding-mruby/mrb-ext/kernel.cpp \
binding-mruby/mrb-ext/time.cpp
}
BINDING_MRI {
LIBS += ./ruby/libruby.so
INCLUDEPATH += ruby/include
DEPENDPATH += ruby/include
DEFINES += BINDING_MRI
EMBED2 = binding-mri/module_rpg.rb
xxdp.output = ${QMAKE_FILE_NAME}.xxd
xxdp.commands = xxd+/xxd+ ${QMAKE_FILE_NAME} -o ${QMAKE_FILE_OUT} --string
xxdp.depends = $$EMBED2
xxdp.input = EMBED2
xxdp.variable_out = HEADERS
QMAKE_EXTRA_COMPILERS += xxdp
HEADERS += \
binding-mri/binding-util.h \
binding-mri/binding-types.h \
binding-mri/serializable-binding.h \
binding-mri/disposable-binding.h \
binding-mri/sceneelement-binding.h \
binding-mri/viewportelement-binding.h \
binding-mri/flashable-binding.h
SOURCES += \
binding-mri/binding-mri.cpp \
binding-mri/binding-util.cpp \
binding-mri/table-binding.cpp \
binding-mri/etc-binding.cpp \
binding-mri/bitmap-binding.cpp \
binding-mri/font-binding.cpp \
binding-mri/graphics-binding.cpp \
binding-mri/input-binding.cpp \
binding-mri/sprite-binding.cpp \
binding-mri/viewport-binding.cpp \
binding-mri/plane-binding.cpp \
binding-mri/window-binding.cpp \
binding-mri/tilemap-binding.cpp \
binding-mri/audio-binding.cpp \
binding-mri/module_rpg.cpp \
binding-mri/filesystem-binding.cpp
}

31
shader/bitmapBlit.frag Normal file
View File

@ -0,0 +1,31 @@
uniform sampler2D source;
uniform sampler2D destination;
uniform vec4 subRect;
uniform float opacity;
void main()
{
vec2 coor = gl_TexCoord[0].xy;
vec2 dstCoor = (coor - subRect.xy) * subRect.zw;
vec4 srcFrag = texture2D(source, coor);
vec4 dstFrag = texture2D(destination, dstCoor);
vec4 resFrag;
float ab = opacity;
const float as = srcFrag.a;
const float ad = dstFrag.a;
const float at = ab*as;
resFrag.a = at + ad - ad*at;
resFrag.rgb = mix(dstFrag.rgb, srcFrag.rgb, ab*as);
// resFrag.rgb /= (resFrag.a);
resFrag.rgb = mix(srcFrag.rgb, resFrag.rgb, ad*resFrag.a);
gl_FragColor = resFrag;
}

40
shader/hue.frag Normal file
View File

@ -0,0 +1,40 @@
uniform sampler2D inputTexture;
uniform float hueAdjust;
void main ()
{
const vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
const vec4 kRGBToI = vec4 (0.596, -0.275, -0.321, 0.0);
const vec4 kRGBToQ = vec4 (0.212, -0.523, 0.311, 0.0);
const vec4 kYIQToR = vec4 (1.0, 0.956, 0.621, 0.0);
const vec4 kYIQToG = vec4 (1.0, -0.272, -0.647, 0.0);
const vec4 kYIQToB = vec4 (1.0, -1.107, 1.704, 0.0);
// Sample the input pixel
vec4 color = texture2D (inputTexture, gl_TexCoord [ 0 ].xy);
// Convert to YIQ
float YPrime = dot (color, kRGBToYPrime);
float I = dot (color, kRGBToI);
float Q = dot (color, kRGBToQ);
// Calculate the hue and chroma
float hue = atan (Q, I);
float chroma = sqrt (I * I + Q * Q);
// Make the user's adjustments
hue += hueAdjust;
// Convert back to YIQ
Q = chroma * sin (hue);
I = chroma * cos (hue);
// Convert back to RGB
vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
color.r = dot (yIQ, kYIQToR);
color.g = dot (yIQ, kYIQToG);
color.b = dot (yIQ, kYIQToB);
// Save the result
gl_FragColor = color;
}

43
shader/sprite.frag Normal file
View File

@ -0,0 +1,43 @@
uniform sampler2D texture;
uniform vec4 tone;
uniform float opacity;
uniform vec4 color;
uniform vec4 flash;
uniform float bushDepth;
uniform float bushOpacity;
const vec3 lumaF = { .299, .587, .114 };
void main()
{
vec2 coor = gl_TexCoord[0].xy;
/* Sample source color */
vec4 frag = texture2D(texture, coor);
/* Apply gray */
const float luma = dot(frag.rgb, lumaF);
frag.rgb = mix(frag.rgb, vec3(luma), tone.w);
/* Apply tone */
frag.rgb += tone.rgb;
/* Apply opacity */
frag.a *= opacity;
/* Apply color */
frag.rgb = mix(frag.rgb, color.rgb, color.a);
/* Apply flash */
frag.rgb = mix(frag.rgb, flash.rgb, flash.a);
/* Apply bush alpha by mathematical if */
float underBush = float(coor.y < bushDepth);
frag.a *= clamp(bushOpacity + underBush, 0, 1);
gl_FragColor = frag;
}

23
shader/trans.frag Normal file
View File

@ -0,0 +1,23 @@
/* Fragment shader dealing with transitions */
uniform sampler2D currentScene;
uniform sampler2D frozenScene;
uniform sampler2D transMap;
/* Normalized */
uniform float prog;
/* Vague [0, 512] normalized */
uniform float vague;
void main()
{
vec2 texCoor = gl_TexCoord[0].st;
float transV = texture2D(transMap, texCoor).r;
float cTransV = clamp(transV, prog, prog+vague);
float alpha = (cTransV - prog) / vague;
vec4 newFrag = texture2D(currentScene, texCoor);
vec4 oldFrag = texture2D(frozenScene, texCoor);
gl_FragColor = mix(newFrag, oldFrag, alpha);
}

13
shader/transSimple.frag Normal file
View File

@ -0,0 +1,13 @@
uniform sampler2D frozenScene;
uniform sampler2D currentScene;
uniform float prog;
void main()
{
vec2 texCoor = gl_TexCoord[0].st;
vec4 newPixel = texture2D(currentScene, texCoor);
vec4 oldPixel = texture2D(frozenScene, texCoor);
gl_FragColor = mix(oldPixel, newPixel, prog);
}

668
src/audio.cpp Normal file
View File

@ -0,0 +1,668 @@
/*
** audio.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "audio.h"
#include "globalstate.h"
#include "util.h"
#include "intrulist.h"
#include "filesystem.h"
#include "exception.h"
#include <SFML/Audio/Music.hpp>
#include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/SoundBuffer.hpp>
#include <SFML/System/Thread.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/System/Sleep.hpp>
#include <QByteArray>
#include <QHash>
#include "SDL2/SDL_thread.h"
//#include "SDL2/SDL_mixer.h"
#include <QDebug>
#define FADE_SLEEP 10
#define SOUND_MAG_SIZE 10
#define SOUND_MAX_MEM (50*1000*1000) // 5 MB
struct MusicEntity
{
sf::Music music;
QByteArray filename;
FileStream currentData;
SDL_mutex *mutex;
int pitch;
volatile bool fading;
struct
{
unsigned int duration;
float msStep;
volatile bool terminate;
sf::Thread *thread;
} fadeData;
/* normalized */
float intVolume;
float extVolume;
bool extPaused;
bool noFadeInFlag;
MusicEntity()
: currentData(0),
pitch(100),
fading(false),
intVolume(1),
extVolume(1),
extPaused(false),
noFadeInFlag(false)
{
music.setLoop(true);
fadeData.thread = 0;
mutex = SDL_CreateMutex();
}
~MusicEntity()
{
SDL_DestroyMutex(mutex);
}
void play(const QByteArray &filename,
int volume,
int pitch)
{
terminateFade();
volume = bound<int>(volume, 0, 100);
pitch = bound<int>(pitch, 50, 150);
if (filename == this->filename
&& volume == (int)music.getVolume()
// && pitch == music.getPitch()
&& music.getStatus() == sf::Music::Playing)
return;
if (filename == this->filename
&& music.getStatus() == sf::Music::Playing)
// && pitch == music.getPitch())
{
intVolume = (float) volume / 100;
updateVolumeSync();
return;
}
SDL_LockMutex(mutex);
this->music.stop();
this->filename = filename;
currentData.close();
currentData =
gState->fileSystem().openRead(filename.constData(), FileSystem::Audio);
if (!this->music.openFromStream(currentData))
return;
intVolume = (float) volume / 100;
updateVolume();
// this->music.setPitch((float) pitch / 100);
if (!extPaused)
this->music.play();
else
noFadeInFlag = true;
SDL_UnlockMutex(mutex);
}
void stop()
{
terminateFade();
stopPriv();
}
void fade(unsigned int ms)
{
if (music.getStatus() != sf::Music::Playing)
return;
if (fading)
return;
delete fadeData.thread;
fadeData.thread = new sf::Thread(&MusicEntity::processFade, this);
fadeData.duration = ms;
fadeData.terminate = false;
fading = true;
fadeData.thread->launch();
}
void updateVolume()
{
music.setVolume(intVolume * extVolume * 100);
}
void updateVolumeSync()
{
SDL_LockMutex(mutex);
updateVolume();
SDL_UnlockMutex(mutex);
}
private:
void terminateFade()
{
if (!fading)
return;
/* Tell our thread to wrap up and wait for it */
fadeData.terminate = true;
fadeData.thread->wait();
fading = false;
}
void stopPriv()
{
SDL_LockMutex(mutex);
music.stop();
SDL_UnlockMutex(mutex);
filename = QByteArray();
}
void processFade()
{
float msStep = music.getVolume() / fadeData.duration;
sf::Clock timer;
sf::Time sleepTime = sf::milliseconds(FADE_SLEEP);
unsigned int currentDur = 0;
while (true)
{
int elapsed = timer.getElapsedTime().asMilliseconds();
timer.restart();
currentDur += elapsed;
if (music.getStatus() != sf::Music::Playing)
break;
if (fadeData.terminate)
break;
if (currentDur >= fadeData.duration)
break;
intVolume = (float) (music.getVolume() - (elapsed * msStep)) / 100;
updateVolumeSync();
sf::sleep(sleepTime);
}
stopPriv();
fading = false;
}
};
//struct SoundBuffer
//{
// Mix_Chunk *sdlBuffer;
// QByteArray filename;
// IntruListLink<SoundBuffer> link;
// SoundBuffer()
// : link(this)
// {}
//};
//struct SoundEntity
//{
// IntruList<SoundBuffer> buffers;
// QHash<QByteArray, SoundBuffer*> bufferHash;
// uint cacheSize; // in chunks, for now
// int channelIndex;
// SoundEntity()
// : cacheSize(0),
// channelIndex(0)
// {
// Mix_AllocateChannels(SOUND_MAG_SIZE);
// }
// ~SoundEntity()
// {
// IntruListLink<SoundBuffer> *iter = buffers.iterStart();
// iter = iter->next;
// for (int i = 0; i < buffers.getSize(); ++i)
// {
// SoundBuffer *buffer = iter->data;
// iter = iter->next;
// delete buffer;
// }
// }
// void play(const char *filename,
// int volume,
// int pitch)
// {
// (void) pitch;
// volume = bound(volume, 0, 100);
// Mix_Chunk *buffer = requestBuffer(filename);
// int nextChIdx = channelIndex++;
// if (channelIndex > SOUND_MAG_SIZE-1)
// channelIndex = 0;
// Mix_HaltChannel(nextChIdx);
// Mix_Volume(nextChIdx, ((float) MIX_MAX_VOLUME / 100) * volume);
// Mix_PlayChannelTimed(nextChIdx, buffer, 0, -1);
// }
// void stop()
// {
// /* Stop all channels */
// Mix_HaltChannel(-1);
// }
//private:
// Mix_Chunk *requestBuffer(const char *filename)
// {
// SoundBuffer *buffer = bufferHash.value(filename, 0);
// if (buffer)
// {
// /* Buffer still in cashe.
// * Move to front of priority list */
// buffers.remove(buffer->link);
// buffers.append(buffer->link);
// return buffer->sdlBuffer;
// }
// else
// {
// /* Buffer not in cashe, needs to be loaded */
// SDL_RWops ops;
// gState->fileSystem().openRead(ops, filename, FileSystem::Audio);
// Mix_Chunk *sdlBuffer = Mix_LoadWAV_RW(&ops, 1);
// if (!sdlBuffer)
// {
// SDL_RWclose(&ops);
// throw Exception(Exception::RGSSError, "Unable to read sound file");
// }
// buffer = new SoundBuffer;
// buffer->sdlBuffer = sdlBuffer;
// buffer->filename = filename;
// ++cacheSize;
// bufferHash.insert(filename, buffer);
// buffers.prepend(buffer->link);
// if (cacheSize > 20)
// {
// SoundBuffer *last = buffers.tail();
// bufferHash.remove(last->filename);
// buffers.remove(last->link);
// --cacheSize;
// qDebug() << "Deleted buffer" << last->filename;
// delete last;
// }
// return buffer->sdlBuffer;
// }
// }
//};
struct SoundBuffer
{
sf::SoundBuffer sfBuffer;
QByteArray filename;
IntruListLink<SoundBuffer> link;
SoundBuffer()
: link(this)
{}
};
struct SoundEntity
{
IntruList<SoundBuffer> buffers;
QHash<QByteArray, SoundBuffer*> bufferHash;
unsigned int bufferSamples;
sf::Sound soundMag[SOUND_MAG_SIZE];
int magIndex;
SoundEntity()
: bufferSamples(0),
magIndex(0)
{}
~SoundEntity()
{
QHash<QByteArray, SoundBuffer*>::iterator iter;
for (iter = bufferHash.begin(); iter != bufferHash.end(); ++iter)
delete iter.value();
}
void play(const char *filename,
int volume,
int pitch)
{
(void) pitch;
volume = bound<int>(volume, 0, 100);
sf::SoundBuffer &buffer = allocateBuffer(filename);
int soundIndex = magIndex++;
if (magIndex > SOUND_MAG_SIZE-1)
magIndex = 0;
sf::Sound &sound = soundMag[soundIndex];
sound.stop();
sound.setBuffer(buffer);
sound.setVolume(volume);
sound.play();
}
void stop()
{
for (int i = 0; i < SOUND_MAG_SIZE; i++)
soundMag[i].stop();
}
private:
sf::SoundBuffer &allocateBuffer(const char *filename)
{
SoundBuffer *buffer = bufferHash.value(filename, 0);
if (buffer)
{
/* Buffer still in cashe.
* Move to front of priority list */
buffers.remove(buffer->link);
buffers.append(buffer->link);
return buffer->sfBuffer;
}
else
{
/* Buffer not in cashe, needs to be loaded */
FileStream data =
gState->fileSystem().openRead(filename, FileSystem::Audio);
buffer = new SoundBuffer;
buffer->sfBuffer.loadFromStream(data);
bufferSamples += buffer->sfBuffer.getSampleCount();
data.close();
// qDebug() << "SoundCache: Current memory consumption:" << bufferSamples/2;
buffer->filename = filename;
bufferHash.insert(filename, buffer);
buffers.prepend(buffer->link);
// FIXME this part would look better if it actually looped until enough memory is freed
/* If memory limit is reached, delete lowest priority buffer.
* Samples are 2 bytes big */
if ((bufferSamples/2) > SOUND_MAX_MEM && !buffers.isEmpty())
{
SoundBuffer *last = buffers.tail();
bufferHash.remove(last->filename);
buffers.remove(last->link);
bufferSamples -= last->sfBuffer.getSampleCount();
qDebug() << "Deleted buffer" << last->filename;
delete last;
}
return buffer->sfBuffer;
}
}
};
struct AudioPrivate
{
MusicEntity bgm;
MusicEntity bgs;
MusicEntity me;
SoundEntity se;
sf::Thread *meWatchThread;
bool meWatchRunning;
bool meWatchThreadTerm;
AudioPrivate()
: meWatchThread(0),
meWatchRunning(false),
meWatchThreadTerm(false)
{
me.music.setLoop(false);
}
~AudioPrivate()
{
if (meWatchThread)
{
meWatchThreadTerm = true;
meWatchThread->wait();
delete meWatchThread;
}
bgm.stop();
bgs.stop();
me.stop();
se.stop();
}
void scheduleMeWatch()
{
if (meWatchRunning)
return;
meWatchRunning = true;
if (meWatchThread)
meWatchThread->wait();
bgm.extPaused = true;
delete meWatchThread;
meWatchThread = new sf::Thread(&AudioPrivate::meWatchFunc, this);
meWatchThread->launch();
}
void meWatchFunc()
{
// FIXME Need to catch the case where an ME is started while
// the BGM is still being faded in from this function
sf::Time sleepTime = sf::milliseconds(FADE_SLEEP);
const int bgmFadeOutSteps = 20;
const int bgmFadeInSteps = 100;
/* Fade out BGM */
for (int i = bgmFadeOutSteps; i > 0; --i)
{
if (meWatchThreadTerm)
return;
if (bgm.music.getStatus() != sf::Music::Playing)
{
bgm.extVolume = 0;
bgm.updateVolumeSync();
break;
}
bgm.extVolume = (1.0 / bgmFadeOutSteps) * (i-1);
bgm.updateVolumeSync();
sf::sleep(sleepTime);
}
SDL_LockMutex(bgm.mutex);
if (bgm.music.getStatus() == sf::Music::Playing)
bgm.music.pause();
SDL_UnlockMutex(bgm.mutex);
/* Linger while ME plays */
while (me.music.getStatus() == sf::Music::Playing)
{
if (meWatchThreadTerm)
return;
sf::sleep(sleepTime);
}
SDL_LockMutex(bgm.mutex);
bgm.extPaused = false;
if (bgm.music.getStatus() == sf::Music::Paused)
bgm.music.play();
SDL_UnlockMutex(bgm.mutex);
/* Fade in BGM again */
for (int i = 0; i < bgmFadeInSteps; ++i)
{
if (meWatchThreadTerm)
return;
SDL_LockMutex(bgm.mutex);
if (bgm.music.getStatus() != sf::Music::Playing || bgm.noFadeInFlag)
{
bgm.noFadeInFlag = false;
bgm.extVolume = 1;
bgm.updateVolume();
bgm.music.play();
SDL_UnlockMutex(bgm.mutex);
break;
}
bgm.extVolume = (1.0 / bgmFadeInSteps) * (i+1);
bgm.updateVolume();
SDL_UnlockMutex(bgm.mutex);
sf::sleep(sleepTime);
}
meWatchRunning = false;
}
};
Audio::Audio()
: p(new AudioPrivate)
{
}
void Audio::bgmPlay(const char *filename,
int volume,
int pitch)
{
p->bgm.play(filename, volume, pitch);
}
void Audio::bgmStop()
{
p->bgm.stop();
}
void Audio::bgmFade(int time)
{
p->bgm.fade(time);
}
void Audio::bgsPlay(const char *filename,
int volume,
int pitch)
{
p->bgs.play(filename, volume, pitch);
}
void Audio::bgsStop()
{
p->bgs.stop();
}
void Audio::bgsFade(int time)
{
p->bgs.fade(time);
}
void Audio::mePlay(const char *filename,
int volume,
int pitch)
{
p->me.play(filename, volume, pitch);
p->scheduleMeWatch();
}
void Audio::meStop()
{
p->me.stop();
}
void Audio::meFade(int time)
{
p->me.fade(time);
}
void Audio::sePlay(const char *filename,
int volume,
int pitch)
{
p->se.play(filename, volume, pitch);
}
void Audio::seStop()
{
p->se.stop();
}
Audio::~Audio() { delete p; }

52
src/audio.h Normal file
View File

@ -0,0 +1,52 @@
/*
** audio.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AUDIO_H
#define AUDIO_H
struct AudioPrivate;
class Audio
{
public:
Audio();
~Audio();
void bgmPlay(const char *filename, int volume = 100, int pitch = 100);
void bgmStop();
void bgmFade(int time);
void bgsPlay(const char *filename, int volume = 100, int pitch = 100);
void bgsStop();
void bgsFade(int time);
void mePlay(const char *filename, int volume = 100, int pitch = 100);
void meStop();
void meFade(int time);
void sePlay(const char *filename, int volume = 100, int pitch = 100);
void seStop();
private:
AudioPrivate *p;
};
#endif // AUDIO_H

199
src/autotiles.cpp Normal file
View File

@ -0,0 +1,199 @@
struct StaticRect { float x, y, w, h; };
extern const StaticRect autotileRects[] =
{
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 80.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 16.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 16.5, 64.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 32.5, 48.5, 15, 15 },
{ 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 },
{ 64.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 80.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 32.5, 96.5, 15, 15 },
{ 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 48.5, 96.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 32.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 0.5, 64.5, 15, 15 },
{ 80.5, 64.5, 15, 15 },
{ 80.5, 80.5, 15, 15 },
{ 0.5, 80.5, 15, 15 },
{ 32.5, 32.5, 15, 15 },
{ 48.5, 32.5, 15, 15 },
{ 48.5, 112.5, 15, 15 },
{ 32.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 16.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 80.5, 16.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 48.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 64.5, 16.5, 15, 15 },
{ 64.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 64.5, 0.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 16.5, 96.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 80.5, 0.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 48.5, 15, 15 },
{ 0.5, 48.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 16.5, 32.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 0.5, 96.5, 15, 15 },
{ 80.5, 96.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 0.5, 112.5, 15, 15 },
{ 64.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 80.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 0.5, 32.5, 15, 15 },
{ 80.5, 32.5, 15, 15 },
{ 16.5, 112.5, 15, 15 },
{ 64.5, 112.5, 15, 15 },
{ 0.5, 0.5, 15, 15 },
{ 16.5, 0.5, 15, 15 },
{ 16.5, 16.5, 15, 15 },
{ 0.5, 16.5, 15, 15 }
};
extern const int autotileRectsN = sizeof(autotileRects) / sizeof(autotileRects[0]);

43
src/binding.h Normal file
View File

@ -0,0 +1,43 @@
/*
** binding.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BINDING_H
#define BINDING_H
struct ScriptBinding
{
/* Starts the part where the binding takes over,
* loading the compressed scripts and executing them.
* This function returns as soon as the scripts finish
* execution or an error is encountered */
void (*execute) (void);
/* Instructs the binding
* to immediately terminate script execution. This
* function will perform a longjmp instead of returning,
* so be careful about any variables with local storage */
void (*terminate) (void);
};
/* VTable defined in the binding source */
extern ScriptBinding *scriptBinding;
#endif // BINDING_H

573
src/bitmap.cpp Normal file
View File

@ -0,0 +1,573 @@
/*
** bitmap.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bitmap.h"
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include "SDL2/SDL_ttf.h"
#include "gl-util.h"
#include "quad.h"
#include "quadarray.h"
#include "exception.h"
#include "globalstate.h"
#include "glstate.h"
#include "texpool.h"
#include "shader.h"
#include "filesystem.h"
#include "font.h"
#include "eventthread.h"
#define DISP_CLASS_NAME "bitmap"
struct BitmapPrivate
{
TexFBO tex;
/* 'setPixel()' calls are cached and executed
* in batches on 'flush()' */
PointArray pointArray;
Font *font;
BitmapPrivate()
{
font = &gState->defaultFont();
}
void bindTextureWithMatrix()
{
Tex::bind(tex.tex);
Tex::bindMatrix(tex.width, tex.height);
}
void bindFBO()
{
FBO::bind(tex.fbo);
}
void pushSetViewport() const
{
glState.pushSetViewport(tex.width, tex.height);
}
void popViewport() const
{
glState.popViewport();
}
void blitQuad(Quad &quad)
{
glState.blendMode.pushSet(BlendNone);
quad.draw();
glState.blendMode.pop();
}
void flushPoints()
{
if (pointArray.count() == 0)
return;
Tex::unbind();
bindFBO();
pushSetViewport();
glState.blendMode.pushSet(BlendNone);
pointArray.commit();
pointArray.draw();
pointArray.reset();
glState.blendMode.pop();
popViewport();
}
void fillRect(const IntRect &rect,
const Vec4 &color)
{
flushPoints();
bindFBO();
glState.scissorTest.pushSet(true);
glState.scissorBox.pushSet(rect);
glState.clearColor.pushSet(color);
glClear(GL_COLOR_BUFFER_BIT);
glState.clearColor.pop();
glState.scissorBox.pop();
glState.scissorTest.pop();
}
static void ensureFormat(SDL_Surface *&surf, Uint32 format)
{
if (surf->format->format == format)
return;
SDL_Surface *surfConv = SDL_ConvertSurfaceFormat(surf, format, 0);
SDL_FreeSurface(surf);
surf = surfConv;
}
};
Bitmap::Bitmap(const char *filename)
{
SDL_RWops ops;
gState->fileSystem().openRead(ops, filename, FileSystem::Image);
SDL_Surface *imgSurf = IMG_Load_RW(&ops, 1);
if (!imgSurf)
throw Exception(Exception::SDLError, "SDL: %s", SDL_GetError());
p = new BitmapPrivate;
p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888);
p->tex = gState->texPool().request(imgSurf->w, imgSurf->h);
Tex::bind(p->tex.tex);
Tex::uploadImage(p->tex.width, p->tex.height, imgSurf->pixels, GL_RGBA);
SDL_FreeSurface(imgSurf);
}
Bitmap::Bitmap(int width, int height)
{
p = new BitmapPrivate;
p->tex = gState->texPool().request(width, height);
clear();
}
Bitmap::Bitmap(const Bitmap &other)
{
p = new BitmapPrivate;
p->tex = gState->texPool().request(other.width(), other.height());
other.flush();
blt(0, 0, other, rect());
}
Bitmap::~Bitmap()
{
dispose();
}
int Bitmap::width() const
{
GUARD_DISPOSED
return p->tex.width;
}
int Bitmap::height() const
{
GUARD_DISPOSED
return p->tex.height;
}
IntRect Bitmap::rect() const
{
return IntRect(0, 0, width(), height());
}
void Bitmap::blt(int x, int y,
const Bitmap &source, const IntRect &rect,
int opacity)
{
stretchBlt(IntRect(x, y, rect.w, rect.h),
source, rect, opacity);
}
void Bitmap::stretchBlt(const IntRect &destRect,
const Bitmap &source, const IntRect &sourceRect,
int opacity)
{
GUARD_DISPOSED;
opacity = bound(opacity, 0, 255);
if (opacity == 0)
{
return;
}
// else if (opacity == 255) /* Fast blit */
// {
// flush();
// FBO::bind(source.p->tex.fbo, FBO::Read);
// FBO::bind(p->tex.fbo, FBO::Draw);
// FBO::blit(sourceRect.x, sourceRect.y, sourceRect.w, sourceRect.h,
// destRect.x, destRect.y, destRect.w, destRect.h);
// }
else /* Fragment pipeline */
{
flush();
float normOpacity = (float) opacity / 255.0f;
TexFBO &gpTex = gState->gpTexFBO(destRect.w, destRect.h);
FBO::bind(gpTex.fbo, FBO::Draw);
FBO::bind(p->tex.fbo, FBO::Read);
FBO::blit(destRect.x, destRect.y, 0, 0, destRect.w, destRect.h);
FloatRect bltSubRect((float) sourceRect.x / source.width(),
(float) sourceRect.y / source.height(),
((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width),
((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height));
BltShader &shader = gState->bltShader();
shader.bind();
shader.setDestination(gpTex.tex);
shader.setSubRect(bltSubRect);
shader.setOpacity(normOpacity);
Quad quad;
quad.setTexPosRect(sourceRect, destRect);
quad.setColor(Vec4(1, 1, 1, normOpacity));
source.p->bindTextureWithMatrix();
p->bindFBO();
p->pushSetViewport();
p->blitQuad(quad);
p->popViewport();
shader.unbind();
}
modified();
}
void Bitmap::fillRect(int x, int y,
int width, int height,
const Vec4 &color)
{
fillRect(IntRect(x, y, width, height), color);
}
void Bitmap::fillRect(const IntRect &rect, const Vec4 &color)
{
GUARD_DISPOSED
p->fillRect(rect, color);
modified();
}
void Bitmap::gradientFillRect(int x, int y,
int width, int height,
const Vec4 &color1, const Vec4 &color2,
bool vertical)
{
gradientFillRect(IntRect(x, y, width, height), color1, color2, vertical);
}
void Bitmap::gradientFillRect(const IntRect &rect,
const Vec4 &color1, const Vec4 &color2,
bool vertical)
{
GUARD_DISPOSED
flush();
Quad quad;
if (vertical)
{
quad.vert[0].color = color2;
quad.vert[1].color = color2;
quad.vert[2].color = color1;
quad.vert[3].color = color1;
}
else
{
quad.vert[0].color = color1;
quad.vert[3].color = color1;
quad.vert[1].color = color2;
quad.vert[2].color = color2;
}
quad.setPosRect(rect);
Tex::unbind();
p->bindFBO();
p->pushSetViewport();
p->blitQuad(quad);
p->popViewport();
modified();
}
void Bitmap::clearRect(int x, int y, int width, int height)
{
clearRect(IntRect(x, y, width, height));
}
void Bitmap::clearRect(const IntRect &rect)
{
GUARD_DISPOSED
p->fillRect(rect, Vec4());
modified();
}
void Bitmap::clear()
{
GUARD_DISPOSED
/* Any queued points won't be visible after this anyway */
p->pointArray.reset();
p->bindFBO();
glState.clearColor.pushSet(Vec4());
glClear(GL_COLOR_BUFFER_BIT);
glState.clearColor.pop();
modified();
}
Vec4 Bitmap::getPixel(int x, int y) const
{
GUARD_DISPOSED;
if (x < 0 || y < 0 || x >= width() || y >= height())
return Vec4();
flush();
p->bindFBO();
glState.viewport.push();
Vec4 pixel = FBO::getPixel(x, y, width(), height());
glState.viewport.pop();
return pixel;
}
void Bitmap::setPixel(int x, int y, const Vec4 &color)
{
GUARD_DISPOSED
p->pointArray.append(Vec2(x+.5, y+.5), color);
modified();
}
void Bitmap::hueChange(int hue)
{
GUARD_DISPOSED
if ((hue % 360) == 0)
return;
flush();
TexFBO newTex = gState->texPool().request(width(), height());
FloatRect texRect(rect());
Quad quad;
quad.setTexPosRect(texRect, texRect);
/* Calculate hue parameter */
hue = wrapRange(hue, 0, 359);
float hueAdj = -((M_PI * 2) / 360) * hue;
HueShader &shader = gState->hueShader();
shader.bind();
shader.setHueAdjust(hueAdj);
shader.setInputTexture(p->tex.tex);
FBO::bind(newTex.fbo);
Tex::bindMatrix(width(), height());
p->pushSetViewport();
p->blitQuad(quad);
shader.unbind();
p->popViewport();
gState->texPool().release(p->tex);
p->tex = newTex;
modified();
}
void Bitmap::drawText(int x, int y,
int width, int height,
const char *str, int align)
{
drawText(IntRect(x, y, width, height), str, align);
}
void Bitmap::drawText(const IntRect &rect, const char *str, int align)
{
GUARD_DISPOSED
if (*str == '\0')
return;
flush();
TTF_Font *font = p->font->getSdlFont();
SDL_Color c;
p->font->getColor()->toSDLColor(c);
SDL_Surface *txtSurf;
if (gState->rtData().config.solidFonts)
txtSurf = TTF_RenderUTF8_Solid(font, str, c);
else
txtSurf = TTF_RenderUTF8_Blended(font, str, c);
p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ARGB8888);
int alignX = rect.x;
switch (align)
{
default:
case Left :
break;
case Center :
alignX += (rect.w - txtSurf->w) / 2;
break;
case Right :
alignX += rect.w - txtSurf->w;
break;
}
if (alignX < rect.x)
alignX = rect.x;
int alignY = rect.y + (rect.h - txtSurf->h) / 2;
float squeeze = (float) rect.w / txtSurf->w;
if (squeeze > 1)
squeeze = 1;
FloatRect posRect(alignX, alignY, txtSurf->w * squeeze, txtSurf->h);
Vec2 gpTexSize;
gState->ensureTexSize(txtSurf->w, txtSurf->h, gpTexSize);
// if (str[1] != '\0')
{
/* Aquire a partial copy of the destination
* buffer we're about to render to */
TexFBO &gpTex2 = gState->gpTexFBO(posRect.w, posRect.h);
FBO::bind(gpTex2.fbo, FBO::Draw);
FBO::bind(p->tex.fbo, FBO::Read);
FBO::blit(posRect.x, posRect.y, 0, 0, posRect.w, posRect.h);
FloatRect bltRect(0, 0,
gpTexSize.x / gpTex2.width,
gpTexSize.y / gpTex2.height);
BltShader &shader = gState->bltShader();
shader.bind();
shader.setSource();
shader.setDestination(gpTex2.tex);
shader.setSubRect(bltRect);
shader.setOpacity(p->font->getColor()->norm.w);
}
gState->bindTex();
Tex::uploadSubImage(0, 0, txtSurf->w, txtSurf->h, txtSurf->pixels, GL_BGRA);
Tex::setSmooth(true);
Quad quad;
quad.setTexRect(FloatRect(0, 0, txtSurf->w, txtSurf->h));
quad.setPosRect(posRect);
SDL_FreeSurface(txtSurf);
p->bindFBO();
p->pushSetViewport();
glState.blendMode.pushSet(BlendNone);
quad.draw();
glState.blendMode.pop();
p->popViewport();
FragShader::unbind();
modified();
}
IntRect Bitmap::textSize(const char *str)
{
GUARD_DISPOSED
TTF_Font *font = p->font->getSdlFont();
int w, h;
TTF_SizeUTF8(font, str, &w, &h);
// if (strlen(str) == 1)
// TTF_GlyphMetrics(font, *str, 0, 0, 0, 0, &w);
return IntRect(0, 0, w, h);
}
DEF_ATTR_SIMPLE(Bitmap, Font, Font*, p->font)
void Bitmap::flush() const
{
p->flushPoints();
}
TexFBO &Bitmap::getGLTypes()
{
return p->tex;
}
void Bitmap::bindTexWithMatrix()
{
p->bindTextureWithMatrix();
}
void Bitmap::releaseResources()
{
gState->texPool().release(p->tex);
delete p;
}

115
src/bitmap.h Normal file
View File

@ -0,0 +1,115 @@
/*
** bitmap.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BITMAP_H
#define BITMAP_H
#include "disposable.h"
#include "etc-internal.h"
#include "etc.h"
#include "sigc++/signal.h"
class Font;
struct TexFBO;
struct BitmapPrivate;
// FIXME make this class use proper RGSS classes again
class Bitmap : public Disposable
{
public:
Bitmap(const char *filename);
Bitmap(int width, int height);
/* Clone constructor */
Bitmap(const Bitmap &other);
~Bitmap();
int width() const;
int height() const;
IntRect rect() const;
void blt(int x, int y,
const Bitmap &source, const IntRect &rect,
int opacity = 255);
void stretchBlt(const IntRect &destRect,
const Bitmap &source, const IntRect &sourceRect,
int opacity = 255);
void fillRect(int x, int y,
int width, int height,
const Vec4 &color);
void fillRect(const IntRect &rect, const Vec4 &color);
/* RGSS2 */
void gradientFillRect(int x, int y,
int width, int height,
const Vec4 &color1, const Vec4 &color2,
bool vertical = false);
void gradientFillRect(const IntRect &rect,
const Vec4 &color1, const Vec4 &color2,
bool vertical = false);
void clearRect(int x, int y,
int width, int height);
void clearRect(const IntRect &rect);
// void radialBlur(int angle, int divisions);
// /* ----- */
void clear();
Vec4 getPixel(int x, int y) const;
void setPixel(int x, int y, const Vec4 &color);
void hueChange(int hue);
enum TextAlign
{
Left = 0,
Center = 1,
Right = 2
};
void drawText(int x, int y,
int width, int height,
const char *str, int align = Left);
void drawText(const IntRect &rect,
const char *str, int align = Left);
IntRect textSize(const char *str);
DECL_ATTR(Font, Font*)
void flush() const;
TexFBO &getGLTypes();
void bindTexWithMatrix();
sigc::signal<void> modified;
private:
void releaseResources();
BitmapPrivate *p;
};
#endif // BITMAP_H

87
src/config.cpp Normal file
View File

@ -0,0 +1,87 @@
/*
** config.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <QSettings>
#include <QFileInfo>
#include <QString>
#include <QStringList>
#include <QFile>
#include <QRegExp>
Config::Config()
: debugMode(false),
winResizable(false),
fullscreen(false),
vsync(false),
defScreenW(640),
defScreenH(480),
solidFonts(false),
gameFolder(".")
{}
void Config::read()
{
QSettings confFile("mkxp.conf", QSettings::IniFormat);
#define READ_VAL(key, Type) key = confFile.value(#key, key).to##Type()
READ_VAL(debugMode, Bool);
READ_VAL(winResizable, Bool);
READ_VAL(fullscreen, Bool);
READ_VAL(vsync, Bool);
READ_VAL(defScreenW, Int);
READ_VAL(defScreenH, Int);
READ_VAL(solidFonts, Bool);
READ_VAL(gameFolder, ByteArray);
READ_VAL(customScript, ByteArray);
QStringList _rtps = confFile.value("RTPs").toStringList();
Q_FOREACH(const QString &s, _rtps)
rtps << s.toUtf8();
}
void Config::readGameINI()
{
if (!customScript.isEmpty())
{
game.title = basename(customScript.constData());
return;
}
QSettings gameINI(gameFolder + "/Game.ini", QSettings::IniFormat);
QFileInfo finfo(gameFolder.constData());
game.title = gameINI.value("Game/Title", finfo.baseName()).toByteArray();
/* Gotta read the "Scripts" entry manually because Qt can't handle '\' */
QFile gameINIFile(gameFolder + "/Game.ini");
if (gameINIFile.open(QFile::ReadOnly))
{
QString gameINIContents = gameINIFile.readAll();
QRegExp scriptsRE(".*Scripts=(.*)\r\nTitle=.*");
if (scriptsRE.exactMatch(gameINIContents))
{
game.scripts = scriptsRE.cap(1).toUtf8();
game.scripts.replace('\\', '/');
}
}
}

58
src/config.h Normal file
View File

@ -0,0 +1,58 @@
/*
** config.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <QByteArray>
#include <QVector>
struct Config
{
bool debugMode;
bool winResizable;
bool fullscreen;
bool vsync;
int defScreenW;
int defScreenH;
bool solidFonts;
QByteArray gameFolder;
QByteArray customScript;
QVector<QByteArray> rtps;
/* Game INI contents */
struct {
QByteArray scripts;
QByteArray title;
} game;
Config();
void read();
void readGameINI();
};
#endif // CONFIG_H

123
src/debuglogger.cpp Normal file
View File

@ -0,0 +1,123 @@
/*
** debuglogger.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "debuglogger.h"
#include "GL/glew.h"
#include <QFile>
#include <QTime>
#include <QTextStream>
#include <QDebug>
struct DebugLoggerPrivate
{
QFile logFile;
QTextStream *stream;
DebugLoggerPrivate(const char *logFilename)
{
if (logFilename)
{
logFile.setFileName(logFilename);
logFile.open(QFile::WriteOnly);
stream = new QTextStream(&logFile);
}
else
{
stream = new QTextStream(stderr, QIODevice::WriteOnly);
}
}
~DebugLoggerPrivate()
{
delete stream;
}
void writeTimestamp()
{
QTime time = QTime::currentTime();
*stream << "[" << time.toString().toAscii() << "] ";
}
void writeLine(const char *line)
{
*stream << line << "\n";
stream->flush();
}
};
static void amdDebugFunc(GLuint id,
GLenum category,
GLenum severity,
GLsizei length,
const GLchar* message,
GLvoid* userParam)
{
DebugLoggerPrivate *p = static_cast<DebugLoggerPrivate*>(userParam);
(void) id;
(void) category;
(void) severity;
(void) length;
p->writeTimestamp();
p->writeLine(message);
}
static void arbDebugFunc(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
GLvoid* userParam)
{
DebugLoggerPrivate *p = static_cast<DebugLoggerPrivate*>(userParam);
(void) source;
(void) type;
(void) id;
(void) severity;
(void) length;
p->writeTimestamp();
p->writeLine(message);
}
DebugLogger::DebugLogger(const char *filename)
{
p = new DebugLoggerPrivate(filename);
if (GLEW_KHR_debug)
glDebugMessageCallback(arbDebugFunc, p);
else if (GLEW_ARB_debug_output)
glDebugMessageCallbackARB(arbDebugFunc, p);
else if (GLEW_AMD_debug_output)
glDebugMessageCallbackAMD(amdDebugFunc, p);
else
qDebug() << "DebugLogger: no debug extensions found";
}
DebugLogger::~DebugLogger()
{
delete p;
}

37
src/debuglogger.h Normal file
View File

@ -0,0 +1,37 @@
/*
** debuglogger.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEBUGLOGGER_H
#define DEBUGLOGGER_H
struct DebugLoggerPrivate;
class DebugLogger
{
public:
DebugLogger(const char *filename = 0);
~DebugLogger();
private:
DebugLoggerPrivate *p;
};
#endif // DEBUGLOGGER_H

63
src/disposable.h Normal file
View File

@ -0,0 +1,63 @@
/*
** disposable.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DISPOSABLE_H
#define DISPOSABLE_H
#include "exception.h"
#include "sigc++/signal.h"
class Disposable
{
public:
Disposable()
: disposed(false)
{}
virtual ~Disposable() {}
void dispose()
{
if (disposed)
return;
releaseResources();
disposed = true;
wasDisposed();
}
bool isDisposed() const { return disposed; }
sigc::signal<void> wasDisposed;
protected:
virtual void releaseResources() = 0;
private:
bool disposed;
};
/* Every cpp needs to define DISP_CLASS_NAME for itself (lowercase) */
#define GUARD_DISPOSED \
{ if (isDisposed()) throw Exception(Exception::RGSSError, "disposed %S", DISP_CLASS_NAME); }
#endif // DISPOSABLE_H

251
src/etc-internal.h Normal file
View File

@ -0,0 +1,251 @@
/*
** etc-internal.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ETC_TYPES_H
#define ETC_TYPES_H
#include "util.h"
struct Vec2
{
float x, y;
Vec2()
: x(0), y(0)
{}
Vec2(float x, float y)
: x(x), y(y)
{}
bool operator==(const Vec2 &other) const
{
return (x == other.x && y == other.y);
}
};
struct Vec4
{
float x, y, z, w;
Vec4()
: x(0), y(0), z(0), w(0)
{}
Vec4(float x, float y, float z, float w)
: x(x), y(y), z(z), w(w)
{}
bool operator==(const Vec4 &other) const
{
return (x == other.x && y == other.y && z == other.z && w == other.w);
}
};
struct Vec2i
{
int x, y;
Vec2i()
: x(0), y(0)
{}
Vec2i(int x, int y)
: x(x), y(y)
{}
bool operator==(const Vec2i &other)
{
return x == other.x && y == other.y;
}
};
/* Simple Vertex */
struct SVertex
{
Vec2 pos;
Vec2 texPos;
static const void *posOffset()
{
return (const void*) 0;
}
static const void *texPosOffset()
{
return (const void*) sizeof(Vec2);
}
};
/* Color Vertex */
struct CVertex
{
Vec2 pos;
Vec4 color;
CVertex()
: color(1, 1, 1, 1)
{}
static const void *posOffset()
{
return (const void*) 0;
}
static const void *colorOffset()
{
return (const void*) sizeof(pos);
}
};
struct Vertex
{
Vec2 pos;
Vec2 texPos;
Vec4 color;
Vertex()
: color(1, 1, 1, 1)
{}
static const void *posOffset()
{
return (const void*) 0;
}
static const void *texPosOffset()
{
return (const void*) sizeof(Vec2);
}
static const void *colorOffset()
{
return (const void*) sizeof(SVertex);
}
};
struct IntRect
{
int x, y, w, h;
IntRect()
: x(0), y(0), w(0), h(0)
{}
IntRect(int x, int y, int w, int h)
: x(x), y(y), w(w), h(h)
{}
bool operator==(const IntRect &other) const
{
return (x == other.x && y == other.y &&
w == other.w && h == other.h);
}
};
struct StaticRect { float x, y, w, h; };
struct FloatRect
{
float x, y, w, h;
FloatRect()
: x(0), y(0), w(0), h(0)
{}
FloatRect(float x, float y, float w, float h)
: x(x), y(y), w(w), h(h)
{}
FloatRect(const StaticRect &d)
: x(d.x), y(d.y), w(d.w), h(d.h)
{}
FloatRect(const IntRect &r)
: x(r.x), y(r.y), w(r.w), h(r.h)
{}
Vec2 topLeft() const { return Vec2(x, y); }
Vec2 bottomLeft() const { return Vec2(x, y+h); }
Vec2 topRight() const { return Vec2(x+w, y); }
Vec2 bottomRight() const { return Vec2(x+w, y+h); }
void shrinkHalf()
{
x += 0.5;
y += 0.5;
w -= 1.0;
h -= 1.0;
}
FloatRect vFlipped() const
{
return FloatRect(x, y+h, w, -h);
}
FloatRect hFlipped() const
{
return FloatRect(x+w, y, -w, h);
}
Vec2 corner(int i) const
{
switch (i)
{
case 0 : return topLeft();
case 1 : return topRight();
case 2 : return bottomRight();
case 3 : return bottomLeft();
default : return Vec2();
}
}
};
/* Value between 0 and 255 with internal
* normalized representation */
struct NormValue
{
int unNorm;
float norm;
NormValue()
: unNorm(0),
norm(0)
{}
NormValue(int unNorm)
: unNorm(unNorm),
norm(unNorm / 255.0)
{}
void operator =(int value)
{
unNorm = bound(value, 0, 255);
norm = unNorm / 255.0;
}
operator int() const
{
return unNorm;
}
};
#endif // ETC_TYPES_H

316
src/etc.cpp Normal file
View File

@ -0,0 +1,316 @@
/*
** etc.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "etc.h"
#include "serial-util.h"
#include "exception.h"
#include "SDL2/SDL_types.h"
#include "SDL2/SDL_pixels.h"
Color::Color(double red, double green, double blue, double alpha)
: red(red), green(green), blue(blue), alpha(alpha)
{
updateInternal();
}
Color::Color(const Vec4 &norm)
: norm(norm)
{
updateExternal();
}
Color::Color(const Color &o)
: red(o.red), green(o.green), blue(o.blue), alpha(o.alpha),
norm(o.norm)
{}
bool Color::operator==(const Color &o) const
{
return red == o.red &&
green == o.green &&
blue == o.blue &&
alpha == o.alpha;
}
void Color::updateInternal()
{
norm.x = red / 255;
norm.y = green / 255;
norm.z = blue / 255;
norm.w = alpha / 255;
}
void Color::updateExternal()
{
red = norm.x * 255;
green = norm.y * 255;
blue = norm.z * 255;
alpha = norm.w * 255;
}
void Color::set(double red, double green, double blue, double alpha)
{
this->red = red;
this->green = green;
this->blue = blue;
this->alpha = alpha;
updateInternal();
}
void Color::setRed(double value)
{
red = value;
norm.x = bound<double>(value, 0, 255) / 255;
}
void Color::setGreen(double value)
{
green = value;
norm.y = bound<double>(value, 0, 255) / 255;
}
void Color::setBlue(double value)
{
blue = value;
norm.z = bound<double>(value, 0, 255) / 255;
}
void Color::setAlpha(double value)
{
alpha = value;
norm.w = bound<double>(value, 0, 255) / 255;
}
void Color::toSDLColor(SDL_Color &c) const
{
c.r = bound<double>(red, 0, 255);
c.g = bound<double>(green, 0, 255);
c.b = bound<double>(blue, 0, 255);
// c.a = bound<double>(alpha, 0, 255);
c.a = 255;
}
/* Serializable */
int Color::serialSize() const
{
return 4 * 8;
}
void Color::serialize(char *buffer) const
{
char *buf = buffer;
write_double(&buf, red);
write_double(&buf, green);
write_double(&buf, blue);
write_double(&buf, alpha);
}
Color *Color::deserialize(const char *data, int len)
{
if (len != 32)
throw Exception(Exception::ArgumentError, "Color: Serialized data invalid");
Color *c = new Color();
uint i = 0;
c->red = read_double(data, i);
c->green = read_double(data, i);
c->blue = read_double(data, i);
c->alpha = read_double(data, i);
c->updateInternal();
return c;
}
Tone::Tone(double red, double green, double blue, double gray)
: red(red), green(green), blue(blue), gray(gray)
{
updateInternal();
}
Tone::Tone(const Tone &o)
: red(o.red), green(o.green), blue(o.blue), gray(o.gray),
norm(o.norm)
{}
bool Tone::operator==(const Tone &o) const
{
return red == o.red &&
green == o.green &&
blue == o.blue &&
gray == o.gray;
}
void Tone::updateInternal()
{
norm.x = (float) bound<double>(red, -255, 255) / 255;
norm.y = (float) bound<double>(green, -255, 255) / 255;
norm.z = (float) bound<double>(blue, -255, 255) / 255;
norm.w = (float) bound<double>(gray, 0, 255) / 255;
}
void Tone::set(double red, double green, double blue, double gray)
{
this->red = red;
this->green = green;
this->blue = blue;
this->gray = gray;
updateInternal();
}
void Tone::setRed(double value)
{
red = value;
norm.x = (float) bound<double>(value, -255, 255) / 255;
}
void Tone::setGreen(double value)
{
green = value;
norm.y = (float) bound<double>(value, -255, 255) / 255;
}
void Tone::setBlue(double value)
{
blue = value;
norm.z = (float) bound<double>(value, -255, 255) / 255;
}
void Tone::setGray(double value)
{
gray = value;
norm.w = (float) bound<double>(value, 0, 255) / 255;
}
/* Serializable */
int Tone::serialSize() const
{
return 4 * 8;
}
void Tone::serialize(char *buffer) const
{
char *buf = buffer;
write_double(&buf, red);
write_double(&buf, green);
write_double(&buf, blue);
write_double(&buf, gray);
}
Tone *Tone::deserialize(const char *data, int len)
{
if (len != 32)
throw Exception(Exception::ArgumentError, "Tone: Serialized data invalid");
Tone *t = new Tone();
uint i = 0;
t->red = read_double(data, i);
t->green = read_double(data, i);
t->blue = read_double(data, i);
t->gray = read_double(data, i);
t->updateInternal();
return t;
}
Rect::Rect(int x, int y, int width, int height)
: x(x), y(y), width(width), height(height)
{}
Rect::Rect(const Rect &o)
: x(o.x), y(o.y),
width(o.width), height(o.height)
{}
Rect::Rect(const IntRect &r)
: x(r.x), y(r.y), width(r.w), height(r.h)
{}
bool Rect::operator==(const Rect &o) const
{
return x == o.x &&
y == o.y &&
width == o.width &&
height == o.height;
}
void Rect::operator=(const IntRect &rect)
{
x = rect.x;
y = rect.y;
width = rect.w;
height = rect.h;
}
void Rect::set(int x, int y, int w, int h)
{
this->x = x;
this->y = y;
width = w;
height = h;
valueChanged();
}
void Rect::empty()
{
x = y = width = height = 0;
valueChanged();
}
int Rect::serialSize() const
{
return 4 * 4;
}
void Rect::serialize(char *buffer) const
{
char *buf = buffer;
write_int32(&buf, x);
write_int32(&buf, y);
write_int32(&buf, width);
write_int32(&buf, height);
}
Rect *Rect::deserialize(const char *data, int len)
{
if (len != 16)
throw Exception(Exception::ArgumentError, "Rect: Serialized data invalid");
Rect *r = new Rect();
uint i = 0;
r->x = read_int32(data, i);
r->y = read_int32(data, i);
r->width = read_int32(data, i);
r->height = read_int32(data, i);
return r;
}

207
src/etc.h Normal file
View File

@ -0,0 +1,207 @@
/*
** etc.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ETC_H
#define ETC_H
#include "sigc++/signal.h"
#include "serializable.h"
#include "etc-internal.h"
struct SDL_Color;
enum BlendType
{
BlendNone = -1, /* Only internal use */
BlendNormal = 0,
BlendAddition = 1,
BlendSubstraction = 2
};
struct Color : public Serializable
{
Color()
: red(0), green(0), blue(0), alpha(0)
{}
Color(double red, double green, double blue, double alpha = 255);
Color(const Vec4 &norm);
Color(const Color &o);
bool operator==(const Color &o) const;
void updateInternal();
void updateExternal();
void set(double red, double green, double blue, double alpha);
void setRed(double value);
void setGreen(double value);
void setBlue(double value);
void setAlpha(double value);
double getRed() const { return red; }
double getGreen() const { return green; }
double getBlue() const { return blue; }
double getAlpha() const { return alpha; }
bool hasEffect()
{
return (alpha != 0);
}
void toSDLColor(SDL_Color &c) const;
/* Serializable */
int serialSize() const;
void serialize(char *buffer) const;
static Color *deserialize(const char *data, int len);
/* Range (0.0 ~ 255.0) */
double red;
double green;
double blue;
double alpha;
/* Normalized (0.0 ~ 1.0) */
Vec4 norm;
};
struct Tone : public Serializable
{
Tone()
: red(0), green(0), blue(0), gray(0)
{}
Tone(double red, double green, double blue, double gray = 0);
Tone(const Tone &o);
bool operator==(const Tone &o) const;
void updateInternal();
void set(double red, double green, double blue, double gray);
void setRed(double value);
void setGreen(double value);
void setBlue(double value);
void setGray(double value);
double getRed() const { return red; }
double getGreen() const { return green; }
double getBlue() const { return blue; }
double getGray() const { return gray; }
bool hasEffect()
{
return ((int)red != 0 ||
(int)green != 0 ||
(int)blue != 0 ||
(int)gray != 0);
}
/* Serializable */
int serialSize() const;
void serialize(char *buffer) const;
static Tone *deserialize(const char *data, int len);
/* Range (-255.0 ~ 255.0) */
double red;
double green;
double blue;
/* Range (0.0 ~ 255.0) */
double gray;
/* Normalized (-1.0 ~ 1.0) */
Vec4 norm;
};
struct Rect : public Serializable
{
Rect()
: x(0), y(0), width(0), height(0)
{}
Rect(int x, int y, int width, int height);
Rect(const Rect &o);
Rect(const IntRect &r);
bool operator==(const Rect &o) const;
void operator=(const IntRect &rect);
void set(int x, int y, int w, int h);
FloatRect toFloatRect() const
{
return FloatRect(x, y, width, height);
}
IntRect toIntRect()
{
return IntRect(x, y, width, height);
}
void empty();
bool isEmpty() const
{
return !(x || y || width || height);
}
DECL_ATTR_INLINE(X, int, x)
DECL_ATTR_INLINE(Y, int, y)
DECL_ATTR_INLINE(Width, int, width)
DECL_ATTR_INLINE(Height, int, height)
int serialSize() const;
void serialize(char *buffer) const;
static Rect *deserialize(const char *data, int len);
int x;
int y;
int width;
int height;
sigc::signal<void> valueChanged;
};
/* For internal use.
* All drawable classes have properties of one or more of the above
* types, which in an interpreted environment act as independent
* objects, and rely on the GC to clean them up. When a drawable
* class is constructed, these properties must have default objects
* that are constructed with the class. C++ however has no GC, so
* there is no way to clean them up when used directly with it.
* Therefore the default objects are first created embedded in the
* drawable class (so they get destroyed automatically from within
* C++ if no pointers were changed), and the binding then takes
* care of properly allocating new, independent objects and replacing
* the defaults. Thus both C++ and the interpreted API can be used
* without memory leakage.
* This can be removed at a later point when no testing directly
* from C++ is needed anymore. */
struct EtcTemps
{
Color color;
Tone tone;
Rect rect;
};
#endif // ETC_H

259
src/eventthread.cpp Normal file
View File

@ -0,0 +1,259 @@
/*
** eventthread.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "eventthread.h"
#include "SDL2/SDL_events.h"
#include "SDL2/SDL_joystick.h"
#include "SDL2/SDL_messagebox.h"
#include "SDL2/SDL_timer.h"
#include "SDL2/SDL_thread.h"
#include "globalstate.h"
#include "graphics.h"
#include "string.h"
#include <QDebug>
bool EventThread::keyStates[] = { false };
EventThread::JoyState EventThread::joyState =
{
0, 0, { false }
};
EventThread::MouseState EventThread::mouseState =
{
0, 0, { false }
};
const Uint32 REQUEST_TERMINATION = SDL_USEREVENT+0;
const Uint32 REQUEST_SETFULLSCREEN = SDL_USEREVENT+1;
const Uint32 REQUEST_WINRESIZE = SDL_USEREVENT+2;
const Uint32 SHOW_MESSAGEBOX = SDL_USEREVENT+3;
EventThread::EventThread()
: fullscreen(false)
{}
void EventThread::process(RGSSThreadData &rtData)
{
SDL_Event event;
SDL_Window *win = rtData.window;
WindowSizeNotify &windowSizeMsg = rtData.windowSizeMsg;
fullscreen = rtData.config.fullscreen;
bool terminate = false;
SDL_Joystick *js = 0;
if (SDL_NumJoysticks() > 0)
js = SDL_JoystickOpen(0);
while (true)
{
if (!SDL_WaitEvent(&event))
{
qDebug() << "EventThread: Event error";
break;
}
switch (event.type)
{
case SDL_WINDOWEVENT :
switch (event.window.event)
{
case SDL_WINDOWEVENT_RESIZED :
windowSizeMsg.notifyChange(event.window.data1,
event.window.data2);
break;
case SDL_WINDOWEVENT_CLOSE :
terminate = true;
break;
case SDL_WINDOWEVENT_FOCUS_LOST :
resetInput();
break;
}
break;
case SDL_QUIT :
case REQUEST_TERMINATION :
terminate = true;
qDebug() << "EventThread termination requested";
break;
case SDL_KEYDOWN :
if (event.key.keysym.scancode == SDL_SCANCODE_RETURN &&
(event.key.keysym.mod & KMOD_LALT))
{
setFullscreen(win, !fullscreen);
break;
}
keyStates[event.key.keysym.scancode] = true;
break;
case REQUEST_SETFULLSCREEN :
setFullscreen(win, static_cast<bool>(event.user.code));
break;
case REQUEST_WINRESIZE :
SDL_SetWindowSize(win, event.window.data1, event.window.data2);
break;
case SHOW_MESSAGEBOX :
SDL_ShowSimpleMessageBox(event.user.code,
rtData.config.game.title.constData(),
(const char*) event.user.data1, win);
free(event.user.data1);
msgBoxDone = true;
break;
case SDL_KEYUP :
keyStates[event.key.keysym.scancode] = false;
break;
case SDL_JOYBUTTONDOWN :
joyState.buttons[event.jbutton.button] = true;
break;
case SDL_JOYBUTTONUP :
joyState.buttons[event.jbutton.button] = false;
break;
case SDL_JOYAXISMOTION :
if (event.jaxis.axis == 0)
joyState.xAxis = event.jaxis.value;
else
joyState.yAxis = event.jaxis.value;
break;
case SDL_JOYDEVICEADDED :
if (event.jdevice.which > 0)
break;
js = SDL_JoystickOpen(0);
break;
case SDL_JOYDEVICEREMOVED :
resetInput();
break;
case SDL_MOUSEBUTTONDOWN :
mouseState.buttons[event.button.button] = true;
break;
case SDL_MOUSEBUTTONUP :
mouseState.buttons[event.button.button] = false;
break;
case SDL_MOUSEMOTION :
mouseState.x = event.motion.x;
mouseState.y = event.motion.y;
break;
}
if (terminate)
break;
}
if (SDL_JoystickGetAttached(js))
SDL_JoystickClose(js);
}
void EventThread::cleanup()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SHOW_MESSAGEBOX)
{
free(event.user.data1);
}
}
}
void EventThread::resetInput()
{
memset(&keyStates, 0, sizeof(keyStates));
memset(&joyState, 0, sizeof(joyState));
memset(&mouseState.buttons, 0, sizeof(mouseState.buttons));
}
void EventThread::setFullscreen(SDL_Window *win, bool mode)
{
SDL_SetWindowFullscreen
(win, mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
fullscreen = mode;
}
void EventThread::requestTerminate()
{
SDL_Event event;
event.type = REQUEST_TERMINATION;
SDL_PushEvent(&event);
}
void EventThread::requestFullscreenMode(bool mode)
{
if (mode == fullscreen)
return;
SDL_Event event;
event.type = REQUEST_SETFULLSCREEN;
event.user.code = static_cast<Sint32>(mode);
SDL_PushEvent(&event);
}
void EventThread::requestWindowResize(int width, int height)
{
SDL_Event event;
event.type = REQUEST_WINRESIZE;
event.window.data1 = width;
event.window.data2 = height;
SDL_PushEvent(&event);
}
void EventThread::showMessageBox(const char *body, int flags)
{
msgBoxDone = false;
SDL_Event event;
event.user.code = flags;
event.user.data1 = strdup(body);
event.type = SHOW_MESSAGEBOX;
SDL_PushEvent(&event);
/* Keep repainting screen while box is open */
gState->graphics().repaintWait(&msgBoxDone);
/* Prevent endless loops */
resetInput();
}
bool EventThread::getFullscreen()
{
return fullscreen;
}

169
src/eventthread.h Normal file
View File

@ -0,0 +1,169 @@
/*
** eventthread.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EVENTTHREAD_H
#define EVENTTHREAD_H
#include "config.h"
#include "etc-internal.h"
#include "SDL2/SDL_scancode.h"
#include "SDL2/SDL_joystick.h"
#include "SDL2/SDL_mouse.h"
#include "SDL2/SDL_mutex.h"
#include <QByteArray>
#include <QVector>
struct RGSSThreadData;
struct SDL_Thread;
struct SDL_Window;
class EventThread
{
public:
static bool keyStates[SDL_NUM_SCANCODES];
struct JoyState
{
int xAxis;
int yAxis;
bool buttons[16];
};
static JoyState joyState;
struct MouseState
{
int x, y;
bool buttons[SDL_BUTTON_X2+1];
};
static MouseState mouseState;
EventThread();
void process(RGSSThreadData &rtData);
void cleanup();
/* Called from render thread */
void requestFullscreenMode(bool mode);
void requestWindowResize(int width, int height);
void requestTerminate();
bool getFullscreen();
void showMessageBox(const char *body, int flags = 0);
private:
void resetInput();
void setFullscreen(SDL_Window *, bool mode);
bool fullscreen;
volatile bool msgBoxDone;
};
struct WindowSizeNotify
{
SDL_mutex *mutex;
volatile bool changedFlag;
volatile int w, h;
WindowSizeNotify()
{
mutex = SDL_CreateMutex();
changedFlag = false;
w = h = 0;
}
~WindowSizeNotify()
{
SDL_DestroyMutex(mutex);
}
/* Done from the sending side */
void notifyChange(int w, int h)
{
SDL_LockMutex(mutex);
this->w = w;
this->h = h;
changedFlag = true;
SDL_UnlockMutex(mutex);
}
/* Done from the receiving side */
bool pollChange(int *w, int *h)
{
if (!changedFlag)
return false;
SDL_LockMutex(mutex);
*w = this->w;
*h = this->h;
changedFlag = false;
SDL_UnlockMutex(mutex);
return true;
}
};
struct RGSSThreadData
{
/* Main thread sets this to request render thread to terminate */
volatile bool rqTerm;
/* In response, render thread sets this to confirm
* that it received the request and isn't stuck */
volatile bool rqTermAck;
EventThread *ethread;
WindowSizeNotify windowSizeMsg;
const char *argv0;
SDL_Window *window;
Vec2 sizeResoRatio;
Config config;
QByteArray rgssErrorMsg;
RGSSThreadData(EventThread *ethread,
const char *argv0,
SDL_Window *window)
: rqTerm(false),
rqTermAck(false),
ethread(ethread),
argv0(argv0),
window(window),
sizeResoRatio(1, 1)
{}
};
#endif // EVENTTHREAD_H

63
src/exception.h Normal file
View File

@ -0,0 +1,63 @@
/*
** exception.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <QByteArray>
#include <stdio.h>
struct Exception
{
enum Type
{
RGSSError,
NoFileError,
IOError,
/* Already defined by ruby */
TypeError,
ArgumentError,
/* New types introduced in mkxp */
PHYSFSError,
SDLError,
MKXPError
};
Type type;
QByteArray fmt;
QByteArray arg1;
QByteArray arg2;
Exception(Type type, QByteArray fmt,
QByteArray arg1 = QByteArray(),
QByteArray arg2 = QByteArray())
: type(type), fmt(fmt), arg1(arg1), arg2(arg2)
{}
void snprintf(char *buffer, size_t bufSize) const
{
::snprintf(buffer, bufSize, fmt.constData(), arg1.constData(), arg2.constData());
}
};
#endif // EXCEPTION_H

735
src/filesystem.cpp Normal file
View File

@ -0,0 +1,735 @@
/*
** filesystem.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "filesystem.h"
#include "util.h"
#include "exception.h"
#include "physfs.h"
#include <QHash>
#include <QByteArray>
#include "stdio.h"
#include "string.h"
#include <QDebug>
struct RGSS_entryData
{
qint64 offset;
quint64 size;
quint32 startMagic;
};
struct RGSS_entryHandle
{
RGSS_entryData data;
quint32 currentMagic;
quint64 currentOffset;
PHYSFS_Io *io;
RGSS_entryHandle(const RGSS_entryData &data)
: data(data),
currentMagic(data.startMagic),
currentOffset(0)
{}
RGSS_entryHandle(const RGSS_entryHandle &other)
: data(other.data),
currentMagic(other.currentMagic),
currentOffset(other.currentOffset)
{}
};
typedef QList<QByteArray> QByteList;
struct RGSS_archiveData
{
PHYSFS_Io *archiveIo;
QHash<QByteArray, RGSS_entryData> entryHash;
QHash<QByteArray, bool> dirHash;
};
static bool
readUint32(PHYSFS_Io *io, quint32 &result)
{
char buff[4];
PHYSFS_sint64 count = io->read(io, buff, 4);
result = ((buff[0] << 0x00) & 0x000000FF) |
((buff[1] << 0x08) & 0x0000FF00) |
((buff[2] << 0x10) & 0x00FF0000) |
((buff[3] << 0x18) & 0xFF000000) ;
return (count == 4);
}
#define RGSS_HEADER_1 0x53534752
#define RGSS_HEADER_2 0x1004441
#define RGSS_MAGIC 0xDEADCAFE
#define PHYSFS_ALLOC(type) \
static_cast<type*>(PHYSFS_getAllocator()->Malloc(sizeof(type)))
static inline quint32
advanceMagic(quint32 &magic)
{
quint32 old = magic;
magic = magic * 7 + 3;
return old;
}
struct MagicState
{
quint32 magic;
quint64 offset;
MagicState(quint64 offset = 0)
: offset(offset)
{
magic = RGSS_MAGIC;
for (uint i = 0; i < (offset/4); ++i)
advanceBlock();
}
quint8 advancePath()
{
quint8 ret = magic & 0xFF;
offset++;
advanceBlock();
return ret;
}
quint8 advanceData()
{
quint8 ret = magic & 0xFF;
if (offset++ % 4 == 0)
advanceBlock();
return ret;
}
private:
void advanceBlock()
{
magic = magic * 7 + 3;
}
};
static PHYSFS_sint64
RGSS_ioRead(PHYSFS_Io *self, void *buffer, PHYSFS_uint64 len)
{
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
quint64 toRead = qMin(entry->data.size - entry->currentOffset, len);
quint64 offs = entry->currentOffset;
entry->io->seek(entry->io, entry->data.offset + offs);
quint64 buffI = 0;
for (quint64 o = offs; o < offs + toRead;)
{
quint8 bitOffset = (0x8 * (o % 4));
quint8 magicByte = (entry->currentMagic >> bitOffset) & 0xFF;
quint8 byte;
entry->io->read(entry->io, &byte, 1);
((quint8*) buffer)[buffI++] = byte ^ magicByte;
if (++o % 4 == 0)
advanceMagic(entry->currentMagic);
}
entry->currentOffset += toRead;
return toRead;
}
static int
RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset)
{
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
if (offset == entry->currentOffset)
return 1;
if (offset > entry->data.size-1)
return 0;
/* If rewinding, we need to rewind to begining */
if (offset < entry->currentOffset)
{
entry->currentOffset = 0;
entry->currentMagic = entry->data.startMagic;
}
/* For each 4 bytes sought, advance magic */
quint64 dwordsSought = (offset - entry->currentOffset) / 4;
for (quint64 i = 0; i < dwordsSought; ++i)
advanceMagic(entry->currentMagic);
entry->currentOffset = offset;
entry->io->seek(entry->io, entry->data.offset + entry->currentOffset);
return 1;
}
static PHYSFS_sint64
RGSS_ioTell(PHYSFS_Io *self)
{
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
return entry->currentOffset;
}
static PHYSFS_sint64
RGSS_ioLength(PHYSFS_Io *self)
{
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
return entry->data.size;
}
static PHYSFS_Io*
RGSS_ioDuplicate(PHYSFS_Io *self)
{
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry);
PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io);
*dup = *self;
dup->opaque = entryDup;
return dup;
}
static void
RGSS_ioDestroy(PHYSFS_Io *self)
{
RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
delete entry;
PHYSFS_getAllocator()->Free(self);
}
static const PHYSFS_Io RGSS_IoTemplate =
{
0, /* version */
0, /* opaque */
RGSS_ioRead,
0, /* write */
RGSS_ioSeek,
RGSS_ioTell,
RGSS_ioLength,
RGSS_ioDuplicate,
0, /* flush */
RGSS_ioDestroy
};
static void*
RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
{
if (forWrite)
return 0;
/* Check header */
quint32 header1, header2;
readUint32(io, header1);
readUint32(io, header2);
if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2)
return 0;
RGSS_archiveData *data = new RGSS_archiveData;
data->archiveIo = io;
quint32 magic = RGSS_MAGIC;
while (true)
{
/* Read filename length,
* if nothing was read, no files remain */
quint32 nameLen;
if (!readUint32(io, nameLen))
break;
nameLen ^= advanceMagic(magic);
static char nameBuf[512];
uint i;
for (i = 0; i < nameLen; ++i)
{
char c;
io->read(io, &c, 1);
nameBuf[i] = c ^ (advanceMagic(magic) & 0xFF);
if (nameBuf[i] == '\\')
nameBuf[i] = '/';
}
nameBuf[i] = 0;
quint32 entrySize;
readUint32(io, entrySize);
entrySize ^= advanceMagic(magic);
RGSS_entryData entry;
entry.offset = io->tell(io);
entry.size = entrySize;
entry.startMagic = magic;
data->entryHash.insert(nameBuf, entry);
/* Test for new folder */
for (i = nameLen; i > 0; i--)
if (nameBuf[i] == '/')
{
nameBuf[i] = '\0';
if (!data->dirHash.contains(nameBuf))
data->dirHash.insert(nameBuf, true);
}
io->seek(io, entry.offset + entry.size);
}
return data;
}
static void
RGSS_enumerateFiles(void *opaque, const char *dirname,
PHYSFS_EnumFilesCallback cb,
const char *origdir, void *callbackdata)
{
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
QString dirn(dirname);
char dirBuf[512];
char baseBuf[512];
QByteList keys = data->entryHash.keys();
keys += data->dirHash.keys();
Q_FOREACH (const QByteArray &filename, keys)
{
/* Get the filename directory part */
strcpy(dirBuf, filename.constData());
strcpy(baseBuf, filename.constData());
/* Extract path and basename */
const char *dirpath = "";
char *basename = dirBuf;
for (int i = filename.size(); i >= 0; i--)
if (dirBuf[i] == '/')
{
dirBuf[i] = '\0';
dirpath = dirBuf;
basename = &dirBuf[i+1];
break;
}
/* Compare to provided dirname */
if (strcmp(dirpath, dirname) == 0)
cb(callbackdata, origdir, basename);
}
}
static PHYSFS_Io*
RGSS_openRead(void *opaque, const char *filename)
{
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
if (!data->entryHash.contains(filename))
return 0;
RGSS_entryHandle *entry = new RGSS_entryHandle(data->entryHash[filename]);
entry->io = data->archiveIo->duplicate(data->archiveIo);
PHYSFS_Io *io = PHYSFS_ALLOC(PHYSFS_Io);
*io = RGSS_IoTemplate;
io->opaque = entry;
return io;
}
static int
RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
{
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
bool hasFile = data->entryHash.contains(filename);
bool hasDir = data->dirHash.contains(filename);
if (!hasFile && !hasDir)
{
PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
return 0;
}
stat->modtime =
stat->createtime =
stat->accesstime = 0;
stat->readonly = 1;
if (hasFile)
{
RGSS_entryData &entry = data->entryHash[filename];
stat->filesize = entry.size;
stat->filetype = PHYSFS_FILETYPE_REGULAR;
}
else
{
stat->filesize = 0;
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
}
return 1;
}
static void
RGSS_closeArchive(void *opaque)
{
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
delete data;
}
static PHYSFS_Io*
RGSS_noop1(void*, const char*)
{
return 0;
}
static int
RGSS_noop2(void*, const char*)
{
return 0;
}
static const PHYSFS_Archiver RGSS_Archiver =
{
0,
{
"RGSSAD",
"RGSS encrypted archive format",
"Jonas Kulla <Nyocurio@gmail.com>",
"http://k-du.de/rgss/rgss.html",
0 /* symlinks not supported */
},
RGSS_openArchive,
RGSS_enumerateFiles,
RGSS_openRead,
RGSS_noop1, /* openWrite */
RGSS_noop1, /* openAppend */
RGSS_noop2, /* remove */
RGSS_noop2, /* mkdir */
RGSS_stat,
RGSS_closeArchive
};
FileStream::FileStream(PHYSFS_File *file)
{
p = file;
}
FileStream::~FileStream()
{
// if (p)
// PHYSFS_close(p);
}
void FileStream::operator=(const FileStream &o)
{
p = o.p;
}
sf::Int64 FileStream::read(void *data, sf::Int64 size)
{
if (!p)
return -1;
return PHYSFS_readBytes(p, data, size);
}
sf::Int64 FileStream::seek(sf::Int64 position)
{
if (!p)
return -1;
int success = PHYSFS_seek(p, (PHYSFS_uint64) position);
return success ? position : -1;
}
sf::Int64 FileStream::tell()
{
if (!p)
return -1;
return PHYSFS_tell(p);
}
sf::Int64 FileStream::getSize()
{
if (!p)
return -1;
return PHYSFS_fileLength(p);
}
sf::Int64 FileStream::write(const void *data, sf::Int64 size)
{
if (!p)
return -1;
return PHYSFS_writeBytes(p, data, size);
}
void FileStream::close()
{
if (p)
{
PHYSFS_close(p);
p = 0;
}
}
static void enumCB(void *, const char *origdir,
const char *fname)
{
qDebug() << origdir << fname;
char buf[128];
sprintf(buf, "%s/%s", origdir, fname);
PHYSFS_enumerateFilesCallback(buf, enumCB, 0);
}
FileSystem::FileSystem(const char *argv0)
{
PHYSFS_init(argv0);
PHYSFS_registerArchiver(&RGSS_Archiver);
}
FileSystem::~FileSystem()
{
if (PHYSFS_deinit() == 0)
qDebug() << "PhyFS failed to deinit.";
}
void FileSystem::addPath(const char *path)
{
PHYSFS_mount(path, 0, 1);
}
static const char *imgExt[] =
{
"jpg",
"png"
};
static const char *audExt[] =
{
// "mid",
// "midi",
"mp3",
"ogg",
"wav",
"wma" // FIXME this prolly isn't even supported lol
};
static const char *fonExt[] =
{
"ttf"
};
struct FileExtensions
{
const char **ext;
int count;
} fileExtensions[] =
{
{ imgExt, ARRAY_SIZE(imgExt) },
{ audExt, ARRAY_SIZE(audExt) },
{ fonExt, ARRAY_SIZE(fonExt) }
};
static const char *completeFileName(const char *filename,
FileSystem::FileType type)
{
static char buff[1024];
if (PHYSFS_exists(filename))
return filename;
if (type != FileSystem::Undefined)
{
FileExtensions *extTest = &fileExtensions[type];
for (int i = 0; i < extTest->count; ++i)
{
snprintf(buff, sizeof(buff), "%s.%s", filename, extTest->ext[i]);
if (PHYSFS_exists(buff))
return buff;
}
}
return 0;
}
static PHYSFS_File *openReadInt(const char *filename,
FileSystem::FileType type)
{
const char *foundName = completeFileName(filename, type);
if (!foundName)
throw Exception(Exception::NoFileError,
"No such file or directory - %s", filename);
PHYSFS_File *handle = PHYSFS_openRead(foundName);
if (!handle)
throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError());
PHYSFS_fileLength(handle);
return handle;
}
FileStream FileSystem::openRead(const char *filename,
FileType type)
{
PHYSFS_File *handle = openReadInt(filename, type);
return FileStream(handle);
}
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, Sint64 offset, int whence)
{
PHYSFS_File *f = sdlPHYS(ops);
if (!f)
return -1;
Sint64 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);
return (result != 0) ? 0 : -1;
}
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
void FileSystem::openRead(SDL_RWops &ops,
const char *filename,
FileType type)
{
PHYSFS_File *handle = openReadInt(filename, type);
ops.size = SDL_RWopsSize;
ops.seek = SDL_RWopsSeek;
ops.read = SDL_RWopsRead;
ops.write = SDL_RWopsWrite;
ops.close = SDL_RWopsClose;
ops.type = SDL_RWOPS_PHYSFS;
ops.hidden.unknown.data1 = handle;
}
bool FileSystem::exists(const char *filename, FileType type)
{
const char *foundName = completeFileName(filename, type);
return (foundName != 0);
}

82
src/filesystem.h Normal file
View File

@ -0,0 +1,82 @@
/*
** filesystem.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
#include "SFML/System/InputStream.hpp"
#include "SDL2/SDL_rwops.h"
struct PHYSFS_File;
class FileStream : public sf::InputStream
{
public:
FileStream(PHYSFS_File *);
~FileStream();
void operator=(const FileStream &o);
sf::Int64 read(void *data, sf::Int64 size);
sf::Int64 seek(sf::Int64 position);
sf::Int64 tell();
sf::Int64 getSize();
sf::Int64 write(const void *data, sf::Int64 size);
void close();
private:
PHYSFS_File *p; /* NULL denotes invalid stream */
};
class FileSystem
{
public:
FileSystem(const char *argv0);
~FileSystem();
void addPath(const char *path);
/* For extension supplementing */
enum FileType
{
Image = 0,
Audio,
Font,
Undefined
};
FileStream openRead(const char *filename,
FileType type = Undefined);
void openRead(SDL_RWops &ops,
const char *filename,
FileType type = Undefined);
bool exists(const char *filename,
FileType type = Undefined);
};
extern const Uint32 SDL_RWOPS_PHYSFS;
#endif // FILESYSTEM_H

92
src/flashable.h Normal file
View File

@ -0,0 +1,92 @@
/*
** flashable.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FLASHABLE_H
#define FLASHABLE_H
#include "etc.h"
#include "etc-internal.h"
#include <QDebug>
class Flashable
{
public:
Flashable()
: flashColor(0, 0, 0, 0),
flashing(false),
emptyFlashFlag(false)
{}
virtual ~Flashable() {}
void flash(const Vec4 *color, int duration)
{
if (duration < 1)
return;
flashing = true;
this->duration = duration;
counter = 0;
if (!color)
{
emptyFlashFlag = true;
return;
}
flashColor = *color;
flashAlpha = flashColor.w;
}
void update()
{
if (!flashing)
return;
if (++counter > duration)
{
/* Flash finished. Cleanup */
flashColor = Vec4(0, 0, 0, 0);
flashing = false;
emptyFlashFlag = false;
return;
}
/* No need to update flash color on empty flash */
if (emptyFlashFlag)
return;
float prog = (float) counter / duration;
flashColor.w = flashAlpha * (1 - prog);
}
protected:
Vec4 flashColor;
bool flashing;
bool emptyFlashFlag;
private:
float flashAlpha;
int duration;
int counter;
};
#endif // FLASHABLE_H

240
src/font.cpp Normal file
View File

@ -0,0 +1,240 @@
/*
** font.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "font.h"
#include "globalstate.h"
#include "filesystem.h"
#include "exception.h"
#include "../assets/liberation.ttf.xxd"
#include "SDL2/SDL_ttf.h"
#include <QHash>
#include <QByteArray>
#include <QPair>
#include <QDebug>
#define BUNDLED_FONT liberation
#define BUNDLED_FONT_D(f) assets_## f ##_ttf
#define BUNDLED_FONT_L(f) assets_## f ##_ttf_len
// Go fuck yourself CPP
#define BNDL_F_D(f) BUNDLED_FONT_D(f)
#define BNDL_F_L(f) BUNDLED_FONT_L(f)
typedef QPair<QByteArray, int> FontKey;
struct FontPoolPrivate
{
QHash<FontKey, TTF_Font*> hash;
};
FontPool::FontPool()
{
p = new FontPoolPrivate;
}
FontPool::~FontPool()
{
QHash<FontKey, TTF_Font*>::const_iterator iter;
for (iter = p->hash.begin(); iter != p->hash.end(); ++iter)
TTF_CloseFont(iter.value());
delete p;
}
static SDL_RWops *openBundledFont()
{
return SDL_RWFromConstMem(BNDL_F_D(BUNDLED_FONT), BNDL_F_L(BUNDLED_FONT));
}
_TTF_Font *FontPool::request(const char *filename,
int size)
{
// FIXME Find out how font path resolution is done in VX/Ace
QByteArray nameKey = QByteArray(filename).toLower();
nameKey.replace(' ', '_');
bool useBundled = false;
QByteArray path = QByteArray("Fonts/") + nameKey;
if (!gState->fileSystem().exists(path.constData(), FileSystem::Font))
{
useBundled = true;
nameKey = " bundled";
}
FontKey key(nameKey, size);
TTF_Font *font = p->hash.value(key, 0);
if (font)
{
// static int i=0;qDebug() << "FontPool: <?+>" << i++;
return font;
}
// qDebug() << "FontPool: <?->";
/* Not in hash, create */
SDL_RWops *ops;
if (useBundled)
{
ops = openBundledFont();
}
else
{
ops = SDL_AllocRW();
gState->fileSystem().openRead(*ops, path.constData(), FileSystem::Font);
}
// FIXME 0.9 is guesswork at this point
font = TTF_OpenFontRW(ops, 1, (float) size * .90);
if (!font)
throw Exception(Exception::SDLError, "SDL: %s", SDL_GetError());
p->hash.insert(key, font);
return font;
}
struct FontPrivate
{
QByteArray name;
int size;
bool bold;
bool italic;
Color *color;
Color colorTmp;
static QByteArray defaultName;
static int defaultSize;
static bool defaultBold;
static bool defaultItalic;
static Color *defaultColor;
static Color defaultColorTmp;
TTF_Font *sdlFont;
FontPrivate(const char *name = 0,
int size = 0)
: name(name ? QByteArray(name) : defaultName),
size(size ? size : defaultSize),
bold(defaultBold),
italic(defaultItalic),
color(&colorTmp),
colorTmp(*defaultColor)
{
sdlFont = gState->fontPool().request(this->name.constData(),
this->size);
}
};
QByteArray FontPrivate::defaultName = "Arial";
int FontPrivate::defaultSize = 22;
bool FontPrivate::defaultBold = false;
bool FontPrivate::defaultItalic = false;
Color *FontPrivate::defaultColor = &FontPrivate::defaultColorTmp;
Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
bool Font::doesExist(const char *name)
{
QByteArray path = QByteArray("fonts/") + QByteArray(name);
return gState->fileSystem().exists(path.constData(), FileSystem::Font);
}
Font::Font(const char *name,
int size)
{
p = new FontPrivate(name, size);
}
Font::~Font()
{
delete p;
}
const char *Font::getName() const
{
return p->name.constData();
}
void Font::setName(const char *value)
{
p->name = value;
}
void Font::setSize(int value)
{
if (p->size == value)
return;
p->size = value;
p->sdlFont = gState->fontPool().request(p->name.constData(), value);
}
#undef CHK_DISP
#define CHK_DISP
DEF_ATTR_RD_SIMPLE(Font, Size, int, p->size)
DEF_ATTR_SIMPLE(Font, Bold, bool, p->bold)
DEF_ATTR_SIMPLE(Font, Italic, bool, p->italic)
DEF_ATTR_SIMPLE(Font, Color, Color*, p->color)
DEF_ATTR_SIMPLE_STATIC(Font, DefaultSize, int, FontPrivate::defaultSize)
DEF_ATTR_SIMPLE_STATIC(Font, DefaultBold, bool, FontPrivate::defaultBold)
DEF_ATTR_SIMPLE_STATIC(Font, DefaultItalic, bool, FontPrivate::defaultItalic)
DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color*, FontPrivate::defaultColor)
const char *Font::getDefaultName()
{
return FontPrivate::defaultName.constData();
}
void Font::setDefaultName(const char *value)
{
FontPrivate::defaultName = value;
}
_TTF_Font *Font::getSdlFont()
{
int style = TTF_STYLE_NORMAL;
if (p->bold)
style |= TTF_STYLE_BOLD;
if (p->italic)
style |= TTF_STYLE_ITALIC;
TTF_SetFontStyle(p->sdlFont, style);
return p->sdlFont;
}

76
src/font.h Normal file
View File

@ -0,0 +1,76 @@
/*
** font.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FONT_H
#define FONT_H
#include "etc.h"
#include "util.h"
struct _TTF_Font;
struct FontPoolPrivate;
class FontPool
{
public:
FontPool();
~FontPool();
_TTF_Font *request(const char *filename,
int size);
private:
FontPoolPrivate *p;
};
struct FontPrivate;
class Font
{
public:
static bool doesExist(const char *name);
Font(const char *name = 0,
int size = 0);
~Font();
const char *getName() const;
void setName(const char *value);
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Color, Color* )
DECL_ATTR_STATIC( DefaultName, const char* )
DECL_ATTR_STATIC( DefaultSize, int )
DECL_ATTR_STATIC( DefaultBold, bool )
DECL_ATTR_STATIC( DefaultItalic, bool )
DECL_ATTR_STATIC( DefaultColor, Color* )
/* internal */
_TTF_Font *getSdlFont();
private:
FontPrivate *p;
};
#endif // FONT_H

388
src/gl-util.h Normal file
View File

@ -0,0 +1,388 @@
/*
** gl-util.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLUTIL_H
#define GLUTIL_H
#include "GL/glew.h"
#include "etc-internal.h"
#include <QDebug>
/* Struct wrapping GLuint for some light type safety */
#define DEF_GL_ID \
struct ID \
{ \
GLuint gl; \
explicit ID(GLuint gl = 0) \
: gl(gl) \
{} \
ID &operator=(const ID &o) \
{ \
gl = o.gl; \
return *this; \
} \
bool operator==(const ID &o) const \
{ \
return gl == o.gl; \
} \
};
namespace Tex
{
DEF_GL_ID
inline ID gen()
{
ID id;
glGenTextures(1, &id.gl);
return id;
}
inline void del(ID id)
{
glDeleteTextures(1, &id.gl);
}
inline void bind(ID id)
{
glBindTexture(GL_TEXTURE_2D, id.gl);
}
inline void unbind()
{
bind(ID(0));
}
inline void bindMatrix(int width, int height, int xOffset = 0)
{
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glScalef(1.f / width, 1.f / height, 1.f);
glTranslatef(xOffset, 0, 0);
glMatrixMode(GL_MODELVIEW);
}
inline void bindWithMatrix(ID id, int width, int height, int xOffset = 0)
{
bind(id);
bindMatrix(width, height, xOffset);
}
inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, format, GL_UNSIGNED_BYTE, data);
}
inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format)
{
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, format, GL_UNSIGNED_BYTE, data);
}
inline void allocEmpty(GLsizei width, GLsizei height)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
inline void setRepeat(bool mode)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
}
inline void setSmooth(bool mode)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST);
}
}
namespace RB
{
DEF_GL_ID
inline ID gen()
{
ID id;
glGenRenderbuffers(1, &id.gl);
return id;
}
inline void del(ID id)
{
glDeleteRenderbuffers(1, &id.gl);
}
inline void bind(ID id)
{
glBindRenderbuffer(GL_RENDERBUFFER, id.gl);
}
inline void unbind()
{
bind(ID(0));
}
inline void allocEmpty(GLsizei width, GLsizei height)
{
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
}
}
namespace FBO
{
DEF_GL_ID
enum Mode
{
Draw = 0,
Read = 1,
Default = 2
};
inline ID gen()
{
ID id;
glGenFramebuffers(1, &id.gl);
return id;
}
inline void del(ID id)
{
glDeleteFramebuffers(1, &id.gl);
}
inline void bind(ID id, Mode mode = Default)
{
static const GLenum modes[] =
{
GL_DRAW_FRAMEBUFFER,
GL_READ_FRAMEBUFFER,
GL_FRAMEBUFFER
};
glBindFramebuffer(modes[mode], id.gl);
}
inline void unbind(Mode mode = Default)
{
bind(ID(0), mode);
}
inline void setTexTarget(Tex::ID texTarget, unsigned colorAttach = 0)
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, texTarget.gl, 0);
}
inline void setRBTarget(RB::ID rbTarget, unsigned colorAttach = 0)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_RENDERBUFFER, rbTarget.gl);
}
inline void blit(int srcX, int srcY,
int srcW, int srcH,
int dstX, int dstY,
int dstW, int dstH)
{
glBlitFramebuffer(srcX, srcY, srcX+srcW, srcY+srcH,
dstX, dstY, dstX+dstW, dstY+dstH,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
inline void blit(int srcX, int srcY,
int dstX, int dstY,
int srcW, int srcH)
{
blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH);
}
inline Vec4 getPixel(int x, int y, int texWidth, int texHeight)
{
Vec4 pixel;
glViewport(0, 0, texWidth, texHeight);
glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &pixel.x);
return pixel;
}
}
namespace VAO
{
DEF_GL_ID
inline ID gen()
{
ID id;
glGenVertexArrays(1, &id.gl);
return id;
}
inline void del(ID id)
{
glDeleteVertexArrays(1, &id.gl);
}
inline void bind(ID id)
{
glBindVertexArray(id.gl);
}
inline void unbind()
{
bind(ID(0));
}
}
template<GLenum target>
struct GenericBO
{
DEF_GL_ID
inline static ID gen()
{
ID id;
glGenBuffers(1, &id.gl);
return id;
}
inline static void del(ID id)
{
glDeleteBuffers(1, &id.gl);
}
inline static void bind(ID id)
{
glBindBuffer(target, id.gl);
}
inline static void unbind()
{
bind(ID(0));
}
inline static void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW)
{
glBufferData(target, size, data, usage);
}
inline static void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data)
{
glBufferSubData(target, offset, size, data);
}
inline static void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW)
{
uploadData(size, 0, usage);
}
};
typedef struct GenericBO<GL_ARRAY_BUFFER> VBO;
typedef struct GenericBO<GL_ELEMENT_ARRAY_BUFFER> IBO;
struct TexFBO
{
Tex::ID tex;
FBO::ID fbo;
int width, height;
TexFBO()
: tex(0), fbo(0), width(0), height(0)
{}
bool operator==(const TexFBO &other) const
{
return (tex == other.tex) && (fbo == other.fbo);
}
static inline void init(TexFBO &obj)
{
obj.tex = Tex::gen();
obj.fbo = FBO::gen();
Tex::bind(obj.tex);
Tex::setRepeat(false);
Tex::setSmooth(false);
}
static inline void allocEmpty(TexFBO &obj, int width, int height)
{
Tex::bind(obj.tex);
Tex::allocEmpty(width, height);
obj.width = width;
obj.height = height;
}
static inline void linkFBO(TexFBO &obj)
{
FBO::bind(obj.fbo);
FBO::setTexTarget(obj.tex);
}
static inline void fini(TexFBO &obj)
{
FBO::del(obj.fbo);
Tex::del(obj.tex);
}
};
struct RBFBO
{
RB::ID rb;
FBO::ID fbo;
int width, height;
RBFBO()
: rb(0), fbo(0), width(0), height(0)
{}
static inline void init(RBFBO &obj)
{
obj.rb = RB::gen();
obj.fbo = FBO::gen();
}
static inline void allocEmpty(RBFBO &obj, int width, int height)
{
RB::bind(obj.rb);
RB::allocEmpty(width, height);
obj.width = width;
obj.height = height;
}
static inline void linkFBO(RBFBO &obj)
{
FBO::bind(obj.fbo);
FBO::setRBTarget(obj.rb);
}
static inline void fini(RBFBO &obj)
{
FBO::del(obj.fbo);
RB::del(obj.rb);
}
};
#endif // GLUTIL_H

66
src/global-ibo.h Normal file
View File

@ -0,0 +1,66 @@
/*
** global-ibo.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBALIBO_H
#define GLOBALIBO_H
#include <gl-util.h>
#include <QVector>
struct GlobalIBO
{
IBO::ID ibo;
QVector<quint32> buffer;
GlobalIBO()
{
ibo = IBO::gen();
}
~GlobalIBO()
{
IBO::del(ibo);
}
void ensureSize(int quadCount)
{
if (buffer.size() >= quadCount*6)
return;
int startInd = buffer.size() / 6;
buffer.reserve(quadCount*6);
for (int i = startInd; i < quadCount; ++i)
{
static const int indTemp[] = { 0, 1, 2, 2, 3, 0 };
for (int j = 0; j < 6; ++j)
buffer.append(i * 4 + indTemp[j]);
}
IBO::bind(ibo);
IBO::uploadData(buffer.count() * sizeof(int),
buffer.constData());
IBO::unbind();
}
};
#endif // GLOBALIBO_H

271
src/globalstate.cpp Normal file
View File

@ -0,0 +1,271 @@
/*
** globalstate.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "globalstate.h"
#include "util.h"
#include "filesystem.h"
#include "graphics.h"
#include "input.h"
#include "audio.h"
#include "glstate.h"
#include "shader.h"
#include "texpool.h"
#include "font.h"
#include "eventthread.h"
#include "gl-util.h"
#include "global-ibo.h"
#include "binding.h"
#include <QFile>
#include <unistd.h>
#include <QDebug>
GlobalState *GlobalState::instance = 0;
static GlobalIBO *globalIBO = 0;
#define GAME_ARCHIVE "Game.rgssad"
struct GlobalStatePrivate
{
void *bindingData;
SDL_Window *sdlWindow;
Scene *screen;
FileSystem fileSystem;
EventThread &eThread;
RGSSThreadData &rtData;
Config &config;
Graphics graphics;
Input input;
Audio audio;
GLState _glState;
SpriteShader spriteShader;
TransShader transShader;
SimpleTransShader sTransShader;
HueShader hueShader;
BltShader bltShader;
TexPool texPool;
FontPool fontPool;
Font *defaultFont;
Tex::ID globalTex;
int globalTexW, globalTexH;
TexFBO gpTexFBO;
unsigned int stampCounter;
GlobalStatePrivate(RGSSThreadData *threadData)
: bindingData(0),
sdlWindow(threadData->window),
fileSystem(threadData->argv0),
eThread(*threadData->ethread),
rtData(*threadData),
config(threadData->config),
graphics(threadData),
stampCounter(0)
{
if (!config.gameFolder.isEmpty())
{
int unused = chdir(config.gameFolder.constData());
(void) unused;
fileSystem.addPath(config.gameFolder.constData());
}
// FIXME find out correct archive filename
QByteArray archPath = threadData->config.gameFolder + "/" GAME_ARCHIVE;
if (QFile::exists(archPath.constData()))
fileSystem.addPath(archPath.constData());
for (int i = 0; i < config.rtps.count(); ++i)
fileSystem.addPath(config.rtps[i].constData());
globalTexW = 128;
globalTexH = 64;
globalTex = Tex::gen();
Tex::bind(globalTex);
Tex::setRepeat(false);
Tex::setSmooth(false);
Tex::allocEmpty(globalTexW, globalTexH);
TexFBO::init(gpTexFBO);
/* Reuse starting values */
TexFBO::allocEmpty(gpTexFBO, globalTexW, globalTexH);
TexFBO::linkFBO(gpTexFBO);
}
~GlobalStatePrivate()
{
Tex::del(globalTex);
TexFBO::fini(gpTexFBO);
}
};
void GlobalState::initInstance(RGSSThreadData *threadData)
{
globalIBO = new GlobalIBO();
globalIBO->ensureSize(1);
GlobalState *state = new GlobalState(threadData);
GlobalState::instance = state;
state->p->defaultFont = new Font();
}
void GlobalState::finiInstance()
{
delete GlobalState::instance->p->defaultFont;
delete GlobalState::instance;
delete globalIBO;
}
void GlobalState::setScreen(Scene &screen)
{
p->screen = &screen;
}
#define GSATT(type, lower) \
type GlobalState :: lower() \
{ \
return p->lower; \
}
GSATT(void*, bindingData)
GSATT(SDL_Window*, sdlWindow)
GSATT(Scene*, screen)
GSATT(FileSystem&, fileSystem)
GSATT(EventThread&, eThread)
GSATT(RGSSThreadData&, rtData)
GSATT(Config&, config)
GSATT(Graphics&, graphics)
GSATT(Input&, input)
GSATT(Audio&, audio)
GSATT(GLState&, _glState)
GSATT(SpriteShader&, spriteShader)
GSATT(TransShader&, transShader)
GSATT(SimpleTransShader&, sTransShader)
GSATT(HueShader&, hueShader)
GSATT(BltShader&, bltShader)
GSATT(TexPool&, texPool)
GSATT(FontPool&, fontPool)
void GlobalState::setBindingData(void *data)
{
p->bindingData = data;
}
void GlobalState::ensureQuadIBO(int minSize)
{
globalIBO->ensureSize(minSize);
}
void GlobalState::bindQuadIBO()
{
IBO::bind(globalIBO->ibo);
}
void GlobalState::bindTex()
{
Tex::bind(p->globalTex);
Tex::allocEmpty(p->globalTexW, p->globalTexH);
Tex::bindMatrix(p->globalTexW, p->globalTexH);
}
void GlobalState::ensureTexSize(int minW, int minH, Vec2 &currentSizeOut)
{
if (minW > p->globalTexW)
p->globalTexW = findNextPow2(minW);
if (minH > p->globalTexH)
p->globalTexH = findNextPow2(minH);
currentSizeOut = Vec2(p->globalTexW, p->globalTexH);
}
TexFBO &GlobalState::gpTexFBO(int minW, int minH)
{
bool needResize = false;
if (minW > p->gpTexFBO.width)
{
p->gpTexFBO.width = findNextPow2(minW);
needResize = true;
}
if (minH > p->gpTexFBO.height)
{
p->gpTexFBO.height = findNextPow2(minH);
needResize = true;
}
if (needResize)
{
Tex::bind(p->gpTexFBO.tex);
Tex::allocEmpty(p->gpTexFBO.width, p->gpTexFBO.height);
}
return p->gpTexFBO;
}
void GlobalState::checkShutdown()
{
if (!p->rtData.rqTerm)
return;
p->rtData.rqTermAck = true;
p->texPool.disable();
scriptBinding->terminate();
}
Font &GlobalState::defaultFont()
{
return *p->defaultFont;
}
unsigned int GlobalState::genTimeStamp()
{
return p->stampCounter++;
}
GlobalState::GlobalState(RGSSThreadData *threadData)
{
p = new GlobalStatePrivate(threadData);
p->screen = p->graphics.getScreen();
}
GlobalState::~GlobalState()
{
delete p;
}

120
src/globalstate.h Normal file
View File

@ -0,0 +1,120 @@
/*
** globalstate.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLOBALSTATE_H
#define GLOBALSTATE_H
#include "sigc++/signal.h"
#define gState GlobalState::instance
#define glState gState->_glState()
struct GlobalStatePrivate;
struct RGSSThreadData;
struct GlobalIBO;
struct mrb_state;
struct SDL_Window;
struct TexFBO;
class Scene;
class FileSystem;
class EventThread;
class Graphics;
class Input;
class Audio;
class GLState;
class SpriteShader;
class TransShader;
class SimpleTransShader;
class HueShader;
class BltShader;
class TexPool;
class FontPool;
class Font;
struct GlobalIBO;
struct Config;
struct Vec2;
struct GlobalState
{
void *bindingData();
void setBindingData(void *data);
SDL_Window *sdlWindow();
Scene *screen();
void setScreen(Scene &screen);
FileSystem &fileSystem();
EventThread &eThread();
RGSSThreadData &rtData();
Config &config();
Graphics &graphics();
Input &input();
Audio &audio();
GLState &_glState();
SpriteShader &spriteShader();
TransShader &transShader();
SimpleTransShader &sTransShader();
HueShader &hueShader();
BltShader &bltShader();
TexPool &texPool();
FontPool &fontPool();
Font &defaultFont();
sigc::signal<void> prepareDraw;
unsigned int genTimeStamp();
/* Returns global quad IBO, and ensures it has indices
* for at least minSize quads */
void ensureQuadIBO(int minSize);
void bindQuadIBO();
/* Global general purpose texture */
void bindTex();
void ensureTexSize(int minW, int minH, Vec2 &currentSizeOut);
TexFBO &gpTexFBO(int minW, int minH);
/* Checks EventThread's shutdown request flag and if set,
* requests the binding to terminate. In this case, this
* function will most likely not return */
void checkShutdown();
static GlobalState *instance;
static void initInstance(RGSSThreadData *threadData);
static void finiInstance();
private:
GlobalState(RGSSThreadData *threadData);
~GlobalState();
GlobalStatePrivate *p;
};
#endif // GLOBALSTATE_H

139
src/glstate.cpp Normal file
View File

@ -0,0 +1,139 @@
/*
** glstate.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "glstate.h"
#include "GL/glew.h"
#include "SDL2/SDL_rect.h"
#include "etc.h"
void GLClearColor::apply(const Vec4 &value)
{
glClearColor(value.x, value.y, value.z, value.w);
}
void GLScissorBox::apply(const IntRect &value)
{
glScissor(value.x, value.y, value.w, value.h);
}
void GLScissorBox::setIntersect(const IntRect &value)
{
IntRect &current = get();
SDL_Rect r1 = { current.x, current.y, current.w, current.h };
SDL_Rect r2 = { value.x, value.y, value.w, value.h };
SDL_Rect result;
if (!SDL_IntersectRect(&r1, &r2, &result))
result.w = result.h = 0;
set(IntRect(result.x, result.y, result.w, result.h));
}
void GLScissorTest::apply(const bool &value)
{
value ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST);
}
void GLTexture2D::apply(const bool &value)
{
value ? glEnable(GL_TEXTURE_2D) : glDisable(GL_TEXTURE_2D);
}
void GLBlendMode::apply(const BlendType &value)
{
switch (value)
{
case BlendNone :
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ZERO);
break;
case BlendNormal :
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
break;
case BlendAddition :
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE,
GL_ONE, GL_ONE);
break;
case BlendSubstraction :
// FIXME Alpha calculation is untested
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE,
GL_ONE, GL_ONE);
break;
}
}
void GLViewport::apply(const IntRect &value)
{
glViewport(value.x, value.y, value.w, value.h);
}
void GLState::setViewport(int width, int height)
{
viewport.set(IntRect(0, 0, width, height));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, 0, 1);
glMatrixMode(GL_MODELVIEW);
}
void GLState::pushSetViewport(int width, int height)
{
viewport.pushSet(IntRect(0, 0, width, height));
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, width, 0, height, 0, 1);
glMatrixMode(GL_MODELVIEW);
}
void GLState::popViewport()
{
viewport.pop();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
GLState::Caps::Caps()
{
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
}
GLState::GLState()
{
clearColor.init(Vec4(0, 0, 0, 1));
blendMode.init(BlendNormal);
scissorTest.init(false);
scissorBox.init(IntRect(0, 0, 640, 480));
texture2D.init(true);
}

145
src/glstate.h Normal file
View File

@ -0,0 +1,145 @@
/*
** glstate.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GLSTATE_H
#define GLSTATE_H
#include "etc.h"
#include <QStack>
template<typename T>
struct GLProperty
{
void init(const T &value)
{
current = value;
apply(value);
}
void push() { stack.push(current); }
void pop() { set(stack.pop()); }
T &get() { return current; }
void set(const T &value)
{
if (value == current)
return;
init(value);
}
void pushSet(const T &value)
{
push();
set(value);
}
private:
virtual void apply(const T &value) = 0;
T current;
QStack<T> stack;
};
// Not needed
template<typename T>
struct GLPropSaver
{
GLPropSaver(GLProperty<T> &p)
: p(p)
{
p.push();
}
~GLPropSaver()
{
p.pop();
}
private:
GLProperty<T> &p;
};
class GLClearColor : public GLProperty<Vec4>
{
void apply(const Vec4 &);
};
class GLScissorBox : public GLProperty<IntRect>
{
public:
/* Sets the intersection of the current box with value */
void setIntersect(const IntRect &value);
private:
void apply(const IntRect &value);
};
class GLScissorTest : public GLProperty<bool>
{
void apply(const bool &value);
};
class GLTexture2D : public GLProperty<bool>
{
void apply(const bool &value);
};
class GLBlendMode : public GLProperty<BlendType>
{
void apply(const BlendType &value);
};
class GLViewport : public GLProperty<IntRect>
{
void apply(const IntRect &value);
};
class GLState
{
public:
GLClearColor clearColor;
GLScissorBox scissorBox;
GLScissorTest scissorTest;
GLTexture2D texture2D;
GLBlendMode blendMode;
GLViewport viewport;
/* These functions pushSet/pop both the viewport
* and a glOrtho projection matrix.
* Useful for setting up rendering to FBOs of differing sizes */
void setViewport(int width, int height);
void pushSetViewport(int width, int height);
void popViewport();
struct Caps
{
int maxTexSize;
Caps();
} caps;
GLState();
};
#endif // GLSTATE_H

855
src/graphics.cpp Normal file
View File

@ -0,0 +1,855 @@
/*
** graphics.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "graphics.h"
#include "util.h"
#include "gl-util.h"
#include "globalstate.h"
#include "glstate.h"
#include "shader.h"
#include "scene.h"
#include "quad.h"
#include "eventthread.h"
#include "texpool.h"
#include "bitmap.h"
#include "etc-internal.h"
#include "binding.h"
#include "SDL2/SDL_video.h"
#include "SDL2/SDL_timer.h"
#include "stdint.h"
#include "SFML/System/Clock.hpp"
struct TimerQuery
{
GLuint query;
static bool queryActive;
bool thisQueryActive;
TimerQuery()
: thisQueryActive(false)
{
glGenQueries(1, &query);
}
void begin()
{
if (queryActive)
return;
if (thisQueryActive)
return;
glBeginQuery(GL_TIME_ELAPSED, query);
queryActive = true;
thisQueryActive = true;
}
void end()
{
if (!thisQueryActive)
return;
glEndQuery(GL_TIME_ELAPSED);
queryActive = false;
thisQueryActive = false;
}
bool getResult(GLuint64 *result)
{
if (thisQueryActive)
return false;
GLint isReady;
glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
if (isReady != GL_TRUE)
{
// qDebug() << "TimerQuery result not ready";
return false;
}
glGetQueryObjectui64v(query, GL_QUERY_RESULT, result);
if (glGetError() == GL_INVALID_OPERATION)
{
qDebug() << "Something went wrong with getting TimerQuery results";
return false;
}
return true;
}
GLuint64 getResultSync()
{
if (thisQueryActive)
return 0;
GLuint64 result;
GLint isReady = GL_FALSE;
while (isReady == GL_FALSE)
glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
glGetQueryObjectui64v(query, GL_QUERY_RESULT, &result);
return result;
}
~TimerQuery()
{
if (thisQueryActive)
end();
glDeleteQueries(1, &query);
}
};
bool TimerQuery::queryActive = false;
struct GPUTimer
{
TimerQuery queries[2];
const int iter;
uchar ind;
quint64 acc;
qint32 counter;
bool first;
GPUTimer(int iter)
: iter(iter),
ind(0),
acc(0),
counter(0),
first(true)
{}
void startTiming()
{
queries[ind].begin();
}
void endTiming()
{
queries[ind].end();
if (first)
{
first = false;
return;
}
swapInd();
GLuint64 result;
if (!queries[ind].getResult(&result))
return;
acc += result;
if (++counter < iter)
return;
qDebug() << " Avg. GPU time:" << ((double) acc / (iter * 1000 * 1000)) << "ms";
acc = counter = 0;
}
void swapInd()
{
ind = ind ? 0 : 1;
}
};
struct CPUTimer
{
const int iter;
quint64 acc;
qint32 counter;
sf::Clock clock;
CPUTimer(int iter)
: iter(iter),
acc(0),
counter(0)
{
}
void startTiming()
{
clock.restart();
}
void endTiming()
{
acc += clock.getElapsedTime().asMicroseconds();
if (++counter < iter)
return;
qDebug() << "Avg. CPU time:" << ((double) acc / (iter * 1000)) << "ms";
acc = counter = 0;
}
};
struct PingPong
{
TexFBO rt[2];
unsigned srcInd, dstInd;
int screenW, screenH;
PingPong(int screenW, int screenH)
: srcInd(0), dstInd(1),
screenW(screenW), screenH(screenH)
{
for (int i = 0; i < 2; ++i)
{
TexFBO::init(rt[i]);
TexFBO::allocEmpty(rt[i], screenW, screenH);
TexFBO::linkFBO(rt[i]);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
}
~PingPong()
{
for (int i = 0; i < 2; ++i)
TexFBO::fini(rt[i]);
}
/* Binds FBO of last good buffer for reading */
void bindLastBuffer()
{
FBO::bind(rt[dstInd].fbo, FBO::Read);
}
/* Better not call this during render cycles */
void resize(int width, int height)
{
screenW = width;
screenH = height;
for (int i = 0; i < 2; ++i)
{
Tex::bind(rt[i].tex);
Tex::allocEmpty(width, height);
}
}
void startRender()
{
bind();
}
void swapRender()
{
swapIndices();
/* Discard dest buffer */
Tex::bind(rt[dstInd].tex);
Tex::allocEmpty(screenW, screenH);
bind();
}
void blitFBOs()
{
FBO::blit(0, 0, 0, 0, screenW, screenH);
}
void finishRender()
{
FBO::unbind(FBO::Draw);
FBO::bind(rt[dstInd].fbo, FBO::Read);
}
private:
void bind()
{
Tex::bindWithMatrix(rt[srcInd].tex, screenW, screenH, true);
FBO::bind(rt[srcInd].fbo, FBO::Read);
FBO::bind(rt[dstInd].fbo, FBO::Draw);
}
void swapIndices()
{
unsigned tmp = srcInd;
srcInd = dstInd;
dstInd = tmp;
}
};
class ScreenScene : public Scene
{
public:
ScreenScene(int width, int height)
: pp(width, height),
brightEffect(false),
actW(width), actH(height)
{
updateReso(width, height);
brightnessQuad.setColor(Vec4());
}
void composite()
{
const int w = geometry.rect.w;
const int h = geometry.rect.h;
gState->prepareDraw();
pp.startRender();
glState.setViewport(w, h);
glClear(GL_COLOR_BUFFER_BIT);
Scene::composite();
if (brightEffect)
{
glState.texture2D.pushSet(false);
brightnessQuad.draw();
glState.texture2D.pop();
}
pp.finishRender();
}
void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t)
{
pp.swapRender();
pp.blitFBOs();
SpriteShader &shader = gState->spriteShader();
shader.bind();
shader.resetUniforms();
shader.setColor(c);
shader.setFlash(f);
shader.setTone(t);
glState.blendMode.pushSet(BlendNone);
Tex::bindMatrix(geometry.rect.w, geometry.rect.h);
screenQuad.draw();
glState.blendMode.pop();
shader.unbind();
}
void setBrightness(float norm)
{
brightnessQuad.setColor(Vec4(0, 0, 0, 1.0 - norm));
brightEffect = norm < 1.0;
}
void updateReso(int width, int height)
{
geometry.rect.w = width;
geometry.rect.h = height;
screenQuad.setTexPosRect(geometry.rect, geometry.rect);
brightnessQuad.setTexPosRect(geometry.rect, geometry.rect);
notifyGeometryChange();
}
void setResolution(int width, int height)
{
pp.resize(width, height);
updateReso(width, height);
}
void setScreenSize(int width, int height)
{
actW = width;
actH = height;
}
PingPong &getPP()
{
return pp;
}
private:
PingPong pp;
Quad screenQuad;
Quad brightnessQuad;
bool brightEffect;
int actW, actH;
};
struct FPSLimiter
{
unsigned lastTickCount;
unsigned mspf; /* ms per frame */
FPSLimiter(unsigned desiredFPS)
: lastTickCount(SDL_GetTicks())
{
setDesiredFPS(desiredFPS);
}
void setDesiredFPS(unsigned value)
{
mspf = 1000 / value;
}
void delay()
{
unsigned tmpTicks = SDL_GetTicks();
unsigned tickDelta = tmpTicks - lastTickCount;
lastTickCount = tmpTicks;
int toDelay = mspf - tickDelta;
if (toDelay < 0)
toDelay = 0;
SDL_Delay(toDelay);
lastTickCount = SDL_GetTicks();
}
};
struct Timer
{
uint64_t lastTicks;
uint64_t acc;
int counter;
Timer()
: lastTicks(SDL_GetPerformanceCounter()),
acc(0),
counter(0)
{}
};
struct GraphicsPrivate
{
/* Screen resolution */
Vec2i scRes;
/* Actual screen size */
Vec2i scSize;
ScreenScene screen;
RGSSThreadData *threadData;
int frameRate;
int frameCount;
int brightness;
FPSLimiter fpsLimiter;
GPUTimer gpuTimer;
CPUTimer cpuTimer;
bool frozen;
TexFBO frozenScene;
TexFBO currentScene;
Quad screenQuad;
RBFBO transBuffer;
GraphicsPrivate()
: scRes(640, 480),
scSize(scRes),
screen(scRes.x, scRes.y),
frameRate(40),
frameCount(0),
brightness(255),
fpsLimiter(frameRate),
gpuTimer(frameRate),
cpuTimer(frameRate),
frozen(false)
{
TexFBO::init(frozenScene);
TexFBO::allocEmpty(frozenScene, scRes.x, scRes.y);
TexFBO::linkFBO(frozenScene);
TexFBO::init(currentScene);
TexFBO::allocEmpty(currentScene, scRes.x, scRes.y);
TexFBO::linkFBO(currentScene);
FloatRect screenRect(0, 0, scRes.x, scRes.y);
screenQuad.setTexPosRect(screenRect, screenRect);
RBFBO::init(transBuffer);
RBFBO::allocEmpty(transBuffer, scRes.x, scRes.y);
RBFBO::linkFBO(transBuffer);
}
~GraphicsPrivate()
{
TexFBO::fini(frozenScene);
TexFBO::fini(currentScene);
RBFBO::fini(transBuffer);
}
void updateScreenResoRatio()
{
Vec2 &ratio = gState->rtData().sizeResoRatio;
ratio.x = (float) scRes.x / scSize.x;
ratio.y = (float) scRes.y / scSize.y;
}
void checkResize()
{
if (threadData->windowSizeMsg.pollChange(&scSize.x, &scSize.y))
{
screen.setScreenSize(scSize.x, scSize.y);
updateScreenResoRatio();
}
}
void shutdown()
{
threadData->rqTermAck = true;
gState->texPool().disable();
scriptBinding->terminate();
}
void swapGLBuffer()
{
SDL_GL_SwapWindow(threadData->window);
fpsLimiter.delay();
++frameCount;
}
void compositeToBuffer(FBO::ID fbo)
{
screen.composite();
FBO::bind(fbo, FBO::Draw);
FBO::blit(0, 0, 0, 0, scRes.x, scRes.y);
}
void blitBuffer()
{
FBO::blit(0, 0, 0, 0, scRes.x, scRes.y);
}
void blitBufferScaled()
{
FBO::blit(0, 0, scRes.x, scRes.y, 0, 0, scSize.x, scSize.y);
}
void blitBufferFlippedScaled()
{
FBO::blit(0, 0, scRes.x, scRes.y, 0, scSize.y, scSize.x, -scSize.y);
}
/* Blits currently bound read FBO to screen (upside-down) */
void blitToScreen()
{
FBO::unbind(FBO::Draw);
blitBufferFlippedScaled();
}
void redrawScreen()
{
screen.composite();
blitToScreen();
swapGLBuffer();
}
};
Graphics::Graphics(RGSSThreadData *data)
{
p = new GraphicsPrivate;
p->threadData = data;
}
Graphics::~Graphics()
{
delete p;
}
void Graphics::update()
{
gState->checkShutdown();
// p->cpuTimer.endTiming();
// p->gpuTimer.startTiming();
if (p->frozen)
return;
p->checkResize();
p->redrawScreen();
// p->gpuTimer.endTiming();
// p->cpuTimer.startTiming();
}
void Graphics::wait(int duration)
{
for (int i = 0; i < duration; ++i)
{
gState->checkShutdown();
p->checkResize();
p->redrawScreen();
}
}
void Graphics::fadeout(int duration)
{
if (p->frozen)
FBO::bind(p->frozenScene.fbo, FBO::Read);
for (int i = duration-1; i > -1; --i)
{
setBrightness((255.0 / duration) * i);
if (p->frozen)
{
p->blitToScreen();
p->swapGLBuffer();
}
else
{
update();
}
}
}
void Graphics::fadein(int duration)
{
if (p->frozen)
FBO::bind(p->frozenScene.fbo, FBO::Read);
for (int i = 0; i < duration; ++i)
{
setBrightness((255.0 / duration) * i);
if (p->frozen)
{
p->blitToScreen();
p->swapGLBuffer();
}
else
{
update();
}
}
}
void Graphics::freeze()
{
p->frozen = true;
gState->checkShutdown();
p->checkResize();
/* Capture scene into frozen buffer */
p->compositeToBuffer(p->frozenScene.fbo);
}
void Graphics::transition(int duration,
const char *filename,
int vague)
{
vague = bound(vague, 0, 512);
Bitmap *transMap = filename ? new Bitmap(filename) : 0;
setBrightness(255);
/* Capture new scene */
p->compositeToBuffer(p->currentScene.fbo);
if (transMap)
{
TransShader &shader = gState->transShader();
shader.bind();
shader.setFrozenScene(p->frozenScene.tex);
shader.setCurrentScene(p->currentScene.tex);
shader.setTransMap(transMap->getGLTypes().tex);
shader.setVague(vague / 512.0f);
}
else
{
SimpleTransShader &shader = gState->sTransShader();
shader.bind();
shader.setFrozenScene(p->frozenScene.tex);
shader.setCurrentScene(p->currentScene.tex);
}
Tex::bindMatrix(p->scRes.x, p->scRes.y);
glState.blendMode.pushSet(BlendNone);
for (int i = 0; i < duration; ++i)
{
if (p->threadData->rqTerm)
{
FragShader::unbind();
delete transMap;
p->shutdown();
}
const float prog = i * (1.0 / duration);
if (transMap)
gState->transShader().setProg(prog);
else
gState->sTransShader().setProg(prog);
FBO::bind(p->transBuffer.fbo);
glClear(GL_COLOR_BUFFER_BIT);
p->screenQuad.draw();
p->checkResize();
FBO::bind(p->transBuffer.fbo, FBO::Read);
p->blitToScreen();
p->swapGLBuffer();
}
glState.blendMode.pop();
FragShader::unbind();
delete transMap;
p->frozen = false;
}
Bitmap *Graphics::snapToBitmap()
{
Bitmap *bitmap = new Bitmap(width(), height());
p->compositeToBuffer(bitmap->getGLTypes().fbo);
return bitmap;
}
void Graphics::frameReset()
{
}
int Graphics::width() const
{
return p->scRes.x;
}
int Graphics::height() const
{
return p->scRes.y;
}
void Graphics::resizeScreen(int width, int height)
{
width = bound(width, 1, 640);
height = bound(height, 1, 480);
Vec2i size(width, height);
if (p->scRes == size)
return;
gState->eThread().requestWindowResize(width, height);
p->scRes = size;
p->screen.setResolution(width, height);
Tex::bind(p->frozenScene.tex);
Tex::allocEmpty(width, height);
Tex::bind(p->currentScene.tex);
Tex::allocEmpty(width, height);
FloatRect screenRect(0, 0, width, height);
p->screenQuad.setTexPosRect(screenRect, screenRect);
RB::bind(p->transBuffer.rb);
RB::allocEmpty(width, height);
p->updateScreenResoRatio();
}
#undef RET_IF_DISP
#define RET_IF_DISP(x)
#undef CHK_DISP
#define CHK_DISP
DEF_ATTR_RD_SIMPLE(Graphics, FrameRate, int, p->frameRate)
DEF_ATTR_RD_SIMPLE(Graphics, Brightness, int, p->brightness)
DEF_ATTR_SIMPLE(Graphics, FrameCount, int, p->frameCount)
void Graphics::setFrameRate(int value)
{
p->frameRate = bound(value, 10, 120);
p->fpsLimiter.setDesiredFPS(p->frameRate);
}
void Graphics::setBrightness(int value)
{
value = bound(value, 0, 255);
if (p->brightness == value)
return;
p->brightness = value;
p->screen.setBrightness(value / 255.0);
}
bool Graphics::getFullscreen() const
{
return p->threadData->ethread->getFullscreen();
}
void Graphics::setFullscreen(bool value)
{
p->threadData->ethread->requestFullscreenMode(value);
}
Scene *Graphics::getScreen() const
{
return &p->screen;
}
void Graphics::repaintWait(volatile bool *exitCond)
{
if (*exitCond)
return;
/* Repaint the screen with the last good frame we drew */
p->screen.getPP().bindLastBuffer();
FBO::unbind(FBO::Draw);
while (!*exitCond)
{
gState->checkShutdown();
p->blitBufferFlippedScaled();
SDL_GL_SwapWindow(p->threadData->window);
p->fpsLimiter.delay();
}
}

73
src/graphics.h Normal file
View File

@ -0,0 +1,73 @@
/*
** graphics.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include "util.h"
class Scene;
class Bitmap;
struct RGSSThreadData;
struct GraphicsPrivate;
class Graphics
{
public:
Graphics(RGSSThreadData *data);
~Graphics();
void update();
void freeze();
void transition(int duration = 8,
const char *filename = 0,
int vague = 40);
void wait(int duration);
void fadeout(int duration);
void fadein(int duration);
Bitmap *snapToBitmap();
void frameReset();
int width() const;
int height() const;
void resizeScreen(int width, int height);
DECL_ATTR( FrameRate, int )
DECL_ATTR( FrameCount, int )
DECL_ATTR( Brightness, int )
/* Non-standard extension */
DECL_ATTR( Fullscreen, bool )
/* <internal> */
Scene *getScreen() const;
/* Repaint screen with static image until exitCond
* turns true. Used in EThread::showMessageBox() */
void repaintWait(volatile bool *exitCond);
private:
GraphicsPrivate *p;
};
#endif // GRAPHICS_H

669
src/input.cpp Normal file
View File

@ -0,0 +1,669 @@
/*
** input.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "input.h"
#include "globalstate.h"
#include "eventthread.h"
#include "exception.h"
#include "util.h"
#include "SDL2/SDL_scancode.h"
#include "SDL2/SDL_mouse.h"
#include <QVector>
#include "string.h"
#include <QDebug>
const int Input::buttonCodeSize = 24;
struct ButtonState
{
bool pressed;
bool triggered;
bool repeated;
ButtonState()
: pressed(false),
triggered(false),
repeated(false)
{}
};
struct KbBindingData
{
SDL_Scancode source;
Input::ButtonCode target;
};
struct JsBindingData
{
unsigned int source;
Input::ButtonCode target;
};
struct Binding
{
Binding(Input::ButtonCode target = Input::None)
: target(target)
{}
virtual bool sourceActive() const = 0;
virtual bool sourceRepeatable() const = 0;
Input::ButtonCode target;
};
/* Keyboard binding */
struct KbBinding : public Binding
{
KbBinding() {}
KbBinding(const KbBindingData &data)
: Binding(data.target),
source(data.source)
{}
bool sourceActive() const
{
return EventThread::keyStates[source];
}
bool sourceRepeatable() const
{
// return (source >= sf::Keyboard::A && source <= sf::Keyboard::Num9) ||
// (source >= sf::Keyboard::Left && source <= sf::Keyboard::F15);
return (source >= SDL_SCANCODE_A && source <= SDL_SCANCODE_0) ||
(source >= SDL_SCANCODE_RIGHT && source <= SDL_SCANCODE_UP) ||
(source >= SDL_SCANCODE_F1 && source <= SDL_SCANCODE_F12);
}
SDL_Scancode source;
};
/* Joystick button binding */
struct JsButtonBinding : public Binding
{
JsButtonBinding() {}
JsButtonBinding(const JsBindingData &data)
: Binding(data.target),
source(data.source)
{}
bool sourceActive() const
{
return EventThread::joyState.buttons[source];
}
bool sourceRepeatable() const
{
return true;
}
unsigned int source;
};
/* Joystick axis binding */
struct JsAxisBinding : public Binding
{
JsAxisBinding() {}
JsAxisBinding(int *source,
int compareValue,
Input::ButtonCode target)
: Binding(target),
source(source),
compareValue(compareValue)
{}
bool sourceActive() const
{
return (*source == compareValue);
}
bool sourceRepeatable() const
{
return true;
}
int *source;
int compareValue;
};
/* Mouse button binding */
struct MsBinding : public Binding
{
MsBinding() {}
MsBinding(int buttonIndex,
Input::ButtonCode target)
: Binding(target),
index(buttonIndex)
{}
bool sourceActive() const
{
return EventThread::mouseState.buttons[index];
}
bool sourceRepeatable() const
{
return false;
}
int index;
};
/* Not rebindable */
//static const KbBindingData staticKbBindings[] =
//{
// { sf::Keyboard::Left, Input::Left },
// { sf::Keyboard::Right, Input::Right },
// { sf::Keyboard::Up, Input::Up },
// { sf::Keyboard::Down, Input::Down },
// { sf::Keyboard::LShift, Input::Shift },
// { sf::Keyboard::RShift, Input::Shift },
// { sf::Keyboard::LControl, Input::Ctrl },
// { sf::Keyboard::RControl, Input::Ctrl },
// { sf::Keyboard::LAlt, Input::Alt },
// { sf::Keyboard::RAlt, Input::Alt },
// { sf::Keyboard::F5, Input::F5 },
// { sf::Keyboard::F6, Input::F6 },
// { sf::Keyboard::F7, Input::F7 },
// { sf::Keyboard::F8, Input::F8 },
// { sf::Keyboard::F9, Input::F9 }
//};
static const KbBindingData staticKbBindings[] =
{
{ SDL_SCANCODE_LEFT, Input::Left },
{ SDL_SCANCODE_RIGHT, Input::Right },
{ SDL_SCANCODE_UP, Input::Up },
{ SDL_SCANCODE_DOWN, Input::Down },
{ SDL_SCANCODE_LSHIFT, Input::Shift },
{ SDL_SCANCODE_RSHIFT, Input::Shift },
{ SDL_SCANCODE_LCTRL, Input::Ctrl },
{ SDL_SCANCODE_RCTRL, Input::Ctrl },
{ SDL_SCANCODE_LALT, Input::Alt },
{ SDL_SCANCODE_RALT, Input::Alt },
{ SDL_SCANCODE_F5, Input::F5 },
{ SDL_SCANCODE_F6, Input::F6 },
{ SDL_SCANCODE_F7, Input::F7 },
{ SDL_SCANCODE_F8, Input::F8 },
{ SDL_SCANCODE_F9, Input::F9 }
};
static elementsN(staticKbBindings);
/* Rebindable */
//static const KbBindingData defaultKbBindings[] =
//{
// { sf::Keyboard::Space, Input::C },
// { sf::Keyboard::Return, Input::C },
// { sf::Keyboard::Escape, Input::B },
// { sf::Keyboard::Num0, Input::B },
// { sf::Keyboard::LShift, Input::A },
// { sf::Keyboard::RShift, Input::A },
// { sf::Keyboard::Z, Input::A },
// { sf::Keyboard::X, Input::B },
// { sf::Keyboard::C, Input::C },
// { sf::Keyboard::V, Input::None },
// { sf::Keyboard::B, Input::None },
// { sf::Keyboard::A, Input::X },
// { sf::Keyboard::S, Input::Y },
// { sf::Keyboard::D, Input::Z },
// { sf::Keyboard::Q, Input::L },
// { sf::Keyboard::W, Input::R }
//};
static const KbBindingData defaultKbBindings[] =
{
{ SDL_SCANCODE_SPACE, Input::C },
{ SDL_SCANCODE_RETURN, Input::C },
{ SDL_SCANCODE_ESCAPE, Input::B },
{ SDL_SCANCODE_KP_0, Input::B },
{ SDL_SCANCODE_LSHIFT, Input::A },
{ SDL_SCANCODE_RSHIFT, Input::A },
{ SDL_SCANCODE_Z, Input::A },
{ SDL_SCANCODE_X, Input::B },
{ SDL_SCANCODE_C, Input::C },
{ SDL_SCANCODE_V, Input::None },
{ SDL_SCANCODE_B, Input::None },
{ SDL_SCANCODE_S, Input::X },
{ SDL_SCANCODE_A, Input::Y },
{ SDL_SCANCODE_D, Input::Z },
{ SDL_SCANCODE_Q, Input::L },
{ SDL_SCANCODE_W, Input::R }
};
static elementsN(defaultKbBindings);
/* Rebindable */
static const JsBindingData defaultJsBindings[] =
{
{ 0, Input::A },
{ 1, Input::B },
{ 2, Input::C },
{ 3, Input::X },
{ 4, Input::Y },
{ 5, Input::Z },
{ 6, Input::L },
{ 7, Input::R },
{ 8, Input::None },
{ 9, Input::None }
};
static elementsN(defaultJsBindings);
static const int mapToIndex[] =
{
0, 0,
1, 0, 2, 0, 3, 0, 4, 0,
0,
5, 6, 7, 8, 9, 10, 11, 12,
0, 0,
13, 14, 15,
0,
16, 17, 18, 19, 20,
0, 0, 0, 0, 0, 0, 0, 0,
21, 22, 23
};
static elementsN(mapToIndex);
static const Input::ButtonCode dirs[] =
{ Input::Down, Input::Left, Input::Right, Input::Up };
static const int dirFlags[] =
{
1 << Input::Down,
1 << Input::Left,
1 << Input::Right,
1 << Input::Up
};
/* Dir4 is always zero on these combinations */
static const int deadDirFlags[] =
{
dirFlags[0] | dirFlags[3],
dirFlags[1] | dirFlags[2]
};
static const Input::ButtonCode otherDirs[4][3] =
{
{ Input::Left, Input::Right, Input::Up }, // Down
{ Input::Down, Input::Up, Input::Right }, // Left
{ Input::Down, Input::Up, Input::Left }, // Right
{ Input::Left, Input::Right, Input::Up } // Up
};
struct InputPrivate
{
QVector<KbBinding> kbBindings;
QVector<JsAxisBinding> jsABindings;
QVector<JsButtonBinding> jsBBindings;
QVector<MsBinding> msBindings;
/* Collective binding array */
QVector<Binding*> bindings;
ButtonState *states;
ButtonState *statesOld;
Input::ButtonCode repeating;
unsigned int repeatCount;
struct
{
int active;
Input::ButtonCode previous;
} dir4Data;
struct
{
int active;
} dir8Data;
InputPrivate()
{
initKbBindings();
initJsBindings();
initMsBindings();
states = new ButtonState[Input::buttonCodeSize];
statesOld = new ButtonState[Input::buttonCodeSize];
// Clear buffers
clearBuffer();
swapBuffers();
clearBuffer();
repeating = Input::None;
repeatCount = 0;
dir4Data.active = 0;
dir4Data.previous = Input::None;
dir8Data.active = 0;
}
~InputPrivate()
{
delete states;
delete statesOld;
}
inline ButtonState &getStateCheck(int code)
{
int index;
if (code < 0 || code > mapToIndexN-1)
index = 0;
else
index = mapToIndex[code];
return states[index];
}
inline ButtonState &getState(Input::ButtonCode code)
{
return states[mapToIndex[code]];
}
inline ButtonState &getOldState(Input::ButtonCode code)
{
return statesOld[mapToIndex[code]];
}
void swapBuffers()
{
ButtonState *tmp = states;
states = statesOld;
statesOld = tmp;
}
void clearBuffer()
{
static int size = sizeof(ButtonState) * Input::buttonCodeSize;
memset(states, 0, size);
}
void initKbBindings()
{
kbBindings.resize(staticKbBindingsN+defaultKbBindingsN);
int n = 0;
for (int i = 0; i < staticKbBindingsN; ++i)
kbBindings[n++] = KbBinding(staticKbBindings[i]);
for (int i = 0; i < defaultKbBindingsN; ++i)
kbBindings[n++] = KbBinding(defaultKbBindings[i]);
/* Add to binging array */
for (int i = 0; i < kbBindings.count(); ++i)
bindings.append(&kbBindings[i]);
}
void initJsBindings()
{
/* Create axis bindings */
jsABindings.resize(4);
int i = 0;
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, 0x7FFF, Input::Right);
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, -0x8000, Input::Left);
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, 0x7FFF, Input::Down);
jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, -0x8000, Input::Up);
/* Create button bindings */
jsBBindings.resize(defaultJsBindingsN);
for (int i = 0; i < defaultJsBindingsN; ++i)
jsBBindings[i] = JsButtonBinding(defaultJsBindings[i]);
/* Add to binging array */
for (int i = 0; i < jsABindings.count(); ++i)
bindings.append(&jsABindings[i]);
for (int i = 0; i < jsBBindings.count(); ++i)
bindings.append(&jsBBindings[i]);
}
void initMsBindings()
{
msBindings.resize(3);
int i = 0;
msBindings[i++] = MsBinding(SDL_BUTTON_LEFT, Input::MouseLeft);
msBindings[i++] = MsBinding(SDL_BUTTON_MIDDLE, Input::MouseMiddle);
msBindings[i++] = MsBinding(SDL_BUTTON_RIGHT, Input::MouseRight);
/* Add to binding array */
for (int i = 0; i < msBindings.count(); ++i)
bindings.append(&msBindings[i]);
}
void pollBindings(Input::ButtonCode &repeatCand)
{
Q_FOREACH (const Binding *b, bindings)
pollBindingPriv(*b, repeatCand);
updateDir4();
updateDir8();
}
void pollBindingPriv(const Binding &b,
Input::ButtonCode &repeatCand)
{
if (!b.sourceActive())
return;
if (b.target == Input::None)
return;
ButtonState &state = getState(b.target);
ButtonState &oldState = getOldState(b.target);
state.pressed = true;
/* Must have been released before to trigger */
if (!oldState.pressed)
state.triggered = true;
/* Unbound keys don't create/break repeat */
if (repeatCand != Input::None)
return;
if (repeating != b.target &&
!oldState.pressed)
{
if (b.sourceRepeatable())
repeatCand = b.target;
else
/* Unrepeatable keys still break current repeat */
repeating = Input::None;
}
}
void updateDir4()
{
int dirFlag = 0;
for (int i = 0; i < 4; ++i)
dirFlag |= (getState(dirs[i]).pressed ? dirFlags[i] : 0);
if (dirFlag == deadDirFlags[0] || dirFlag == deadDirFlags[1])
{
dir4Data.active = Input::None;
return;
}
if (dir4Data.previous != Input::None)
{
/* Check if prev still pressed */
if (getState(dir4Data.previous).pressed)
{
for (int i = 0; i < 3; ++i)
{
Input::ButtonCode other =
otherDirs[(dir4Data.previous/2)-1][i];
if (!getState(other).pressed)
continue;
dir4Data.active = other;
return;
}
}
}
for (int i = 0; i < 4; ++i)
{
if (!getState(dirs[i]).pressed)
continue;
dir4Data.active = dirs[i];
dir4Data.previous = dirs[i];
return;
}
dir4Data.active = Input::None;
dir4Data.previous = Input::None;
}
void updateDir8()
{
static const int combos[4][4] =
{
{ 2, 1, 3, 0 },
{ 1, 4, 0, 7 },
{ 3, 0, 6, 9 },
{ 0, 7, 9, 8 }
};
dir8Data.active = 0;
for (int i = 0; i < 4; ++i)
{
Input::ButtonCode one = dirs[i];
if (!getState(one).pressed)
continue;
for (int j = 0; j < 3; ++j)
{
Input::ButtonCode other = otherDirs[i][j];
if (!getState(other).pressed)
continue;
dir8Data.active = combos[(one/2)-1][(other/2)-1];
return;
}
dir8Data.active = one;
return;
}
}
};
Input::Input()
{
p = new InputPrivate;
}
void Input::update()
{
gState->checkShutdown();
p->swapBuffers();
p->clearBuffer();
ButtonCode repeatCand = None;
/* Poll all bindings */
p->pollBindings(repeatCand);
/* Check for new repeating key */
if (repeatCand != None && repeatCand != p->repeating)
{
p->repeating = repeatCand;
p->repeatCount = 0;
p->getState(repeatCand).repeated = true;
return;
}
/* Check if repeating key is still pressed */
if (p->getState(p->repeating).pressed)
{
p->repeatCount++;
/* Repeatsequence is [r...............(r...)+] */
if (p->repeatCount > 15 && ((p->repeatCount % 4) == 0))
p->getState(p->repeating).repeated = true;
return;
}
p->repeating = None;
}
bool Input::isPressed(int button)
{
return p->getStateCheck(button).pressed;
}
bool Input::isTriggered(int button)
{
return p->getStateCheck(button).triggered;
}
bool Input::isRepeated(int button)
{
return p->getStateCheck(button).repeated;
}
int Input::dir4Value()
{
return p->dir4Data.active;
}
int Input::dir8Value()
{
return p->dir8Data.active;
}
int Input::mouseX()
{
return EventThread::mouseState.x * gState->rtData().sizeResoRatio.x;
}
int Input::mouseY()
{
return EventThread::mouseState.y * gState->rtData().sizeResoRatio.y;
}
Input::~Input()
{
delete p;
}

70
src/input.h Normal file
View File

@ -0,0 +1,70 @@
/*
** input.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INPUT_H
#define INPUT_H
struct InputPrivate;
class Input
{
public:
enum ButtonCode
{
None = 0,
Down = 2, Left = 4, Right = 6, Up = 8,
A = 11, B = 12, C = 13,
X = 14, Y = 15, Z = 16,
L = 17, R = 18,
Shift = 21, Ctrl = 22, Alt = 23,
F5 = 25, F6 = 26, F7 = 27, F8 = 28, F9 = 29,
/* Non-standard extensions */
MouseLeft = 38, MouseMiddle = 39, MouseRight = 40
};
static const int buttonCodeSize;
Input();
~Input();
void update();
bool isPressed(int button);
bool isTriggered(int button);
bool isRepeated(int button);
int dir4Value();
int dir8Value();
/* Non-standard extensions */
int mouseX();
int mouseY();
private:
InputPrivate *p;
};
#endif // INPUT_H

138
src/intrulist.h Normal file
View File

@ -0,0 +1,138 @@
/*
** intrulist.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INTRULIST_H
#define INTRULIST_H
template <typename T>
struct IntruListLink
{
IntruListLink<T> *prev;
IntruListLink<T> *next;
T *data;
IntruListLink(T *data)
: prev(0),
next(0),
data(data)
{}
~IntruListLink()
{
if (prev && next)
{
next->prev = prev;
prev->next = next;
}
}
};
template <typename T>
class IntruList
{
IntruListLink<T> root;
int size;
public:
IntruList()
: root(0),
size(0)
{
root.prev = &root;
root.next = &root;
}
void prepend(IntruListLink<T> &node)
{
root.next->prev = &node;
node.prev = &root;
node.next = root.next;
root.next = &node;
size++;
}
void append(IntruListLink<T> &node)
{
root.prev->next = &node;
node.next = &root;
node.prev = root.prev;
root.prev = &node;
size++;
}
void insertBefore(IntruListLink<T> &node,
IntruListLink<T> &prev)
{
node.next = &prev;
node.prev = prev.prev;
prev.prev->next = &node;
prev.prev = &node;
size++;
}
void remove(IntruListLink<T> &node)
{
if (!node.next)
return;
node.prev->next = node.next;
node.next->prev = node.prev;
node.prev = 0;
node.next = 0;
size--;
}
T *tail() const
{
IntruListLink<T> *node = root.prev;
if (node == &root)
return 0;
return node->data;
}
IntruListLink<T> *begin()
{
return root.next;
}
IntruListLink<T> *end()
{
return &root;
}
bool isEmpty() const
{
return root.next == &root;
}
int getSize() const
{
return size;
}
};
#endif // INTRULIST_H

209
src/main.cpp Normal file
View File

@ -0,0 +1,209 @@
/*
** main.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GL/glew.h"
#include "SDL2/SDL.h"
#include "SDL2/SDL_image.h"
#include "SDL2/SDL_ttf.h"
#include "globalstate.h"
#include "eventthread.h"
#include "debuglogger.h"
#include "binding.h"
#include <QDebug>
static const char *reqExt[] =
{
"GL_ARB_fragment_program",
"GL_ARB_fragment_shader",
"GL_ARB_framebuffer_object",
"GL_ARB_imaging",
"GL_ARB_shader_objects",
"GL_ARB_shading_language_100",
"GL_ARB_texture_non_power_of_two",
"GL_ARB_vertex_array_object",
"GL_ARB_vertex_buffer_object",
"GL_EXT_bgra",
"GL_EXT_blend_func_separate",
"GL_EXT_blend_subtract",
"GL_EXT_framebuffer_blit",
0
};
int rgssThreadFun(void *userdata)
{
RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata);
SDL_Window *win = threadData->window;
SDL_GLContext ctx;
/* Setup GL context */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if (threadData->config.debugMode)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
ctx = SDL_GL_CreateContext(win);
if (!ctx)
{
threadData->rgssErrorMsg =
QByteArray("Error creating context: ") + SDL_GetError();
threadData->ethread->requestTerminate();
threadData->rqTermAck = true;
return 0;
}
if (glewInit() != GLEW_OK)
{
threadData->rgssErrorMsg = "Error initializing glew";
SDL_GL_DeleteContext(ctx);
threadData->ethread->requestTerminate();
threadData->rqTermAck = true;
return 0;
}
/* Check for required GL extensions */
const char **ext = reqExt;
for (int i = 0; ext[i]; ++i)
{
if (!glewIsSupported(ext[i]))
{
threadData->rgssErrorMsg =
QByteArray("Required GL extension \"") + ext[i] + "\" not present";
threadData->ethread->requestTerminate();
threadData->rqTermAck = true;
return 0;
}
}
SDL_GL_SetSwapInterval(threadData->config.vsync ? 1 : 0);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
DebugLogger dLogger;
GlobalState::initInstance(threadData);
/* Start script execution */
scriptBinding->execute();
threadData->ethread->requestTerminate();
GlobalState::finiInstance();
SDL_GL_DeleteContext(ctx);
return 0;
}
int main(int, char *argv[])
{
Config conf;
conf.read();
conf.readGameINI();
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
{
qDebug() << "Error initializing SDL:" << SDL_GetError();
return 0;
}
IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
TTF_Init();
SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0");
SDL_Window *win;
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
if (conf.winResizable)
winFlags |= SDL_WINDOW_RESIZABLE;
if (conf.fullscreen)
winFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
win = SDL_CreateWindow(conf.game.title.constData(),
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
conf.defScreenW, conf.defScreenH, winFlags);
if (!win)
{
qDebug() << "Error creating window";
return 0;
}
EventThread eventThread;
RGSSThreadData rtData(&eventThread, argv[0], win);
rtData.config = conf;
/* Start RGSS thread */
SDL_Thread *rgssThread =
SDL_CreateThread(rgssThreadFun, "rgss", &rtData);
/* Start event processing */
eventThread.process(rtData);
/* Request RGSS thread to stop */
rtData.rqTerm = true;
/* Wait for RGSS thread response */
for (int i = 0; i < 1000; ++i)
{
/* We can stop waiting when the request was ack'd */
if (rtData.rqTermAck)
{
qDebug() << "RGSS thread ack'd request after" << i*10 << "ms";
break;
}
/* Give RGSS thread some time to respond */
SDL_Delay(10);
}
/* If RGSS thread ack'd request, wait for it to shutdown,
* otherwise abandon hope and just end the process as is. */
if (rtData.rqTermAck)
SDL_WaitThread(rgssThread, 0);
else
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.constData(),
"The RGSS script seems to be stuck and mkxp will now force quit", win);
if (!rtData.rgssErrorMsg.isEmpty())
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.constData(),
rtData.rgssErrorMsg.constData(), win);
/* Clean up any remainin events */
eventThread.cleanup();
qDebug() << "Shutting down.";
SDL_DestroyWindow(win);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}

217
src/plane.cpp Normal file
View File

@ -0,0 +1,217 @@
/*
** plane.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "plane.h"
#include "globalstate.h"
#include "bitmap.h"
#include "etc.h"
#include "util.h"
#include "gl-util.h"
#include "quad.h"
#include "transform.h"
#include "etc-internal.h"
#include "shader.h"
#include "glstate.h"
struct PlanePrivate
{
Bitmap *bitmap;
NormValue opacity;
BlendType blendType;
Color *color;
Tone *tone;
int ox, oy;
float zoomX, zoomY;
Scene::Geometry sceneGeo;
bool quadSourceDirty;
Quad quad;
EtcTemps tmp;
PlanePrivate()
: bitmap(0),
opacity(255),
blendType(BlendNormal),
color(&tmp.color),
tone(&tmp.tone),
ox(0), oy(0),
zoomX(1), zoomY(1),
quadSourceDirty(false)
{}
void updateQuadSource()
{
FloatRect srcRect;
srcRect.x = (sceneGeo.yOrigin + ox) / zoomX;
srcRect.y = (sceneGeo.xOrigin + oy) / zoomY;
srcRect.w = sceneGeo.rect.w / zoomX;
srcRect.h = sceneGeo.rect.h / zoomY;
quad.setTexRect(srcRect);
}
};
Plane::Plane(Viewport *viewport)
: ViewportElement(viewport)
{
p = new PlanePrivate();
onGeometryChange(scene->getGeometry());
}
#define DISP_CLASS_NAME "plane"
DEF_ATTR_RD_SIMPLE(Plane, OX, int, p->ox)
DEF_ATTR_RD_SIMPLE(Plane, OY, int, p->oy)
DEF_ATTR_RD_SIMPLE(Plane, ZoomX, float, p->zoomX)
DEF_ATTR_RD_SIMPLE(Plane, ZoomY, float, p->zoomY)
DEF_ATTR_RD_SIMPLE(Plane, BlendType, int, p->blendType)
DEF_ATTR_SIMPLE(Plane, Opacity, int, p->opacity)
DEF_ATTR_SIMPLE(Plane, Bitmap, Bitmap*, p->bitmap)
DEF_ATTR_SIMPLE(Plane, Color, Color*, p->color)
DEF_ATTR_SIMPLE(Plane, Tone, Tone*, p->tone)
Plane::~Plane()
{
dispose();
}
void Plane::setOX(int value)
{
GUARD_DISPOSED
p->ox = value;
p->quadSourceDirty = true;
}
void Plane::setOY(int value)
{
GUARD_DISPOSED
p->oy = value;
p->quadSourceDirty = true;
}
void Plane::setZoomX(float value)
{
GUARD_DISPOSED
p->zoomX = value;
p->quadSourceDirty = true;
}
void Plane::setZoomY(float value)
{
GUARD_DISPOSED
p->zoomY = value;
p->quadSourceDirty = true;
}
void Plane::setBlendType(int value)
{
GUARD_DISPOSED
switch (value)
{
default :
case BlendNormal :
p->blendType = BlendNormal;
return;
case BlendAddition :
p->blendType = BlendAddition;
return;
case BlendSubstraction :
p->blendType = BlendSubstraction;
return;
}
}
void Plane::draw()
{
if (!p->bitmap)
return;
if (p->bitmap->isDisposed())
return;
if (!p->opacity)
return;
if (p->quadSourceDirty)
{
p->updateQuadSource();
p->quadSourceDirty = false;
}
if (p->color->hasEffect() || p->tone->hasEffect() || p->opacity != 255)
{
SpriteShader &shader = gState->spriteShader();
shader.bind();
shader.setTone(p->tone->norm);
shader.setColor(p->color->norm);
shader.setFlash(Vec4());
shader.setOpacity(p->opacity.norm);
shader.setBushOpacity(1);
shader.setBushDepth(0);
}
glState.blendMode.pushSet(p->blendType);
p->bitmap->flush();
p->bitmap->bindTexWithMatrix();
Tex::setRepeat(true);
p->quad.draw();
Tex::setRepeat(false);
FragShader::unbind();
}
void Plane::onGeometryChange(const Scene::Geometry &geo)
{
p->quad.setPosRect(FloatRect(geo.rect));
p->sceneGeo = geo;
p->quadSourceDirty = true;
}
void Plane::aboutToAccess() const
{
GUARD_DISPOSED
}
void Plane::releaseResources()
{
unlink();
delete p;
}

63
src/plane.h Normal file
View File

@ -0,0 +1,63 @@
/*
** plane.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLANE_H
#define PLANE_H
#include "disposable.h"
#include "viewport.h"
#include "SFML/Graphics/Sprite.hpp"
#include "SFML/Graphics/RectangleShape.hpp"
class Bitmap;
struct Color;
struct Tone;
struct PlanePrivate;
class Plane : public ViewportElement, public Disposable
{
public:
Plane(Viewport *viewport = 0);
~Plane();
DECL_ATTR( Bitmap, Bitmap* )
DECL_ATTR( OX, int )
DECL_ATTR( OY, int )
DECL_ATTR( ZoomX, float )
DECL_ATTR( ZoomY, float )
DECL_ATTR( Opacity, int )
DECL_ATTR( BlendType, int )
DECL_ATTR( Color, Color* )
DECL_ATTR( Tone, Tone* )
private:
PlanePrivate *p;
void draw();
void onGeometryChange(const Scene::Geometry &);
void aboutToAccess() const;
void releaseResources();
};
#endif // PLANE_H

182
src/quad.h Normal file
View File

@ -0,0 +1,182 @@
/*
** quad.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QUAD_H
#define QUAD_H
#include "GL/glew.h"
#include "etc-internal.h"
#include "gl-util.h"
#include "globalstate.h"
#include "global-ibo.h"
struct Quad
{
Vertex vert[4];
VBO::ID vbo;
VAO::ID vao;
bool vboDirty;
static void setPosRect(CVertex *vert, const FloatRect &r)
{
int i = 0;
vert[i++].pos = r.topLeft();
vert[i++].pos = r.topRight();
vert[i++].pos = r.bottomRight();
vert[i++].pos = r.bottomLeft();
}
static void setColor(CVertex *vert, const Vec4 &c)
{
for (int i = 0; i < 4; ++i)
vert[i].color = c;
}
static void setPosRect(SVertex *vert, const FloatRect &r)
{
int i = 0;
vert[i++].pos = r.topLeft();
vert[i++].pos = r.topRight();
vert[i++].pos = r.bottomRight();
vert[i++].pos = r.bottomLeft();
}
static void setTexRect(SVertex *vert, const FloatRect &r)
{
int i = 0;
vert[i++].texPos = r.topLeft();
vert[i++].texPos = r.topRight();
vert[i++].texPos = r.bottomRight();
vert[i++].texPos = r.bottomLeft();
}
static void setPosRect(Vertex *vert, const FloatRect &r)
{
int i = 0;
vert[i++].pos = r.topLeft();
vert[i++].pos = r.topRight();
vert[i++].pos = r.bottomRight();
vert[i++].pos = r.bottomLeft();
}
static void setTexRect(Vertex *vert, const FloatRect &r)
{
int i = 0;
vert[i++].texPos = r.topLeft();
vert[i++].texPos = r.topRight();
vert[i++].texPos = r.bottomRight();
vert[i++].texPos = r.bottomLeft();
}
static int setTexPosRect(SVertex *vert, const FloatRect &tex, const FloatRect &pos)
{
setPosRect(vert, pos);
setTexRect(vert, tex);
return 1;
}
static int setTexPosRect(Vertex *vert, const FloatRect &tex, const FloatRect &pos)
{
setPosRect(vert, pos);
setTexRect(vert, tex);
return 1;
}
Quad()
: vbo(VBO::gen()),
vao(VAO::gen()),
vboDirty(true)
{
VAO::bind(vao);
VBO::bind(vbo);
gState->bindQuadIBO();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColorPointer (4, GL_FLOAT, sizeof(Vertex), Vertex::colorOffset());
glVertexPointer (2, GL_FLOAT, sizeof(Vertex), Vertex::posOffset());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), Vertex::texPosOffset());
VAO::unbind();
VBO::unbind();
IBO::unbind();
setColor(Vec4(1, 1, 1, 1));
}
~Quad()
{
VAO::del(vao);
VBO::del(vbo);
}
void updateBuffer()
{
VBO::bind(vbo);
VBO::allocEmpty(sizeof(Vertex) * 4, GL_DYNAMIC_DRAW);
VBO::uploadData(sizeof(Vertex) * 4, vert, GL_DYNAMIC_DRAW);
}
void setPosRect(const FloatRect &r)
{
setPosRect(vert, r);
vboDirty = true;
}
void setTexRect(const FloatRect &r)
{
setTexRect(vert, r);
vboDirty = true;
}
void setTexPosRect(const FloatRect &tex, const FloatRect &pos)
{
setTexPosRect(vert, tex, pos);
vboDirty = true;
}
void setColor(const Vec4 &c)
{
for (int i = 0; i < 4; ++i)
vert[i].color = c;
vboDirty = true;
}
void draw()
{
if (vboDirty)
{
updateBuffer();
vboDirty = false;
}
VAO::bind(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
VAO::unbind();
}
};
#endif // QUAD_H

173
src/quadarray.h Normal file
View File

@ -0,0 +1,173 @@
/*
** quadarray.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QUADARRAY_H
#define QUADARRAY_H
#include <QtGlobal>
#include "gl-util.h"
#include "globalstate.h"
#include "global-ibo.h"
typedef quint32 index_t;
#define _GL_INDEX_TYPE GL_UNSIGNED_INT
struct ColorQuadArray
{
QVector<Vertex> vertices;
VBO::ID vbo;
VAO::ID vao;
int quadCount;
ColorQuadArray()
: quadCount(0)
{
vbo = VBO::gen();
vao = VAO::gen();
VAO::bind(vao);
VBO::bind(vbo);
gState->bindQuadIBO();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer (2, GL_FLOAT, sizeof(Vertex), Vertex::posOffset());
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), Vertex::texPosOffset());
glColorPointer (4, GL_FLOAT, sizeof(Vertex), Vertex::colorOffset());
VAO::unbind();
IBO::unbind();
VBO::unbind();
}
~ColorQuadArray()
{
VBO::del(vbo);
VAO::del(vao);
}
void resize(int size)
{
vertices.resize(size * 4);
quadCount = size;
}
/* This needs to be called after the final 'append()' call
* and previous to the first 'draw()' call. */
void commit()
{
VBO::bind(vbo);
VBO::uploadData(vertices.size() * sizeof(Vertex), vertices.constData(), GL_DYNAMIC_DRAW);
VBO::unbind();
gState->ensureQuadIBO(quadCount);
}
void draw(uint offset, uint count)
{
VAO::bind(vao);
const char *_offset = (const char*) 0 + offset * 6 * sizeof(index_t);
glDrawElements(GL_TRIANGLES, count * 6, _GL_INDEX_TYPE, _offset);
VAO::unbind();
}
void draw()
{
draw(0, quadCount);
}
int count() const
{
return quadCount;
}
};
struct PointArray
{
QVector<Vertex> vertices;
VBO::ID vbo;
VAO::ID vao;
PointArray()
{
vbo = VBO::gen();
vao = VAO::gen();
VAO::bind(vao);
VBO::bind(vbo);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (const GLvoid*) 0);
glColorPointer (4, GL_FLOAT, sizeof(Vertex), (const GLvoid*) sizeof(SVertex));
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.append(vert);
}
void commit()
{
VBO::bind(vbo);
VBO::uploadData(vertices.size() * sizeof(Vertex), vertices.constData());
VBO::unbind();
}
void reset()
{
vertices.clear();
}
void draw()
{
VAO::bind(vao);
glDrawArrays(GL_POINTS, 0, count());
VAO::unbind();
}
int count()
{
return vertices.count();
}
};
#endif // QUADARRAY_H

146
src/scene.cpp Normal file
View File

@ -0,0 +1,146 @@
/*
** scene.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "scene.h"
#include "globalstate.h"
#include <QDebug>
Scene::Scene()
{
geometry.xOrigin = geometry.yOrigin = 0;
geometry.rect = IntRect();
}
void Scene::insert(SceneElement &element)
{
IntruListLink<SceneElement> *iter;
for (iter = elements.begin(); iter != elements.end(); iter = iter->next)
{
SceneElement *e = iter->data;
if (element.z <= e->z)
{
if (element.z == e->z)
if (element.creationStamp > e->creationStamp)
continue;
elements.insertBefore(element.link, *iter);
return;
}
}
elements.append(element.link);
}
void Scene::reinsert(SceneElement &element)
{
elements.remove(element.link);
insert(element);
}
void Scene::notifyGeometryChange()
{
IntruListLink<SceneElement> *iter;
for (iter = elements.begin(); iter != elements.end(); iter = iter->next)
{
iter->data->onGeometryChange(geometry);
}
}
void Scene::composite()
{
IntruListLink<SceneElement> *iter;
for (iter = elements.begin(); iter != elements.end(); iter = iter->next)
{
SceneElement *e = iter->data;
if (e->visible)
e->draw();
}
}
SceneElement::SceneElement(Scene &scene, int z)
: link(this),
creationStamp(gState->genTimeStamp()),
z(z),
visible(true),
scene(&scene)
{
scene.insert(*this);
}
SceneElement::~SceneElement()
{
unlink();
}
void SceneElement::setScene(Scene &scene)
{
unlink();
this->scene = &scene;
scene.insert(*this);
onGeometryChange(scene.getGeometry());
}
int SceneElement::getZ() const
{
aboutToAccess();
return z;
}
void SceneElement::setZ(int value)
{
aboutToAccess();
if (z == value)
return;
z = value;
scene->reinsert(*this);
}
bool SceneElement::getVisible() const
{
aboutToAccess();
return visible;
}
void SceneElement::setVisible(bool value)
{
aboutToAccess();
visible = value;
}
void SceneElement::unlink()
{
scene->elements.remove(link);
}

96
src/scene.h Normal file
View File

@ -0,0 +1,96 @@
/*
** scene.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SCENE_H
#define SCENE_H
#include "util.h"
#include "intrulist.h"
#include "etc.h"
#include "etc-internal.h"
class SceneElement;
class Viewport;
class Window;
class Scene
{
public:
struct Geometry
{
int xOrigin, yOrigin;
IntRect rect;
};
Scene();
virtual ~Scene() {}
virtual void composite();
virtual void requestViewportRender(Vec4& /*color*/, Vec4& /*flash*/, Vec4& /*tone*/) {}
const Geometry &getGeometry() const { return geometry; }
protected:
void insert(SceneElement &element);
void reinsert(SceneElement &element);
/* Notify all elements that geometry has changed */
void notifyGeometryChange();
IntruList<SceneElement> elements;
Geometry geometry;
friend class SceneElement;
friend class Window;
};
class SceneElement
{
public:
SceneElement(Scene &scene, int z = 0);
virtual ~SceneElement();
void setScene(Scene &scene);
DECL_ATTR_VIRT( Z, int )
DECL_ATTR_VIRT( Visible, bool )
/* Disposable classes reimplement this to
* check if they're disposed before access */
virtual void aboutToAccess() const {}
protected:
virtual void draw() = 0;
virtual void onGeometryChange(const Scene::Geometry &) {}
void unlink();
IntruListLink<SceneElement> link;
const unsigned int creationStamp;
int z;
bool visible;
Scene *scene;
friend class Scene;
friend class Viewport;
};
#endif // SCENE_H

105
src/serial-util.h Normal file
View File

@ -0,0 +1,105 @@
/*
** serial-util.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERIALUTIL_H
#define SERIALUTIL_H
#include <stdint.h>
typedef unsigned uint;
static inline int16_t
read_int16(const char *data, uint &i)
{
int16_t result = (data[i] & 0x000000FF) | ((data[i+1] << 8) & 0x0000FF00);
i += 2;
return result;
}
static inline int32_t
read_int32(const char *data, uint &i)
{
int32_t result = ((data[i+0] << 0x00) & 0x000000FF)
| ((data[i+1] << 0x08) & 0x0000FF00)
| ((data[i+2] << 0x10) & 0x00FF0000)
| ((data[i+3] << 0x18) & 0xFF000000);
i += 4;
return result;
}
static inline void
write_int16(char **data, int16_t value)
{
*(*data)++ = (value >> 0) & 0xFF;
*(*data)++ = (value >> 8) & 0xFF;
}
static inline void
write_int32(char **data, int32_t value)
{
*(*data)++ = (value >> 0x00) & 0xFF;
*(*data)++ = (value >> 0x08) & 0xFF;
*(*data)++ = (value >> 0x10) & 0xFF;
*(*data)++ = (value >> 0x18) & 0xFF;
}
union doubleInt
{
double d;
int64_t i;
};
static inline void
write_double(char **data, double value)
{
doubleInt di;
di.d = value;
*(*data)++ = (di.i >> 0x00) & 0xFF;
*(*data)++ = (di.i >> 0x08) & 0xFF;
*(*data)++ = (di.i >> 0x10) & 0xFF;
*(*data)++ = (di.i >> 0x18) & 0xFF;
*(*data)++ = (di.i >> 0x20) & 0xFF;
*(*data)++ = (di.i >> 0x28) & 0xFF;
*(*data)++ = (di.i >> 0x30) & 0xFF;
*(*data)++ = (di.i >> 0x38) & 0xFF;
}
static inline double
read_double(const char *data, uint &i)
{
doubleInt di;
di.i = (((int64_t)data[i+0] << 0x00) & 0x00000000000000FF)
| (((int64_t)data[i+1] << 0x08) & 0x000000000000FF00)
| (((int64_t)data[i+2] << 0x10) & 0x0000000000FF0000)
| (((int64_t)data[i+3] << 0x18) & 0x00000000FF000000)
| (((int64_t)data[i+4] << 0x20) & 0x000000FF00000000)
| (((int64_t)data[i+5] << 0x28) & 0x0000FF0000000000)
| (((int64_t)data[i+6] << 0x30) & 0x00FF000000000000)
| (((int64_t)data[i+7] << 0x38) & 0xFF00000000000000);
i += 8;
return di.d;
}
#endif // SERIALUTIL_H

39
src/serializable.h Normal file
View File

@ -0,0 +1,39 @@
/*
** serializable.h
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERIALIZABLE_H
#define SERIALIZABLE_H
struct Serializable
{
virtual ~Serializable() {}
virtual int serialSize() const = 0;
virtual void serialize(char *buffer) const = 0;
};
template<class C>
C *deserialize(const char *data)
{
return C::deserialize(data);
}
#endif // SERIALIZABLE_H

270
src/shader.cpp Normal file
View File

@ -0,0 +1,270 @@
/*
** shader.cpp
**
** This file is part of mkxp.
**
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
**
** mkxp is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** mkxp is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include "shader.h"
#include "GL/glew.h"
#include <QFile>
#include "../shader/sprite.frag.xxd"
#include "../shader/hue.frag.xxd"
#include "../shader/trans.frag.xxd"
#include "../shader/transSimple.frag.xxd"
#include "../shader/bitmapBlit.frag.xxd"
#define GET_U(name) u_##name = glGetUniformLocation(program, #name)
FragShader::~FragShader()
{
glUseProgram(0);
glDeleteProgram(program);
glDeleteShader(shader);
}
void FragShader::bind()
{
glUseProgram(program);
}
void FragShader::unbind()
{
glActiveTexture(GL_TEXTURE0);
glUseProgram(0);
}
void FragShader::init(const unsigned char *source, int length)
{
GLint success;
shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(shader, 1, (const GLchar**) &source, (const GLint*) &length);
glCompileShader(shader);
glGetObjectParameterivARB(shader, GL_COMPILE_STATUS, &success);
Q_ASSERT(success);
program = glCreateProgram();
glAttachShader(program, shader);
glLinkProgram(program);
glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
Q_ASSERT(success);
}
void FragShader::initFromFile(const char *filename)
{
QFile shaderFile(filename);
shaderFile.open(QFile::ReadOnly);
QByteArray contents = shaderFile.readAll();
shaderFile.close();
init((const unsigned char*) contents.constData(), contents.size());
}
void FragShader::setVec4Uniform(GLint location, const Vec4 &vec)
{
glUniform4f(location, vec.x, vec.y, vec.z, vec.w);
}
void FragShader::setTexUniform(GLint location, unsigned unitIndex, Tex::ID texture)
{
GLenum texUnit = GL_TEXTURE0 + unitIndex;
glActiveTexture(texUnit);
glBindTexture(GL_TEXTURE_2D, texture.gl);
glUniform1i(location, unitIndex);
glActiveTexture(GL_TEXTURE0);
}
TransShader::TransShader()
{
init(shader_trans_frag,
shader_trans_frag_len);
GET_U(currentScene);
GET_U(frozenScene);
GET_U(transMap);
GET_U(prog);
GET_U(vague);
}
void TransShader::setCurrentScene(Tex::ID tex)
{
setTexUniform(u_currentScene, 0, tex);
}
void TransShader::setFrozenScene(Tex::ID tex)
{
setTexUniform(u_frozenScene, 1, tex);
}
void TransShader::setTransMap(Tex::ID tex)
{
setTexUniform(u_transMap, 2, tex);
}
void TransShader::setProg(float value)
{
glUniform1f(u_prog, value);
}
void TransShader::setVague(float value)
{
glUniform1f(u_vague, value);
}
SimpleTransShader::SimpleTransShader()
{
init(shader_transSimple_frag,
shader_transSimple_frag_len);
GET_U(currentScene);
GET_U(frozenScene);
GET_U(prog);
}
void SimpleTransShader::setCurrentScene(Tex::ID tex)
{
setTexUniform(u_currentScene, 0, tex);
}
void SimpleTransShader::setFrozenScene(Tex::ID tex)
{
setTexUniform(u_frozenScene, 1, tex);
}
void SimpleTransShader::setProg(float value)
{
glUniform1f(u_prog, value);
}
SpriteShader::SpriteShader()
{
init(shader_sprite_frag,
shader_sprite_frag_len);
GET_U(tone);
GET_U(color);
GET_U(flash);
GET_U(opacity);
GET_U(bushDepth);
GET_U(bushOpacity);
bind();
resetUniforms();
unbind();
}
void SpriteShader::resetUniforms()
{
setTone(Vec4());
setColor(Vec4());
setFlash(Vec4());
setOpacity(1);
setBushDepth(0);
setBushOpacity(0.5);
}
void SpriteShader::setTone(const Vec4 &tone)
{
setVec4Uniform(u_tone, tone);
}
void SpriteShader::setColor(const Vec4 &color)
{
setVec4Uniform(u_color, color);
}
void SpriteShader::setFlash(const Vec4 &flash)
{
setVec4Uniform(u_flash, flash);
}
void SpriteShader::setOpacity(float value)
{
glUniform1f(u_opacity, value);
}
void SpriteShader::setBushDepth(float value)
{
glUniform1f(u_bushDepth, value);
}
void SpriteShader::setBushOpacity(float value)
{
glUniform1f(u_bushOpacity, value);
}
HueShader::HueShader()
{
init(shader_hue_frag,
shader_hue_frag_len);
GET_U(hueAdjust);
GET_U(inputTexture);
}
void HueShader::setHueAdjust(float value)
{
glUniform1f(u_hueAdjust, value);
}
void HueShader::setInputTexture(Tex::ID tex)
{
setTexUniform(u_inputTexture, 0, tex);
}
BltShader::BltShader()
{
init(shader_bitmapBlit_frag,
shader_bitmapBlit_frag_len);
GET_U(source);
GET_U(destination);
GET_U(subRect);
GET_U(opacity);
}
void BltShader::setSource()
{
glUniform1i(u_source, 0);
}
void BltShader::setDestination(const Tex::ID value)
{
setTexUniform(u_destination, 1, value);
}
void BltShader::setSubRect(const FloatRect &value)
{
glUniform4f(u_subRect, value.x, value.y, value.w, value.h);
}
void BltShader::setOpacity(float value)
{
glUniform1f(u_opacity, value);
}

Some files were not shown because too many files have changed in this diff Show More