qmlfrontend/game_view.cpp
branchtransitional_engine
changeset 16051 2003b466b279
parent 16046 e8afb1bf2779
--- a/qmlfrontend/game_view.cpp	Wed Aug 28 15:31:51 2024 +0200
+++ b/qmlfrontend/game_view.cpp	Wed Aug 28 15:34:49 2024 +0200
@@ -1,114 +1,109 @@
 #include "game_view.h"
 
 #include <QtQuick/qquickwindow.h>
+
 #include <QCursor>
+#include <QOpenGLFramebufferObjectFormat>
+#include <QQuickOpenGLUtils>
 #include <QTimer>
 #include <QtGui/QOpenGLContext>
-#include <QtGui/QOpenGLShaderProgram>
+
+class GameViewRenderer : public QQuickFramebufferObject::Renderer {
+ public:
+  explicit GameViewRenderer() = default;
+
+  GameViewRenderer(const GameViewRenderer&) = delete;
+  GameViewRenderer(GameViewRenderer&&) = delete;
+  GameViewRenderer& operator=(const GameViewRenderer&) = delete;
+  GameViewRenderer& operator=(GameViewRenderer&&) = delete;
+
+  void render() override;
+  QOpenGLFramebufferObject* createFramebufferObject(const QSize& size) override;
+  void synchronize(QQuickFramebufferObject* fbo) override;
+
+  QPointer<GameView> m_gameView;
+  QPointer<QQuickWindow> m_window;
+  bool m_dirty{true};
+  QSizeF m_gameViewSize;
+};
+
+void GameViewRenderer::render() {
+  const auto engine = m_gameView->engineInstance();
+
+  if (!engine) {
+    return;
+  }
+
+  if (m_dirty) {
+    m_dirty = false;
+    engine->setOpenGLContext(QOpenGLContext::currentContext());
+  }
 
-GameView::GameView(QQuickItem* parent)
-    : QQuickItem(parent), m_delta(0), m_windowChanged(true) {
-  connect(this, &QQuickItem::windowChanged, this,
-          &GameView::handleWindowChanged);
+  engine->renderFrame();
+
+  QQuickOpenGLUtils::resetOpenGLState();
+}
+
+QOpenGLFramebufferObject* GameViewRenderer::createFramebufferObject(
+    const QSize& size) {
+  QOpenGLFramebufferObjectFormat format;
+  format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+  format.setSamples(8);
+  auto fbo = new QOpenGLFramebufferObject(size, format);
+  return fbo;
+}
+
+void GameViewRenderer::synchronize(QQuickFramebufferObject* fbo) {
+  if (!m_gameView) {
+    m_gameView = qobject_cast<GameView*>(fbo);
+    m_window = fbo->window();
+  }
+
+  if (const auto currentSize = m_gameView->size();
+      currentSize != m_gameViewSize) {
+    m_gameViewSize = currentSize;
+    m_dirty = true;
+  }
+
+  m_gameView->executeActions();
+}
+
+GameView::GameView(QQuickItem* parent) : QQuickFramebufferObject(parent) {
+  setMirrorVertically(true);
 }
 
 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();
-  }
+  addAction([delta](auto engine) { engine->advance(delta); });
 }
 
 EngineInstance* GameView::engineInstance() const { return m_engineInstance; }
 
-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;
-  }
+QQuickFramebufferObject::Renderer* GameView::createRenderer() const {
+  return new GameViewRenderer{};
 }
 
-void GameView::cleanup() { m_renderer.reset(); }
+void GameView::executeActions() {
+  if (!m_engineInstance) {
+    return;
+  }
+
+  for (const auto& action : m_actions) {
+    action(m_engineInstance);
+  }
+
+  m_actions.clear();
+}
 
 void GameView::setEngineInstance(EngineInstance* engineInstance) {
   if (m_engineInstance == engineInstance) {
     return;
   }
 
-  cleanup();
   m_engineInstance = engineInstance;
 
-  emit engineInstanceChanged(m_engineInstance);
+  Q_EMIT engineInstanceChanged(m_engineInstance);
 }
 
-void GameView::sync() {
-  if (!m_renderer && m_engineInstance) {
-    m_engineInstance->setOpenGLContext(window()->openglContext());
-    m_renderer.reset(new GameViewRenderer());
-    m_renderer->setEngineInstance(m_engineInstance);
-    connect(window(), &QQuickWindow::beforeRendering, m_renderer.data(),
-            &GameViewRenderer::paint, Qt::DirectConnection);
-  }
-
-  if (m_windowChanged || (m_viewportSize != size())) {
-    m_windowChanged = false;
-
-    if (m_engineInstance)
-      m_engineInstance->setOpenGLContext(window()->openglContext());
-
-    m_viewportSize = size().toSize();
-    m_centerPoint = QPoint(m_viewportSize.width(), m_viewportSize.height()) / 2;
-  }
-
-  if (m_engineInstance) {
-    const auto delta = mapFromGlobal(QCursor::pos()).toPoint() - m_centerPoint;
-
-    m_engineInstance->moveCamera(delta);
-
-    QCursor::setPos(window()->screen(), mapToGlobal(m_centerPoint).toPoint());
-  }
-
-  if (m_renderer) {
-    m_renderer->tick(m_delta);
-  }
+void GameView::addAction(std::function<void(EngineInstance*)>&& action) {
+  m_actions.append(std::move(action));
 }
-
-GameViewRenderer::GameViewRenderer()
-    : QObject(), m_delta(0), m_engineInstance(nullptr) {}
-
-GameViewRenderer::~GameViewRenderer() {}
-
-void GameViewRenderer::tick(quint32 delta) { m_delta = delta; }
-
-void GameViewRenderer::setEngineInstance(EngineInstance* engineInstance) {
-  m_engineInstance = engineInstance;
-}
-
-void GameViewRenderer::paint() {
-  if (m_delta == 0) {
-    return;
-  }
-
-  if (m_engineInstance) {
-    m_engineInstance->advance(m_delta);
-    m_engineInstance->renderFrame();
-  }
-
-  // m_window->resetOpenGLState();
-}
-
-void GameViewRenderer::onViewportSizeChanged(QQuickWindow* window) {
-  if (m_engineInstance)
-    m_engineInstance->setOpenGLContext(window->openglContext());
-}