Some refactoring of qmlfrontend. It now shows land preview generated by hedgewars-engine
authorunC0Rr
Wed, 07 Nov 2018 15:59:51 +0100
changeset 14159 8354b390f1a2
parent 14158 b273b43b16d2
child 14160 8f82d87d223f
Some refactoring of qmlfrontend. It now shows land preview generated by hedgewars-engine
.hgignore
qmlfrontend/CMakeLists.txt
qmlfrontend/Page1.qml
qmlfrontend/Page1Form.ui.qml
qmlfrontend/engine_instance.cpp
qmlfrontend/engine_instance.h
qmlfrontend/engine_interface.h
qmlfrontend/flib.h
qmlfrontend/game_config.cpp
qmlfrontend/game_config.h
qmlfrontend/game_view.cpp
qmlfrontend/game_view.h
qmlfrontend/gameconfig.cpp
qmlfrontend/gameconfig.h
qmlfrontend/gameview.cpp
qmlfrontend/gameview.h
qmlfrontend/hwengine.cpp
qmlfrontend/hwengine.h
qmlfrontend/main.cpp
qmlfrontend/preview_image_provider.cpp
qmlfrontend/preview_image_provider.h
qmlfrontend/previewimageprovider.cpp
qmlfrontend/previewimageprovider.h
qmlfrontend/runqueue.cpp
qmlfrontend/runqueue.h
rust/hedgewars-engine/src/world.rs
--- a/.hgignore	Wed Nov 07 15:55:32 2018 +0100
+++ b/.hgignore	Wed Nov 07 15:59:51 2018 +0100
@@ -16,7 +16,6 @@
 *.ppu
 *.*~
 *.core
-hedgewars.pro.user
 config.inc
 cmake_install.cmake
 QTfrontend/hwconsts.cpp
@@ -83,8 +82,10 @@
 xcuserdata
 *.mode1v3
 *.mode2v3
-gameServer2/target
-gameServer2/Cargo.lock
-gameServer2/gameServer2.iml
 .idea
 Testing/
