1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qscene2d.h"
38#include "qscene2d_p.h"
39#include "scene2d_p.h"
40#include "scene2dmanager_p.h"
41#include "scene2devent_p.h"
42
43QT_BEGIN_NAMESPACE
44
45using namespace Qt3DCore;
46
47namespace Qt3DRender {
48
49namespace Quick {
50
51class RenderControl : public QQuickRenderControl
52{
53public:
54 RenderControl(QWindow *w) : m_window(w) { }
55 QWindow *renderWindow(QPoint *offset) override;
56
57private:
58 QWindow *m_window;
59};
60
61QWindow *RenderControl::renderWindow(QPoint *offset)
62{
63 if (offset)
64 *offset = QPoint(0, 0);
65 return m_window;
66}
67
68/*!
69 \internal
70 Constructs qml render manager.
71 */
72Scene2DManager::Scene2DManager(QScene2DPrivate *priv)
73 : m_rootItem(nullptr)
74 , m_item(nullptr)
75 , m_priv(priv)
76 , m_sharedObject(new Scene2DSharedObject(this))
77 , m_renderPolicy(QScene2D::Continuous)
78 , m_requested(false)
79 , m_initialized(false)
80 , m_renderSyncRequested(false)
81 , m_backendInitialized(false)
82 , m_mouseEnabled(true)
83{
84 m_sharedObject->m_surface = new QOffscreenSurface;
85 m_sharedObject->m_surface->setFormat(QSurfaceFormat::defaultFormat());
86 m_sharedObject->m_surface->create();
87
88 // Create render control
89 m_sharedObject->m_renderControl = new RenderControl(nullptr);
90
91 // Create window to render the QML with
92 m_sharedObject->m_quickWindow = new QQuickWindow(m_sharedObject->m_renderControl);
93 m_sharedObject->m_quickWindow->setClearBeforeRendering(true);
94 m_sharedObject->m_quickWindow->setColor(Qt::transparent);
95
96 connect(sender: m_sharedObject->m_renderControl, signal: &QQuickRenderControl::renderRequested,
97 receiver: this, slot: &Scene2DManager::requestRender);
98 connect(sender: m_sharedObject->m_renderControl, signal: &QQuickRenderControl::sceneChanged,
99 receiver: this, slot: &Scene2DManager::requestRenderSync);
100}
101
102Scene2DManager::~Scene2DManager()
103{
104 m_sharedObject = nullptr;
105}
106
107void Scene2DManager::requestRender()
108{
109 // Don't request render until the backend is initialized.
110 if (m_sharedObject->canRender()) {
111 if (!m_requested) {
112 m_requested = true;
113 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::Render));
114 }
115 }
116}
117
118void Scene2DManager::requestRenderSync()
119{
120 // Don't request render until the backed is initialized.
121 if (m_sharedObject->canRender()) {
122 if (!m_requested) {
123 m_requested = true;
124 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
125 }
126 } else {
127 m_renderSyncRequested = true;
128 }
129}
130
131void Scene2DManager::startIfInitialized()
132{
133 if (!m_initialized && m_backendInitialized && m_item != nullptr) {
134 m_rootItem = m_item;
135
136 // Associate root item with the window.
137 m_rootItem->setParentItem(m_sharedObject->m_quickWindow->contentItem());
138
139 // Update window size.
140 updateSizes();
141
142 m_initialized = true;
143 m_sharedObject->setInitialized();
144
145 // Request render if we have already been requested and preparation has already been done
146 if (m_sharedObject->isPrepared() && m_renderSyncRequested) {
147 if (!m_requested) {
148 m_requested = true;
149 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
150 }
151 m_renderSyncRequested = false;
152 }
153 }
154}
155
156void Scene2DManager::stopAndClean()
157{
158 if (m_sharedObject->isInitialized()) {
159 QMutexLocker lock(&m_sharedObject->m_mutex);
160 m_sharedObject->requestQuit();
161 m_sharedObject->wait();
162 m_sharedObject->cleanup();
163 }
164}
165
166void Scene2DManager::updateSizes()
167{
168 const int width = m_rootItem->width();
169 const int height = m_rootItem->height();
170 if (width == 0 || height == 0) {
171 qWarning() << "QScene2D: Root item size not set.";
172 return;
173 }
174 m_sharedObject->m_quickWindow->setGeometry(posx: 0, posy: 0, w: width, h: height);
175}
176
177void Scene2DManager::setItem(QQuickItem *item)
178{
179 m_item = item;
180 startIfInitialized();
181}
182
183bool Scene2DManager::event(QEvent *e)
184{
185 switch (static_cast<Scene2DEvent::Type>(e->type())) {
186
187 case Scene2DEvent::Render: {
188 // just render request, don't need to call sync in render thread
189 QMutexLocker lock(&m_sharedObject->m_mutex);
190 m_sharedObject->requestRender(sync: false);
191 m_requested = false;
192 return true;
193 }
194
195 case Scene2DEvent::RenderSync: {
196 // sync and render request, main and render threads must be synchronized
197 if (!m_sharedObject->isQuit())
198 doRenderSync();
199 m_requested = false;
200 return true;
201 }
202
203 case Scene2DEvent::Prepare: {
204 m_sharedObject->m_renderControl->prepareThread(targetThread: m_sharedObject->m_renderThread);
205 m_sharedObject->setPrepared();
206
207 if (m_renderSyncRequested) {
208 if (!m_requested) {
209 m_requested = true;
210 QCoreApplication::postEvent(receiver: this, event: new Scene2DEvent(Scene2DEvent::RenderSync));
211 }
212 m_renderSyncRequested = false;
213 }
214 return true;
215 }
216
217 case Scene2DEvent::Initialized: {
218 // backend is initialized, start the qml
219 m_backendInitialized = true;
220 startIfInitialized();
221 return true;
222 }
223
224 case Scene2DEvent::Rendered: {
225 // render is done, excellent, now clean anything not needed anymore.
226 stopAndClean();
227 return true;
228 }
229
230 default:
231 break;
232 }
233 return QObject::event(event: e);
234}
235
236void Scene2DManager::doRenderSync()
237{
238 QMutexLocker lock(&m_sharedObject->m_mutex);
239
240 m_sharedObject->requestRender(sync: true);
241 m_sharedObject->m_renderControl->polishItems();
242
243 // begin waiting render thread
244 m_sharedObject->wait();
245 m_requested = false;
246}
247
248void Scene2DManager::cleanup()
249{
250 stopAndClean();
251}
252
253} // namespace Quick
254} // namespace Qt3DRender
255
256QT_END_NAMESPACE
257

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