Display maps from OCaml

master
Fabien Freling 2019-07-05 14:20:17 +02:00
parent d4e753a6e1
commit 35ea1690fe
11 changed files with 121 additions and 10 deletions

View File

@ -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;

View File

@ -3,6 +3,7 @@
; combine static pthread with dynamic libc
(executable
(name cbindings)
(libraries bigarray)
(modes object))
; Standalone binary

View File

@ -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

View File

@ -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
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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 {

View File

@ -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;
}

View File

@ -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
View 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
View 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;
};