blob: b0a7fbeb8f66ab84d6d21133b3b8cca3fda57b0d [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QTest>
#include <Qt3DQuickScene2D/qscene2d.h>
#include <private/qscene2d_p.h>
#include <private/scene2d_p.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/qbuffer.h>
#include <private/trianglesvisitor_p.h>
#include <private/nodemanagers_p.h>
#include <private/managers_p.h>
#include <private/geometryrenderer_p.h>
#include <private/geometryrenderermanager_p.h>
#include <private/buffermanager_p.h>
#include <Qt3DRender/qpicktriangleevent.h>
#include <private/qpickevent_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <qbackendnodetester.h>
#include "testrenderer.h"
using namespace Qt3DRender::Quick;
using namespace Qt3DRender::Render;
using namespace Qt3DRender::Render::Quick;
bool qFuzzyComparePointF(const QPointF& a, const QPointF& b) {
return qFuzzyCompare(a.x(), b.x()) && qFuzzyCompare(a.y(), b.y());
}
class TestWindow : public QQuickWindow
{
Q_OBJECT
public:
TestWindow()
: QQuickWindow()
{
}
bool event(QEvent *e) override
{
if (e->type() >= QEvent::MouseButtonPress &&
e->type() <= QEvent::MouseMove) {
QMouseEvent *me = static_cast<QMouseEvent *>(e);
m_eventTypes.push_back(e->type());
m_mousePoints.push_back(me->localPos());
}
return QQuickWindow::event(e);
}
bool verifyEventPos(uint index, QEvent::Type type, const QPointF& pos)
{
if (index >= unsigned(m_eventTypes.size()) ||
m_eventTypes[index] != type ||
!qFuzzyComparePointF(pos, m_mousePoints[index]))
return false;
return true;
}
void clear()
{
m_eventTypes.clear();
m_mousePoints.clear();
}
private:
QVector<QEvent::Type> m_eventTypes;
QVector<QPointF> m_mousePoints;
};
class tst_Scene2D : public Qt3DCore::QBackendNodeTester
{
Q_OBJECT
private Q_SLOTS:
void checkInitialState()
{
// GIVEN
Scene2D backendScene2d;
// THEN
QCOMPARE(backendScene2d.isEnabled(), false);
QVERIFY(backendScene2d.peerId().isNull());
QCOMPARE(backendScene2d.m_context, nullptr);
QCOMPARE(backendScene2d.m_shareContext, nullptr);
QCOMPARE(backendScene2d.m_renderThread, nullptr);
QCOMPARE(backendScene2d.m_outputId, Qt3DCore::QNodeId());
QCOMPARE(backendScene2d.m_initialized, false);
QCOMPARE(backendScene2d.m_renderInitialized, false);
QCOMPARE(backendScene2d.m_renderPolicy, QScene2D::Continuous);
QCOMPARE(backendScene2d.m_mouseEnabled, true);
backendScene2d.cleanup();
}
void checkInitializeFromPeer()
{
// GIVEN
Qt3DRender::Quick::QScene2D frontend;
TestRenderer renderer;
{
// WHEN
QScopedPointer<Scene2D> backendScene2d(new Scene2D());
backendScene2d->setRenderer(&renderer);
simulateInitializationSync(&frontend, backendScene2d.data());
// THEN
QCOMPARE(backendScene2d->isEnabled(), true);
QCOMPARE(backendScene2d->peerId(), frontend.id());
QCOMPARE(backendScene2d->m_outputId, Qt3DCore::QNodeId());
QVERIFY(backendScene2d->m_sharedObject.data() != nullptr);
QCOMPARE(backendScene2d->m_renderPolicy, QScene2D::Continuous);
QCOMPARE(backendScene2d->m_mouseEnabled, true);
backendScene2d->cleanup();
}
{
// WHEN
QScopedPointer<Scene2D> backendScene2d(new Scene2D());
frontend.setEnabled(false);
backendScene2d->setRenderer(&renderer);
simulateInitializationSync(&frontend, backendScene2d.data());
// THEN
QCOMPARE(backendScene2d->peerId(), frontend.id());
QCOMPARE(backendScene2d->isEnabled(), false);
backendScene2d->cleanup();
}
}
void checkSceneChangeEvents()
{
// GIVEN
Qt3DRender::Quick::QScene2D frontend;
QScopedPointer<Scene2D> backendScene2d(new Scene2D());
TestRenderer renderer;
QScopedPointer<Qt3DRender::QRenderTargetOutput> output(new Qt3DRender::QRenderTargetOutput());
backendScene2d->setRenderer(&renderer);
simulateInitializationSync(&frontend, backendScene2d.data());
{
// WHEN
const bool newValue = false;
frontend.setEnabled(false);
backendScene2d->syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backendScene2d->isEnabled(), newValue);
}
{
// WHEN
const Qt3DCore::QNodeId newValue = output.data()->id();
frontend.setOutput(output.data());
backendScene2d->syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backendScene2d->m_outputId, newValue);
}
{
// WHEN
const QScene2D::RenderPolicy newValue = QScene2D::SingleShot;
frontend.setRenderPolicy(newValue);
backendScene2d->syncFromFrontEnd(&frontend, false);
// THEN
QCOMPARE(backendScene2d->m_renderPolicy, newValue);
}
{
// WHEN
const bool newValue = false;
frontend.setMouseEnabled(newValue);
// THEN
QCOMPARE(backendScene2d->isEnabled(), newValue);
}
backendScene2d->cleanup();
}
void testCoordinateCalculation()
{
// GIVEN
qputenv("QT3D_SCENE2D_DISABLE_RENDERING", "1");
QScopedPointer<TestWindow> testWindow(new TestWindow());
Scene2DSharedObjectPtr sharedObject(new Scene2DSharedObject(nullptr));
TestRenderer renderer;
QScopedPointer<Scene2D> scene2d(new Scene2D());
QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DRender::QGeometryRenderer();
Qt3DRender::QAttribute *positionAttribute = new Qt3DRender::QAttribute();
Qt3DRender::QAttribute *texcoordAttribute = new Qt3DRender::QAttribute();
Qt3DRender::QBuffer *dataBuffer =new Qt3DRender::QBuffer();
QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity());
entity->addComponent(geometryRenderer);
renderer.setNodeManagers(nodeManagers.data());
scene2d->setRenderer(&renderer);
scene2d->setEnabled(true);
sharedObject->m_quickWindow = testWindow.data();
scene2d->setSharedObject(sharedObject);
testWindow->setGeometry(0,0,1024,1024);
QByteArray data;
data.resize(sizeof(float) * 5 * 6);
float *dataPtr = reinterpret_cast<float *>(data.data());
int i = 0;
dataPtr[i++] = -1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 0;
dataPtr[i++] = 0;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 0;
dataPtr[i++] = 1.0f;
dataPtr[i++] = -1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = -1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 0;
dataPtr[i++] = 0;
dataPtr[i++] = 1.0f;
dataPtr[i++] = -1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = -1.0f;
dataPtr[i++] = -1.0f;
dataPtr[i++] = 1.0f;
dataPtr[i++] = 0.0f;
dataPtr[i++] = 1.0f;
dataBuffer->setData(data);
Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
backendBuffer->setRenderer(&renderer);
backendBuffer->setManager(nodeManagers->bufferManager());
simulateInitializationSync(dataBuffer, backendBuffer);
positionAttribute->setBuffer(dataBuffer);
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(sizeof(float) * 5);
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
geometry->addAttribute(positionAttribute);
texcoordAttribute->setBuffer(dataBuffer);
texcoordAttribute->setName(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName());
texcoordAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
texcoordAttribute->setVertexSize(2);
texcoordAttribute->setCount(6);
texcoordAttribute->setByteStride(sizeof(float) * 5);
texcoordAttribute->setByteOffset(sizeof(float) * 3);
texcoordAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
geometry->addAttribute(texcoordAttribute);
geometryRenderer->setGeometry(geometry);
geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(
positionAttribute->id());
backendAttribute->setRenderer(&renderer);
simulateInitializationSync(positionAttribute, backendAttribute);
Attribute *backendTexcoordAttribute = nodeManagers->attributeManager()
->getOrCreateResource(texcoordAttribute->id());
backendTexcoordAttribute->setRenderer(&renderer);
simulateInitializationSync(texcoordAttribute, backendTexcoordAttribute);
Geometry *backendGeometry = nodeManagers->geometryManager()
->getOrCreateResource(geometry->id());
backendGeometry->setRenderer(&renderer);
simulateInitializationSync(geometry, backendGeometry);
GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()
->getOrCreateResource(geometryRenderer->id());
backendRenderer->setRenderer(&renderer);
backendRenderer->setManager(nodeManagers->geometryRendererManager());
simulateInitializationSync(geometryRenderer, backendRenderer);
Entity *backendEntity = nodeManagers->renderNodesManager()->getOrCreateResource(entity->id());
backendEntity->setRenderer(&renderer);
backendEntity->setNodeManagers(nodeManagers.data());
simulateInitializationSync(entity.data(), backendEntity);
#define PICK_TRIANGLE(tri, v0, v1, v2, uvw) \
new Qt3DRender::QPickTriangleEvent(QPointF(), QVector3D(), QVector3D(), 0.0f, \
tri, v0, v1, v2, Qt3DRender::QPickEvent::LeftButton, Qt::LeftButton, 0, uvw)
{
QSKIP("Disabled until Renderer plugin refactoring is complete");
// WHEN
QVector3D uvw(1.0, 0.0f, 0.0f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(0,1024)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(0.0, 1.0f, 0.0f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(1024,1024)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(0.0, 0.0f, 1.0f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(1024,0)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(1.0, 0.0f, 0.0f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(0,1024)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(0.0, 1.0f, 0.0f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(1024,0)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(0.0, 0.0f, 1.0f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(0,0)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(0.5f, 0.25f, 0.25f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(0, 0, 1, 2, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(512.0, 768.0)));
testWindow->clear();
}
{
// WHEN
QVector3D uvw(0.875f, 0.09375f, 0.03125f);
Qt3DRender::QPickEventPtr ev = Qt3DRender::QPickEventPtr(PICK_TRIANGLE(1, 3, 4, 5, uvw));
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entity = entity->id();
Qt3DRender::QPickEventPrivate::get(ev.data())->m_entityPtr = entity.data();
scene2d->handlePickEvent(QEvent::MouseButtonPress, ev.data());
QCoreApplication::processEvents();
// THEN
QVERIFY(testWindow->verifyEventPos(0, QEvent::MouseButtonPress, QPointF(96.0, 896.0)));
testWindow->clear();
}
scene2d.reset();
}
};
QTEST_MAIN(tst_Scene2D)
#include "tst_scene2d.moc"