+rust/*/target
+*.lock
+*.user
+*.iml
+build-qmlfrontend*
--- a/qmlfrontend/CMakeLists.txt	Wed Nov 07 15:55:32 2018 +0100
+++ b/qmlfrontend/CMakeLists.txt	Wed Nov 07 15:59:51 2018 +0100
@@ -10,11 +10,10 @@
 
 add_executable(${PROJECT_NAME} "main.cpp" "qml.qrc"
     "hwengine.cpp" "hwengine.h"
-    "gameconfig.cpp" "gameconfig.h"
-    "runqueue.cpp" "runqueue.h"
-    "gameview.cpp" "gameview.h"
+    "game_config.cpp" "game_config.h"
     "team.cpp" "team.h"
-    "previewimageprovider.cpp" "previewimageprovider.h"
-    "flib.h")
+    "engine_instance.cpp" "engine_instance.h"
+    "preview_image_provider.cpp" "preview_image_provider.h"
+    "engine_interface.h")
 
 target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick)
--- a/qmlfrontend/Page1.qml	Wed Nov 07 15:55:32 2018 +0100
+++ b/qmlfrontend/Page1.qml	Wed Nov 07 15:59:51 2018 +0100
@@ -3,7 +3,8 @@
 
 Page1Form {
   tickButton.onClicked: {
-    item1.tick(100)
+
+    //    item1.tick(100)
   }
   gameButton.onClicked: {
     HWEngine.runQuickGame()
--- a/qmlfrontend/Page1Form.ui.qml	Wed Nov 07 15:55:32 2018 +0100
+++ b/qmlfrontend/Page1Form.ui.qml	Wed Nov 07 15:59:51 2018 +0100
@@ -5,45 +5,75 @@
 import Hedgewars.Engine 1.0
 
 Item {
-    property alias button1: button1
-    property alias previewImage: previewImage
-    property alias gameButton: gameButton
-    width: 1024
-    height: 800
-    property alias tickButton: tickButton
-    property alias item1: item1
+  property alias button1: button1
+  property alias previewImage: previewImage
+  property alias gameButton: gameButton
+  width: 1024
+  height: 800
+  property alias tickButton: tickButton
+
+  //property alias item1: item1
+  ColumnLayout {
+    anchors.fill: parent
 
     RowLayout {
-        anchors.horizontalCenter: parent.horizontalCenter
-        anchors.topMargin: 20
-        anchors.top: parent.top
+      Layout.alignment: Qt.AlignHCenter
 
-        Button {
-            id: button1
-            text: qsTr("Preview")
-        }
+      Button {
+        id: button1
+        text: qsTr("Preview")
+      }
 
-        Button {
-            id: gameButton
-            text: qsTr("Game")
-        }
+      Button {
+        id: gameButton
+        text: qsTr("Game")
+      }
 
-        Button {
-            id: tickButton
-            text: qsTr("Tick")
-        }
+      Button {
+        id: tickButton
+        text: qsTr("Tick")
+      }
     }
 
-    Image {
+    Rectangle {
+      border.color: "orange"
+      border.width: 5
+      radius: 5
+
+      Layout.fillWidth: true
+      Layout.fillHeight: true
+
+      gradient: Gradient {
+        GradientStop {
+          position: 0
+          color: "lightblue"
+        }
+        GradientStop {
+          position: 0.9
+          color: "blue"
+        }
+        GradientStop {
+          position: 0.9
+          color: "darkblue"
+        }
+        GradientStop {
+          position: 1.0
+          color: "darkblue"
+        }
+      }
+
+      Image {
         id: previewImage
-        x: 8
-        y: 20
-        width: 256
-        height: 128
+
+        anchors.fill: parent
+        anchors.margins: parent.radius
         source: "qrc:/res/iconTime.png"
+        fillMode: Image.PreserveAspectFit
         cache: false
+      }
     }
-
+  }
+  /*
     GameView {
         id: item1
         x: 8
@@ -51,4 +81,5 @@
         width: 1008
         height: 638
     }
+    */
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/engine_instance.cpp	Wed Nov 07 15:59:51 2018 +0100
@@ -0,0 +1,14 @@
+#include "engine_instance.h"
+
+EngineInstance::EngineInstance(QObject *parent)
+    : QObject(parent), m_instance(Engine::start_engine()) {}
+
+EngineInstance::~EngineInstance() { Engine::cleanup(m_instance); }
+
+Engine::PreviewInfo EngineInstance::generatePreview() {
+  Engine::PreviewInfo pinfo;
+
+  Engine::generate_preview(m_instance, &pinfo);
+
+  return pinfo;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/engine_instance.h	Wed Nov 07 15:59:51 2018 +0100
@@ -0,0 +1,24 @@
+#ifndef ENGINEINSTANCE_H
+#define ENGINEINSTANCE_H
+
+#include "engine_interface.h"
+
+#include <QObject>
+
+class EngineInstance : public QObject {
+  Q_OBJECT
+ public:
+  explicit EngineInstance(QObject *parent = nullptr);
+  ~EngineInstance();
+
+  Engine::PreviewInfo generatePreview();
+
+ signals:
+
+ public slots:
+
+ private:
+  Engine::EngineInstance *m_instance;
+};
+
+#endif  // ENGINEINSTANCE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/engine_interface.h	Wed Nov 07 15:59:51 2018 +0100
@@ -0,0 +1,36 @@
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+namespace Engine {
+extern "C" {
+#endif
+
+typedef struct _EngineInstance EngineInstance;
+
+typedef struct {
+  uint32_t width;
+  uint32_t height;
+  uint8_t hedgehogs_number;
+  unsigned char* land;
+} PreviewInfo;
+
+typedef uint32_t protocol_version_t();
+typedef EngineInstance* start_engine_t();
+typedef void generate_preview_t(EngineInstance* engine_state,
+                                PreviewInfo* preview);
+typedef void cleanup_t(EngineInstance* engine_state);
+
+extern protocol_version_t* protocol_version;
+extern start_engine_t* start_engine;
+extern generate_preview_t* generate_preview;
+extern cleanup_t* cleanup;
+
+#ifdef __cplusplus
+}
+};
+#endif
+
+#endif  // ENGINE_H
--- a/qmlfrontend/flib.h	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#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/game_config.cpp	Wed Nov 07 15:59:51 2018 +0100
@@ -0,0 +1,81 @@
+#include "game_config.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/game_config.h	Wed Nov 07 15:59:51 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/game_view.cpp	Wed Nov 07 15:59:51 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/game_view.h	Wed Nov 07 15:59:51 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
--- a/qmlfrontend/gameconfig.cpp	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-#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);
-}
--- a/qmlfrontend/gameconfig.h	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-#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
--- a/qmlfrontend/gameview.cpp	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-#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();
-}
--- a/qmlfrontend/gameview.h	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-#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
--- a/qmlfrontend/hwengine.cpp	Wed Nov 07 15:55:32 2018 +0100
+++ b/qmlfrontend/hwengine.cpp	Wed Nov 07 15:59:51 2018 +0100
@@ -1,72 +1,23 @@
-#include "hwengine.h"
-
 #include <QDebug>
 #include <QLibrary>
 #include <QQmlEngine>
 #include <QUuid>
 
