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 } |
|