qmlfrontend/game_view.cpp
changeset 16039 a73b9770467a
parent 15923 9b8d4f34e0f3
equal deleted inserted replaced
16035:1f9f971adec4 16039:a73b9770467a
     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>
    10 
       
    11 class GameViewRenderer : public QQuickFramebufferObject::Renderer {
       
    12  public:
       
    13   explicit GameViewRenderer() = default;
       
    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_inited{false};
       
    27 };
       
    28 
       
    29 void GameViewRenderer::render() {
       
    30   const auto engine = m_gameView->engineInstance();
       
    31 
       
    32   if (!engine) {
       
    33     return;
       
    34   }
       
    35 
       
    36   if (!m_inited) {
       
    37     m_inited = true;
       
    38     engine->setOpenGLContext(QOpenGLContext::currentContext());
       
    39   }
       
    40 
       
    41   engine->renderFrame();
       
    42 
       
    43   QQuickOpenGLUtils::resetOpenGLState();
       
    44 }
       
    45 
       
    46 QOpenGLFramebufferObject* GameViewRenderer::createFramebufferObject(
       
    47     const QSize& size) {
       
    48   QOpenGLFramebufferObjectFormat format;
       
    49   format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
       
    50   format.setSamples(8);
       
    51   auto fbo = new QOpenGLFramebufferObject(size, format);
       
    52   return fbo;
       
    53 }
       
    54 
       
    55 void GameViewRenderer::synchronize(QQuickFramebufferObject* fbo) {
       
    56   if (!m_gameView) {
       
    57     m_gameView = qobject_cast<GameView*>(fbo);
       
    58     m_window = fbo->window();
       
    59   }
       
    60 }
     8 
    61 
     9 GameView::GameView(QQuickItem* parent)
    62 GameView::GameView(QQuickItem* parent)
    10     : QQuickItem(parent), m_delta(0), m_windowChanged(true) {
    63     : QQuickFramebufferObject(parent), m_delta(0) {
    11   connect(this, &QQuickItem::windowChanged, this,
    64   setMirrorVertically(true);
    12           &GameView::handleWindowChanged);
       
    13 }
    65 }
    14 
    66 
    15 void GameView::tick(quint32 delta) {
    67 void GameView::tick(quint32 delta) {
    16   m_delta = delta;
    68   m_delta = delta;
    17 
    69 
    18   if (window()) {
    70   if (window()) {
    19     QTimer* timer = new QTimer(this);
    71     QTimer* timer = new QTimer(this);
    20     connect(timer, &QTimer::timeout, window(), &QQuickWindow::update);
    72     connect(timer, &QTimer::timeout, this, &GameView::update);
    21     timer->start(100);
    73     timer->start(100);
    22 
       
    23     // window()->update();
       
    24   }
    74   }
    25 }
    75 }
    26 
    76 
    27 EngineInstance* GameView::engineInstance() const { return m_engineInstance; }
    77 EngineInstance* GameView::engineInstance() const { return m_engineInstance; }
    28 
    78 
    29 void GameView::handleWindowChanged(QQuickWindow* win) {
    79 QQuickFramebufferObject::Renderer* GameView::createRenderer() const {
    30   if (win) {
    80   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 }
    81 }
    41 
       
    42 void GameView::cleanup() { m_renderer.reset(); }
       
    43 
    82 
    44 void GameView::setEngineInstance(EngineInstance* engineInstance) {
    83 void GameView::setEngineInstance(EngineInstance* engineInstance) {
    45   if (m_engineInstance == engineInstance) {
    84   if (m_engineInstance == engineInstance) {
    46     return;
    85     return;
    47   }
    86   }
    48 
    87 
    49   cleanup();
       
    50   m_engineInstance = engineInstance;
    88   m_engineInstance = engineInstance;
    51 
    89 
    52   emit engineInstanceChanged(m_engineInstance);
    90   Q_EMIT engineInstanceChanged(m_engineInstance);
    53 }
    91 }
    54 
       
    55 void GameView::sync() {
       
    56   if (!m_renderer && m_engineInstance) {
       
    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 }
       
    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 }