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_version" Version.version;
|
||||
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
|
||||
(executable
|
||||
(name cbindings)
|
||||
(libraries bigarray)
|
||||
(modes object))
|
||||
|
||||
; Standalone binary
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* LICENSE file at the top level directory of this source tree.
|
||||
*)
|
||||
|
||||
open Bigarray
|
||||
open Bytes
|
||||
open Printf
|
||||
|
||||
|
@ -107,3 +108,13 @@ let update_timers mem cycles =
|
|||
(* TODO: INT 50 - Timer interupt *)
|
||||
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
|
||||
minimumHeight: height
|
||||
|
||||
BackgroundMapForm {
|
||||
anchors.fill: parent
|
||||
}
|
||||
// BackgroundMapForm {
|
||||
// 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)
|
||||
|
||||
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_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Quick)
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <caml/mlvalues.h>
|
||||
#include <caml/callback.h>
|
||||
|
||||
#include "oboy.h"
|
||||
#include "oimageprovider.h"
|
||||
|
||||
#include <caml/callback.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -16,6 +16,7 @@ int main(int argc, char *argv[])
|
|||
qmlRegisterType<OBoy>("com.oboy.oboy", 1, 0, "OBoy");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
engine.addImageProvider(QLatin1String("oboy"), new OImageProvider(engine));
|
||||
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
|
||||
|
||||
caml_main(argv);
|
||||
|
|
|
@ -27,6 +27,7 @@ ApplicationWindow {
|
|||
title: qsTr("View")
|
||||
MenuItem {
|
||||
text: qsTr("Background maps")
|
||||
enabled: oboy.loaded
|
||||
onTriggered: {
|
||||
console.log("Background maps");
|
||||
var component = Qt.createComponent("BackgroundMap.qml")
|
||||
|
@ -52,6 +53,7 @@ ApplicationWindow {
|
|||
|
||||
OBoy {
|
||||
id: oboy
|
||||
objectName: "qml_oboy"
|
||||
}
|
||||
|
||||
MainForm {
|
||||
|
|
|
@ -1,15 +1,26 @@
|
|||
#include "oboy.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <caml/mlvalues.h>
|
||||
#include <caml/callback.h>
|
||||
#include <caml/alloc.h>
|
||||
#include <caml/bigarray.h>
|
||||
#include <caml/memory.h>
|
||||
#include <caml/misc.h>
|
||||
#include <caml/osdeps.h>
|
||||
|
||||
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
|
||||
|
@ -19,7 +30,7 @@ QString OBoy::name() const
|
|||
{
|
||||
CAMLparam0();
|
||||
|
||||
value * closure_f = caml_named_value("oboy_name");
|
||||
static value * closure_f = fetch_caml_callback("oboy_name");
|
||||
if (closure_f == nullptr) {
|
||||
CAMLdrop;
|
||||
return QString("<Unreachable>");
|
||||
|
@ -34,7 +45,7 @@ QString OBoy::version() const
|
|||
{
|
||||
CAMLparam0();
|
||||
|
||||
value * closure_f = caml_named_value("oboy_version");
|
||||
static value * closure_f = fetch_caml_callback("oboy_version");
|
||||
if (closure_f == nullptr) {
|
||||
CAMLdrop;
|
||||
return QString("<Unreachable>");
|
||||
|
@ -50,7 +61,7 @@ bool OBoy::load(const QString &path)
|
|||
CAMLparam0();
|
||||
CAMLlocal1(ocaml_path) ;
|
||||
|
||||
value * closure_f = caml_named_value("oboy_load");
|
||||
static value * closure_f = fetch_caml_callback("oboy_load");
|
||||
if (closure_f == nullptr) {
|
||||
CAMLdrop;
|
||||
return false;
|
||||
|
@ -72,3 +83,41 @@ bool OBoy::loaded() const
|
|||
{
|
||||
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
|
||||
|
||||
#include <QObject>
|
||||
#include <QImage>
|
||||
#include <QString>
|
||||
|
||||
class OBoy : public QObject
|
||||
{
|
||||
|
@ -8,6 +10,7 @@ class OBoy : public QObject
|
|||
Q_PROPERTY(QString name READ name CONSTANT)
|
||||
Q_PROPERTY(QString version READ version CONSTANT)
|
||||
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
|
||||
Q_PROPERTY(QImage backgroundMap READ backgroundMap CONSTANT)
|
||||
public:
|
||||
explicit OBoy(QObject *parent = nullptr);
|
||||
|
||||
|
@ -15,6 +18,7 @@ public:
|
|||
QString version() const;
|
||||
bool loaded() const;
|
||||
Q_INVOKABLE bool load(const QString &path);
|
||||
QImage backgroundMap() const;
|
||||
|
||||
signals:
|
||||
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