/**************************************************************************** ** ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). ** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "testarbiter.h" using namespace Qt3DCore; using namespace Qt3DRender; using namespace Qt3DRender::Render; class tst_QRenderState : public QBackendNodeTester { Q_OBJECT public: tst_QRenderState() {} ~tst_QRenderState() {} private: RenderStateManager m_renderStateManager; TestRenderer m_renderer; RenderStateNode* createBackendNode(QRenderState *frontend) { RenderStateNode *backend = m_renderStateManager.getOrCreateResource(frontend->id()); backend->setRenderer(&m_renderer); simulateInitializationSync(frontend, backend); return backend; } // Create two frontend objects of class T and set given property to v1 / v2 respectively template void addTestCase(Qt3DRender::Render::StateMask mask, const char *property, Setter setter, V v1, V v2) { T *obj1 = new T(); T *obj2 = new T(); (obj1->*(setter))(v1); (obj2->*(setter))(v2); QTest::addRow("%s::%s", obj1->metaObject()->className(), property) << (QRenderState*) obj1 << (QRenderState*) obj2 << (quint64) mask << QString(property) << QVariant(v2); } // Create two frontend objects of class T and set given property to v1 / v2 respectively, for the specified arguments sub-object template void addStencilTestCase(Qt3DRender::Render::StateMask mask, const char *argsName, const char *property, Setter setter, V v1, V v2) { T *obj1 = new T(); T *obj2 = new T(); const QMetaObject *metaObj = obj1->metaObject(); const int pIndex = metaObj->indexOfProperty(argsName); const QMetaProperty prop = metaObj->property(pIndex); Args *args1 = qvariant_cast(prop.read(obj1)); Args *args2 = qvariant_cast(prop.read(obj2)); (args1->*(setter))(v1); (args2->*(setter))(v2); QTest::addRow("%s::%s::%s", metaObj->className(), argsName, property) << (QRenderState*) obj1 << (QObject*) args1 << (QRenderState*) obj2 << (quint64) mask << QString(property) << QVariant(v2); } private Q_SLOTS: void checkPropertyUpdates_data() { QTest::addColumn("frontend1"); QTest::addColumn("frontend2"); QTest::addColumn("mask"); QTest::addColumn("propertyName"); QTest::addColumn("value"); addTestCase(AlphaTestMask, "alphaFunction", &QAlphaTest::setAlphaFunction, QAlphaTest::Always, QAlphaTest::LessOrEqual); addTestCase(AlphaTestMask, "referenceValue", &QAlphaTest::setReferenceValue, 0.f, 1.f); addTestCase(BlendStateMask, "blendFunction", &QBlendEquation::setBlendFunction, QBlendEquation::Add, QBlendEquation::Subtract); addTestCase(BlendEquationArgumentsMask, "sourceRgb", &QBlendEquationArguments::setSourceRgb, QBlendEquationArguments::Zero, QBlendEquationArguments::One); addTestCase(BlendEquationArgumentsMask, "sourceAlpha", &QBlendEquationArguments::setSourceAlpha, QBlendEquationArguments::SourceAlpha, QBlendEquationArguments::OneMinusSource1Color); addTestCase(BlendEquationArgumentsMask, "destinationRgb", &QBlendEquationArguments::setDestinationRgb, QBlendEquationArguments::DestinationColor, QBlendEquationArguments::OneMinusSourceAlpha); addTestCase(BlendEquationArgumentsMask, "destinationAlpha", &QBlendEquationArguments::setDestinationAlpha, QBlendEquationArguments::DestinationAlpha, QBlendEquationArguments::DestinationColor); addTestCase(BlendEquationArgumentsMask, "bufferIndex", &QBlendEquationArguments::setBufferIndex, 0, 1); addTestCase(ClipPlaneMask, "planeIndex", &QClipPlane::setPlaneIndex, 0, 1); addTestCase(ClipPlaneMask, "normal", &QClipPlane::setNormal, QVector3D(0, 1, 0), QVector3D(0, 0, 1)); addTestCase(ClipPlaneMask, "distance", &QClipPlane::setDistance, 1.f, 2.f); addTestCase(ColorStateMask, "redMasked", &QColorMask::setRedMasked, false, true); addTestCase(ColorStateMask, "blueMasked", &QColorMask::setBlueMasked, false, true); addTestCase(ColorStateMask, "greenMasked", &QColorMask::setGreenMasked, false, true); addTestCase(ColorStateMask, "alphaMasked", &QColorMask::setAlphaMasked, false, true); addTestCase(CullFaceStateMask, "mode", &QCullFace::setMode, QCullFace::Back, QCullFace::FrontAndBack); addTestCase(FrontFaceStateMask, "direction", &QFrontFace::setDirection, QFrontFace::ClockWise, QFrontFace::CounterClockWise); addTestCase(PointSizeMask, "sizeMode", &QPointSize::setSizeMode, QPointSize::Programmable, QPointSize::Fixed); addTestCase(PointSizeMask, "value", &QPointSize::setValue, 2.f, 4.f); addTestCase(PolygonOffsetStateMask, "scaleFactor", &QPolygonOffset::setScaleFactor, 1.f, 2.f); addTestCase(PolygonOffsetStateMask, "depthSteps", &QPolygonOffset::setDepthSteps, 1.f, 2.f); addTestCase(ScissorStateMask, "left", &QScissorTest::setLeft, 10, 20); addTestCase(ScissorStateMask, "bottom", &QScissorTest::setBottom, 10, 20); addTestCase(ScissorStateMask, "width", &QScissorTest::setWidth, 10, 20); addTestCase(ScissorStateMask, "height", &QScissorTest::setHeight, 10, 20); addTestCase(StencilWriteStateMask, "frontOutputMask", &QStencilMask::setFrontOutputMask, 0x12, 0x34); addTestCase(StencilWriteStateMask, "backOutputMask", &QStencilMask::setBackOutputMask, 0x12, 0x34); addTestCase(DepthRangeMask, "nearValue", &QDepthRange::setNearValue, 0.1, 0.2); addTestCase(DepthRangeMask, "farValue", &QDepthRange::setFarValue, 0.5, 0.6); } void checkPropertyUpdates() { // GIVEN QFETCH(QRenderState*, frontend1); QFETCH(QRenderState*, frontend2); QFETCH(quint64, mask); QFETCH(QString, propertyName); QFETCH(QVariant, value); // THEN RenderStateNode *backend1 = createBackendNode(frontend1); RenderStateNode *backend2 = createBackendNode(frontend2); QVERIFY(backend1->type() == mask); QVERIFY(backend2->type() == mask); QVERIFY(backend1->impl() != backend2->impl()); // WHEN TestArbiter arbiter; arbiter.setArbiterOnNode(frontend1); const QMetaObject *metaObj = frontend1->metaObject(); const int pIndex = metaObj->indexOfProperty(propertyName.toStdString().c_str()); metaObj->property(pIndex).write(frontend1, value); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), frontend1); // WHEN backend1->syncFromFrontEnd(frontend1, false); // THEN QVERIFY(backend1->impl() == backend2->impl()); arbiter.clear(); } void checkStencilUpdates_data() { QTest::addColumn("frontend1"); QTest::addColumn("args1"); QTest::addColumn("frontend2"); QTest::addColumn("mask"); QTest::addColumn("propertyName"); QTest::addColumn("value"); qRegisterMetaType("QStencilOperationArguments*"); qRegisterMetaType("QStencilTestArguments*"); for (bool front : QVector{false, true}) { const char *argsProperty = front ? "front" : "back"; addStencilTestCase( StencilOpMask, argsProperty, "allTestsPassOperation", &QStencilOperationArguments::setAllTestsPassOperation, QStencilOperationArguments::Zero, QStencilOperationArguments::Keep); addStencilTestCase( StencilOpMask, argsProperty, "depthTestFailureOperation", &QStencilOperationArguments::setDepthTestFailureOperation, QStencilOperationArguments::Replace, QStencilOperationArguments::Zero); addStencilTestCase( StencilOpMask, argsProperty, "stencilTestFailureOperation", &QStencilOperationArguments::setStencilTestFailureOperation, QStencilOperationArguments::Increment, QStencilOperationArguments::Decrement); addStencilTestCase( StencilTestStateMask, argsProperty, "comparisonMask", &QStencilTestArguments::setComparisonMask, 0x12, 0x34); addStencilTestCase( StencilTestStateMask, argsProperty, "referenceValue", &QStencilTestArguments::setReferenceValue, 1, 2); addStencilTestCase( StencilTestStateMask, argsProperty, "stencilFunction", &QStencilTestArguments::setStencilFunction, QStencilTestArguments::Always, QStencilTestArguments::Equal); } } void checkStencilUpdates() { // GIVEN QFETCH(QRenderState*, frontend1); QFETCH(QObject*, args1); QFETCH(QRenderState*, frontend2); QFETCH(quint64, mask); QFETCH(QString, propertyName); QFETCH(QVariant, value); // THEN RenderStateNode *backend1 = createBackendNode(frontend1); RenderStateNode *backend2 = createBackendNode(frontend2); QVERIFY(backend1->type() == mask); QVERIFY(backend2->type() == mask); QVERIFY(backend1->impl() != backend2->impl()); // WHEN TestArbiter arbiter; arbiter.setArbiterOnNode(frontend1); const QMetaObject *metaObj = args1->metaObject(); const int pIndex = metaObj->indexOfProperty(propertyName.toStdString().c_str()); metaObj->property(pIndex).write(args1, value); QCoreApplication::processEvents(); // THEN QCOMPARE(arbiter.dirtyNodes().size(), 1); QCOMPARE(arbiter.dirtyNodes().front(), frontend1); // WHEN backend1->syncFromFrontEnd(frontend1, false); // THEN QVERIFY(backend1->impl() == backend2->impl()); } }; QTEST_MAIN(tst_QRenderState) #include "tst_qrenderstate.moc"