1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QTest>
30#include <Qt3DQuickScene2D/qscene2d.h>
31#include <private/qscene2d_p.h>
32#include <private/scene2d_p.h>
33#include <Qt3DRender/qgeometryrenderer.h>
34#include <Qt3DRender/qbuffer.h>
35#include <private/trianglesvisitor_p.h>
36#include <private/nodemanagers_p.h>
37#include <private/managers_p.h>
38#include <private/geometryrenderer_p.h>
39#include <private/geometryrenderermanager_p.h>
40#include <private/buffermanager_p.h>
41#include <Qt3DRender/qpicktriangleevent.h>
42#include <private/qpickevent_p.h>
43#include <Qt3DCore/qpropertyupdatedchange.h>
44#include <qbackendnodetester.h>
45#include "testrenderer.h"
46
47using namespace Qt3DRender::Quick;
48using namespace Qt3DRender::Render;
49using namespace Qt3DRender::Render::Quick;
50
51bool qFuzzyComparePointF(const QPointF& a, const QPointF& b) {
52 return qFuzzyCompare(p1: a.x(), p2: b.x()) && qFuzzyCompare(p1: a.y(), p2: b.y());
53}
54
55class TestWindow : public QQuickWindow
56{
57 Q_OBJECT
58public:
59 TestWindow()
60 : QQuickWindow()
61 {
62
63 }
64
65 bool event(QEvent *e) override
66 {
67 if (e->type() >= QEvent::MouseButtonPress &&
68 e->type() <= QEvent::MouseMove) {
69 QMouseEvent *me = static_cast<QMouseEvent *>(e);
70 m_eventTypes.push_back(t: e->type());
71 m_mousePoints.push_back(t: me->localPos());
72 }
73 return QQuickWindow::event(e);
74 }
75
76 bool verifyEventPos(uint index, QEvent::Type type, const QPointF& pos)
77 {
78 if (index >= unsigned(m_eventTypes.size()) ||
79 m_eventTypes[index] != type ||
80 !qFuzzyComparePointF(a: pos, b: m_mousePoints[index]))
81 return false;
82 return true;
83 }
84
85 void clear()
86 {
87 m_eventTypes.clear();
88 m_mousePoints.clear();
89 }
90
91private:
92 QVector<QEvent::Type> m_eventTypes;
93 QVector<QPointF> m_mousePoints;
94};
95
96class tst_Scene2D : public Qt3DCore::QBackendNodeTester
97{
98 Q_OBJECT
99
100private Q_SLOTS:
101
102 void checkInitialState()
103 {
104 // GIVEN
105 Scene2D backendScene2d;
106
107 // THEN
108 QCOMPARE(backendScene2d.isEnabled(), false);
109 QVERIFY(backendScene2d.peerId().isNull());
110 QCOMPARE(backendScene2d.m_context, nullptr);
111 QCOMPARE(backendScene2d.m_shareContext, nullptr);
112 QCOMPARE(backendScene2d.m_renderThread, nullptr);
113 QCOMPARE(backendScene2d.m_outputId, Qt3DCore::QNodeId());
114 QCOMPARE(backendScene2d.m_initialized, false);
115 QCOMPARE(backendScene2d.m_renderInitialized, false);
116 QCOMPARE(backendScene2d.m_renderPolicy, QScene2D::Continuous);
117 QCOMPARE(backendScene2d.m_mouseEnabled, true);
118 backendScene2d.cleanup();
119 }
120
121 void checkInitializeFromPeer()
122 {
123 // GIVEN
124 Qt3DRender::Quick::QScene2D frontend;
125 TestRenderer renderer;
126
127 {
128 // WHEN
129 QScopedPointer<Scene2D> backendScene2d(new Scene2D());
130 backendScene2d->setRenderer(&renderer);
131 simulateInitializationSync(frontend: &frontend, backend: backendScene2d.data());
132
133 // THEN
134 QCOMPARE(backendScene2d->isEnabled(), true);
135 QCOMPARE(backendScene2d->peerId(), frontend.id());
136 QCOMPARE(backendScene2d->m_outputId, Qt3DCore::QNodeId());
137 QVERIFY(backendScene2d->m_sharedObject.data() != nullptr);
138 QCOMPARE(backendScene2d->m_renderPolicy, QScene2D::Continuous);
139 QCOMPARE(backendScene2d->m_mouseEnabled, true);
140 backendScene2d->cleanup();
141 }
142 {
143 // WHEN
144 QScopedPointer<Scene2D> backendScene2d(new Scene2D());
145 frontend.setEnabled(false);
146 backendScene2d->setRenderer(&renderer);
147 simulateInitializationSync(frontend: &frontend, backend: backendScene2d.data());
148
149 // THEN
150 QCOMPARE(backendScene2d->peerId(), frontend.id());
151 QCOMPARE(backendScene2d->isEnabled(), false);
152 backendScene2d->cleanup();
153 }
154 }
155
156 void checkSceneChangeEvents()
157 {
158 // GIVEN
159 Qt3DRender::Quick::QScene2D frontend;
160 QScopedPointer<Scene2D> backendScene2d(new Scene2D());
161 TestRenderer renderer;
162 QScopedPointer<Qt3DRender::QRenderTargetOutput> output(new Qt3DRender::QRenderTargetOutput());
163 backendScene2d->setRenderer(&renderer);
164 simulateInitializationSync(frontend: &frontend, backend: backendScene2d.data());
165
166 {
167 // WHEN
168 const bool newValue = false;
169 frontend.setEnabled(false);
170 backendScene2d->syncFromFrontEnd(frontEnd: &frontend, firstTime: false);
171
172 // THEN
173 QCOMPARE(backendScene2d->isEnabled(), newValue);
174 }
175 {
176 // WHEN
177 const Qt3DCore::QNodeId newValue = output.data()->id();
178 frontend.setOutput(output.data());
179 backendScene2d->syncFromFrontEnd(frontEnd: &frontend, firstTime: false);
180
181 // THEN
182 QCOMPARE(backendScene2d->m_outputId, newValue);
183 }
184 {
185 // WHEN
186 const QScene2D::RenderPolicy newValue = QScene2D::SingleShot;
187 frontend.setRenderPolicy(newValue);
188 backendScene2d->syncFromFrontEnd(frontEnd: &frontend, firstTime: false);
189
190 // THEN
191 QCOMPARE(backendScene2d->m_renderPolicy, newValue);
192 }
193 {
194 // WHEN
195 const bool newValue = false;
196 frontend.setMouseEnabled(newValue);
197
198 // THEN
199 QCOMPARE(backendScene2d->isEnabled(), newValue);
200 }
201
202 backendScene2d->cleanup();
203 }
204
205 void testCoordinateCalculation()
206 {
207 // GIVEN
208 qputenv(varName: "QT3D_SCENE2D_DISABLE_RENDERING", value: "1");
209
210 QScopedPointer<TestWindow> testWindow(new TestWindow());
211 Scene2DSharedObjectPtr sharedObject(new Scene2DSharedObject(nullptr));
212 TestRenderer renderer;
213 QScopedPointer<Scene2D> scene2d(new Scene2D());
214 QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
215 Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
216 Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DRender::QGeometryRenderer();
217 Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
218 Qt3DRender::QAttribute *texcoordAttribute = new Qt3DRender::QAttribute();
219 Qt3DRender::QBuffer *dataBuffer =new Qt3DRender::QBuffer();
220 QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity());
221 entity->addComponent(comp: geometryRenderer);
222 renderer.setNodeManagers(nodeManagers.data());
223 scene2d->setRenderer(&renderer);
224 scene2d->setEnabled(true);
225 sharedObject->m_quickWindow = testWindow.data();
226 scene2d->setSharedObject(sharedObject);
227 testWindow->setGeometry(posx: 0,posy: 0,w: 1024,h: 1024);
228
229 QByteArray data;
230 data.resize(size: sizeof(float) * 5 * 6);
231 float *dataPtr = reinterpret_cast<float *>(data.data());
232 int i = 0;
233 dataPtr[i++] = -1.0f;
234 dataPtr[i++] = 1.0f;
235 dataPtr[i++] = 1.0f;
236 dataPtr[i++] = 0;
237 dataPtr[i++] = 0;
238
239 dataPtr[i++] = 1.0f;
240 dataPtr[i++] = 1.0f;
241 dataPtr[i++] = 1.0f;
242 dataPtr[i++] = 1.0f;
243 dataPtr[i++] = 0;
244
245 dataPtr[i++] = 1.0f;
246 dataPtr[i++] = -1.0f;
247 dataPtr[i++] = 1.0f;
248 dataPtr[i++] = 1.0f;
249 dataPtr[i++] = 1.0f;
250
251 dataPtr[i++] = -1.0f;
252 dataPtr[i++] = 1.0f;
253 dataPtr[i++] = 1.0f;
254 dataPtr[i++] = 0;
255 dataPtr[i++] = 0;
256
257 dataPtr[i++] = 1.0f;
258 dataPtr[i++] = -1.0f;
259 dataPtr[i++] = 1.0f;
260 dataPtr[i++] = 1.0f;
261 dataPtr[i++] = 1.0f;
262
263 dataPtr[i++] = -1.0f;
264 dataPtr[i++] = -1.0f;
265 dataPtr[i++] = 1.0f;
266 dataPtr[i++] = 0.0f;
267 dataPtr[i++] = 1.0f;
268
269 dataBuffer->setData(data);
270 Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(id: dataBuffer->id());
271 backendBuffer->setRenderer(&renderer);
272 backendBuffer->setManager(nodeManagers->bufferManager());
273 simulateInitializationSync(frontend: dataBuffer, backend: backendBuffer);
274
275 positionAttribute->setBuffer(dataBuffer);
276 positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
277 positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
278 positionAttribute->setVertexSize(3);
279 positionAttribute->setCount(6);
280 positionAttribute->setByteStride(sizeof(float) * 5);
281 positionAttribute->setByteOffset(0);
282 positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
283 geometry->addAttribute(attribute: positionAttribute);
284
285 texcoordAttribute->setBuffer(dataBuffer);
286 texcoordAttribute->setName(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName());
287 texcoordAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
288 texcoordAttribute->setVertexSize(2);
289 texcoordAttribute->setCount(6);
290 texcoordAttribute->setByteStride(sizeof(float) * 5);
291 texcoordAttribute->setByteOffset(sizeof(float) * 3);
292 texcoordAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
293 geometry->addAttribute(attribute: texcoordAttribute);
294
295 geometryRenderer->setGeometry(geometry);
296 geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
297
298 Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(
299 id: positionAttribute->id());
300 backendAttribute->setRenderer(&renderer);
301 simulateInitializationSync(frontend: positionAttribute, backend: backendAttribute);
302
303 Attribute *backendTexcoordAttribute = nodeManagers->attributeManager()
304 ->getOrCreateResource(id: texcoordAttribute->id());
305 backendTexcoordAttribute->setRenderer(&renderer);
306 simulateInitializationSync(frontend: texcoordAttribute, backend: backendTexcoordAttribute);
307
308 Geometry *backendGeometry = nodeManagers->geometryManager()
309 ->getOrCreateResource(id: geometry->id());
310 backendGeometry->setRenderer(&renderer);
311 simulateInitializationSync(frontend: geometry, backend: backendGeometry);
312
313 GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()
314 ->getOrCreateResource(id: geometryRenderer->id());
315 backendRenderer->setRenderer(&renderer);
316 backendRenderer->setManager(nodeManagers->geometryRendererManager());
317 simulateInitializationSync(frontend: geometryRenderer, backend: backendRenderer);
318
319 Entity *backendEntity = nodeManagers->renderNodesManager()->getOrCreateResource(id: entity->id());
320 backendEntity->setRenderer(&renderer);
321 backendEntity->setNodeManagers(nodeManagers.data());
322 simulateInitializationSync(frontend: entity.data(), backend: backendEntity);
323
324#define PICK_TRIANGLE(tri, v0, v1, v2, uvw) \
325 new Qt3DRender::QPickTriangleEvent(QPointF(), QVector3D(), QVector3D(), 0.0f, \
326 tri, v0, v1, v2, Qt3DRender::QPickEvent::LeftButton, Qt::LeftButton, 0, uvw)
327
328 {
329 QSKIP("Disabled until Renderer plugin refactoring is complete");
330 // WHEN
331 QVector3D uvw(1.0, 0.0f, 0.0f);
332 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
333 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
334 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
335 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
336
337 QCoreApplication::processEvents();
338
339 // THEN
340 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(0,1024)));
341 testWindow->clear();
342 }
343
344 {
345 // WHEN
346 QVector3D uvw(0.0, 1.0f, 0.0f);
347 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
348 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
349 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
350 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
351
352 QCoreApplication::processEvents();
353
354 // THEN
355 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(1024,1024)));
356 testWindow->clear();
357 }
358
359 {
360 // WHEN
361 QVector3D uvw(0.0, 0.0f, 1.0f);
362 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
363 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
364 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
365 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
366
367 QCoreApplication::processEvents();
368
369 // THEN
370 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(1024,0)));
371 testWindow->clear();
372 }
373
374 {
375 // WHEN
376 QVector3D uvw(1.0, 0.0f, 0.0f);
377 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
378 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
379 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
380 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
381
382 QCoreApplication::processEvents();
383
384 // THEN
385 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(0,1024)));
386 testWindow->clear();
387 }
388
389 {
390 // WHEN
391 QVector3D uvw(0.0, 1.0f, 0.0f);
392 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
393 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
394 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
395 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
396
397 QCoreApplication::processEvents();
398
399 // THEN
400 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(1024,0)));
401 testWindow->clear();
402 }
403
404 {
405 // WHEN
406 QVector3D uvw(0.0, 0.0f, 1.0f);
407 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
408 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
409 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
410 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
411
412 QCoreApplication::processEvents();
413
414 // THEN
415 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(0,0)));
416 testWindow->clear();
417 }
418
419 {
420 // WHEN
421 QVector3D uvw(0.5f, 0.25f, 0.25f);
422 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
423 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
424 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
425 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
426
427 QCoreApplication::processEvents();
428
429 // THEN
430 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(512.0, 768.0)));
431 testWindow->clear();
432 }
433
434 {
435 // WHEN
436 QVector3D uvw(0.875f, 0.09375f, 0.03125f);
437 Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
438 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entity = entity->id();
439 Qt3DRender::QPickEventPrivate::get(object: ev.data())->m_entityPtr = entity.data();
440 scene2d->handlePickEvent(type: QEvent::MouseButtonPress, ev: ev.data());
441
442 QCoreApplication::processEvents();
443
444 // THEN
445 QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(96.0, 896.0)));
446 testWindow->clear();
447 }
448
449 scene2d.reset();
450 }
451};
452
453QTEST_MAIN(tst_Scene2D)
454
455#include "tst_scene2d.moc"
456

source code of qt3d/tests/auto/render/scene2d/tst_scene2d.cpp