-#include "gameview.h"
-#include "previewimageprovider.h"
-#include "runqueue.h"
+#include "engine_instance.h"
+#include "engine_interface.h"
+#include "game_view.h"
+#include "preview_image_provider.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;
-}
+#include "hwengine.h"
 
 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_previewProvider(new PreviewImageProvider()) {
   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(); }
+HWEngine::~HWEngine() {}
 
 static QObject* hwengine_singletontype_provider(QQmlEngine* engine,
                                                 QJSEngine* scriptEngine) {
@@ -80,44 +31,7 @@
   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;
-    }
-  }
+  // qmlRegisterType<GameView>("Hedgewars.Engine", 1, 0, "GameView");
 }
 
 void HWEngine::getPreview() {
@@ -125,7 +39,22 @@
   m_gameConfig.cmdSeed(m_seed);
   m_gameConfig.setPreview(true);
 
-  m_runQueue->queue(m_gameConfig);
+  EngineInstance engine;
+  Engine::PreviewInfo preview = engine.generatePreview();
+
+  QVector<QRgb> colorTable;
+  colorTable.resize(256);
+  for (int i = 0; i < 256; ++i) colorTable[i] = qRgba(255, 255, 0, i);
+
+  QImage previewImage(preview.land, preview.width, preview.height,
+                      QImage::Format_Indexed8);
+  previewImage.setColorTable(colorTable);
+  previewImage.detach();
+
+  m_previewProvider->setImage(previewImage);
+
+  emit previewImageChanged();
+  // m_runQueue->queue(m_gameConfig);
 }
 
 void HWEngine::runQuickGame() {
@@ -140,7 +69,7 @@
   m_gameConfig.cmdTeam(team2);
   m_gameConfig.setPreview(false);
 
-  m_runQueue->queue(m_gameConfig);
+  // m_runQueue->queue(m_gameConfig);
 }
 
 int HWEngine::previewHedgehogsCount() const { return m_previewHedgehogsCount; }
--- a/qmlfrontend/hwengine.h	Wed Nov 07 15:55:32 2018 +0100
+++ b/qmlfrontend/hwengine.h	Wed Nov 07 15:59:51 2018 +0100
@@ -4,12 +4,11 @@
 #include <QList>
 #include <QObject>
 
-#include "flib.h"
-#include "gameconfig.h"
+#include "engine_interface.h"
+#include "game_config.h"
 
 class QQmlEngine;
 class PreviewImageProvider;
