Transition from QtCore to stdc++ / STL / boost

This looks like a pretty major change, but in reality,
80% of it is just renames of types and corresponding
methods.

The config parsing code has been completely replaced
with a boost::program_options based version. This
means that the config file format slightly changed
(checkout the updated README).

I still expect there to be bugs / unforseen events.
Those should be fixed in follow up commits.

Also, finally reverted back to using pkg-config to
locate and link libruby. Yay for less hacks!
This commit is contained in:
Jonas Kulla 2013-12-11 20:46:54 +01:00
parent 01529c5741
commit 2adf8ab265
40 changed files with 722 additions and 456 deletions

View File

@ -5,7 +5,7 @@ mkxp is a project that seeks to provide a fully open source implementation of th
It is licensed under the GNU General Public License v2+. It is licensed under the GNU General Public License v2+.
## Bindings ## Bindings
Bindings provide the glue code for an interpreted language environment to run game scripts in. As of right now, they are compiled directly into the executable (however, the scripting language itself might not be). Currently there are three bindings: Bindings provide the glue code for an interpreted language environment to run game scripts in. Currently there are three bindings:
### MRI ### MRI
Website: https://www.ruby-lang.org/en/ Website: https://www.ruby-lang.org/en/
@ -15,8 +15,6 @@ Matz's Ruby Interpreter, also called CRuby, is the most widely deployed version
For a list of differences, see: For a list of differences, see:
http://stackoverflow.com/questions/21574/what-is-the-difference-between-ruby-1-8-and-ruby-1-9 http://stackoverflow.com/questions/21574/what-is-the-difference-between-ruby-1-8-and-ruby-1-9
To select this binding, run `qmake BINDING=BINDING_MRI`
### mruby (Lightweight Ruby) ### mruby (Lightweight Ruby)
Website: https://github.com/mruby/mruby Website: https://github.com/mruby/mruby
@ -24,23 +22,20 @@ mruby is a new endeavor by Matz and others to create a more lightweight, spec-ad
Due to heavy differences between mruby and MRI as well as lacking modules, running RPG Maker games with this binding will most likely not work correctly. It is provided as experimental code. You can eg. write your own ruby scripts and run them. Due to heavy differences between mruby and MRI as well as lacking modules, running RPG Maker games with this binding will most likely not work correctly. It is provided as experimental code. You can eg. write your own ruby scripts and run them.
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. Some extensions to the standard classes/modules are provided, taking the RPG Maker XP helpfile as a quasi "reference". These include Marshal, File, FileTest and Time.
**Important:** If you decide to use [mattn's oniguruma regexp gem](https://github.com/mattn/mruby-onig-regexp), don't forget to add `-lonig` to the linker flags to avoid ugly symbol overlaps with libc. **Important:** If you decide to use [mattn's oniguruma regexp gem](https://github.com/mattn/mruby-onig-regexp), don't forget to add `-lonig` to the linker flags to avoid ugly symbol overlaps with libc.
To select this binding, run `qmake BINDING=BINDING_MRUBY`
### null ### null
This binding only exists for testing purposes and does nothing (the engine quits immediately). It can be used to eg. run a minimal RGSS game loop directly in C++. This binding only exists for testing purposes and does nothing (the engine quits immediately). It can be used to eg. run a minimal RGSS game loop directly in C++.
To select this binding, run `qmake BINDING=BINDING_NULL` ## Dependencies / Building
## Dependencies * Boost.Unordered (headers only)
* Boost.Program_options
* QtCore 4.8 * libsigc++ 2.0
* libsigc++ * PhysFS (latest hg)
* PhysFS * GLEW >= 1.7
* glew
* OpenAL * OpenAL
* SDL2 * SDL2
* SDL2_image * SDL2_image
@ -49,44 +44,44 @@ To select this binding, run `qmake BINDING=BINDING_NULL`
* pixman * pixman
* zlib (only ruby bindings) * zlib (only ruby bindings)
(If no version specified, assume latest *development version*, ie. freshest one from git/hg/svn) mkxp employs Qt's qmake build system, so you'll need to install that beforehand.
qmake will use pkg-config to locate the respective include/library paths. If you installed any dependencies into non-standard prefixes, make sure to adjust your `PKG_CONFIG_PATH` variable accordingly.
The exception is boost, which is weird in that it still hasn't managed to pull off pkg-config support (seriously?). *If you installed boost in a non-standard prefix*, you will need to pass its include path via `BOOST_I` and library path via `BOOST_L`, either as direct arguments to qmake (`qmake BOOST_I="/usr/include" ...`) or via environment variables.
**MRI-Binding**: pkg-config will look for `ruby-2.1.pc`, but you can modify mkxp.pro to use 2.0 instead. This is the default binding, so no arguments to qmake needed (`BINDING=BINDING_MRI` to be explicit).
**MRuby-Binding**: place the "mruby" folder into the project folder and build it first. Add `BINDING=BINDING_MRUBY` to qmake's arguments.
**Null-Binding**: Add `BINDING=BINDING_NULL` to qmake's arguments.
### Supported image/audio formats ### Supported image/audio formats
These depend on the auxiliary libraries. For maximum RGSS compliance, build SDL2_image with png/jpg support, and SDL_sound with oggvorbis/wav/mp3 support. These depend on the SDL auxiliary libraries. For maximum RGSS compliance, build SDL2_image with png/jpg support, and SDL_sound with oggvorbis/wav/mp3 support.
### MRI binding:
Place a recent version of ruby in the project folder, apply all patches from "patches/ruby" 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 2.0** with an up-to-date driver installed. To run mkxp, you should have a graphics card capable of at least **OpenGL 2.0** with an up-to-date driver installed.
## 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 binding (currently MRI), then `make`.
## Configuration ## Configuration
mkxp reads configuration data from the file "mkxp.conf" contained in the current directory. The format is ini-style. The "[General]" group may contain following entries: mkxp reads configuration data from the file "mkxp.conf" contained in the current directory. The format is ini-style. Do *not* use quotes around file paths (spaces won't break). Following entries are interpreted:
| Key | Type | Default | Description | | Key | Type | Default | Description |
| ---------------- | ----------- | ------- | ------------------------------------------------------------------------------- | | ---------------- | ------ | ------- | ------------------------------------------------------------------------------- |
| debugMode | bool | false | Log OpenGL debug information to the console | | debugMode | bool | false | Log OpenGL debug information to the console |
| winResizable | bool | false | Game window is resizable | | winResizable | bool | false | Game window is resizable |
| fullscreen | bool | false | Start game in fullscreen (this can always be toggled with Alt-Enter at runtime) | | fullscreen | bool | false | Start game in fullscreen (this can always be toggled with Alt-Enter at runtime) |
| fixedAspectRatio | bool | true | Don't stretch the game screen to fit the window size | | fixedAspectRatio | bool | true | Don't stretch the game screen to fit the window size |
| smoothScaling | bool | false | Apply linear interpolation when game screen is stretched | | smoothScaling | bool | false | Apply linear interpolation when game screen is stretched |
| vsync | bool | false | Sync screen redraws to the monitor refresh rate | | vsync | bool | false | Sync screen redraws to the monitor refresh rate |
| defScreenW | int | 640 | Width the game window starts in (this is **not** the game resolution) | | defScreenW | int | 640 | Width the game window starts in (this is **not** the game resolution) |
| defScreenH | int | 480 | Height the game window starts in | | defScreenH | int | 480 | Height the game window starts in |
| fixedFramerate | int | 0 | FPS will be fixed to this amount. Ignored if 0. | | fixedFramerate | int | 0 | FPS will be fixed to this amount. Ignored if 0. |
| frameSkip | bool | true | Skip frames to catch up (useful to disable eg. with Valgrind) | | frameSkip | bool | true | Skip frames to catch up (useful to disable eg. with Valgrind) |
| solidFonts | bool | false | Don't use alpha blending for fonts | | solidFonts | bool | false | Don't use alpha blending for fonts |
| gameFolder | string | "." | mkxp will look for all game related files here | | gameFolder | string | "." | mkxp will look for all game related files here |
| allowSymlinks | bool | false | Allow symlinks to be followed in the game folder. | | allowSymlinks | bool | false | Allow symlinks to be followed in the game folder. |
| customScript | string | "" | Execute a raw ruby script file instead of an RPG Maker game. | | customScript | string | "" | Execute a raw ruby script file instead of an RPG Maker game. |
| RTPs | string list | "" | A list of space separated paths to RTPs to be used (See next section) | | RTP | string | "" | Path to a Run Time Package to be used. Can be specified multiple times. |
## RTPs ## RTPs

View File

@ -24,19 +24,18 @@
#include "sharedstate.h" #include "sharedstate.h"
#include "eventthread.h" #include "eventthread.h"
#include "filesystem.h" #include "filesystem.h"
#include "util.h"
#include "debugwriter.h"
#include "./ruby/include/ruby.h" #include <ruby.h>
#include "./ruby/include/ruby/encoding.h" #include <ruby/encoding.h>
#include <string>
#include <zlib.h> #include <zlib.h>
#include <SDL_filesystem.h> #include <SDL_filesystem.h>
#include <QFile>
#include <QByteArray>
#include <QDebug>
extern const char module_rpg[]; extern const char module_rpg[];
static void mriBindingExecute(); static void mriBindingExecute();
@ -102,9 +101,9 @@ static void mriBindingInit()
} }
static void static void
showMsg(const QByteArray &msg) showMsg(const std::string &msg)
{ {
shState->eThread().showMessageBox(msg.constData()); shState->eThread().showMessageBox(msg.c_str());
} }
RB_METHOD(mkxpPuts) RB_METHOD(mkxpPuts)
@ -114,7 +113,7 @@ RB_METHOD(mkxpPuts)
const char *str; const char *str;
rb_get_args(argc, argv, "z", &str RB_ARG_END); rb_get_args(argc, argv, "z", &str RB_ARG_END);
qDebug() << str; Debug() << str;
return Qnil; return Qnil;
} }
@ -174,49 +173,45 @@ RB_METHOD(mriDataDirectory)
static void runCustomScript(const char *filename) static void runCustomScript(const char *filename)
{ {
QFile scriptFile(filename); std::string scriptData("#encoding:utf-8\n");
if (!scriptFile.open(QFile::ReadOnly))
if (!readFile(filename, scriptData))
{ {
showMsg(QByteArray("Unable to open '") + filename + "'"); showMsg(std::string("Unable to open '") + filename + "'");
return; return;
} }
QByteArray scriptData = scriptFile.readAll(); rb_eval_string_protect(scriptData.c_str(), 0);
scriptFile.close();
scriptData.prepend("#encoding:utf-8\n");
rb_eval_string_protect(scriptData.constData(), 0);
} }
VALUE kernelLoadDataInt(const char *filename); VALUE kernelLoadDataInt(const char *filename);
struct Script struct Script
{ {
QByteArray name; std::string name;
QByteArray encData; std::string encData;
uint32_t unknown; uint32_t unknown;
QByteArray decData; std::string decData;
}; };
static void runRMXPScripts() static void runRMXPScripts()
{ {
const QByteArray &scriptPack = shState->rtData().config.game.scripts; const std::string &scriptPack = shState->rtData().config.game.scripts;
if (scriptPack.isEmpty()) if (scriptPack.empty())
{ {
showMsg("No game scripts specified (missing Game.ini?)"); showMsg("No game scripts specified (missing Game.ini?)");
return; return;
} }
if (!shState->fileSystem().exists(scriptPack.constData())) if (!shState->fileSystem().exists(scriptPack.c_str()))
{ {
showMsg("Unable to open '" + scriptPack + "'"); showMsg("Unable to open '" + scriptPack + "'");
return; return;
} }
VALUE scriptArray = kernelLoadDataInt(scriptPack.constData()); VALUE scriptArray = kernelLoadDataInt(scriptPack.c_str());
if (rb_type(scriptArray) != RUBY_T_ARRAY) if (rb_type(scriptArray) != RUBY_T_ARRAY)
{ {
@ -226,7 +221,7 @@ static void runRMXPScripts()
size_t scriptCount = RARRAY_LEN(scriptArray); size_t scriptCount = RARRAY_LEN(scriptArray);
QByteArray decodeBuffer; std::string decodeBuffer;
decodeBuffer.resize(0x1000); decodeBuffer.resize(0x1000);
std::vector<Script> encScripts(scriptCount); std::vector<Script> encScripts(scriptCount);
@ -246,7 +241,7 @@ static void runRMXPScripts()
Script &sc = encScripts[i]; Script &sc = encScripts[i];
sc.name = RSTRING_PTR(scriptName); sc.name = RSTRING_PTR(scriptName);
sc.encData = QByteArray(RSTRING_PTR(scriptString), RSTRING_LEN(scriptString)); sc.encData = std::string(RSTRING_PTR(scriptString), RSTRING_LEN(scriptString));
sc.unknown = FIX2UINT(scriptUnknown); sc.unknown = FIX2UINT(scriptUnknown);
} }
@ -260,9 +255,9 @@ static void runRMXPScripts()
while (true) while (true)
{ {
unsigned char *bufferPtr = unsigned char *bufferPtr =
reinterpret_cast<unsigned char*>(const_cast<char*>(decodeBuffer.constData())); reinterpret_cast<unsigned char*>(const_cast<char*>(decodeBuffer.c_str()));
const unsigned char *sourcePtr = const unsigned char *sourcePtr =
reinterpret_cast<const unsigned char*>(sc.encData.constData()); reinterpret_cast<const unsigned char*>(sc.encData.c_str());
bufferLen = decodeBuffer.length(); bufferLen = decodeBuffer.length();
@ -282,21 +277,25 @@ static void runRMXPScripts()
static char buffer[256]; static char buffer[256];
/* FIXME: '%zu' apparently gcc only? */ /* FIXME: '%zu' apparently gcc only? */
snprintf(buffer, sizeof(buffer), "Error decoding script %zu: '%s'", snprintf(buffer, sizeof(buffer), "Error decoding script %zu: '%s'",
i, sc.name.constData()); i, sc.name.c_str());
showMsg(buffer); showMsg(buffer);
break; break;
} }
sc.decData = QByteArray(decodeBuffer.constData(), bufferLen); /* Store encoding header + the decoded script
sc.decData.prepend("#encoding:utf-8\n"); * in 'sc.decData' */
sc.decData = "#encoding:utf-8\n";
size_t hdSize = sc.decData.size();
sc.decData.resize(hdSize + bufferLen);
memcpy(&sc.decData[hdSize], decodeBuffer.c_str(), bufferLen);
ruby_script(sc.name.constData()); ruby_script(sc.name.c_str());
rb_gc_start(); rb_gc_start();
/* Execute code */ /* Execute code */
rb_eval_string_protect(sc.decData.constData(), 0); rb_eval_string_protect(sc.decData.c_str(), 0);
VALUE exc = rb_gv_get("$!"); VALUE exc = rb_gv_get("$!");
if (rb_type(exc) != RUBY_T_NIL) if (rb_type(exc) != RUBY_T_NIL)
@ -314,23 +313,23 @@ static void mriBindingExecute()
mriBindingInit(); mriBindingInit();
QByteArray &customScript = shState->rtData().config.customScript; std::string &customScript = shState->rtData().config.customScript;
if (!customScript.isEmpty()) if (!customScript.empty())
runCustomScript(customScript.constData()); runCustomScript(customScript.c_str());
else else
runRMXPScripts(); runRMXPScripts();
VALUE exc = rb_gv_get("$!"); VALUE exc = rb_gv_get("$!");
if (rb_type(exc) != RUBY_T_NIL && !rb_eql(rb_obj_class(exc), rb_eSystemExit)) if (rb_type(exc) != RUBY_T_NIL && !rb_eql(rb_obj_class(exc), rb_eSystemExit))
{ {
qDebug() << "Had exception:" << rb_class2name(rb_obj_class(exc)); Debug() << "Had exception:" << rb_class2name(rb_obj_class(exc));
VALUE bt = rb_funcall(exc, rb_intern("backtrace"), 0); VALUE bt = rb_funcall(exc, rb_intern("backtrace"), 0);
rb_p(bt); rb_p(bt);
VALUE msg = rb_funcall(exc, rb_intern("message"), 0); VALUE msg = rb_funcall(exc, rb_intern("message"), 0);
if (RSTRING_LEN(msg) < 256) if (RSTRING_LEN(msg) < 256)
showMsg(RSTRING_PTR(msg)); showMsg(RSTRING_PTR(msg));
else else
qDebug() << (RSTRING_PTR(msg)); Debug() << (RSTRING_PTR(msg));
} }
ruby_cleanup(0); ruby_cleanup(0);

View File

@ -26,8 +26,7 @@
#include "util.h" #include "util.h"
#include <stdarg.h> #include <stdarg.h>
#include <assert.h>
#include <QDebug>
void initType(rb_data_type_struct &type, void initType(rb_data_type_struct &type,
const char *name, const char *name,
@ -244,7 +243,7 @@ rb_get_args(int argc, VALUE *argv, const char *format, ...)
} }
} }
#ifndef QT_NO_DEBUG #ifndef NDEBUG
/* Pop remaining arg pointers off /* Pop remaining arg pointers off
* the stack to check for RB_ARG_END */ * the stack to check for RB_ARG_END */
@ -288,8 +287,8 @@ rb_get_args(int argc, VALUE *argv, const char *format, ...)
/* Verify correct termination */ /* Verify correct termination */
void *argEnd = va_arg(ap, void*); void *argEnd = va_arg(ap, void*);
Q_UNUSED(argEnd); (void) argEnd;
Q_ASSERT(argEnd == RB_ARG_END_VAL); assert(argEnd == RB_ARG_END_VAL);
#endif #endif

