1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qscene2d.h"
5#include "qscene2d_p.h"
6#include "scene2d_p.h"
7#include "scene2dmanager_p.h"
8#include "scene2devent_p.h"
9
10QT_BEGIN_NAMESPACE
11
12
13namespace Qt3DRender {
14
15namespace Quick {
16
17using namespace Qt3DCore;
18
19class RenderControl : public QQuickRenderControl
20{
21public:
22 RenderControl(QWindow *w) : m_window(w) { }
23 QWindow *renderWindow(QPoint *offset) override;
24
25private:
26 QWindow *m_window;
27};
28
29QWindow *RenderControl::renderWindow(QPoint *offset)
30{
31 if (offset)
32 *offset = QPoint(0, 0);
33 return m_window;
34}
35
36/*!
37 \internal
38 Constructs qml render manager.
39 */
40Scene2DManager::Scene2DManager(QScene2DPrivate *priv)
41 : m_rootItem(nullptr)
42 , m_item(nullptr)
43 , m_priv(priv)
44 , m_sharedObject(new Scene2DSharedObject(this))
45 , m_renderPolicy(QScene2D::Continuous)
46 , m_requested(false)
47 , m_initialized(false)
48 , m_renderSyncRequested(false)
49 , m_backendInitialized(false)
50 , m_mouseEnabled(true)
51{
52 m_sharedObject->m_surface = new QOffscreenSurface;
53 m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat());
54 m_sharedObject->m_surface->create();
55
56 // Create render control
57 m_sharedObject->m_renderControl = new RenderControl(nullptr);
58
59 // Create window to render the QML with
60 m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl);
61 // TODOQT6 see qtdeclarative 0d43e21429ee23442ec3a99f641a5665d66e75e2
62 //m_sharedObject->m_quickWindow->setClearBeforeRendering(true);
63 m_sharedObject->m_quickWindow->setColor(Qt::transparent);
64
65 connect(sender: m_sharedObject->m_renderControl, signal: &QQuickRenderControl::renderRequested,
66 context: this, slot: &Scene2DManager::requestRender);
67 connect(sender: m_sharedObject->m_renderControl, signal: &QQuickRenderControl::sceneChanged,
68 context: this, slot: &Scene2DManager::requestRenderSync);
69}
70
71Scene2DManager::~Scene2DManager()
72{
73 m_sharedObject = nullptr;
74}
75
76void Scene2DManager::requestRender()
77{
78 // Don't request render until the backend is initialized.
79 if (m_sharedObject->canRender()) {
80 if (!m_requested) {
81 m_requested = true;
82 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::Render));
83 }
84 }
85}
86
87void Scene2DManager::requestRenderSync()
88{
89 // Don't request render until the backed is initialized.
90 if (m_sharedObject->canRender()) {
91 if (!m_requested) {
92 m_requested = true;
93 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
94 }
95 } else {
96 m_renderSyncRequested = true;
97 }
98}
99
100void Scene2DManager::startIfInitialized()
101{
102 if (!m_initialized && m_backendInitialized && m_item != nullptr) {
103 m_rootItem = m_item;
104
105 // Associate root item with the window.
106 m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
107
108 // Update window size.
109 updateSizes();
110
111 m_initialized = true;
112 m_sharedObject->setInitialized();
113
114 // Request render if we have already been requested and preparation has already been done
115 if (m_sharedObject->isPrepared() && m_renderSyncRequested) {
116 if (!m_requested) {
117 m_requested = true;
118 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
119 }
120 m_renderSyncRequested = false;
121 }
122 }
123}
124
125void Scene2DManager::stopAndClean()
126{
127 if (m_sharedObject->isInitialized()) {
128 QMutexLocker lock(&m_sharedObject->m_mutex);
129 m_sharedObject->requestQuit();
130 m_sharedObject->wait();
131 m_sharedObject->cleanup();
132 }
133}
134
135void Scene2DManager::updateSizes()
136{
137 const int width = m_rootItem->width();
138 const int height = m_rootItem->height();
139 if (width == 0 || height == 0) {
140 qWarning() << "QScene2D: Root item size not set.";
141 return;
142 }
143 m_sharedObject->m_quickWindow->setGeometry(posx: 0, posy: 0, w: width, h: height);
144}
145
146void Scene2DManager::setItem(QQuickItem *item)
147{
148 m_item = item;
149 startIfInitialized();
150}
151
152bool Scene2DManager::event(QEvent *e)
153{
154 switch (static_cast<Scene2DEvent::Type>(e->type())) {
155
156 case Scene2DEvent::Render: {
157 // just render request, don't need to call sync in render thread
158 QMutexLocker lock(&m_sharedObject->m_mutex);
159 m_sharedObject->requestRender(sync: false);
160 m_requested = false;
161 return true;
162 }
163
164 case Scene2DEvent::RenderSync: {
165 // sync and render request, main and render threads must be synchronized
166 if (!m_sharedObject->isQuit())
167 doRenderSync();
168 m_requested = false;
169 return true;
170 }
171
172 case Scene2DEvent::Prepare: {
173 m_sharedObject->m_renderControl->prepareThread(targetThread: m_sharedObject->m_renderThread);
174 m_sharedObject->setPrepared();
175
176 if (m_renderSyncRequested) {
177 if (!m_requested) {
178 m_requested = true;
179 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
180 }
181 m_renderSyncRequested = false;
182 }
183 return true;
184 }
185
186 case Scene2DEvent::Initialized: {
187 // backend is initialized, start the qml
188 m_backendInitialized = true;
189 startIfInitialized();
190 return true;
191 }
192
193 case Scene2DEvent::Rendered: {
194 // render is done, excellent, now clean anything not needed anymore.
195 stopAndClean();
196 return true;
197 }
198
199 default:
200 break;
201 }
202 return QObject::event(event: e);
203}
204
205void Scene2DManager::doRenderSync()
206{
207 QMutexLocker lock(&m_sharedObject->m_mutex);
208
209 m_sharedObject->requestRender(sync: true);
210 m_sharedObject->m_renderControl->polishItems();
211
212 // begin waiting render thread
213 m_sharedObject->wait();
214 m_requested = false;
215}
216
217void Scene2DManager::cleanup()
218{
219 stopAndClean();
220}
221
222} // namespace Quick
223} // namespace Qt3DRender
224
225QT_END_NAMESPACE
226
227#include "moc_scene2dmanager_p.cpp"
228

source code of qt3d/src/quick3d/quick3dscene2d/items/scene2dmanager.cpp