qmlfrontend/game_view.cpp
branchtransitional_engine
changeset 16051 2003b466b279
parent 16046 e8afb1bf2779
equal deleted inserted replaced
16050:6a3dc15b78b9 16051:2003b466b279
     1 #include "game_view.h"
     1 #include "game_view.h"
     2 
     2 
     3 #include <QtQuick/qquickwindow.h>
     3 #include <QtQuick/qquickwindow.h>
       
     4 
     4 #include <QCursor>
     5 #include <QCursor>
       
     6 #include <QOpenGLFramebufferObjectFormat>
       
     7 #include <QQuickOpenGLUtils>
     5 #include <QTimer>
     8 #include <QTimer>
     6 #include <QtGui/QOpenGLContext>
     9 #include <QtGui/QOpenGLContext>
     7 #include <QtGui/QOpenGLShaderProgram>
       
     8 
    10 
     9 GameView::GameView(QQuickItem* parent)
    11 class GameViewRenderer : public QQuickFramebufferObject::Renderer {
    10     : QQuickItem(parent), m_delta(0), m_windowChanged(true) {
    12  public:
    11   connect(this, &QQuickItem::windowChanged, this,
    13   explicit GameViewRenderer() = default;
    12           &GameView::handleWindowChanged);
    14 
       
    15   GameViewRenderer(const GameViewRenderer&) = delete;
       
    16   GameViewRenderer(GameViewRenderer&&) = delete;
       
    17   GameViewRenderer& operator=(const GameViewRenderer&) = delete;
       
    18   GameViewRenderer& operator=(GameViewRenderer&&) = delete;
       
    19 
       
    20   void render() override;
       
    21   QOpenGLFramebufferObject* createFramebufferObject(const QSize& size) override;
       
    22   void synchronize(QQuickFramebufferObject* fbo) override;
       
    23 
       
    24   QPointer<GameView> m_gameView;
       
    25   QPointer<QQuickWindow> m_window;
       
    26   bool m_dirty{true};
       
    27   QSizeF m_gameViewSize;
       
    28 };
       
    29 
       
    30 void GameViewRenderer::render() {
       
    31   const auto engine = m_gameView->engineInstance();
       
    32 
       
    33   if (!engine) {
       
    34     return;
       
    35   }
       
    36 
       
    37   if (m_dirty) {
       
    38     m_dirty = false;
       
    39     engine->setOpenGLContext(QOpenGLContext::currentContext());
       
    40   }
       
    41 
       
    42   engine->renderFrame();
       
    43 
       
    44   QQuickOpenGLUtils::resetOpenGLState();
       
    45 }
       
    46 
       
    47 QOpenGLFramebufferObject* GameViewRenderer::createFramebufferObject(
       
    48     const QSize& size) {
       
    49   QOpenGLFramebufferObjectFormat format;
       
    50   format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
       
    51   format.setSamples(8);
       
    52   auto fbo = new QOpenGLFramebufferObject(size, format);
       
    53   return fbo;
       
    54 }
       
    55 
       
    56 void GameViewRenderer::synchronize(QQuickFramebufferObject* fbo) {
       
    57   if (!m_gameView) {
       
    58     m_gameView = qobject_cast<GameView*>(fbo);
       
    59     m_window = fbo->window();
       
    60   }
       
    61 
       
    62   if (const auto currentSize = m_gameView->size();
       
    63       currentSize != m_gameViewSize) {
       
    64     m_gameViewSize = currentSize;
       
    65     m_dirty = true;
       
    66   }
       
    67 
       
    68   m_gameView->executeActions();
       
    69 }
       
    70 
       
    71 GameView::GameView(QQuickItem* parent) : QQuickFramebufferObject(parent) {
       
    72   setMirrorVertically(true);
    13 }
    73 }
    14 
    74 
    15 void GameView::tick(quint32 delta) {
    75 void GameView::tick(quint32 delta) {
    16   m_delta = delta;
    76   addAction([delta](auto engine) { engine->advance(delta); });
    17 
       
    18   if (window()) {
       
    19     QTimer* timer = new QTimer(this);
       
    20     connect(timer, &QTimer::timeout, window(), &QQuickWindow::update);
       
    21     timer->start(100);
       
    22 
       
    23     // window()->update();
       
    24   }
       
    25 }
    77 }
    26 
    78 
    27 EngineInstance* GameView::engineInstance() const { return m_engineInstance; }
    79 EngineInstance* GameView::engineInstance() const { return m_engineInstance; }
    28 
    80 
    29 void GameView::handleWindowChanged(QQuickWindow* win) {
    81 QQuickFramebufferObject::Renderer* GameView::createRenderer() const {
    30   if (win) {
    82   return new GameViewRenderer{};
    31     connect(win, &QQuickWindow::beforeSynchronizing, this, &GameView::sync,
       
    32             Qt::DirectConnection);
       
    33     connect(win, &QQuickWindow::sceneGraphInvalidated, this, &GameView::cleanup,
       
    34             Qt::DirectConnection);
       
    35 
       
    36     win->setClearBeforeRendering(false);
       
    37 
       
    38     m_windowChanged = true;
       
    39   }
       
    40 }
    83 }
    41 
    84 
    42 void GameView::cleanup() { m_renderer.reset(); }
    85 void GameView::executeActions() {
       
    86   if (!m_engineInstance) {
       
    87     return;
       
    88   }
       
    89 
       
    90   for (const auto& action : m_actions) {
       
    91     action(m_engineInstance);
       
    92   }
       
    93 
       
    94   m_actions.clear();
       
    95 }
    43 
    96 
    44 void GameView::setEngineInstance(EngineInstance* engineInstance) {
    97 void GameView::setEngineInstance(EngineInstance* engineInstance) {
    45   if (m_engineInstance == engineInstance) {
    98   if (m_engineInstance == engineInstance) {
    46     return;
    99     return;
    47   }
   100   }
    48 
   101 
    49   cleanup();
       
    50   m_engineInstance = engineInstance;
   102   m_engineInstance = engineInstance;
    51 
   103 
    52   emit engineInstanceChanged(m_engineInstance);
   104   Q_EMIT engineInstanceChanged(m_engineInstance);
    53 }
   105 }
    54 
   106 
    55 void GameView::sync() {
   107 void GameView::addAction(std::function<void(EngineInstance*)>&& action) {
    56   if (!m_renderer && m_engineInstance) {
   108   m_actions.append(std::move(action));
    57     m_engineInstance->setOpenGLContext(window()->openglContext());
       
    58     m_renderer.reset(new GameViewRenderer());
       
    59     m_renderer->setEngineInstance(m_engineInstance);
       
    60     connect(window(), &QQuickWindow::beforeRendering, m_renderer.data(),
       
    61             &GameViewRenderer::paint, Qt::DirectConnection);
       
    62   }
       
    63 
       
    64   if (m_windowChanged || (m_viewportSize != size())) {
       
    65     m_windowChanged = false;
       
    66 
       
    67     if (m_engineInstance)
       
    68       m_engineInstance->setOpenGLContext(window()->openglContext());
       
    69 
       
    70     m_viewportSize = size().toSize();
       
    71     m_centerPoint = QPoint(m_viewportSize.width(), m_viewportSize.height()) / 2;
       
    72   }
       
    73 
       
    74   if (m_engineInstance) {
       
    75     const auto delta = mapFromGlobal(QCursor::pos()).toPoint() - m_centerPoint;
       
    76 
       
    77     m_engineInstance->moveCamera(delta);
       
    78 
       
    79     QCursor::setPos(window()->screen(), mapToGlobal(m_centerPoint).toPoint());
       
    80   }
       
    81 
       
    82   if (m_renderer) {
       
    83     m_renderer->tick(m_delta);
       
    84   }
       
    85 }
   109 }
    86 
       
    87 GameViewRenderer::GameViewRenderer()
       
    88     : QObject(), m_delta(0), m_engineInstance(nullptr) {}
       
    89 
       
    90 GameViewRenderer::~GameViewRenderer() {}
       
    91 
       
    92 void GameViewRenderer::tick(quint32 delta) { m_delta = delta; }
       
    93 
       
    94 void GameViewRenderer::setEngineInstance(EngineInstance* engineInstance) {
       
    95   m_engineInstance = engineInstance;
       
    96 }
       
    97 
       
    98 void GameViewRenderer::paint() {
       
    99   if (m_delta == 0) {
       
   100     return;
       
   101   }
       
   102 
       
   103   if (m_engineInstance) {
       
   104     m_engineInstance->advance(m_delta);
       
   105     m_engineInstance->renderFrame();
       
   106   }
       
   107 
       
   108   // m_window->resetOpenGLState();
       
   109 }
       
   110 
       
   111 void GameViewRenderer::onViewportSizeChanged(QQuickWindow* window) {
       
   112   if (m_engineInstance)
       
   113     m_engineInstance->setOpenGLContext(window->openglContext());
       
   114 }