View File

@ -22,7 +22,7 @@
#ifndef BINDING_UTIL_H #ifndef BINDING_UTIL_H
#define BINDING_UTIL_H #define BINDING_UTIL_H
#include "./ruby/ruby.h" #include <ruby.h>
enum RbException enum RbException
{ {
@ -134,7 +134,7 @@ int
rb_get_args(int argc, VALUE *argv, const char *format, ...); rb_get_args(int argc, VALUE *argv, const char *format, ...);
/* Always terminate 'rb_get_args' with this */ /* Always terminate 'rb_get_args' with this */
#ifndef QT_NO_DEBUG #ifndef NDEBUG
# define RB_ARG_END_VAL ((void*) -1) # define RB_ARG_END_VAL ((void*) -1)
# define RB_ARG_END ,RB_ARG_END_VAL # define RB_ARG_END ,RB_ARG_END_VAL
#else #else

View File

@ -26,8 +26,6 @@
#include "binding-util.h" #include "binding-util.h"
#include "binding-types.h" #include "binding-types.h"
#include <QDebug>
#define DISP_CLASS_NAME "bitmap" #define DISP_CLASS_NAME "bitmap"
DEF_TYPE(Bitmap); DEF_TYPE(Bitmap);

View File

@ -23,8 +23,6 @@
#include "binding-util.h" #include "binding-util.h"
#include "serializable-binding.h" #include "serializable-binding.h"
#include <QDebug>
DEF_TYPE(Color); DEF_TYPE(Color);
DEF_TYPE(Tone); DEF_TYPE(Tone);
DEF_TYPE(Rect); DEF_TYPE(Rect);

View File

@ -27,8 +27,6 @@
#include "ruby/encoding.h" #include "ruby/encoding.h"
#include "ruby/intern.h" #include "ruby/intern.h"
#include <QDebug>
DEF_TYPE(FileInt); DEF_TYPE(FileInt);
static VALUE static VALUE

View File

@ -30,11 +30,11 @@
#include <mruby/proc.h> #include <mruby/proc.h>
#include <mruby/dump.h> #include <mruby/dump.h>
#include "binding-util.h"
#include <stdio.h> #include <stdio.h>
#include <zlib.h> #include <zlib.h>
#include <string>
#include <SDL_messagebox.h> #include <SDL_messagebox.h>
#include <SDL_rwops.h> #include <SDL_rwops.h>
#include <SDL_timer.h> #include <SDL_timer.h>
@ -45,6 +45,7 @@
#include "filesystem.h" #include "filesystem.h"
#include "exception.h" #include "exception.h"
#include "binding-util.h"
#include "binding-types.h" #include "binding-types.h"
#include "mrb-ext/marshal.h" #include "mrb-ext/marshal.h"
@ -180,9 +181,9 @@ checkException(mrb_state *mrb)
static void static void
showError(const QByteArray &msg) showError(const std::string &msg)
{ {
shState->eThread().showMessageBox(msg.constData()); shState->eThread().showMessageBox(msg.c_str());
} }
static void static void
@ -245,17 +246,17 @@ runMrbFile(mrb_state *mrb, const char *filename)
static void static void
runRMXPScripts(mrb_state *mrb, mrbc_context *ctx) runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
{ {
const QByteArray &scriptPack = shState->rtData().config.game.scripts; const std::string &scriptPack = shState->rtData().config.game.scripts;
if (scriptPack.isEmpty()) if (scriptPack.empty())
{ {
showError("No game scripts specified (missing Game.ini?)"); showError("No game scripts specified (missing Game.ini?)");
return; return;
} }
if (!shState->fileSystem().exists(scriptPack.constData())) if (!shState->fileSystem().exists(scriptPack.c_str()))
{ {
showError("Unable to open '" + scriptPack + "'"); showError(std::string("Unable to open '") + scriptPack + "'");
return; return;
} }
@ -263,10 +264,10 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
mrb_state *scriptMrb = mrb_open(); mrb_state *scriptMrb = mrb_open();
SDL_RWops ops; SDL_RWops ops;
shState->fileSystem().openRead(ops, scriptPack.constData()); shState->fileSystem().openRead(ops, scriptPack.c_str());
mrb_value scriptArray = mrb_nil_value(); mrb_value scriptArray = mrb_nil_value();
QByteArray readError; std::string readError;
try try
{ {
@ -275,22 +276,22 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
catch (const Exception &e) catch (const Exception &e)
{ {
char buffer[512]; char buffer[512];
snprintf(buffer, sizeof(buffer), e.fmt.constData(), e.arg1.constData(), e.arg2.constData()); snprintf(buffer, sizeof(buffer), e.fmt.c_str(), e.arg1.c_str(), e.arg2.c_str());
readError = QByteArray(": ") + QByteArray(buffer); readError = std::string(": ") + std::string(buffer);
} }
SDL_RWclose(&ops); SDL_RWclose(&ops);
if (!mrb_array_p(scriptArray)) if (!mrb_array_p(scriptArray))
{ {
showError(QByteArray("Failed to read script data") + readError); showError(std::string("Failed to read script data") + readError);
mrb_close(scriptMrb); mrb_close(scriptMrb);
return; return;
} }
int scriptCount = mrb_ary_len(scriptMrb, scriptArray); int scriptCount = mrb_ary_len(scriptMrb, scriptArray);
QByteArray decodeBuffer; std::string decodeBuffer;
decodeBuffer.resize(0x1000); decodeBuffer.resize(0x1000);
for (int i = 0; i < scriptCount; ++i) for (int i = 0; i < scriptCount; ++i)
@ -309,7 +310,7 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
while (true) while (true)
{ {
unsigned char *bufferPtr = unsigned char *bufferPtr =
reinterpret_cast<unsigned char*>(const_cast<char*>(decodeBuffer.constData())); reinterpret_cast<unsigned char*>(const_cast<char*>(decodeBuffer.c_str()));
unsigned char *sourcePtr = unsigned char *sourcePtr =
reinterpret_cast<unsigned char*>(RSTRING_PTR(scriptString)); reinterpret_cast<unsigned char*>(RSTRING_PTR(scriptString));
@ -342,7 +343,7 @@ runRMXPScripts(mrb_state *mrb, mrbc_context *ctx)
int ai = mrb_gc_arena_save(mrb); int ai = mrb_gc_arena_save(mrb);
/* Execute code */ /* Execute code */
mrb_load_nstring_cxt(mrb, decodeBuffer.constData(), bufferLen, ctx); mrb_load_nstring_cxt(mrb, decodeBuffer.c_str(), bufferLen, ctx);
mrb_gc_arena_restore(mrb, ai); mrb_gc_arena_restore(mrb, ai);
@ -370,14 +371,15 @@ static void mrbBindingExecute()
mrbc_context *ctx = mrbc_context_new(mrb); mrbc_context *ctx = mrbc_context_new(mrb);
ctx->capture_errors = 1; ctx->capture_errors = 1;
Config &conf = shState->rtData().config; const Config &conf = shState->rtData().config;
QByteArray &customScript = conf.customScript; const std::string &customScript = conf.customScript;
QByteArray mrbFile = conf.bindingConf.value("mrbFile").toByteArray(); // const std::string &mrbFile = conf.mrbFile;
(void) runMrbFile; // FIXME mrbFile support on ice for now
if (!customScript.isEmpty()) if (!customScript.empty())
runCustomScript(mrb, ctx, customScript.constData()); runCustomScript(mrb, ctx, customScript.c_str());
else if (!mrbFile.isEmpty()) // else if (!mrbFile.empty())
runMrbFile(mrb, mrbFile.constData()); // runMrbFile(mrb, mrbFile.c_str());
else else
runRMXPScripts(mrb, ctx); runRMXPScripts(mrb, ctx);

View File

@ -26,8 +26,6 @@
#include "binding-util.h" #include "binding-util.h"
#include "binding-types.h" #include "binding-types.h"
#include <QDebug>
#define DISP_CLASS_NAME "bitmap" #define DISP_CLASS_NAME "bitmap"
DEF_TYPE(Bitmap); DEF_TYPE(Bitmap);

View File

@ -25,6 +25,8 @@
#include "disposable.h" #include "disposable.h"
#include "binding-util.h" #include "binding-util.h"
#include <string.h>
template<class C> template<class C>
MRB_METHOD(disposableDispose) MRB_METHOD(disposableDispose)
{ {

View File

@ -24,8 +24,6 @@
#include "binding-types.h" #include "binding-types.h"
#include "serializable-binding.h" #include "serializable-binding.h"
#include <QDebug>
#define ATTR_RW(Type, attr, arg_type, mrb_val, arg_t_s) \ #define ATTR_RW(Type, attr, arg_type, mrb_val, arg_t_s) \
MRB_METHOD(Type##Get_##attr) \ MRB_METHOD(Type##Get_##attr) \
{ \ { \

View File

@ -21,6 +21,8 @@
#include "file.h" #include "file.h"
#include "debugwriter.h"
#include "../binding-util.h" #include "../binding-util.h"
#include <mruby/string.h> #include <mruby/string.h>
#include <mruby/array.h> #include <mruby/array.h>
@ -36,8 +38,6 @@
#include <vector> #include <vector>
#include <QDebug>
extern mrb_value timeFromSecondsInt(mrb_state *mrb, time_t seconds); extern mrb_value timeFromSecondsInt(mrb_state *mrb, time_t seconds);
static void static void
@ -87,7 +87,7 @@ getOpenMode(const char *mode)
STR_CASE("a", Write) STR_CASE("a", Write)
STR_CASE("a+", ReadWrite) STR_CASE("a+", ReadWrite)
qDebug() << "getOpenMode failed for:" << mode; Debug() << "getOpenMode failed for:" << mode;
return 0; return 0;
} }
@ -225,7 +225,7 @@ MRB_FUNCTION(fileExpandPath)
// FIXME No idea how to integrate 'default_dir' right now // FIXME No idea how to integrate 'default_dir' right now
if (defDir) if (defDir)
qDebug() << "FIXME: File.expand_path: default_dir not implemented"; Debug() << "FIXME: File.expand_path: default_dir not implemented";
char buffer[512]; char buffer[512];
char *unused = realpath(path, buffer); char *unused = realpath(path, buffer);
@ -457,7 +457,7 @@ MRB_METHOD(fileReadLines)
const char *rs = "\n"; (void) rs; const char *rs = "\n"; (void) rs;
if (mrb->c->ci->argc > 0) if (mrb->c->ci->argc > 0)
{ {
qDebug() << "FIXME: File.readlines: rs not implemented"; Debug() << "FIXME: File.readlines: rs not implemented";
if (mrb_string_p(arg)) if (mrb_string_p(arg))
rs = RSTRING_PTR(arg); rs = RSTRING_PTR(arg);

View File

@ -36,8 +36,6 @@
#include "filesystem.h" #include "filesystem.h"
#include "binding.h" #include "binding.h"
#include <QDebug>
void mrbBindingTerminate(); void mrbBindingTerminate();
MRB_FUNCTION(kernelEval) MRB_FUNCTION(kernelEval)

View File

@ -38,14 +38,11 @@
#include "file.h" #include "file.h"
#include "rwmem.h" #include "rwmem.h"
#include "exception.h" #include "exception.h"
#include "boost-hash.h"
#include "debugwriter.h"
#include <SDL_timer.h> #include <SDL_timer.h>
#include <QHash>
#include <QByteArray>
#include <QDebug>
#define MARSHAL_MAJOR 4 #define MARSHAL_MAJOR 4
#define MARSHAL_MINOR 8 #define MARSHAL_MINOR 8
@ -76,9 +73,9 @@
// FIXME make these dynamically allocatd, per MarshalContext // FIXME make these dynamically allocatd, per MarshalContext
static char gpbuffer[512]; static char gpbuffer[512];
inline uint qHash(mrb_value key) inline size_t hash_value(mrb_value key)
{ {
return qHash(key.value.p); return boost::hash_value(key.value.p);
} }
inline bool operator==(mrb_value v1, mrb_value v2) inline bool operator==(mrb_value v1, mrb_value v2)
@ -109,7 +106,7 @@ template<typename T>
struct LinkBuffer struct LinkBuffer
{ {
/* Key: val, Value: idx in vec */ /* Key: val, Value: idx in vec */
QHash<T, int> hash; BoostHash<T, int> hash;
std::vector<T> vec; std::vector<T> vec;
bool contains(T value) bool contains(T value)
@ -551,9 +548,8 @@ read_value(MarshalContext *ctx)
break; break;
default : default :
qDebug() << "Value type" << (char)type << "not supported!";
throw Exception(Exception::MKXPError, "Marshal.load: unsupported value type '%s'", throw Exception(Exception::MKXPError, "Marshal.load: unsupported value type '%s'",
QByteArray(1, (char)type)); std::string(1, (char)type));
} }
mrb_gc_arena_restore(mrb, arena); mrb_gc_arena_restore(mrb, arena);
@ -973,7 +969,7 @@ MRB_FUNCTION(marshalLoad)
} }
else else
{ {
qDebug() << "FIXME: Marshal.load: generic IO port not implemented"; Debug() << "FIXME: Marshal.load: generic IO port not implemented";
return mrb_nil_value(); return mrb_nil_value();
} }

View File

@ -24,8 +24,6 @@
#include "binding-types.h" #include "binding-types.h"
#include "serializable-binding.h" #include "serializable-binding.h"
#include <QDebug>
DEF_TYPE(Table); DEF_TYPE(Table);
MRB_METHOD(tableInitialize) MRB_METHOD(tableInitialize)

View File

@ -22,12 +22,11 @@
#include "binding.h" #include "binding.h"
#include "sharedstate.h" #include "sharedstate.h"
#include "eventthread.h" #include "eventthread.h"
#include "debugwriter.h"
#include <QDebug>
static void nullBindingExecute() static void nullBindingExecute()
{ {
qDebug() << "The null binding doesn't do anything, so we're done!"; Debug() << "The null binding doesn't do anything, so we're done!";
shState->rtData().rqTermAck = true; shState->rtData().rqTermAck = true;
} }

View File

@ -5,7 +5,29 @@ QT =
TARGET = mkxp TARGET = mkxp
DEPENDPATH += src shader assets DEPENDPATH += src shader assets
INCLUDEPATH += . src INCLUDEPATH += . src
QMAKE_LFLAGS += '-Wl,-rpath,\'\$$ORIGIN/lib\'' LIBS += -lGL
# Deal with boost paths...
isEmpty(BOOST_I) {
BOOST_I = $$(BOOST_I)
}
isEmpty(BOOST_I) {}
else {
INCLUDEPATH += $$BOOST_I
}
isEmpty(BOOST_L) {
BOOST_L = $$(BOOST_L)
}
isEmpty(BOOST_L) {}
else {
LIBS += -L$$BOOST_L
}
LIBS += -lboost_program_options
CONFIG(release, debug|release): DEFINES += NDEBUG
isEmpty(BINDING) { isEmpty(BINDING) {
BINDING = BINDING_MRI BINDING = BINDING_MRI
@ -19,18 +41,14 @@ RGSS2 {
unix { unix {
CONFIG += link_pkgconfig CONFIG += link_pkgconfig
PKGCONFIG += QtCore sigc++-2.0 glew pixman-1 zlib \ PKGCONFIG += sigc++-2.0 glew pixman-1 zlib physfs \
physfs sdl2 SDL2_image SDL2_ttf SDL_sound \ sdl2 SDL2_image SDL2_ttf SDL_sound openal
openal
RGSS2 { RGSS2 {
PKGCONFIG += vorbisfile PKGCONFIG += vorbisfile
} }
} }
# 'slots' keyword fucks with libsigc++
DEFINES += QT_NO_KEYWORDS
# Input # Input
HEADERS += \ HEADERS += \
src/quadarray.h \ src/quadarray.h \
@ -72,7 +90,9 @@ HEADERS += \
src/tileatlas.h \ src/tileatlas.h \
src/perftimer.h \ src/perftimer.h \
src/sharedstate.h \ src/sharedstate.h \
src/al-util.h src/al-util.h \
src/boost-hash.h \
src/debugwriter.h
SOURCES += \ SOURCES += \
src/main.cpp \ src/main.cpp \
@ -185,9 +205,7 @@ BINDING_MRUBY {
} }
BINDING_MRI { BINDING_MRI {
LIBS += ./ruby/libruby.so PKGCONFIG += ruby-2.1
INCLUDEPATH += ruby/include ruby/.ext/include/x86_64-linux # need i386 paths here too!
DEPENDPATH += ruby/include ruby/.ext/include/x86_64-linux
DEFINES += BINDING_MRI DEFINES += BINDING_MRI
# EMBED2 = binding-mri/module_rpg.rb # EMBED2 = binding-mri/module_rpg.rb

View File

@ -27,12 +27,12 @@
#include "filesystem.h" #include "filesystem.h"
#include "exception.h" #include "exception.h"
#include "al-util.h" #include "al-util.h"
#include "boost-hash.h"
#include <QByteArray> #include "debugwriter.h"
#include <QHash>
#include <vector> #include <vector>
#include <string> #include <string>
#include <assert.h>
#include <SDL_audio.h> #include <SDL_audio.h>
#include <SDL_thread.h> #include <SDL_thread.h>
@ -47,8 +47,6 @@
#include <alc.h> #include <alc.h>
#include <QDebug>
#define AUDIO_SLEEP 10 #define AUDIO_SLEEP 10
#define SE_SOURCES 6 #define SE_SOURCES 6
#define SE_CACHE_MEM (10*1024*1024) // 10 MB #define SE_CACHE_MEM (10*1024*1024) // 10 MB
@ -71,8 +69,8 @@ static uint8_t formatSampleSize(int sdlFormat)
return 4; return 4;
default: default:
qDebug() << "Unhandled sample format"; Debug() << "Unhandled sample format";
Q_ASSERT(0); abort();
} }
return 0; return 0;
@ -87,23 +85,23 @@ static ALenum chooseALFormat(int sampleSize, int channelCount)
{ {
case 1 : return AL_FORMAT_MONO8; case 1 : return AL_FORMAT_MONO8;
case 2 : return AL_FORMAT_STEREO8; case 2 : return AL_FORMAT_STEREO8;
default: Q_ASSERT(0); default: abort();
} }
case 2 : case 2 :
switch (channelCount) switch (channelCount)
{ {
case 1 : return AL_FORMAT_MONO16; case 1 : return AL_FORMAT_MONO16;
case 2 : return AL_FORMAT_STEREO16; case 2 : return AL_FORMAT_STEREO16;
default : Q_ASSERT(0); default : abort();
} }
case 4 : case 4 :
switch (channelCount) switch (channelCount)
{ {
case 1 : return AL_FORMAT_MONO_FLOAT32; case 1 : return AL_FORMAT_MONO_FLOAT32;
case 2 : return AL_FORMAT_STEREO_FLOAT32; case 2 : return AL_FORMAT_STEREO_FLOAT32;
default : Q_ASSERT(0); default : abort();
} }
default : Q_ASSERT(0); default : abort();
} }
return 0; return 0;
@ -114,7 +112,7 @@ static const int streamBufSize = 32768;
struct SoundBuffer struct SoundBuffer
{ {
/* Uniquely identifies this or equal buffer */ /* Uniquely identifies this or equal buffer */
QByteArray key; std::string key;
AL::Buffer::ID alBuffer; AL::Buffer::ID alBuffer;
@ -135,11 +133,6 @@ struct SoundBuffer
alBuffer = AL::Buffer::gen(); alBuffer = AL::Buffer::gen();
} }
~SoundBuffer()
{
AL::Buffer::del(alBuffer);
}
static SoundBuffer *ref(SoundBuffer *buffer) static SoundBuffer *ref(SoundBuffer *buffer)
{ {
++buffer->refCount; ++buffer->refCount;
@ -152,12 +145,20 @@ struct SoundBuffer
if (--buffer->refCount == 0) if (--buffer->refCount == 0)
delete buffer; delete buffer;
} }
private:
~SoundBuffer()
{
AL::Buffer::del(alBuffer);
}
}; };
struct SoundEmitter struct SoundEmitter
{ {
typedef BoostHash<std::string, SoundBuffer*> BufferHash;
IntruList<SoundBuffer> buffers; IntruList<SoundBuffer> buffers;
QHash<QByteArray, SoundBuffer*> bufferHash; BufferHash bufferHash;
/* Byte count sum of all cached / playing buffers */ /* Byte count sum of all cached / playing buffers */
uint32_t bufferBytes; uint32_t bufferBytes;
@ -189,12 +190,12 @@ struct SoundEmitter
SoundBuffer::deref(atchBufs[i]); SoundBuffer::deref(atchBufs[i]);
} }
QHash<QByteArray, SoundBuffer*>::iterator iter; BufferHash::const_iterator iter;
for (iter = bufferHash.begin(); iter != bufferHash.end(); ++iter) for (iter = bufferHash.cbegin(); iter != bufferHash.cend(); ++iter)
delete iter.value(); SoundBuffer::deref(iter->second);
} }
void play(const QByteArray &filename, void play(const std::string &filename,
int volume, int volume,
int pitch) int pitch)
{ {
@ -233,7 +234,7 @@ struct SoundEmitter
} }
private: private:
SoundBuffer *allocateBuffer(const QByteArray &filename) SoundBuffer *allocateBuffer(const std::string &filename)
{ {
SoundBuffer *buffer = bufferHash.value(filename, 0); SoundBuffer *buffer = bufferHash.value(filename, 0);
@ -252,7 +253,7 @@ private:
SDL_RWops dataSource; SDL_RWops dataSource;
const char *extension; const char *extension;
shState->fileSystem().openRead(dataSource, filename.constData(), shState->fileSystem().openRead(dataSource, filename.c_str(),
FileSystem::Audio, false, &extension); FileSystem::Audio, false, &extension);
Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, extension, 0, streamBufSize); Sound_Sample *sampleHandle = Sound_NewSample(&dataSource, extension, 0, streamBufSize);
@ -285,7 +286,7 @@ private:
while (wouldBeBytes > SE_CACHE_MEM && !buffers.isEmpty()) while (wouldBeBytes > SE_CACHE_MEM && !buffers.isEmpty())
{ {
SoundBuffer *last = buffers.tail(); SoundBuffer *last = buffers.tail();
bufferHash.remove(last->key); bufferHash.erase(last->key);
buffers.remove(last->link); buffers.remove(last->link);
wouldBeBytes -= last->bytes; wouldBeBytes -= last->bytes;

View File

@ -28,9 +28,6 @@
#include <pixman.h> #include <pixman.h>
#include <QString>
#include <QChar>
#include "gl-util.h" #include "gl-util.h"
#include "quad.h" #include "quad.h"
#include "quadarray.h" #include "quadarray.h"
@ -944,6 +941,50 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align)
modified(); modified();
} }
/* http://www.lemoda.net/c/utf8-to-ucs2/index.html */
static uint16_t utf8_to_ucs2(const char *_input,
const char **end_ptr)
{
const unsigned char *input =
reinterpret_cast<const unsigned char*>(_input);
*end_ptr = _input;
if (input[0] == 0)
return -1;
if (input[0] < 0x80)
{
*end_ptr = _input + 1;
return input[0];
}
if ((input[0] & 0xE0) == 0xE0)
{
if (input[1] == 0 || input[2] == 0)
return -1;
*end_ptr = _input + 3;
return (input[0] & 0x0F)<<12 |
(input[1] & 0x3F)<<6 |
(input[2] & 0x3F);
}
if ((input[0] & 0xC0) == 0xC0)
{
if (input[1] == 0)
return -1;
*end_ptr = _input + 2;
return (input[0] & 0x1F)<<6 |
(input[1] & 0x3F);
}
return -1;
}
IntRect Bitmap::textSize(const char *str) IntRect Bitmap::textSize(const char *str)
{ {
GUARD_DISPOSED; GUARD_DISPOSED;
@ -955,10 +996,14 @@ IntRect Bitmap::textSize(const char *str)
int w, h; int w, h;
TTF_SizeUTF8(font, str, &w, &h); TTF_SizeUTF8(font, str, &w, &h);
QString qstr = QString::fromUtf8(str); /* If str is one character long, *endPtr == 0 */
const char *endPtr;
uint16_t ucs2 = utf8_to_ucs2(str, &endPtr);
if (p->font->getItalic() && qstr.length() == 1) /* For cursive characters, returning the advance
TTF_GlyphMetrics(font, qstr.at(0).unicode(), 0, 0, 0, 0, &w); * as width yields better results */
if (p->font->getItalic() && *endPtr == '\0')
TTF_GlyphMetrics(font, ucs2, 0, 0, 0, 0, &w);
return IntRect(0, 0, w, h); return IntRect(0, 0, w, h);
} }

130
src/boost-hash.h Normal file
View File

@ -0,0 +1,130 @@
/*
** boost-hash.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 BOOSTHASH_H
#define BOOSTHASH_H
#include <boost/unordered/unordered_map.hpp>
#include <boost/unordered/unordered_set.hpp>
#include <utility>
/* Wrappers around the boost unordered template classes,
* exposing an interface similar to Qt's QHash/QSet */
template<typename K, typename V>
class BoostHash
{
private:
typedef boost::unordered_map<K, V> BoostType;
typedef std::pair<K, V> PairType;
BoostType p;
public:
typedef typename BoostType::const_iterator const_iterator;
inline bool contains(const K &key) const
{
const_iterator iter = p.find(key);
return (iter != p.cend());
}
inline void insert(const K &key, const V &value)
{
p.insert(PairType(key, value));
}
inline void erase(const K &key)
{
p.erase(key);
}
inline const V value(const K &key) const
{
const_iterator iter = p.find(key);
if (iter == p.cend())
return V();
return iter->second;
}
inline const V value(const K &key, const V &defaultValue) const
{
const_iterator iter = p.find(key);
if (iter == p.cend())
return defaultValue;
return iter->second;
}
inline V &operator[](const K &key)
{
return p[key];
}
inline const_iterator cbegin() const
{
return p.cbegin();
}
inline const_iterator cend() const
{
return p.cend();
}
};
template<typename K>
class BoostSet
{
private:
typedef boost::unordered_set<K> BoostType;
BoostType p;
public:
typedef typename BoostType::const_iterator const_iterator;
inline bool contains(const K &key)
{
const_iterator iter = p.find(key);
return (iter != p.cend());
}
inline void insert(const K &key)
{
p.insert(key);
}
inline const_iterator cbegin() const
{
return p.cbegin();
}
inline const_iterator cend() const
{
return p.cend();
}
};
#endif // BOOSTHASH_H

View File

@ -21,12 +21,16 @@
#include "config.h" #include "config.h"
#include <QSettings> #include <boost/program_options/options_description.hpp>
#include <QFileInfo> #include <boost/program_options/parsers.hpp>
#include <QString> #include <boost/program_options/variables_map.hpp>
#include <QStringList> #include <fstream>
#include <QFile>
#include <QRegExp> #include "debugwriter.h"
#include "util.h"
typedef std::vector<std::string> StringVec;
namespace po = boost::program_options;
Config::Config() Config::Config()
: debugMode(false), : debugMode(false),
@ -46,68 +50,84 @@ Config::Config()
void Config::read() void Config::read()
{ {
QSettings confFile("mkxp.conf", QSettings::IniFormat); #define PO_DESC_ALL \
PO_DESC(debugMode, bool) \
PO_DESC(winResizable, bool) \
PO_DESC(fullscreen, bool) \
PO_DESC(fixedAspectRatio, bool) \
PO_DESC(smoothScaling, bool) \
PO_DESC(vsync, bool) \
PO_DESC(defScreenW, int) \
PO_DESC(defScreenH, int) \
PO_DESC(fixedFramerate, int) \
PO_DESC(frameSkip, bool) \
PO_DESC(solidFonts, bool) \
PO_DESC(gameFolder, std::string) \
PO_DESC(allowSymlinks, bool) \
PO_DESC(customScript, std::string)
#define READ_VAL(key, Type) key = confFile.value(#key, key).to##Type() #define PO_DESC(key, type) (#key, po::value< type >()->default_value(key))
READ_VAL(debugMode, Bool); po::options_description podesc;
READ_VAL(winResizable, Bool); podesc.add_options()
READ_VAL(fullscreen, Bool); PO_DESC_ALL
READ_VAL(fixedAspectRatio, Bool); ("RTP", po::value<StringVec>())
READ_VAL(smoothScaling, Bool); ;
READ_VAL(vsync, Bool);
READ_VAL(defScreenW, Int);
READ_VAL(defScreenH, Int);
READ_VAL(fixedFramerate, Int);
READ_VAL(frameSkip, Bool);
READ_VAL(solidFonts, Bool);
READ_VAL(gameFolder, ByteArray);
READ_VAL(allowSymlinks, Bool);
READ_VAL(customScript, ByteArray);
QStringList _rtps = confFile.value("RTPs").toStringList(); std::ifstream confFile;
Q_FOREACH(const QString &s, _rtps) confFile.open("mkxp.conf");
rtps.push_back(s.toUtf8());
confFile.beginGroup("Binding"); po::variables_map vm;
po::store(po::parse_config_file(confFile, podesc, true), vm);
po::notify(vm);
QStringList bindingKeys = confFile.childKeys(); confFile.close();
Q_FOREACH (const QString &key, bindingKeys)
{
QVariant value = confFile.value(key);
/* Convert QString to QByteArray */ // Not gonna take your shit boost
if (value.type() == QVariant::String) #define GUARD_ALL( exp ) try { exp } catch(...) {}
value = value.toString().toUtf8();
bindingConf.insert(key.toLatin1(), value); #undef PO_DESC
} #define PO_DESC(key, type) GUARD_ALL( key = vm[#key].as< type >(); )
confFile.endGroup(); PO_DESC_ALL;
GUARD_ALL( rtps = vm["RTP"].as<StringVec>(); );
#undef PO_DESC
#undef PO_DESC_ALL
} }
void Config::readGameINI() void Config::readGameINI()
{ {
if (!customScript.isEmpty()) if (!customScript.empty())
{ {
game.title = basename(customScript.constData()); game.title = basename(customScript.c_str());
return; return;
} }
QSettings gameINI(gameFolder + "/Game.ini", QSettings::IniFormat); po::options_description podesc;
QFileInfo finfo(gameFolder.constData()); podesc.add_options()
game.title = gameINI.value("Game/Title", finfo.baseName()).toByteArray(); ("Game.Title", po::value<std::string>())
("Game.Scripts", po::value<std::string>())
;
/* Gotta read the "Scripts" entry manually because Qt can't handle '\' */ std::string iniPath = gameFolder + "/Game.ini";
QFile gameINIFile(gameFolder + "/Game.ini");
if (gameINIFile.open(QFile::ReadOnly)) std::ifstream iniFile;
{ iniFile.open((iniPath).c_str());
QString gameINIContents = gameINIFile.readAll();
QRegExp scriptsRE(".*Scripts=(.*)\r\nTitle=.*"); po::variables_map vm;
if (scriptsRE.exactMatch(gameINIContents)) po::store(po::parse_config_file(iniFile, podesc, true), vm);
{ po::notify(vm);
game.scripts = scriptsRE.cap(1).toUtf8();
game.scripts.replace('\\', '/'); iniFile.close();
}
} GUARD_ALL( game.title = vm["Game.Title"].as<std::string>(); );
GUARD_ALL( game.scripts = vm["Game.Scripts"].as<std::string>(); );
strReplace(game.scripts, '\\', '/');
if (game.title.empty())
game.title = basename(gameFolder.c_str());
} }

View File

@ -22,10 +22,7 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#include <QByteArray> #include <string>
#include <QHash>
#include <QVariant>
#include <vector> #include <vector>
struct Config struct Config
@ -46,20 +43,16 @@ struct Config
bool solidFonts; bool solidFonts;
QByteArray gameFolder; std::string gameFolder;
bool allowSymlinks; bool allowSymlinks;
QByteArray customScript; std::string customScript;
std::vector<QByteArray> rtps; std::vector<std::string> rtps;
/* Any values in the [Binding]
* group are collected here */
QHash<QByteArray, QVariant> bindingConf;
/* Game INI contents */ /* Game INI contents */
struct { struct {
QByteArray scripts; std::string scripts;
QByteArray title; std::string title;
} game; } game;
Config(); Config();

View File

@ -20,42 +20,30 @@
*/ */
#include "debuglogger.h" #include "debuglogger.h"
#include "debugwriter.h"
#include <glew.h> #include <glew.h>
#include <iostream>
#include <QFile>
#include <QTime>
#include <QTextStream>
#include <QDebug>
struct DebugLoggerPrivate struct DebugLoggerPrivate
{ {
QFile logFile; std::ostream *stream;
QTextStream *stream;
DebugLoggerPrivate(const char *logFilename) DebugLoggerPrivate(const char *logFilename)
{ {
if (logFilename) (void) logFilename;
{
logFile.setFileName(logFilename); stream = &std::clog;
logFile.open(QFile::WriteOnly);
stream = new QTextStream(&logFile);
}
else
{
stream = new QTextStream(stderr, QIODevice::WriteOnly);
}
} }
~DebugLoggerPrivate() ~DebugLoggerPrivate()
{ {
delete stream;
} }
void writeTimestamp() void writeTimestamp()
{ {
QTime time = QTime::currentTime(); // FIXME reintroduce proper time stamps (is this even necessary??)
*stream << "[" << time.toString().toLatin1() << "] "; *stream << "[GLDEBUG] ";
} }
void writeLine(const char *line) void writeLine(const char *line)
@ -114,7 +102,7 @@ DebugLogger::DebugLogger(const char *filename)
else if (GLEW_AMD_debug_output) else if (GLEW_AMD_debug_output)
glDebugMessageCallbackAMD(amdDebugFunc, p); glDebugMessageCallbackAMD(amdDebugFunc, p);
else else
qDebug() << "DebugLogger: no debug extensions found"; Debug() << "DebugLogger: no debug extensions found";
} }
DebugLogger::~DebugLogger() DebugLogger::~DebugLogger()

56
src/debugwriter.h Normal file
View File

@ -0,0 +1,56 @@
/*
** debugwriter.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 DEBUGWRITER_H
#define DEBUGWRITER_H
#include <iostream>
#include <sstream>
/* A cheap replacement for Debug() */
class Debug
{
public:
Debug()
{
buf << std::boolalpha;
}
template<typename T>
Debug &operator<<(const T &t)
{
buf << t;
buf << " ";
return *this;
}
~Debug()
{
std::clog << buf.str() << "\n";
}
private:
std::stringstream buf;
};
#endif // DEBUGWRITER_H

View File

@ -29,11 +29,10 @@
#include "sharedstate.h" #include "sharedstate.h"
#include "graphics.h" #include "graphics.h"
#include "debugwriter.h"
#include <string.h> #include <string.h>
#include <QDebug>
bool EventThread::keyStates[] = { false }; bool EventThread::keyStates[] = { false };
EventThread::JoyState EventThread::joyState = EventThread::JoyState EventThread::joyState =
@ -97,7 +96,7 @@ void EventThread::process(RGSSThreadData &rtData)
{ {
if (!SDL_WaitEvent(&event)) if (!SDL_WaitEvent(&event))
{ {
qDebug() << "EventThread: Event error"; Debug() << "EventThread: Event error";
break; break;
} }
@ -141,7 +140,7 @@ void EventThread::process(RGSSThreadData &rtData)
case SDL_QUIT : case SDL_QUIT :
case REQUEST_TERMINATION : case REQUEST_TERMINATION :
terminate = true; terminate = true;
qDebug() << "EventThread termination requested"; Debug() << "EventThread termination requested";
break; break;
case SDL_KEYDOWN : case SDL_KEYDOWN :
@ -173,13 +172,13 @@ void EventThread::process(RGSSThreadData &rtData)
if (fullscreen) if (fullscreen)
{ {
/* Prevent fullscreen flicker */ /* Prevent fullscreen flicker */
strncpy(pendingTitle, rtData.config.game.title.constData(), strncpy(pendingTitle, rtData.config.game.title.c_str(),
sizeof(pendingTitle)); sizeof(pendingTitle));
havePendingTitle = true; havePendingTitle = true;
break; break;
} }
SDL_SetWindowTitle(win, rtData.config.game.title.constData()); SDL_SetWindowTitle(win, rtData.config.game.title.c_str());
} }
break; break;
@ -201,7 +200,7 @@ void EventThread::process(RGSSThreadData &rtData)
case REQUEST_MESSAGEBOX : case REQUEST_MESSAGEBOX :
SDL_ShowSimpleMessageBox(event.user.code, SDL_ShowSimpleMessageBox(event.user.code,
rtData.config.game.title.constData(), rtData.config.game.title.c_str(),
(const char*) event.user.data1, win); (const char*) event.user.data1, win);
free(event.user.data1); free(event.user.data1);
msgBoxDone = true; msgBoxDone = true;
@ -217,7 +216,7 @@ void EventThread::process(RGSSThreadData &rtData)
break; break;
snprintf(buffer, sizeof(buffer), "%s - %d FPS", snprintf(buffer, sizeof(buffer), "%s - %d FPS",
rtData.config.game.title.constData(), event.user.code); rtData.config.game.title.c_str(), event.user.code);
/* Updating the window title in fullscreen /* Updating the window title in fullscreen
* mode seems to cause flickering */ * mode seems to cause flickering */

View File

@ -30,7 +30,7 @@
#include <SDL_mouse.h> #include <SDL_mouse.h>
#include <SDL_mutex.h> #include <SDL_mutex.h>
#include <QByteArray> #include <string>
#include <stdint.h> #include <stdint.h>
@ -173,7 +173,7 @@ struct RGSSThreadData
Config config; Config config;
QByteArray rgssErrorMsg; std::string rgssErrorMsg;
volatile bool rqScreenshot; volatile bool rqScreenshot;

View File

@ -22,7 +22,7 @@
#ifndef EXCEPTION_H #ifndef EXCEPTION_H
#define EXCEPTION_H #define EXCEPTION_H
#include <QByteArray> #include <string>
#include <stdio.h> #include <stdio.h>
struct Exception struct Exception
@ -44,19 +44,19 @@ struct Exception
}; };
Type type; Type type;
QByteArray fmt; std::string fmt;
QByteArray arg1; std::string arg1;
QByteArray arg2; std::string arg2;
Exception(Type type, QByteArray fmt, Exception(Type type, std::string fmt,
QByteArray arg1 = QByteArray(), std::string arg1 = std::string(),
QByteArray arg2 = QByteArray()) std::string arg2 = std::string())
: type(type), fmt(fmt), arg1(arg1), arg2(arg2) : type(type), fmt(fmt), arg1(arg1), arg2(arg2)
{} {}
void snprintf(char *buffer, size_t bufSize) const void snprintf(char *buffer, size_t bufSize) const
{ {
::snprintf(buffer, bufSize, fmt.constData(), arg1.constData(), arg2.constData()); ::snprintf(buffer, bufSize, fmt.c_str(), arg1.c_str(), arg2.c_str());
} }
}; };

View File

@ -23,22 +23,18 @@
#include "util.h" #include "util.h"
#include "exception.h" #include "exception.h"
#include "boost-hash.h"
#include "debugwriter.h"
#include <physfs.h> #include <physfs.h>
#include <SDL_sound.h> #include <SDL_sound.h>
#include <QHash>
#include <QSet>
#include <QByteArray>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <QDebug>
struct RGSS_entryData struct RGSS_entryData
{ {
int64_t offset; int64_t offset;
@ -73,11 +69,11 @@ struct RGSS_archiveData
/* Maps: file path /* Maps: file path
* to: entry data */ * to: entry data */
QHash<QByteArray, RGSS_entryData> entryHash; BoostHash<std::string, RGSS_entryData> entryHash;
/* Maps: directory path, /* Maps: directory path,
* to: list of contained entries */ * to: list of contained entries */
QHash<QByteArray, QSet<QByteArray> > dirHash; BoostHash<std::string, BoostSet<std::string> > dirHash;
}; };
static bool static bool
@ -313,7 +309,7 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
uint32_t magic = RGSS_MAGIC; uint32_t magic = RGSS_MAGIC;
/* Top level entry list */ /* Top level entry list */
QSet<QByteArray> &topLevel = data->dirHash["."]; BoostSet<std::string> &topLevel = data->dirHash["."];
while (true) while (true)
{ {
@ -373,7 +369,7 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
const char *dir = nameBuf; const char *dir = nameBuf;
const char *entry = &nameBuf[i+1]; const char *entry = &nameBuf[i+1];
QSet<QByteArray> &entryList = data->dirHash[dir]; BoostSet<std::string> &entryList = data->dirHash[dir];
entryList.insert(entry); entryList.insert(entry);
} }
@ -390,16 +386,16 @@ RGSS_enumerateFiles(void *opaque, const char *dirname,
{ {
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque); RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
QByteArray _dirname(dirname); std::string _dirname(dirname);
if (!data->dirHash.contains(_dirname)) if (!data->dirHash.contains(_dirname))
return; return;
const QSet<QByteArray> &entries = data->dirHash.value(_dirname); const BoostSet<std::string> &entries = data->dirHash[_dirname];
QSet<QByteArray>::const_iterator iter; BoostSet<std::string>::const_iterator iter;
for (iter = entries.begin(); iter != entries.end(); ++iter) for (iter = entries.cbegin(); iter != entries.cend(); ++iter)
cb(callbackdata, origdir, iter->constData()); cb(callbackdata, origdir, iter->c_str());
} }
static PHYSFS_Io* static PHYSFS_Io*
@ -500,9 +496,9 @@ static const PHYSFS_Archiver RGSS_Archiver =
struct FileSystemPrivate struct FileSystemPrivate
{ {
/* All keys are lower case */ /* All keys are lower case */
QHash<QByteArray, QByteArray> pathCache; BoostHash<std::string, std::string> pathCache;
std::vector<QByteArray> extensions[FileSystem::Undefined]; std::vector<std::string> extensions[FileSystem::Undefined];
/* Attempt to locate an extension string in a filename. /* Attempt to locate an extension string in a filename.
* Either a pointer into the input string pointing at the * Either a pointer into the input string pointing at the
@ -535,7 +531,7 @@ struct FileSystemPrivate
buff[i] = '\0'; buff[i] = '\0';
QByteArray key(buff); std::string key(buff);
if (pathCache.contains(key)) if (pathCache.contains(key))
{ {
@ -544,17 +540,17 @@ struct FileSystemPrivate
if (foundExt) if (foundExt)
*foundExt = findExt(filename); *foundExt = findExt(filename);
return pathCache[key].constData(); return pathCache[key].c_str();
} }
char buff2[512]; char buff2[512];
if (type != FileSystem::Undefined) if (type != FileSystem::Undefined)
{ {
std::vector<QByteArray> &extList = extensions[type]; std::vector<std::string> &extList = extensions[type];
for (size_t i = 0; i < extList.size(); ++i) for (size_t i = 0; i < extList.size(); ++i)
{ {
const char *ext = extList[i].constData(); const char *ext = extList[i].c_str();
snprintf(buff2, sizeof(buff2), "%s.%s", buff, ext); snprintf(buff2, sizeof(buff2), "%s.%s", buff, ext);
key = buff2; key = buff2;
@ -564,7 +560,7 @@ struct FileSystemPrivate
if (foundExt) if (foundExt)
*foundExt = ext; *foundExt = ext;
return pathCache[key].constData(); return pathCache[key].c_str();
} }
} }
} }
@ -640,7 +636,7 @@ FileSystem::~FileSystem()
delete p; delete p;
if (PHYSFS_deinit() == 0) if (PHYSFS_deinit() == 0)
qDebug() << "PhyFS failed to deinit."; Debug() << "PhyFS failed to deinit.";
} }
void FileSystem::addPath(const char *path) void FileSystem::addPath(const char *path)
@ -660,16 +656,16 @@ static void cacheEnumCB(void *d, const char *origdir,
else else
strncpy(buf, fname, sizeof(buf)); strncpy(buf, fname, sizeof(buf));
QByteArray mixedCase(buf); std::string mixedCase(buf);
for (char *p = buf; *p; ++p) for (char *p = buf; *p; ++p)
*p = tolower(*p); *p = tolower(*p);
QByteArray lowerCase(buf); std::string lowerCase(buf);
p->pathCache.insert(lowerCase, mixedCase); p->pathCache.insert(lowerCase, mixedCase);
PHYSFS_enumerateFilesCallback(mixedCase.constData(), cacheEnumCB, p); PHYSFS_enumerateFilesCallback(mixedCase.c_str(), cacheEnumCB, p);
} }
void FileSystem::createPathCache() void FileSystem::createPathCache()

View File

@ -25,8 +25,6 @@
#include "etc.h" #include "etc.h"
#include "etc-internal.h" #include "etc-internal.h"
#include <QDebug>
class Flashable class Flashable
{ {
public: public:

View File

@ -24,17 +24,16 @@
#include "sharedstate.h" #include "sharedstate.h"
#include "filesystem.h" #include "filesystem.h"
#include "exception.h" #include "exception.h"
#include "boost-hash.h"
#include "util.h"
#include <string>
#include <utility>
#include "../liberation.ttf.xxd" #include "../liberation.ttf.xxd"
#include <SDL_ttf.h> #include <SDL_ttf.h>
#include <QHash>
#include <QByteArray>
#include <QPair>
#include <QDebug>
#define BUNDLED_FONT liberation #define BUNDLED_FONT liberation
#define BUNDLED_FONT_D(f) assets_## f ##_ttf #define BUNDLED_FONT_D(f) assets_## f ##_ttf
@ -44,11 +43,17 @@
#define BNDL_F_D(f) BUNDLED_FONT_D(f) #define BNDL_F_D(f) BUNDLED_FONT_D(f)
#define BNDL_F_L(f) BUNDLED_FONT_L(f) #define BNDL_F_L(f) BUNDLED_FONT_L(f)
typedef QPair<QByteArray, int> FontKey; typedef std::pair<std::string, int> FontKey;
static void strToLower(std::string &str)
{
for (size_t i = 0; i < str.size(); ++i)
str[i] = tolower(str[i]);
}
struct FontPoolPrivate struct FontPoolPrivate
{ {
QHash<FontKey, TTF_Font*> hash; BoostHash<FontKey, TTF_Font*> hash;
}; };
FontPool::FontPool() FontPool::FontPool()
@ -58,9 +63,9 @@ FontPool::FontPool()
FontPool::~FontPool() FontPool::~FontPool()
{ {
QHash<FontKey, TTF_Font*>::const_iterator iter; BoostHash<FontKey, TTF_Font*>::const_iterator iter;
for (iter = p->hash.begin(); iter != p->hash.end(); ++iter) for (iter = p->hash.cbegin(); iter != p->hash.cend(); ++iter)
TTF_CloseFont(iter.value()); TTF_CloseFont(iter->second);
delete p; delete p;
} }
@ -71,16 +76,22 @@ static SDL_RWops *openBundledFont()
} }
_TTF_Font *FontPool::request(const char *filename, _TTF_Font *FontPool::request(const char *filename,
int size) int size)
{ {
// FIXME Find out how font path resolution is done in VX/Ace // FIXME Find out how font path resolution is done in VX/Ace
QByteArray nameKey = QByteArray(filename).toLower(); std::string nameKey(filename);
nameKey.replace(' ', '_'); strToLower(nameKey);
strReplace(nameKey, ' ', '_');
bool useBundled = false; bool useBundled = false;
QByteArray path = QByteArray("Fonts/") + nameKey; std::string path = std::string("Fonts/") + nameKey;
if (!shState->fileSystem().exists(path.constData(), FileSystem::Font)) if (!shState->fileSystem().exists(path.c_str(), FileSystem::Font))
{ {
/* Use the same name key for the bundled font
* even when it resulted from multiple different
* font name requests. The space at the front is
* to prevent collisions (spaces are normally
* replaced with '_' */
useBundled = true; useBundled = true;
nameKey = " bundled"; nameKey = " bundled";
} }
@ -90,14 +101,9 @@ _TTF_Font *FontPool::request(const char *filename,
TTF_Font *font = p->hash.value(key, 0); TTF_Font *font = p->hash.value(key, 0);
if (font) if (font)
{
// static int i=0;qDebug() << "FontPool: <?+>" << i++;
return font; return font;
}
// qDebug() << "FontPool: <?->"; /* Not in hash, open */
/* Not in hash, create */
SDL_RWops *ops; SDL_RWops *ops;
if (useBundled) if (useBundled)
@ -107,7 +113,7 @@ _TTF_Font *FontPool::request(const char *filename,
else else
{ {
ops = SDL_AllocRW(); ops = SDL_AllocRW();
shState->fileSystem().openRead(*ops, path.constData(), FileSystem::Font, true); shState->fileSystem().openRead(*ops, path.c_str(), FileSystem::Font, true);
} }
// FIXME 0.9 is guesswork at this point // FIXME 0.9 is guesswork at this point
@ -124,7 +130,7 @@ _TTF_Font *FontPool::request(const char *filename,
struct FontPrivate struct FontPrivate
{ {
QByteArray name; std::string name;
int size; int size;
bool bold; bool bold;
bool italic; bool italic;
@ -132,7 +138,7 @@ struct FontPrivate
Color colorTmp; Color colorTmp;
static QByteArray defaultName; static std::string defaultName;
static int defaultSize; static int defaultSize;
static bool defaultBold; static bool defaultBold;
static bool defaultItalic; static bool defaultItalic;
@ -144,15 +150,15 @@ struct FontPrivate
FontPrivate(const char *name = 0, FontPrivate(const char *name = 0,
int size = 0) int size = 0)
: name(name ? QByteArray(name) : defaultName), : name(name ? std::string(name) : defaultName),
size(size ? size : defaultSize), size(size ? size : defaultSize),
bold(defaultBold), bold(defaultBold),
italic(defaultItalic), italic(defaultItalic),
color(&colorTmp), color(&colorTmp),
colorTmp(*defaultColor) colorTmp(*defaultColor)
{ {
sdlFont = shState->fontPool().request(this->name.constData(), sdlFont = shState->fontPool().request(this->name.c_str(),
this->size); this->size);
} }
FontPrivate(const FontPrivate &other) FontPrivate(const FontPrivate &other)
@ -166,19 +172,19 @@ struct FontPrivate
{} {}
}; };
QByteArray FontPrivate::defaultName = "Arial"; std::string FontPrivate::defaultName = "Arial";
int FontPrivate::defaultSize = 22; int FontPrivate::defaultSize = 22;
bool FontPrivate::defaultBold = false; bool FontPrivate::defaultBold = false;
bool FontPrivate::defaultItalic = false; bool FontPrivate::defaultItalic = false;
Color *FontPrivate::defaultColor = &FontPrivate::defaultColorTmp; Color *FontPrivate::defaultColor = &FontPrivate::defaultColorTmp;
Color FontPrivate::defaultColorTmp(255, 255, 255, 255); Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
bool Font::doesExist(const char *name) bool Font::doesExist(const char *name)
{ {
QByteArray path = QByteArray("fonts/") + QByteArray(name); std::string path = std::string("fonts/") + std::string(name);
return shState->fileSystem().exists(path.constData(), FileSystem::Font); return shState->fileSystem().exists(path.c_str(), FileSystem::Font);
} }
Font::Font(const char *name, Font::Font(const char *name,
@ -199,7 +205,7 @@ Font::~Font()
const char *Font::getName() const const char *Font::getName() const
{ {
return p->name.constData(); return p->name.c_str();
} }
void Font::setName(const char *value) void Font::setName(const char *value)
@ -213,7 +219,7 @@ void Font::setSize(int value)
return; return;
p->size = value; p->size = value;
p->sdlFont = shState->fontPool().request(p->name.constData(), value); p->sdlFont = shState->fontPool().request(p->name.c_str(), value);
} }
#undef CHK_DISP #undef CHK_DISP
@ -231,7 +237,7 @@ DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color*, FontPrivate::defaultColor)
const char *Font::getDefaultName() const char *Font::getDefaultName()
{ {
return FontPrivate::defaultName.constData(); return FontPrivate::defaultName.c_str();
} }
void Font::setDefaultName(const char *value) void Font::setDefaultName(const char *value)

View File

@ -27,14 +27,15 @@
#include <SDL_ttf.h> #include <SDL_ttf.h>
#include <SDL_sound.h> #include <SDL_sound.h>
#include <string>
#include "sharedstate.h" #include "sharedstate.h"
#include "eventthread.h" #include "eventthread.h"
#include "debuglogger.h" #include "debuglogger.h"
#include "debugwriter.h"
#include "binding.h" #include "binding.h"
#include <QDebug>
static const char *reqExt[] = static const char *reqExt[] =
{ {
"GL_ARB_fragment_shader", "GL_ARB_fragment_shader",
@ -53,7 +54,7 @@ static const char *reqExt[] =
}; };
static void static void
rgssThreadError(RGSSThreadData *rtData, const QByteArray &msg) rgssThreadError(RGSSThreadData *rtData, const std::string &msg)
{ {
rtData->rgssErrorMsg = msg; rtData->rgssErrorMsg = msg;
rtData->ethread->requestTerminate(); rtData->ethread->requestTerminate();
@ -69,10 +70,10 @@ glGetStringInt(GLenum name)
static void static void
printGLInfo() printGLInfo()
{ {
qDebug() << "GL Vendor :" << glGetStringInt(GL_VENDOR); Debug() << "GL Vendor :" << glGetStringInt(GL_VENDOR);
qDebug() << "GL Renderer :" << glGetStringInt(GL_RENDERER); Debug() << "GL Renderer :" << glGetStringInt(GL_RENDERER);
qDebug() << "GL Version :" << glGetStringInt(GL_VERSION); Debug() << "GL Version :" << glGetStringInt(GL_VERSION);
qDebug() << "GLSL Version :" << glGetStringInt(GL_SHADING_LANGUAGE_VERSION); Debug() << "GLSL Version :" << glGetStringInt(GL_SHADING_LANGUAGE_VERSION);
} }
int rgssThreadFun(void *userdata) int rgssThreadFun(void *userdata)
@ -91,7 +92,7 @@ int rgssThreadFun(void *userdata)
if (!glCtx) if (!glCtx)
{ {
rgssThreadError(threadData, QByteArray("Error creating context: ") + SDL_GetError()); rgssThreadError(threadData, std::string("Error creating context: ") + SDL_GetError());
return 0; return 0;
} }
@ -121,7 +122,7 @@ int rgssThreadFun(void *userdata)
{ {
if (!glewIsSupported(reqExt[i])) if (!glewIsSupported(reqExt[i]))
{ {
rgssThreadError(threadData, QByteArray("Required GL extension \"") rgssThreadError(threadData, std::string("Required GL extension \"")
+ reqExt[i] + "\" not present"); + reqExt[i] + "\" not present");
SDL_GL_DeleteContext(glCtx); SDL_GL_DeleteContext(glCtx);
return 0; return 0;
@ -181,7 +182,7 @@ int main(int, char *argv[])
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0)
{ {
qDebug() << "Error initializing SDL:" << SDL_GetError(); Debug() << "Error initializing SDL:" << SDL_GetError();
return 0; return 0;
} }
@ -189,7 +190,7 @@ int main(int, char *argv[])
int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG; int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
if (IMG_Init(imgFlags) != imgFlags) if (IMG_Init(imgFlags) != imgFlags)
{ {
qDebug() << "Error initializing SDL_image:" << SDL_GetError(); Debug() << "Error initializing SDL_image:" << SDL_GetError();
SDL_Quit(); SDL_Quit();
return 0; return 0;
@ -197,7 +198,7 @@ int main(int, char *argv[])
if (TTF_Init() < 0) if (TTF_Init() < 0)
{ {
qDebug() << "Error initializing SDL_ttf:" << SDL_GetError(); Debug() << "Error initializing SDL_ttf:" << SDL_GetError();
IMG_Quit(); IMG_Quit();
SDL_Quit(); SDL_Quit();
@ -206,7 +207,7 @@ int main(int, char *argv[])
if (Sound_Init() == 0) if (Sound_Init() == 0)
{ {
qDebug() << "Error initializing SDL_sound:" << Sound_GetError(); Debug() << "Error initializing SDL_sound:" << Sound_GetError();
TTF_Quit(); TTF_Quit();
IMG_Quit(); IMG_Quit();
SDL_Quit(); SDL_Quit();
@ -224,13 +225,13 @@ int main(int, char *argv[])
if (conf.fullscreen) if (conf.fullscreen)
winFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; winFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
win = SDL_CreateWindow(conf.game.title.constData(), win = SDL_CreateWindow(conf.game.title.c_str(),
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
conf.defScreenW, conf.defScreenH, winFlags); conf.defScreenW, conf.defScreenH, winFlags);
if (!win) if (!win)
{ {
qDebug() << "Error creating window"; Debug() << "Error creating window";
return 0; return 0;
} }
@ -254,7 +255,7 @@ int main(int, char *argv[])
/* We can stop waiting when the request was ack'd */ /* We can stop waiting when the request was ack'd */
if (rtData.rqTermAck) if (rtData.rqTermAck)
{ {
qDebug() << "RGSS thread ack'd request after" << i*10 << "ms"; Debug() << "RGSS thread ack'd request after" << i*10 << "ms";
break; break;
} }
@ -267,17 +268,17 @@ int main(int, char *argv[])
if (rtData.rqTermAck) if (rtData.rqTermAck)
SDL_WaitThread(rgssThread, 0); SDL_WaitThread(rgssThread, 0);
else else
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.constData(), SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.c_str(),
"The RGSS script seems to be stuck and mkxp will now force quit", win); "The RGSS script seems to be stuck and mkxp will now force quit", win);
if (!rtData.rgssErrorMsg.isEmpty()) if (!rtData.rgssErrorMsg.empty())
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.constData(), SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.c_str(),
rtData.rgssErrorMsg.constData(), win); rtData.rgssErrorMsg.c_str(), win);
/* Clean up any remainin events */ /* Clean up any remainin events */
eventThread.cleanup(); eventThread.cleanup();
qDebug() << "Shutting down."; Debug() << "Shutting down.";
SDL_DestroyWindow(win); SDL_DestroyWindow(win);

View File

@ -3,7 +3,7 @@
#include <SDL_timer.h> #include <SDL_timer.h>
#include <glew.h> #include <glew.h>
#include <QDebug> #include "debugwriter.h"
struct TimerQuery struct TimerQuery
{ {
@ -132,7 +132,7 @@ struct GPUTimerGLQuery : public PerfTimer
if (++counter < iter) if (++counter < iter)
return; return;
qDebug() << " " Debug() << " "
"Avg. GPU time:" << ((double) acc / (iter * 1000 * 1000)) << "ms"; "Avg. GPU time:" << ((double) acc / (iter * 1000 * 1000)) << "ms";
acc = counter = 0; acc = counter = 0;
@ -181,7 +181,7 @@ struct CPUTimer : public PerfTimer
if (++counter < iter) if (++counter < iter)
return; return;
qDebug() << "Avg. CPU time:" << ((double) acc / (iter * (perfFreq / 1000))) << "ms"; Debug() << "Avg. CPU time:" << ((double) acc / (iter * (perfFreq / 1000))) << "ms";
acc = counter = 0; acc = counter = 0;
} }
}; };
@ -199,7 +199,7 @@ PerfTimer *createGPUTimer(int iter)
} }
else else
{ {
qDebug() << "GL_EXT_timer_query not present: cannot measure GPU performance"; Debug() << "GL_EXT_timer_query not present: cannot measure GPU performance";
return new GPUTimerDummy(); return new GPUTimerDummy();
} }
} }

View File

@ -22,8 +22,6 @@
#include "scene.h" #include "scene.h"
#include "sharedstate.h" #include "sharedstate.h"
#include <QDebug>
Scene::Scene() Scene::Scene()
{ {
geometry.xOrigin = geometry.yOrigin = 0; geometry.xOrigin = geometry.yOrigin = 0;

View File

@ -22,10 +22,11 @@
#include "shader.h" #include "shader.h"
#include "sharedstate.h" #include "sharedstate.h"
#include "glstate.h" #include "glstate.h"
#include "debugwriter.h"
#include <glew.h> #include <glew.h>
#include <QFile> #include <assert.h>
#include "../sprite.frag.xxd" #include "../sprite.frag.xxd"
#include "../hue.frag.xxd" #include "../hue.frag.xxd"
@ -48,16 +49,14 @@
#include "../blurV.vert.xxd" #include "../blurV.vert.xxd"
#endif #endif
#include <QDebug>
#define INIT_SHADER(vert, frag) \ #define INIT_SHADER(vert, frag) \
{ \ { \
Shader::init(shader_##vert##_vert, shader_##vert##_vert_len, shader_##frag##_frag, shader_##frag##_frag_len); \ Shader::init(shader_##vert##_vert, shader_##vert##_vert_len, shader_##frag##_frag, shader_##frag##_frag_len); \
qDebug() << " From:" << #vert ".vert" << #frag ".frag"; \ Debug() << " From:" << #vert ".vert" << #frag ".frag"; \
} }
#define COMP(shader) qDebug() << "--- Compiling " #shader #define COMP(shader) Debug() << "--- Compiling " #shader
#define GET_U(name) u_##name = glGetUniformLocation(program, #name) #define GET_U(name) u_##name = glGetUniformLocation(program, #name)
@ -98,14 +97,14 @@ void Shader::init(const unsigned char *vert, int vertSize,
glCompileShader(vertShader); glCompileShader(vertShader);
glGetObjectParameterivARB(vertShader, GL_COMPILE_STATUS, &success); glGetObjectParameterivARB(vertShader, GL_COMPILE_STATUS, &success);
Q_ASSERT(success); assert(success); // FIXME should really throw here instead
/* Compile fragment shader */ /* Compile fragment shader */
glShaderSource(fragShader, 1, (const GLchar**) &frag, (const GLint*) &fragSize); glShaderSource(fragShader, 1, (const GLchar**) &frag, (const GLint*) &fragSize);
glCompileShader(fragShader); glCompileShader(fragShader);
glGetObjectParameterivARB(fragShader, GL_COMPILE_STATUS, &success); glGetObjectParameterivARB(fragShader, GL_COMPILE_STATUS, &success);
Q_ASSERT(success); assert(success);
/* Link shader program */ /* Link shader program */
glAttachShader(program, vertShader); glAttachShader(program, vertShader);
@ -118,23 +117,17 @@ void Shader::init(const unsigned char *vert, int vertSize,
glLinkProgram(program); glLinkProgram(program);
glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
Q_ASSERT(success); assert(success);
} }
void Shader::initFromFile(const char *_vertFile, const char *_fragFile) void Shader::initFromFile(const char *_vertFile, const char *_fragFile)
{ {
QFile vertFile(_vertFile); std::string vertContents, fragContents;
vertFile.open(QFile::ReadOnly); readFile(_vertFile, vertContents);
QByteArray vertContents = vertFile.readAll(); readFile(_fragFile, fragContents);
vertFile.close();
QFile fragFile(_fragFile); init((const unsigned char*) vertContents.c_str(), vertContents.size(),
fragFile.open(QFile::ReadOnly); (const unsigned char*) fragContents.c_str(), fragContents.size());
QByteArray fragContents = fragFile.readAll();
fragFile.close();
init((const unsigned char*) vertContents.constData(), vertContents.size(),
(const unsigned char*) fragContents.constData(), fragContents.size());
} }
void Shader::setVec4Uniform(GLint location, const Vec4 &vec) void Shader::setVec4Uniform(GLint location, const Vec4 &vec)

View File

@ -36,11 +36,9 @@
#include "quad.h" #include "quad.h"
#include "binding.h" #include "binding.h"
#include <QFile>
#include <unistd.h> #include <unistd.h>
#include <stdio.h>
#include <QDebug> #include <string>
SharedState *SharedState::instance = 0; SharedState *SharedState::instance = 0;
static GlobalIBO *globalIBO = 0; static GlobalIBO *globalIBO = 0;
@ -93,21 +91,26 @@ struct SharedStatePrivate
graphics(threadData), graphics(threadData),
stampCounter(0) stampCounter(0)
{ {
if (!config.gameFolder.isEmpty()) if (!config.gameFolder.empty())
{ {
int unused = chdir(config.gameFolder.constData()); int unused = chdir(config.gameFolder.c_str());
(void) unused; (void) unused;
fileSystem.addPath("."); fileSystem.addPath(".");
} }
// FIXME find out correct archive filename // FIXME find out correct archive filename
QByteArray archPath = GAME_ARCHIVE; std::string archPath = GAME_ARCHIVE;
if (QFile::exists(archPath.constData())) /* Check if a game archive exists */
fileSystem.addPath(archPath.constData()); FILE *tmp = fopen(archPath.c_str(), "r");
if (tmp)
{
fileSystem.addPath(archPath.c_str());
fclose(tmp);
}
for (size_t i = 0; i < config.rtps.size(); ++i) for (size_t i = 0; i < config.rtps.size(); ++i)
fileSystem.addPath(config.rtps[i].constData()); fileSystem.addPath(config.rtps[i].c_str());
fileSystem.createPathCache(); fileSystem.createPathCache();

View File

@ -37,8 +37,6 @@
#include <sigc++/connection.h> #include <sigc++/connection.h>
#include <QDebug>
struct SpritePrivate struct SpritePrivate
{ {
Bitmap *bitmap; Bitmap *bitmap;

View File

@ -23,17 +23,15 @@
#include "exception.h" #include "exception.h"
#include "sharedstate.h" #include "sharedstate.h"
#include "glstate.h" #include "glstate.h"
#include "boost-hash.h"
#include "debugwriter.h"
#include <QHash> #include <list>
#include <QQueue> #include <utility>
#include <QList> #include <assert.h>
#include <QLinkedList> #include <string.h>
#include <QPair>
#include <QDebug> typedef std::pair<uint16_t, uint16_t> Size;
typedef QPair<uint16_t, uint16_t> Size;
typedef QQueue<TEXFBO> ObjList;
static uint32_t byteCount(Size &s) static uint32_t byteCount(Size &s)
{ {
@ -43,23 +41,23 @@ static uint32_t byteCount(Size &s)
struct CacheNode struct CacheNode
{ {
TEXFBO obj; TEXFBO obj;
QLinkedList<TEXFBO>::iterator prioIter; std::list<TEXFBO>::iterator prioIter;
bool operator==(const CacheNode &o) bool operator==(const CacheNode &o) const
{ {
return obj == o.obj; return obj == o.obj;
} }
}; };
typedef QList<CacheNode> CNodeList; typedef std::list<CacheNode> CNodeList;
struct TexPoolPrivate struct TexPoolPrivate
{ {
/* Contains all cached TexFBOs, grouped by size */ /* Contains all cached TexFBOs, grouped by size */
QHash<Size, CNodeList> poolHash; BoostHash<Size, CNodeList> poolHash;
/* Contains all cached TexFBOs, sorted by release time */ /* Contains all cached TexFBOs, sorted by release time */
QLinkedList<TEXFBO> priorityQueue; std::list<TEXFBO> priorityQueue;
/* Maximal allowed cache memory */ /* Maximal allowed cache memory */
const uint32_t maxMemSize; const uint32_t maxMemSize;
@ -88,14 +86,18 @@ TexPool::TexPool(uint32_t maxMemSize)
TexPool::~TexPool() TexPool::~TexPool()
{ {
while (!p->priorityQueue.isEmpty()) std::list<TEXFBO>::iterator iter;
for (iter = p->priorityQueue.begin();
iter != p->priorityQueue.end();
++iter)
{ {
TEXFBO obj = p->priorityQueue.takeFirst(); TEXFBO obj = *iter;
TEXFBO::fini(obj); TEXFBO::fini(obj);
--p->objCount; --p->objCount;
} }
Q_ASSERT(p->objCount == 0); assert(p->objCount == 0);
delete p; delete p;
} }
@ -108,33 +110,39 @@ TEXFBO TexPool::request(int width, int height)
/* See if we can statisfy request from cache */ /* See if we can statisfy request from cache */
CNodeList &bucket = p->poolHash[size]; CNodeList &bucket = p->poolHash[size];
if (!bucket.isEmpty()) if (!bucket.empty())
{ {
/* Found one! */ /* Found one! */
cnode = bucket.takeLast(); cnode = bucket.back();
bucket.pop_back();
p->priorityQueue.erase(cnode.prioIter); p->priorityQueue.erase(cnode.prioIter);
p->memSize -= byteCount(size); p->memSize -= byteCount(size);
--p->objCount; --p->objCount;
// qDebug() << "TexPool: <?+> (" << width << height << ")"; // Debug() << "TexPool: <?+> (" << width << height << ")";
return cnode.obj; return cnode.obj;
} }
int maxSize = glState.caps.maxTexSize; int maxSize = glState.caps.maxTexSize;
if (width > maxSize || height > maxSize) if (width > maxSize || height > maxSize)
throw Exception(Exception::MKXPError, {
"Texture dimensions [%s, %s] exceed hardware capabilities", char buffer[128];
QByteArray::number(width), QByteArray::number(height)); snprintf(buffer, sizeof(buffer),
"Texture dimensions [%d, %d] exceed hardware capabilities",
width, height);
throw Exception(Exception::MKXPError, buffer);
}
/* Nope, create it instead */ /* Nope, create it instead */
TEXFBO::init(cnode.obj); TEXFBO::init(cnode.obj);
TEXFBO::allocEmpty(cnode.obj, width, height); TEXFBO::allocEmpty(cnode.obj, width, height);
TEXFBO::linkFBO(cnode.obj); TEXFBO::linkFBO(cnode.obj);
// qDebug() << "TexPool: <?-> (" << width << height << ")"; // Debug() << "TexPool: <?-> (" << width << height << ")";
return cnode.obj; return cnode.obj;
} }
@ -150,7 +158,7 @@ void TexPool::release(TEXFBO &obj)
if (p->disabled) if (p->disabled)
{ {
/* If we're disabled, delete without caching */ /* If we're disabled, delete without caching */
// qDebug() << "TexPool: <!#> (" << obj.width << obj.height << ")"; // Debug() << "TexPool: <!#> (" << obj.width << obj.height << ")";
TEXFBO::fini(obj); TEXFBO::fini(obj);
return; return;
} }
@ -166,39 +174,43 @@ void TexPool::release(TEXFBO &obj)
if (p->objCount == 0) if (p->objCount == 0)
break; break;
// qDebug() << "TexPool: <!~> Size:" << p->memSize; // Debug() << "TexPool: <!~> Size:" << p->memSize;
/* Retrieve object with lowest priority for deletion */ /* Retrieve object with lowest priority for deletion */
CacheNode last; CacheNode last;
last.obj = p->priorityQueue.last(); last.obj = p->priorityQueue.back();
Size removedSize(last.obj.width, last.obj.height); Size removedSize(last.obj.width, last.obj.height);
CNodeList &bucket = p->poolHash[removedSize]; CNodeList &bucket = p->poolHash[removedSize];
Q_ASSERT(bucket.contains(last));
bucket.removeOne(last); std::list<CacheNode>::iterator toRemove =
p->priorityQueue.removeLast(); std::find(bucket.begin(), bucket.end(), last);
assert(toRemove != bucket.end());
bucket.erase(toRemove);
p->priorityQueue.pop_back();
TEXFBO::fini(last.obj); TEXFBO::fini(last.obj);
newMemSize -= byteCount(removedSize);; newMemSize -= byteCount(removedSize);
--p->objCount; --p->objCount;
// qDebug() << "TexPool: <!-> (" << last.obj.tex << last.obj.fbo << ")"; // Debug() << "TexPool: <!-> (" << last.obj.width << last.obj.height << ")";
} }
p->memSize = newMemSize; p->memSize = newMemSize;
/* Retain object */ /* Retain object */
p->priorityQueue.prepend(obj); p->priorityQueue.push_front(obj);
CacheNode cnode; CacheNode cnode;
cnode.obj = obj; cnode.obj = obj;
cnode.prioIter = p->priorityQueue.begin(); cnode.prioIter = p->priorityQueue.begin();
CNodeList &bucket = p->poolHash[size]; CNodeList &bucket = p->poolHash[size];
bucket.append(cnode); bucket.push_back(cnode);
++p->objCount; ++p->objCount;
// qDebug() << "TexPool: <!+> (" << obj.width << obj.height << ") Current size:" << p->memSize; // Debug() << "TexPool: <!+> (" << obj.width << obj.height << ") Current size:" << p->memSize;
} }
void TexPool::disable() void TexPool::disable()

View File

@ -22,6 +22,9 @@
#ifndef UTIL_H #ifndef UTIL_H
#define UTIL_H #define UTIL_H
#include <stdio.h>
#include <string>
static inline int static inline int
wrapRange(int value, int min, int max) wrapRange(int value, int min, int max)
{ {
@ -56,6 +59,40 @@ findNextPow2(int start)
return i; return i;
} }
/* Reads the contents of the file at 'path' and
* appends them to 'out'. Returns false on failure */
inline bool readFile(const char *path,
std::string &out)
{
FILE *f = fopen(path, "r");
if (!f)
return false;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
size_t back = out.size();
out.resize(back+size);
size_t read = fread(&out[back], 1, size, f);
fclose(f);
if (read != (size_t) size)
out.resize(back+read);
return true;
}
inline void strReplace(std::string &str,
char before, char after)
{
for (size_t i = 0; i < str.size(); ++i)
if (str[i] == before)
str[i] = after;
}
#define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0])) #define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0]))
#define elementsN(obj) const int obj##N = ARRAY_SIZE(obj) #define elementsN(obj) const int obj##N = ARRAY_SIZE(obj)

View File

@ -31,8 +31,6 @@
#include <sigc++/connection.h> #include <sigc++/connection.h>
#include <QDebug>
struct ViewportPrivate struct ViewportPrivate
{ {
/* Needed for geometry changes */ /* Needed for geometry changes */

View File

@ -36,8 +36,6 @@
#include <sigc++/connection.h> #include <sigc++/connection.h>
#include <QDebug>
template<typename T> template<typename T>
struct Sides struct Sides
{ {