Display maps from OCaml
This commit is contained in:
parent
d4e753a6e1
commit
35ea1690fe
|
@ -2,3 +2,4 @@ let () =
|
||||||
Callback.register "oboy_name" Version.name;
|
Callback.register "oboy_name" Version.name;
|
||||||
Callback.register "oboy_version" Version.version;
|
Callback.register "oboy_version" Version.version;
|
||||||
Callback.register "oboy_load" State.load_cartridge;
|
Callback.register "oboy_load" State.load_cartridge;
|
||||||
|
Callback.register "oboy_bg_map" Memory.background_map;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
; combine static pthread with dynamic libc
|
; combine static pthread with dynamic libc
|
||||||
(executable
|
(executable
|
||||||
(name cbindings)
|
(name cbindings)
|
||||||
|
(libraries bigarray)
|
||||||
(modes object))
|
(modes object))
|
||||||
|
|
||||||
; Standalone binary
|
; Standalone binary
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* LICENSE file at the top level directory of this source tree.
|
* LICENSE file at the top level directory of this source tree.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
open Bigarray
|
||||||
open Bytes
|
open Bytes
|
||||||
open Printf
|
open Printf
|
||||||
|
|
||||||
|
@ -107,3 +108,13 @@ let update_timers mem cycles =
|
||||||
(* TODO: INT 50 - Timer interupt *)
|
(* TODO: INT 50 - Timer interupt *)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let background_map () =
|
||||||
|
let bg_map = Array2.create Bigarray.int8_unsigned Bigarray.c_layout 8 8 in
|
||||||
|
Array2.fill bg_map 0;
|
||||||
|
for j = 0 to (Array2.dim2 bg_map) - 1 do
|
||||||
|
for i = 0 to (Array2.dim1 bg_map) - 1 do
|
||||||
|
bg_map.{i, j} <- (i + j * Array2.dim1 bg_map) mod 4
|
||||||
|
done
|
||||||
|
done;
|
||||||
|
bg_map
|
||||||
|
|
|
@ -12,8 +12,14 @@ Window {
|
||||||
maximumHeight: height
|
maximumHeight: height
|
||||||
minimumHeight: height
|
minimumHeight: height
|
||||||
|
|
||||||
BackgroundMapForm {
|
// BackgroundMapForm {
|
||||||
anchors.fill: parent
|
// anchors.fill: parent
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
Image {
|
||||||
|
source: "image://oboy/bg_map"
|
||||||
|
anchors.fill: parent
|
||||||
|
smooth: false
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
find_package(Qt5 COMPONENTS Core Quick REQUIRED)
|
find_package(Qt5 COMPONENTS Core Quick REQUIRED)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} "main.cpp" "oboy.cpp" "qml.qrc")
|
add_executable(${PROJECT_NAME} "main.cpp" "oboy.cpp" "oimageprovider.cpp" "qml.qrc")
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick)
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <caml/mlvalues.h>
|
|
||||||
#include <caml/callback.h>
|
|
||||||
|
|
||||||
#include "oboy.h"
|
#include "oboy.h"
|
||||||
|
#include "oimageprovider.h"
|
||||||
|
|
||||||
|
#include <caml/callback.h>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,7 @@ int main(int argc, char *argv[])
|
||||||
qmlRegisterType<OBoy>("com.oboy.oboy", 1, 0, "OBoy");
|
qmlRegisterType<OBoy>("com.oboy.oboy", 1, 0, "OBoy");
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
engine.addImageProvider(QLatin1String("oboy"), new OImageProvider(engine));
|
||||||
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||||
|
|
||||||
caml_main(argv);
|
caml_main(argv);
|
||||||
|
|
|
@ -27,6 +27,7 @@ ApplicationWindow {
|
||||||
title: qsTr("View")
|
title: qsTr("View")
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("Background maps")
|
text: qsTr("Background maps")
|
||||||
|
enabled: oboy.loaded
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
console.log("Background maps");
|
console.log("Background maps");
|
||||||
var component = Qt.createComponent("BackgroundMap.qml")
|
var component = Qt.createComponent("BackgroundMap.qml")
|
||||||
|
@ -52,6 +53,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
OBoy {
|
OBoy {
|
||||||
id: oboy
|
id: oboy
|
||||||
|
objectName: "qml_oboy"
|
||||||
}
|
}
|
||||||
|
|
||||||
MainForm {
|
MainForm {
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
#include "oboy.h"
|
#include "oboy.h"
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include <caml/mlvalues.h>
|
#include <caml/mlvalues.h>
|
||||||
#include <caml/callback.h>
|
#include <caml/callback.h>
|
||||||
#include <caml/alloc.h>
|
#include <caml/alloc.h>
|
||||||
|
#include <caml/bigarray.h>
|
||||||
#include <caml/memory.h>
|
#include <caml/memory.h>
|
||||||
#include <caml/misc.h>
|
#include <caml/misc.h>
|
||||||
#include <caml/osdeps.h>
|
#include <caml/osdeps.h>
|
||||||
|
|
||||||
OBoy::OBoy(QObject *parent) : QObject(parent)
|
OBoy::OBoy(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
// load("/Users/ffreling/Downloads/Super_Mario_Land.gb");
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// https://caml.inria.fr/pub/docs/manual-ocaml/intfc.html
|
||||||
|
@ -19,7 +30,7 @@ QString OBoy::name() const
|
||||||
{
|
{
|
||||||
CAMLparam0();
|
CAMLparam0();
|
||||||
|
|
||||||
value * closure_f = caml_named_value("oboy_name");
|
static value * closure_f = fetch_caml_callback("oboy_name");
|
||||||
if (closure_f == nullptr) {
|
if (closure_f == nullptr) {
|
||||||
CAMLdrop;
|
CAMLdrop;
|
||||||
return QString("<Unreachable>");
|
return QString("<Unreachable>");
|
||||||
|
@ -34,7 +45,7 @@ QString OBoy::version() const
|
||||||
{
|
{
|
||||||
CAMLparam0();
|
CAMLparam0();
|
||||||
|
|
||||||
value * closure_f = caml_named_value("oboy_version");
|
static value * closure_f = fetch_caml_callback("oboy_version");
|
||||||
if (closure_f == nullptr) {
|
if (closure_f == nullptr) {
|
||||||
CAMLdrop;
|
CAMLdrop;
|
||||||
return QString("<Unreachable>");
|
return QString("<Unreachable>");
|
||||||
|
@ -50,7 +61,7 @@ bool OBoy::load(const QString &path)
|
||||||
CAMLparam0();
|
CAMLparam0();
|
||||||
CAMLlocal1(ocaml_path) ;
|
CAMLlocal1(ocaml_path) ;
|
||||||
|
|
||||||
value * closure_f = caml_named_value("oboy_load");
|
static value * closure_f = fetch_caml_callback("oboy_load");
|
||||||
if (closure_f == nullptr) {
|
if (closure_f == nullptr) {
|
||||||
CAMLdrop;
|
CAMLdrop;
|
||||||
return false;
|
return false;
|
||||||
|
@ -72,3 +83,41 @@ bool OBoy::loaded() const
|
||||||
{
|
{
|
||||||
return _loaded;
|
return _loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage OBoy::backgroundMap() const
|
||||||
|
{
|
||||||
|
CAMLparam0();
|
||||||
|
|
||||||
|
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_unit));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
class OBoy : public QObject
|
class OBoy : public QObject
|
||||||
{
|
{
|
||||||
|
@ -8,6 +10,7 @@ class OBoy : public QObject
|
||||||
Q_PROPERTY(QString name READ name CONSTANT)
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
Q_PROPERTY(QString version READ version CONSTANT)
|
Q_PROPERTY(QString version READ version CONSTANT)
|
||||||
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
|
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
|
||||||
|
Q_PROPERTY(QImage backgroundMap READ backgroundMap CONSTANT)
|
||||||
public:
|
public:
|
||||||
explicit OBoy(QObject *parent = nullptr);
|
explicit OBoy(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
@ -15,6 +18,7 @@ public:
|
||||||
QString version() const;
|
QString version() const;
|
||||||
bool loaded() const;
|
bool loaded() const;
|
||||||
Q_INVOKABLE bool load(const QString &path);
|
Q_INVOKABLE bool load(const QString &path);
|
||||||
|
QImage backgroundMap() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loadedChanged(bool loaded);
|
void loadedChanged(bool loaded);
|
||||||
|
|
22
src/qt/oimageprovider.cpp
Normal file
22
src/qt/oimageprovider.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include "oimageprovider.h"
|
||||||
|
#include "oboy.h"
|
||||||
|
|
||||||
|
OImageProvider::OImageProvider(QQmlApplicationEngine &engine)
|
||||||
|
: QQuickImageProvider(QQuickImageProvider::Image)
|
||||||
|
, _engine(engine)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage OImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
|
||||||
|
{
|
||||||
|
QList<QObject*> roots = _engine.rootObjects();
|
||||||
|
OBoy *oboy = roots[0]->findChild<OBoy*>("qml_oboy");
|
||||||
|
if (!oboy) {
|
||||||
|
qFatal("Cannot find oboy instance.");
|
||||||
|
}
|
||||||
|
Q_ASSERT(oboy->loaded());
|
||||||
|
|
||||||
|
QImage img = oboy->backgroundMap();
|
||||||
|
return img;
|
||||||
|
}
|
14
src/qt/oimageprovider.h
Normal file
14
src/qt/oimageprovider.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQuickImageProvider>
|
||||||
|
|
||||||
|
class OImageProvider : public QQuickImageProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OImageProvider(QQmlApplicationEngine &engine);
|
||||||
|
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQmlApplicationEngine &_engine;
|
||||||
|
};
|
Loading…
Reference in a new issue