-class RunQueue;
 
 class HWEngine : public QObject {
   Q_OBJECT
@@ -38,16 +37,9 @@
  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	Wed Nov 07 15:55:32 2018 +0100
+++ b/qmlfrontend/main.cpp	Wed Nov 07 15:59:51 2018 +0100
@@ -1,12 +1,48 @@
+#include <QDebug>
 #include <QGuiApplication>
+#include <QLibrary>
 #include <QQmlApplicationEngine>
 
+#include "engine_interface.h"
 #include "hwengine.h"
 
+namespace Engine {
+protocol_version_t* protocol_version;
+start_engine_t* start_engine;
+generate_preview_t* generate_preview;
+cleanup_t* cleanup;
+};  // namespace Engine
+
+void loadEngineLibrary() {
+#ifdef Q_OS_WIN
+  QLibrary hwlib("./libhedgewars_engine.dll");
+#else
+  QLibrary hwlib("./libhedgewars_engine.so");
+#endif
+
+  if (!hwlib.load())
+    qWarning() << "Engine library not found" << hwlib.errorString();
+
+  Engine::protocol_version = reinterpret_cast<Engine::protocol_version_t*>(
+      hwlib.resolve("protocol_version"));
+  Engine::start_engine =
+      reinterpret_cast<Engine::start_engine_t*>(hwlib.resolve("start_engine"));
+  Engine::generate_preview = reinterpret_cast<Engine::generate_preview_t*>(
+      hwlib.resolve("generate_preview"));
+  Engine::cleanup =
+      reinterpret_cast<Engine::cleanup_t*>(hwlib.resolve("cleanup"));
+
+  if (Engine::protocol_version)
+    qDebug() << "Loaded engine library with protocol version"
+             << Engine::protocol_version();
+}
+
 int main(int argc, char* argv[]) {
   QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
   QGuiApplication app(argc, argv);
 
+  loadEngineLibrary();
+
   QQmlApplicationEngine engine;
 
   HWEngine::exposeToQML();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlfrontend/preview_image_provider.cpp	Wed Nov 07 15:59:51 2018 +0100
@@ -0,0 +1,23 @@
+#include "preview_image_provider.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::setImage(const QImage &preview) {
+  m_px = QPixmap::fromImage(preview, 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/preview_image_provider.h	Wed Nov 07 15:59:51 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 setImage(const QImage &preview);
+
+ private:
+  QPixmap m_px;
+};
+
+#endif  // PREVIEWIMAGEPROVIDER_H
--- a/qmlfrontend/previewimageprovider.cpp	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#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);
-}
--- a/qmlfrontend/previewimageprovider.h	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#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/runqueue.cpp	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#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());
-    }
-}
--- a/qmlfrontend/runqueue.h	Wed Nov 07 15:55:32 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#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/rust/hedgewars-engine/src/world.rs	Wed Nov 07 15:59:51 2018 +0100
@@ -0,0 +1,44 @@
+use integral_geometry::{Point, Rect, Size};
+use land2d::Land2D;
+use landgen::{
+    outline_template::OutlineTemplate, template_based::TemplatedLandGenerator,
+    LandGenerationParameters, LandGenerator,
+};
+use lfprng::LaggedFibonacciPRNG;
+
+pub struct World {
+    random_numbers_gen: LaggedFibonacciPRNG,
+    preview: Land2D<u8>,
+}
+
+impl World {
+    pub fn new() -> Self {
+        Self {
+            random_numbers_gen: LaggedFibonacciPRNG::new(&[]),
+            preview: Land2D::new(Size::new(0, 0), 0),
+        }
+    }
+
+    pub fn preview(&self) -> &Land2D<u8> {
+        &self.preview
+    }
+
+    pub fn generate_preview(&mut self) {
+        fn template() -> OutlineTemplate {
+            let mut template = OutlineTemplate::new(Size::new(4096, 2048));
+            template.islands = vec![vec![
+                Rect::from_size_coords(100, 2050, 1, 1),
+                Rect::from_size_coords(100, 500, 400, 1200),
+                Rect::from_size_coords(3600, 500, 400, 1200),
+                Rect::from_size_coords(3900, 2050, 1, 1),
+            ]];
+            template.fill_points = vec![Point::new(1, 0)];
+
+            template
+        }
+
+        let params = LandGenerationParameters::new(0 as u8, 255, 5, false, false);
+        let landgen = TemplatedLandGenerator::new(template());
+        self.preview = landgen.generate_land(&params, &mut self.random_numbers_gen);
+    }
+}