139 lines
2.8 KiB
C++
139 lines
2.8 KiB
C++
#include "oboy.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QUrl>
|
|
#include <QtGlobal>
|
|
|
|
#include <caml/alloc.h>
|
|
#include <caml/bigarray.h>
|
|
#include <caml/callback.h>
|
|
#include <caml/memory.h>
|
|
#include <caml/misc.h>
|
|
#include <caml/mlvalues.h>
|
|
#include <caml/osdeps.h>
|
|
|
|
OBoy::OBoy(QObject* parent)
|
|
: QObject(parent)
|
|
{
|
|
const QStringList args = QCoreApplication::arguments();
|
|
if (args.size() > 1) {
|
|
const QUrl path = QUrl::fromLocalFile(args.at(1));
|
|
load(path);
|
|
}
|
|
}
|
|
|
|
value*
|
|
fetch_caml_callback(const char* name)
|
|
{
|
|
value* closure_f = caml_named_value(name);
|
|
if (closure_f == nullptr) {
|
|
qFatal("Cannot find OCaml function: %s", name);
|
|
}
|
|
return closure_f;
|
|
}
|
|
|
|
// https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html
|
|
// http://www.mega-nerd.com/erikd/Blog/CodeHacking/Ocaml/calling_ocaml.html
|
|
|
|
QString
|
|
OBoy::name() const
|
|
{
|
|
CAMLparam0();
|
|
|
|
static value* closure_f = fetch_caml_callback("oboy_name");
|
|
if (closure_f == nullptr) {
|
|
CAMLdrop;
|
|
return QString("<Unreachable>");
|
|
}
|
|
|
|
const char* str = String_val(caml_callback(*closure_f, Val_unit));
|
|
CAMLdrop;
|
|
return QString(str);
|
|
}
|
|
|
|
QString
|
|
OBoy::version() const
|
|
{
|
|
CAMLparam0();
|
|
|
|
static value* closure_f = fetch_caml_callback("oboy_version");
|
|
if (closure_f == nullptr) {
|
|
CAMLdrop;
|
|
return QString("<Unreachable>");
|
|
}
|
|
|
|
const char* str = String_val(caml_callback(*closure_f, Val_unit));
|
|
CAMLdrop;
|
|
return QString(str);
|
|
}
|
|
|
|
bool
|
|
OBoy::load(const QUrl& path)
|
|
{
|
|
CAMLparam0();
|
|
CAMLlocal1(ocaml_path);
|
|
|
|
static value* closure_f = fetch_caml_callback("oboy_load");
|
|
if (closure_f == nullptr) {
|
|
CAMLdrop;
|
|
return false;
|
|
}
|
|
|
|
const QString local_path = path.toLocalFile();
|
|
const QByteArray ba = local_path.toLocal8Bit();
|
|
|
|
ocaml_path = caml_copy_string_of_os(ba.data());
|
|
|
|
_loaded = Bool_val(caml_callback(*closure_f, ocaml_path));
|
|
this->loadedChanged(_loaded);
|
|
CAMLdrop;
|
|
return _loaded;
|
|
}
|
|
|
|
bool
|
|
OBoy::loaded() const
|
|
{
|
|
return _loaded;
|
|
}
|
|
|
|
QImage
|
|
OBoy::backgroundMap(int index) const
|
|
{
|
|
CAMLparam0();
|
|
CAMLlocal1(ocaml_index);
|
|
ocaml_index = index;
|
|
|
|
static value* closure_f = fetch_caml_callback("oboy_bg_map");
|
|
if (closure_f == nullptr) {
|
|
CAMLdrop;
|
|
return QImage(0, 0, QImage::Format_Indexed8);
|
|
}
|
|
|
|
const auto bg_array = Caml_ba_array_val(caml_callback(*closure_f, Val_int(ocaml_index)));
|
|
const auto bg_raw_data = static_cast<caml_ba_uint8*>(bg_array->data);
|
|
|
|
Q_ASSERT(bg_array->num_dims == 2);
|
|
Q_ASSERT(bg_array->flags & CAML_BA_UINT8);
|
|
|
|
const int width = bg_array->dim[0];
|
|
const int height = bg_array->dim[1];
|
|
QImage img(width, height, QImage::Format_Indexed8);
|
|
|
|
QVector<QRgb> green_palette = {
|
|
qRgb(15, 56, 15),
|
|
qRgb(48, 98, 48),
|
|
qRgb(139, 172, 15),
|
|
qRgb(155, 188, 15),
|
|
};
|
|
img.setColorTable(green_palette);
|
|
|
|
for (int y = 0; y < height; ++y) {
|
|
for (int x = 0; x < width; ++x) {
|
|
img.setPixel(x, y, bg_raw_data[y * width + x] % 4);
|
|
}
|
|
}
|
|
|
|
CAMLdrop;
|
|
return img;
|
|
}
|