--- a/qmlfrontend/CMakeLists.txt Tue Nov 06 16:40:54 2018 +0300
+++ b/qmlfrontend/CMakeLists.txt Tue Nov 06 17:00:35 2018 +0100
@@ -8,6 +8,13 @@
find_package(Qt5 COMPONENTS Core Quick REQUIRED)
-add_executable(${PROJECT_NAME} "main.cpp" "qml.qrc")
+add_executable(${PROJECT_NAME} "main.cpp" "qml.qrc"
+ "hwengine.cpp" "hwengine.h"
+ "gameconfig.cpp" "gameconfig.h"
+ "runqueue.cpp" "runqueue.h"
+ "gameview.cpp" "gameview.h"
+ "team.cpp" "team.h"
+ "previewimageprovider.cpp" "previewimageprovider.h"
+ "flib.h")
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick)
--- a/qmlfrontend/Page1.qml Tue Nov 06 16:40:54 2018 +0300
+++ b/qmlfrontend/Page1.qml Tue Nov 06 17:00:35 2018 +0100
@@ -1,7 +1,24 @@
import QtQuick 2.7
+import Hedgewars.Engine 1.0
Page1Form {
+ tickButton.onClicked: {
+ item1.tick(100)
+ }
+ gameButton.onClicked: {
+ HWEngine.runQuickGame()
+ }
button1.onClicked: {
- console.log("Button Pressed. Entered text: " + textField1.text);
+ HWEngine.getPreview()
+ }
+
+ Connections {
+ target: HWEngine
+ onPreviewImageChanged: {
+ previewImage.source = "image://preview/image"
+ }
+ onPreviewIsRendering: {
+ previewImage.source = "qrc:/res/iconTime.png"
+ }
}
}
--- a/qmlfrontend/Page1Form.ui.qml Tue Nov 06 16:40:54 2018 +0300
+++ b/qmlfrontend/Page1Form.ui.qml Tue Nov 06 17:00:35 2018 +0100
@@ -2,23 +2,53 @@
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
+import Hedgewars.Engine 1.0
+
Item {
- property alias textField1: textField1
property alias button1: button1
+ property alias previewImage: previewImage
+ property alias gameButton: gameButton
+ width: 1024
+ height: 800
+ property alias tickButton: tickButton
+ property alias item1: item1
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: 20
anchors.top: parent.top
- TextField {
- id: textField1
- placeholderText: qsTr("Text Field")
+ Button {
+ id: button1
+ text: qsTr("Preview")
+ }
+
+ Button {
+ id: gameButton
+ text: qsTr("Game")
}
Button {
- id: button1
- text: qsTr("Press Me")
+ id: tickButton
+ text: qsTr("Tick")
}
}
+
+ Image {
+ id: previewImage
+ x: 8
+ y: 20
+ width: 256
+ height: 128
+ source: "qrc:/res/iconTime.png"
+ cache: false
+ }
+
+ GameView {
+ id: item1
+ x: 8
+ y: 154
+ width: 1008
+ height: 638
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/flib.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,47 @@
+#ifndef FLIB_H
+#define FLIB_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum MessageType {
+ MSG_PREVIEW,
+ MSG_PREVIEWHOGCOUNT,
+ MSG_TONET,
+ MSG_GAMEFINISHED,
+};
+
+typedef union string255_ {
+ struct {
+ unsigned char s[256];
+ };
+ struct {
+ unsigned char len;
+ unsigned char str[255];
+ };
+} string255;
+
+typedef void RunEngine_t(int argc, const char** argv);
+typedef void GameTick_t(uint32_t time_delta);
+typedef void ResizeWindow_t(uint32_t width, uint32_t height);
+typedef void ipcToEngineRaw_t(const char* msg, uint32_t len);
+typedef void ipcSetEngineBarrier_t();
+typedef void ipcRemoveBarrierFromEngineQueue_t();
+typedef bool updateMousePosition_t(int32_t centerX, int32_t centerY, int32_t x,
+ int32_t y);
+
+typedef void registerUIMessagesCallback_t(
+ void* context,
+ void (*)(void* context, MessageType mt, const char* msg, uint32_t len));
+typedef void flibInit_t(const char* localPrefix, const char* userPrefix);
+typedef void flibFree_t();
+typedef void passFlibEvent_t(const char* data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // FLIB_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/gameconfig.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,81 @@
+#include "gameconfig.h"
+
+GameConfig::GameConfig() : m_isPreview(true) { setPreview(m_isPreview); }
+
+const char** GameConfig::argv() const {
+ m_argv.resize(m_arguments.size());
+
+ for (int i = 0; i < m_arguments.size(); ++i)
+ m_argv[i] = m_arguments[i].data();
+
+ return m_argv.data();
+}
+
+int GameConfig::argc() const { return m_arguments.size(); }
+
+const QList<QByteArray> GameConfig::config() const {
+ QList<QByteArray> cfg = m_cfg;
+ cfg.append("\x01!");
+ return cfg;
+}
+
+void GameConfig::clear() {
+ m_arguments.clear();
+ m_cfg.clear();
+}
+
+void GameConfig::cmdSeed(const QByteArray& seed) { cfgAppend("eseed " + seed); }
+
+void GameConfig::cmdTheme(const QByteArray& theme) {
+ cfgAppend("e$theme " + theme);
+}
+
+void GameConfig::cmdMapgen(int mapgen) {
+ cfgAppend("e$mapgen " + QByteArray::number(mapgen));
+}
+
+void GameConfig::cmdTeam(const Team& team) {
+ cfgAppend("eaddteam <hash> " + team.color + " " + team.name);
+
+ for (const Hedgehog& h : team.hedgehogs()) {
+ cfgAppend("eaddhh " + QByteArray::number(h.level) + " " +
+ QByteArray::number(h.hp) + " " + h.name);
+ cfgAppend("ehat " + h.hat);
+ }
+ cfgAppend(
+ "eammloadt 9391929422199121032235111001200000000211100101011111000102");
+ cfgAppend(
+ "eammprob 0405040541600655546554464776576666666155510101115411111114");
+ cfgAppend(
+ "eammdelay 0000000000000205500000040007004000000000220000000600020000");
+ cfgAppend(
+ "eammreinf 1311110312111111123114111111111111111211111111111111111111");
+ cfgAppend("eammstore");
+}
+
+bool GameConfig::isPreview() const { return m_isPreview; }
+
+void GameConfig::setPreview(bool isPreview) {
+ m_isPreview = isPreview;
+
+ m_arguments.clear();
+
+ if (m_isPreview) {
+ m_arguments << ""
+ << "--internal"
+ << "--landpreview";
+
+ } else {
+ m_arguments << ""
+ << "--internal"
+ << "--nomusic";
+ }
+}
+
+void GameConfig::cfgAppend(const QByteArray& cmd) {
+ Q_ASSERT(cmd.size() < 256);
+
+ quint8 len = cmd.size();
+ m_cfg.append(QByteArray::fromRawData(reinterpret_cast<const char*>(&len), 1) +
+ cmd);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/gameconfig.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,36 @@
+#ifndef GAMECONFIG_H
+#define GAMECONFIG_H
+
+#include <QList>
+#include <QVector>
+
+#include "team.h"
+
+class GameConfig {
+ public:
+ explicit GameConfig();
+
+ const char** argv() const;
+ int argc() const;
+ const QList<QByteArray> config() const;
+
+ void clear();
+ void cmdSeed(const QByteArray& seed);
+ void cmdTheme(const QByteArray& theme);
+ void cmdMapgen(int mapgen);
+ void cmdTeam(const Team& team);
+
+ bool isPreview() const;
+ void setPreview(bool isPreview);
+
+ private:
+ mutable QVector<const char*> m_argv;
+ QList<QByteArray> m_arguments;
+ QList<QByteArray> m_cfg;
+ QList<Team> m_teams;
+ bool m_isPreview;
+
+ void cfgAppend(const QByteArray& cmd);
+};
+
+#endif // GAMECONFIG_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/gameview.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,87 @@
+#include "gameview.h"
+
+#include <QtQuick/qquickwindow.h>
+#include <QCursor>
+#include <QTimer>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLShaderProgram>
+
+#include "flib.h"
+
+extern "C" {
+extern GameTick_t* flibGameTick;
+extern ResizeWindow_t* flibResizeWindow;
+extern updateMousePosition_t* flibUpdateMousePosition;
+}
+
+GameView::GameView() : m_delta(0), m_renderer(nullptr), m_windowChanged(true) {
+ connect(this, &QQuickItem::windowChanged, this,
+ &GameView::handleWindowChanged);
+}
+
+void GameView::tick(quint32 delta) {
+ m_delta = delta;
+
+ if (window()) {
+ QTimer* timer = new QTimer(this);
+ connect(timer, &QTimer::timeout, window(), &QQuickWindow::update);
+ timer->start(100);
+
+ // window()->update();
+ }
+}
+
+void GameView::handleWindowChanged(QQuickWindow* win) {
+ if (win) {
+ connect(win, &QQuickWindow::beforeSynchronizing, this, &GameView::sync,
+ Qt::DirectConnection);
+ connect(win, &QQuickWindow::sceneGraphInvalidated, this, &GameView::cleanup,
+ Qt::DirectConnection);
+
+ win->setClearBeforeRendering(false);
+
+ m_windowChanged = true;
+ }
+}
+
+void GameView::cleanup() {
+ if (m_renderer) {
+ delete m_renderer;
+ m_renderer = 0;
+ }
+}
+
+void GameView::sync() {
+ if (!m_renderer) {
+ m_renderer = new GameViewRenderer();
+ connect(window(), &QQuickWindow::beforeRendering, m_renderer,
+ &GameViewRenderer::paint, Qt::DirectConnection);
+ }
+
+ if (m_windowChanged) {
+ QSize windowSize = window()->size();
+ m_renderer->setViewportSize(windowSize * window()->devicePixelRatio());
+ m_centerX = windowSize.width() / 2;
+ m_centerY = windowSize.height() / 2;
+ }
+
+ QPoint mousePos = mapFromGlobal(QCursor::pos()).toPoint();
+ if (flibUpdateMousePosition(m_centerX, m_centerY, mousePos.x(), mousePos.y()))
+ QCursor::setPos(mapToGlobal(QPointF(m_centerX, m_centerY)).toPoint());
+
+ m_renderer->tick(m_delta);
+}
+
+GameViewRenderer::~GameViewRenderer() {}
+
+void GameViewRenderer::setViewportSize(const QSize& size) {
+ flibResizeWindow(size.width(), size.height());
+}
+
+void GameViewRenderer::paint() {
+ if (m_delta == 0) return;
+
+ flibGameTick(m_delta);
+
+ // m_window->resetOpenGLState();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/gameview.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,51 @@
+#ifndef GAMEVIEW_H
+#define GAMEVIEW_H
+
+#include <QQuickItem>
+
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLShaderProgram>
+
+class GameViewRenderer : public QObject, protected QOpenGLFunctions {
+ Q_OBJECT
+ public:
+ GameViewRenderer() : m_delta(0) {}
+ ~GameViewRenderer();
+
+ void tick(quint32 delta) { m_delta = delta; }
+ void setViewportSize(const QSize& size);
+
+ public slots:
+ void paint();
+
+ private:
+ quint32 m_delta;
+};
+
+class GameView : public QQuickItem {
+ Q_OBJECT
+
+ public:
+ GameView();
+
+ Q_INVOKABLE void tick(quint32 delta);
+
+ signals:
+ void tChanged();
+
+ public slots:
+ void sync();
+ void cleanup();
+
+ private slots:
+ void handleWindowChanged(QQuickWindow* win);
+
+ private:
+ quint32 m_delta;
+ GameViewRenderer* m_renderer;
+ bool m_windowChanged;
+ qint32 m_centerX;
+ qint32 m_centerY;
+};
+
+#endif // GAMEVIEW_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/hwengine.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,146 @@
+#include "hwengine.h"
+
+#include <QDebug>
+#include <QLibrary>
+#include <QQmlEngine>
+#include <QUuid>
+
+#include "gameview.h"
+#include "previewimageprovider.h"
+#include "runqueue.h"
+
+extern "C" {
+RunEngine_t* flibRunEngine;
+GameTick_t* flibGameTick;
+ResizeWindow_t* flibResizeWindow;
+updateMousePosition_t* flibUpdateMousePosition;
+ipcToEngineRaw_t* flibIpcToEngineRaw;
+ipcSetEngineBarrier_t* flibIpcSetEngineBarrier;
+ipcRemoveBarrierFromEngineQueue_t* flibIpcRemoveBarrierFromEngineQueue;
+registerUIMessagesCallback_t* flibRegisterUIMessagesCallback;
+flibInit_t* flibInit;
+flibFree_t* flibFree;
+passFlibEvent_t* flibPassFlibEvent;
+}
+
+HWEngine::HWEngine(QQmlEngine* engine, QObject* parent)
+ : QObject(parent),
+ m_engine(engine),
+ m_previewProvider(new PreviewImageProvider()),
+ m_runQueue(new RunQueue(this)) {
+ qRegisterMetaType<MessageType>("MessageType");
+
+#ifdef Q_OS_WIN
+ QLibrary hwlib("./libhwengine.dll");
+#else
+ QLibrary hwlib("./libhwengine.so");
+#endif
+
+ if (!hwlib.load())
+ qWarning() << "Engine library not found" << hwlib.errorString();
+
+ flibRunEngine = (RunEngine_t*)hwlib.resolve("RunEngine");
+ flibGameTick = (GameTick_t*)hwlib.resolve("GameTick");
+ flibResizeWindow = (ResizeWindow_t*)hwlib.resolve("ResizeWindow");
+ flibUpdateMousePosition =
+ (updateMousePosition_t*)hwlib.resolve("updateMousePosition");
+ flibIpcToEngineRaw = (ipcToEngineRaw_t*)hwlib.resolve("ipcToEngineRaw");
+ flibIpcSetEngineBarrier =
+ (ipcSetEngineBarrier_t*)hwlib.resolve("ipcSetEngineBarrier");
+ flibIpcRemoveBarrierFromEngineQueue =
+ (ipcRemoveBarrierFromEngineQueue_t*)hwlib.resolve(
+ "ipcRemoveBarrierFromEngineQueue");
+ flibRegisterUIMessagesCallback = (registerUIMessagesCallback_t*)hwlib.resolve(
+ "registerUIMessagesCallback");
+ flibInit = (flibInit_t*)hwlib.resolve("flibInit");
+ flibFree = (flibFree_t*)hwlib.resolve("flibFree");
+
+ flibInit("/usr/home/unC0Rr/Sources/Hedgewars/MainRepo/share/hedgewars/Data",
+ "/usr/home/unC0Rr/.hedgewars");
+ flibRegisterUIMessagesCallback(this, &guiMessagesCallback);
+
+ m_engine->addImageProvider(QLatin1String("preview"), m_previewProvider);
+
+ connect(m_runQueue, &RunQueue::previewIsRendering, this,
+ &HWEngine::previewIsRendering);
+ connect(this, &HWEngine::gameFinished, m_runQueue, &RunQueue::onGameFinished);
+}
+
+HWEngine::~HWEngine() { flibFree(); }
+
+static QObject* hwengine_singletontype_provider(QQmlEngine* engine,
+ QJSEngine* scriptEngine) {
+ Q_UNUSED(scriptEngine)
+
+ HWEngine* hwengine = new HWEngine(engine);
+ return hwengine;
+}
+
+void HWEngine::exposeToQML() {
+ qDebug("HWEngine::exposeToQML");
+ qmlRegisterSingletonType<HWEngine>("Hedgewars.Engine", 1, 0, "HWEngine",
+ hwengine_singletontype_provider);
+ qmlRegisterType<GameView>("Hedgewars.Engine", 1, 0, "GameView");
+}
+
+void HWEngine::guiMessagesCallback(void* context, MessageType mt,
+ const char* msg, uint32_t len) {
+ HWEngine* obj = reinterpret_cast<HWEngine*>(context);
+ QByteArray b = QByteArray(msg, len);
+
+ qDebug() << "FLIPC in" << mt << " size = " << b.size();
+
+ QMetaObject::invokeMethod(obj, "engineMessageHandler", Qt::QueuedConnection,
+ Q_ARG(MessageType, mt), Q_ARG(QByteArray, b));
+}
+
+void HWEngine::engineMessageHandler(MessageType mt, const QByteArray& msg) {
+ switch (mt) {
+ case MSG_PREVIEW: {
+ qDebug("MSG_PREVIEW");
+ m_previewProvider->setPixmap(msg);
+ emit previewImageChanged();
+ break;
+ }
+ case MSG_PREVIEWHOGCOUNT: {
+ qDebug("MSG_PREVIEWHOGCOUNT");
+ m_previewHedgehogsCount = static_cast<quint8>(msg.data()[0]);
+ emit previewHogCountChanged(m_previewHedgehogsCount);
+ break;
+ }
+ case MSG_TONET: {
+ qDebug("MSG_TONET");
+ break;
+ }
+ case MSG_GAMEFINISHED: {
+ qDebug("MSG_GAMEFINISHED");
+ emit gameFinished();
+ break;
+ }
+ }
+}
+
+void HWEngine::getPreview() {
+ m_seed = QUuid::createUuid().toByteArray();
+ m_gameConfig.cmdSeed(m_seed);
+ m_gameConfig.setPreview(true);
+
+ m_runQueue->queue(m_gameConfig);
+}
+
+void HWEngine::runQuickGame() {
+ m_gameConfig.cmdSeed(m_seed);
+ m_gameConfig.cmdTheme("Nature");
+ Team team1;
+ team1.name = "team1";
+ Team team2;
+ team2.name = "team2";
+ team2.color = "7654321";
+ m_gameConfig.cmdTeam(team1);
+ m_gameConfig.cmdTeam(team2);
+ m_gameConfig.setPreview(false);
+
+ m_runQueue->queue(m_gameConfig);
+}
+
+int HWEngine::previewHedgehogsCount() const { return m_previewHedgehogsCount; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/hwengine.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,53 @@
+#ifndef HWENGINE_H
+#define HWENGINE_H
+
+#include <QList>
+#include <QObject>
+
+#include "flib.h"
+#include "gameconfig.h"
+
+class QQmlEngine;
+class PreviewImageProvider;
+class RunQueue;
+
+class HWEngine : public QObject {
+ Q_OBJECT
+
+ Q_PROPERTY(int previewHedgehogsCount READ previewHedgehogsCount NOTIFY
+ previewHedgehogsCountChanged)
+
+ public:
+ explicit HWEngine(QQmlEngine* engine, QObject* parent = nullptr);
+ ~HWEngine();
+
+ static void exposeToQML();
+
+ Q_INVOKABLE void getPreview();
+ Q_INVOKABLE void runQuickGame();
+
+ int previewHedgehogsCount() const;
+
+ signals:
+ void previewIsRendering();
+ void previewImageChanged();
+ void previewHogCountChanged(int count);
+ void gameFinished();
+ void previewHedgehogsCountChanged(int previewHedgehogsCount);
+
+ private:
+ QQmlEngine* m_engine;
+ PreviewImageProvider* m_previewProvider;
+ RunQueue* m_runQueue;
+ GameConfig m_gameConfig;
+ QByteArray m_seed;
+ int m_previewHedgehogsCount;
+
+ static void guiMessagesCallback(void* context, MessageType mt,
+ const char* msg, uint32_t len);
+
+ private slots:
+ void engineMessageHandler(MessageType mt, const QByteArray& msg);
+};
+
+#endif // HWENGINE_H
--- a/qmlfrontend/main.cpp Tue Nov 06 16:40:54 2018 +0300
+++ b/qmlfrontend/main.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -1,15 +1,18 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
-int main(int argc, char *argv[])
-{
+#include "hwengine.h"
+
+int main(int argc, char* argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
+
+ HWEngine::exposeToQML();
+
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
- if (engine.rootObjects().isEmpty())
- return -1;
+ if (engine.rootObjects().isEmpty()) return -1;
return app.exec();
}
--- a/qmlfrontend/main.qml Tue Nov 06 16:40:54 2018 +0300
+++ b/qmlfrontend/main.qml Tue Nov 06 17:00:35 2018 +0100
@@ -11,27 +11,8 @@
SwipeView {
id: swipeView
anchors.fill: parent
- currentIndex: tabBar.currentIndex
Page1 {
}
-
- Page {
- Label {
- text: qsTr("Second page")
- anchors.centerIn: parent
- }
- }
- }
-
- footer: TabBar {
- id: tabBar
- currentIndex: swipeView.currentIndex
- TabButton {
- text: qsTr("First")
- }
- TabButton {
- text: qsTr("Second")
- }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/previewimageprovider.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,31 @@
+#include "previewimageprovider.h"
+
+PreviewImageProvider::PreviewImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Pixmap) {}
+
+QPixmap PreviewImageProvider::requestPixmap(const QString &id, QSize *size,
+ const QSize &requestedSize) {
+ Q_UNUSED(id);
+ Q_UNUSED(requestedSize);
+
+ if (size) *size = m_px.size();
+
+ return m_px;
+}
+
+void PreviewImageProvider::setPixmap(const QByteArray &px) {
+ QVector<QRgb> colorTable;
+ colorTable.resize(256);
+ for (int i = 0; i < 256; ++i) colorTable[i] = qRgba(255, 255, 0, i);
+
+ const quint8 *buf = (const quint8 *)px.constData();
+ QImage im(buf, 256, 128, QImage::Format_Indexed8);
+ im.setColorTable(colorTable);
+
+ m_px = QPixmap::fromImage(im, Qt::ColorOnly);
+ // QPixmap pxres(px.size());
+ // QPainter p(&pxres);
+
+ // p.fillRect(pxres.rect(), linearGrad);
+ // p.drawPixmap(0, 0, px);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/previewimageprovider.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,21 @@
+#ifndef PREVIEWIMAGEPROVIDER_H
+#define PREVIEWIMAGEPROVIDER_H
+
+#include <QPixmap>
+#include <QQuickImageProvider>
+#include <QSize>
+
+class PreviewImageProvider : public QQuickImageProvider {
+ public:
+ PreviewImageProvider();
+
+ QPixmap requestPixmap(const QString &id, QSize *size,
+ const QSize &requestedSize);
+
+ void setPixmap(const QByteArray &px);
+
+ private:
+ QPixmap m_px;
+};
+
+#endif // PREVIEWIMAGEPROVIDER_H
--- a/qmlfrontend/qml.qrc Tue Nov 06 16:40:54 2018 +0300
+++ b/qmlfrontend/qml.qrc Tue Nov 06 17:00:35 2018 +0100
@@ -1,9 +1,9 @@
-<!DOCTYPE RCC>
-<RCC version="1.0">
+<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>Page1.qml</file>
<file>Page1Form.ui.qml</file>
<file>qtquickcontrols2.conf</file>
+ <file>res/iconTime.png</file>
</qresource>
</RCC>
Binary file qmlfrontend/res/iconTime.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/runqueue.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,47 @@
+#include "runqueue.h"
+
+#include "flib.h"
+
+extern "C" {
+extern RunEngine_t* flibRunEngine;
+extern ipcToEngineRaw_t* flibIpcToEngineRaw;
+extern ipcSetEngineBarrier_t* flibIpcSetEngineBarrier;
+extern ipcRemoveBarrierFromEngineQueue_t* flibIpcRemoveBarrierFromEngineQueue;
+}
+
+RunQueue::RunQueue(QObject* parent)
+ : QObject(parent)
+{
+}
+
+void RunQueue::queue(const GameConfig& config)
+{
+ m_runQueue.prepend(config);
+
+ flibIpcSetEngineBarrier();
+ for (const QByteArray& b : m_runQueue.last().config()) {
+ flibIpcToEngineRaw(b.data(), b.size());
+ }
+
+ if (m_runQueue.size() == 1)
+ nextRun();
+}
+
+void RunQueue::onGameFinished()
+{
+ m_runQueue.pop_front();
+
+ nextRun();
+}
+
+void RunQueue::nextRun()
+{
+ if (!m_runQueue.isEmpty()) {
+ if (m_runQueue[0].isPreview())
+ emit previewIsRendering();
+
+ flibIpcRemoveBarrierFromEngineQueue();
+
+ flibRunEngine(m_runQueue[0].argc(), m_runQueue[0].argv());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/runqueue.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,27 @@
+#ifndef RUNQUEUE_H
+#define RUNQUEUE_H
+
+#include <QObject>
+
+#include "gameconfig.h"
+
+class RunQueue : public QObject {
+ Q_OBJECT
+public:
+ explicit RunQueue(QObject* parent = nullptr);
+
+ void queue(const GameConfig& config);
+
+signals:
+ void previewIsRendering();
+
+public slots:
+ void onGameFinished();
+
+private:
+ QList<GameConfig> m_runQueue;
+
+ void nextRun();
+};
+
+#endif // RUNQUEUE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/team.cpp Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,27 @@
+#include "team.h"
+
+Hedgehog::Hedgehog()
+ : name(QObject::tr("unnamed", "default hedgehog name").toUtf8())
+ , hat("NoHat")
+ , hp(100)
+ , level(0)
+{
+}
+
+Team::Team()
+ : name(QObject::tr("unnamed", "default team name").toUtf8())
+ , color("12345678")
+ , m_hedgehogsNumber(4)
+{
+ m_hedgehogs.resize(8);
+}
+
+void Team::resize(int number)
+{
+ m_hedgehogsNumber = number;
+}
+
+QVector<Hedgehog> Team::hedgehogs() const
+{
+ return m_hedgehogs.mid(0, m_hedgehogsNumber);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/team.h Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,31 @@
+#ifndef TEAM_H
+#define TEAM_H
+
+#include <QObject>
+#include <QVector>
+
+struct Hedgehog {
+ Hedgehog();
+
+ QByteArray name;
+ QByteArray hat;
+ quint32 hp;
+ int level;
+};
+
+class Team {
+public:
+ explicit Team();
+
+ void resize(int number);
+ QVector<Hedgehog> hedgehogs() const;
+
+ QByteArray name;
+ QByteArray color;
+
+private:
+ QVector<Hedgehog> m_hedgehogs;
+ int m_hedgehogsNumber;
+};
+
+#endif // TEAM_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hedgewars-engine/Cargo.toml Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,7 @@
+[package]
+name = "hedgewars-engine"
+version = "0.1.0"
+authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
+
+[dependencies]
+land2d = { path = "../land2d" }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hedgewars-engine/src/lib.rs Tue Nov 06 17:00:35 2018 +0100
@@ -0,0 +1,18 @@
+#[repr(C)]
+pub struct Preview {
+ width: u32,
+ height: u32,
+ hedgehogs_number: u8,
+ land: *const u8,
+}
+
+
+#[no_mangle]
+pub extern "C" fn protocol_version() -> u32 {
+ 56
+}
+
+#[no_mangle]
+pub extern "C" fn generate_preview () -> Preview {
+ unimplemented!()
+}