summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-06-28 10:46:43 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-06-28 11:06:43 +0300
commit90702603c5e525190c94f24c10cb9ff83e7abb19 (patch)
treedcf76e4de1dccb9646fbd35c6b9a5a1ea2009922
parent427bf6fac383f066a1378679a88546b16f156c7e (diff)
parent0c4183e5748576845d9ce2aa61f56cf5c69c6350 (diff)
Merge "Merge branch '2.4'"
-rw-r--r--.gitignore21
-rw-r--r--LICENSE.GPL3674
-rw-r--r--LICENSE.GPL3-EXCEPT704
-rw-r--r--commoninclude.pri3
-rw-r--r--examples/studio3d/dynamicelement/demo.cpp319
-rw-r--r--examples/studio3d/dynamicelement/demo.h92
-rw-r--r--examples/studio3d/dynamicelement/demo.mtl10
-rw-r--r--examples/studio3d/dynamicelement/demo.obj2979
-rw-r--r--examples/studio3d/dynamicelement/dynamicelement.pro15
-rw-r--r--examples/studio3d/dynamicelement/dynamicelement.qrc14
-rw-r--r--examples/studio3d/dynamicelement/main.cpp92
-rw-r--r--examples/studio3d/dynamicelement/main.qml80
-rw-r--r--examples/studio3d/dynamicelement/presentation/maps/materials/shadow.pngbin0 -> 334 bytes
-rw-r--r--examples/studio3d/dynamicelement/presentation/maps/materials/spherical_checker.pngbin0 -> 11066 bytes
-rw-r--r--examples/studio3d/dynamicelement/presentation/materials/Copper.materialdef14
-rw-r--r--examples/studio3d/dynamicelement/presentation/materials/Red.materialdef25
-rw-r--r--examples/studio3d/dynamicelement/presentation/materials/copper.shader178
-rw-r--r--examples/studio3d/dynamicelement/presentation/presentation.uia6
-rw-r--r--examples/studio3d/dynamicelement/presentation/presentations/presentation.uip24
-rw-r--r--examples/studio3d/qmldatainput/qml/qmldatainput/main.qml10
-rw-r--r--examples/studio3d/simpleqml/main.qml21
-rw-r--r--examples/studio3d/simpleqml/presentation/barrel.uia28
-rw-r--r--examples/studio3d/simpleqml/presentation/barrel.uip16
-rw-r--r--examples/studio3d/studio3d.pro3
-rw-r--r--ogl-runtime.pro23
m---------src/3rdparty/EASTL0
-rw-r--r--src/api/studio3d/doc/doc.pri9
-rw-r--r--src/api/studio3d/doc/online/qtstudio3d.qdocconf2
-rw-r--r--src/api/studio3d/doc/qt3dstudio-opengl-runtime-project.qdocconf63
-rw-r--r--src/api/studio3d/doc/qtstudio3d.qdocconf2
-rw-r--r--src/api/studio3d/doc/src/attributenames.html911
-rw-r--r--src/api/studio3d/doc/src/attributenames.qdoc71
-rw-r--r--src/api/studio3d/doc/src/building-embedded.qdoc82
-rw-r--r--src/api/studio3d/doc/src/building-integrity.qdoc71
-rw-r--r--src/api/studio3d/doc/src/building-opengl-runtime.qdoc44
-rw-r--r--src/api/studio3d/doc/src/building-qnx.qdoc162
-rw-r--r--src/api/studio3d/doc/src/copyright.qdoc38
-rw-r--r--src/api/studio3d/doc/src/embedded.qdoc32
-rw-r--r--src/api/studio3d/doc/src/examples.qdoc41
-rw-r--r--src/api/studio3d/doc/src/gettingstarted.qdoc117
-rw-r--r--src/api/studio3d/doc/src/images/add-build-step-qnx.pngbin0 -> 212284 bytes
-rw-r--r--src/api/studio3d/doc/src/images/add-build-step.pngbin0 -> 170273 bytes
-rw-r--r--src/api/studio3d/doc/src/images/add-qnx-device.pngbin0 -> 19121 bytes
-rw-r--r--src/api/studio3d/doc/src/images/customsignal.pngbin0 -> 28206 bytes
-rw-r--r--src/api/studio3d/doc/src/images/devices-tab.pngbin0 -> 118542 bytes
-rw-r--r--src/api/studio3d/doc/src/images/embedded-linux-2.pngbin0 -> 136019 bytes
-rw-r--r--src/api/studio3d/doc/src/images/embedded-linux.pngbin0 -> 177270 bytes
-rw-r--r--src/api/studio3d/doc/src/images/intro-app.pngbin0 -> 368639 bytes
-rw-r--r--src/api/studio3d/doc/src/images/intro-editor.pngbin0 -> 289164 bytes
-rw-r--r--src/api/studio3d/doc/src/images/intro-viewer.pngbin0 -> 338976 bytes
-rw-r--r--src/api/studio3d/doc/src/images/ogl-runtime-pro.pngbin0 -> 68177 bytes
-rw-r--r--src/api/studio3d/doc/src/images/qnx-prebuild.pngbin0 -> 112522 bytes
-rw-r--r--src/api/studio3d/doc/src/images/qnx-sdp-folder.pngbin0 -> 22958 bytes
-rw-r--r--src/api/studio3d/doc/src/images/qt-installer-qnx-prebuild.pngbin0 -> 94480 bytes
-rw-r--r--src/api/studio3d/doc/src/images/qt3dstudio-pro.pngbin0 -> 52413 bytes
-rw-r--r--src/api/studio3d/doc/src/images/select-prebuilt-qnx-component.pngbin0 -> 127837 bytes
-rw-r--r--src/api/studio3d/doc/src/images/twolayers.pngbin0 -> 4564 bytes
-rw-r--r--src/api/studio3d/doc/src/index.qdoc45
-rw-r--r--src/api/studio3d/doc/src/mobile.qdoc32
-rw-r--r--src/api/studio3d/doc/src/module.qdoc111
-rw-r--r--src/api/studio3d/doc/src/requirements.qdoc100
-rw-r--r--src/api/studio3d/doc/src/toc.qdoc40
-rw-r--r--src/api/studio3d/doc/style/qt5-sidebar.html26
-rw-r--r--src/api/studio3d/q3dscommandqueue.cpp5
-rw-r--r--src/api/studio3d/q3dscommandqueue_p.h2
-rw-r--r--src/api/studio3d/q3dsdatainput.cpp105
-rw-r--r--src/api/studio3d/q3dsdatainput.h3
-rw-r--r--src/api/studio3d/q3dsdataoutput.cpp27
-rw-r--r--src/api/studio3d/q3dselement.cpp6
-rw-r--r--src/api/studio3d/q3dsgeometry.cpp212
-rw-r--r--src/api/studio3d/q3dspresentation.cpp428
-rw-r--r--src/api/studio3d/q3dssceneelement.cpp16
-rw-r--r--src/api/studio3d/q3dssurfaceviewer.cpp3
-rw-r--r--src/api/studio3d/q3dsviewersettings.cpp92
-rw-r--r--src/api/studio3d/q3dsviewersettings.h7
-rw-r--r--src/api/studio3d/q3dsviewersettings_p.h2
-rw-r--r--src/api/studio3d/studio3d.pro2
-rw-r--r--src/api/studio3dqml/plugins.qmltypes438
-rw-r--r--src/api/studio3dqml/q3dspresentationitem.cpp44
-rw-r--r--src/api/studio3dqml/q3dsrenderer.cpp10
-rw-r--r--src/api/studio3dqml/q3dsrenderer_p.h5
-rw-r--r--src/api/studio3dqml/q3dsstudio3d.cpp26
-rw-r--r--src/api/studio3dqml/q3dsstudio3d_p.h2
-rw-r--r--src/dm/systems/Qt3DSDMStringTable.h1
-rw-r--r--src/engine/Qt3DSRenderRuntimeBindingImplRenderer.cpp1
-rw-r--r--src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp96
-rw-r--r--src/engine/Qt3DSRuntimeView.cpp3
-rw-r--r--src/engine/Qt3DSRuntimeView.h1
-rw-r--r--src/foundation/Qt3DSFoundation.cpp9
-rw-r--r--src/foundation/Qt3DSPreprocessor.h17
-rw-r--r--src/foundation/StringTable.cpp83
-rw-r--r--src/foundation/StringTable.h2
-rw-r--r--src/foundation/qt/formatdiscovery.cpp18
-rw-r--r--src/ogl-runtime-dylib/ogl-runtime-dylib.pro16
-rw-r--r--src/ogl-runtime-static/ogl-runtime-static.pro11
-rw-r--r--src/qmlstreamer/q3dsqmlstream.cpp9
-rw-r--r--src/qmlstreamer/q3dsqmlsubpresentationsettings.cpp8
-rw-r--r--src/runtime/Qt3DSActivationManager.cpp5
-rw-r--r--src/runtime/Qt3DSApplication.cpp14
-rw-r--r--src/runtime/Qt3DSApplication.h5
-rw-r--r--src/runtime/Qt3DSElementSystem.cpp73
-rw-r--r--src/runtime/Qt3DSElementSystem.h3
-rw-r--r--src/runtime/Qt3DSQmlElementHelper.cpp32
-rw-r--r--src/runtime/Qt3DSQmlElementHelper.h3
-rw-r--r--src/runtime/Qt3DSQmlEngine.cpp229
-rw-r--r--src/runtimerender/Qt3DSDistanceFieldRenderer.cpp33
-rw-r--r--src/runtimerender/Qt3DSDistanceFieldRenderer.h1
-rw-r--r--src/runtimerender/Qt3DSOnscreenTextRenderer.cpp14
-rw-r--r--src/runtimerender/Qt3DSRenderContextCore.cpp36
-rw-r--r--src/runtimerender/Qt3DSRenderContextCore.h1
-rw-r--r--src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp4
-rw-r--r--src/runtimerender/Qt3DSRenderCustomMaterialSystem.h2
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderScene.cpp7
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp34
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImpl.h4
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp23
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp32
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h6
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp1
-rw-r--r--src/viewer/Qt3DSViewerApp.cpp14
-rw-r--r--src/viewer/Qt3DSViewerApp.h1
-rw-r--r--testres.qrc14
-rw-r--r--tests/auto/auto.pro10
-rw-r--r--tests/auto/qtextras/qt3dsqmlstream/qt3dsqmlstream.pro18
-rw-r--r--tests/auto/qtextras/qt3dsqmlstream/tst_qt3dsqmlstream.cpp106
-rw-r--r--tests/auto/qtextras/qtextras.pro4
-rw-r--r--tests/auto/runtime/Qt3DSRenderTestBase.cpp101
-rw-r--r--tests/auto/runtime/Qt3DSRenderTestBase.h164
-rw-r--r--tests/auto/runtime/Qt3DSRenderTestMathUtil.cpp118
-rw-r--r--tests/auto/runtime/Qt3DSRenderTestMathUtil.h50
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.cpp248
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.h59
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.cpp251
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.h59
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.cpp332
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.h62
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestClear.cpp131
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestClear.h56
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.cpp847
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.h63
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.cpp358
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.h60
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestPrimitives.cpp321
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestPrimitives.h77
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.cpp401
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.h60
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestTexture2D.cpp288
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestTexture2D.h67
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.cpp436
-rw-r--r--tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.h64
-rw-r--r--tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.cpp636
-rw-r--r--tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.h61
-rw-r--r--tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.cpp299
-rw-r--r--tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.h67
-rw-r--r--tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.cpp390
-rw-r--r--tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.h60
-rw-r--r--tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.cpp367
-rw-r--r--tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.h66
-rw-r--r--tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.cpp560
-rw-r--r--tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.h60
-rw-r--r--tests/auto/runtime/images/NVRenderTestAttribBuffers.pngbin0 -> 3820 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestBackendQuery.pngbin0 -> 2355 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestClear.pngbin0 -> 2327 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestComputeShader.pngbin0 -> 3889 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestDrawIndirectBuffer.pngbin0 -> 2355 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestFboMsaa.pngbin0 -> 3168 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestGeometryShader.pngbin0 -> 3311 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestOcclusionQuery.pngbin0 -> 2355 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestProgramPipeline.pngbin0 -> 3224 bytes
-rw-r--r--tests/auto/runtime/images/NVRenderTestTexture2D.pngbin0 -> 2991 bytes
-rw-r--r--tests/auto/runtime/runtime.pro82
-rw-r--r--tests/auto/runtime/runtime.qrc14
-rw-r--r--tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.cpp469
-rw-r--r--tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.h55
-rw-r--r--tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.cpp574
-rw-r--r--tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.h56
-rw-r--r--tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.cpp155
-rw-r--r--tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.h55
-rw-r--r--tests/auto/runtime/tst_qt3dsruntime.cpp727
-rw-r--r--tests/auto/runtime/tst_qt3dsruntime.h144
-rw-r--r--tests/auto/studio3d/q3dssurfaceviewer/q3dssurfaceviewer.pro10
-rw-r--r--tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp1516
-rw-r--r--tests/auto/studio3d/shared/presentation/animation.uip35
-rw-r--r--tests/auto/studio3d/shared/presentation/blue.uip31
-rw-r--r--tests/auto/studio3d/shared/presentation/datainput.uia18
-rw-r--r--tests/auto/studio3d/shared/presentation/datainput.uip63
-rw-r--r--tests/auto/studio3d/shared/presentation/datainput_sub.uip31
-rw-r--r--tests/auto/studio3d/shared/presentation/fonts/TitilliumWeb-Regular.ttfbin0 -> 63752 bytes
-rw-r--r--tests/auto/studio3d/shared/presentation/mixed.uip36
-rw-r--r--tests/auto/studio3d/shared/presentation/mixed_vertical.uip36
-rw-r--r--tests/auto/studio3d/shared/presentation/mouse.uip54
-rw-r--r--tests/auto/studio3d/shared/presentation/multislide.uip99
-rw-r--r--tests/auto/studio3d/shared/presentation/red.uip31
-rw-r--r--tests/auto/studio3d/shared/presentation/settings.uip31
-rw-r--r--tests/auto/studio3d/shared/shared_presentations.h39
-rw-r--r--tests/auto/studio3d/shared/shared_presentations.qrc15
-rw-r--r--tests/auto/studio3d/studio3d.pro4
-rw-r--r--tests/auto/viewer/tst_qt3dsviewer.cpp764
-rw-r--r--tests/auto/viewer/tst_qt3dsviewer.h80
-rw-r--r--tests/auto/viewer/tst_qt3dsviewer.qml62
-rw-r--r--tests/auto/viewer/viewer.pro21
-rw-r--r--tests/auto/viewer/viewer.qrc16
-rw-r--r--tests/scenes/customvertex/customvertex.uia15
-rw-r--r--tests/scenes/customvertex/materials/simple.shader29
-rw-r--r--tests/scenes/customvertex/presentations/customvertex.uip33
-rw-r--r--tests/scenes/simple_cube_animation/maps/QT-symbol.pngbin0 -> 4541 bytes
-rw-r--r--tests/scenes/simple_cube_animation/maps/materials/shadow.pngbin0 -> 334 bytes
-rw-r--r--tests/scenes/simple_cube_animation/maps/materials/spherical_checker.pngbin0 -> 11066 bytes
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef25
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Green.materialdef25
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Red.materialdef25
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef63
-rw-r--r--tests/scenes/simple_cube_animation/materials/Copper.materialdef14
-rw-r--r--tests/scenes/simple_cube_animation/materials/copper.shader178
-rw-r--r--tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip62
-rw-r--r--tests/scenes/simple_cube_animation/simple_cube_animation.uia16
-rw-r--r--tests/tests.pro3
-rw-r--r--tools/viewer/main.cpp3
-rw-r--r--tools/viewer/qml/main.qml16
219 files changed, 22249 insertions, 609 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5975798
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+build-*
+*.pro.user*
+/*/Viewer/Shared/UICEmbeddedWatermark.cpp
+/.qmake.stash
+fontcache/
+mocinclude.opt
+/installerextras/*/
+/src/3rdparty/boost/
+/src/3rdparty/FBX/
+*.o
+Makefile
+Makefile.*
+.moc/
+.uic/
+.rcc/
+.obj/
+lib/
+moc_*.cpp
+.DS_Store
+*.qmlc
+*.so
diff --git a/LICENSE.GPL3 b/LICENSE.GPL3
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENSE.GPL3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/LICENSE.GPL3-EXCEPT b/LICENSE.GPL3-EXCEPT
new file mode 100644
index 0000000..b1cb1be
--- /dev/null
+++ b/LICENSE.GPL3-EXCEPT
@@ -0,0 +1,704 @@
+This is the GNU General Public License version 3, annotated with The
+Qt Company GPL Exception 1.0:
+
+-------------------------------------------------------------------------
+
+The Qt Company GPL Exception 1.0
+
+Exception 1:
+
+As a special exception you may create a larger work which contains the
+output of this application and distribute that work under terms of your
+choice, so long as the work is not otherwise derived from or based on
+this application and so long as the work does not in itself generate
+output that contains the output from this application in its original
+or modified form.
+
+Exception 2:
+
+As a special exception, you have permission to combine this application
+with Plugins licensed under the terms of your choice, to produce an
+executable, and to copy and distribute the resulting executable under
+the terms of your choice. However, the executable must be accompanied
+by a prominent notice offering all users of the executable the entire
+source code to this application, excluding the source code of the
+independent modules, but including any changes you have made to this
+application, under the terms of this license.
+
+
+-------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/commoninclude.pri b/commoninclude.pri
index 3940e4d..83eb886 100644
--- a/commoninclude.pri
+++ b/commoninclude.pri
@@ -8,8 +8,7 @@ contains(TEMPLATE, lib) {
QT += core gui openglextensions
DEFINES += COMPILED_FROM_DSP \
- QT3DSDM_USE_NVLOG QT3DSDM_META_DATA_NO_SIGNALS \
- QT3DS_AUTOTESTS_ENABLED
+ QT3DSDM_USE_NVLOG QT3DSDM_META_DATA_NO_SIGNALS
INCLUDEPATH += \
$$PWD/src \
diff --git a/examples/studio3d/dynamicelement/demo.cpp b/examples/studio3d/dynamicelement/demo.cpp
new file mode 100644
index 0000000..9564d1b
--- /dev/null
+++ b/examples/studio3d/dynamicelement/demo.cpp
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qfile.h>
+#include <QtCore/qrandom.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qdebug.h>
+#include <array>
+#include "demo.h"
+
+Demo::Demo(Q3DSPresentation *presentation, QObject *parent)
+ : QObject(parent),
+ m_presentation(presentation)
+{
+ m_elementData.resize(200);
+}
+
+void Demo::setup()
+{
+ createMaterials();
+
+ QObject::connect(m_presentation, &Q3DSPresentation::materialsCreated,
+ [&](const QStringList &materialNames, const QString &error) {
+ if (!error.isEmpty())
+ qDebug() << "createMaterials error: " << error;
+ else
+ qDebug() << "materialNames: " << materialNames;
+
+ createMeshes();
+ });
+
+ QObject::connect(m_presentation, &Q3DSPresentation::meshesCreated,
+ [&](const QStringList &meshNames, const QString &error) {
+ if (!error.isEmpty())
+ qDebug() << "createMeshes error: " << error;
+ else
+ qDebug() << "meshNames: " << meshNames;
+
+ createElements();
+ });
+
+ QObject::connect(m_presentation, &Q3DSPresentation::elementsCreated,
+ [&](const QStringList &elementNames, const QString &error) {
+ if (!error.isEmpty())
+ qDebug() << "createElements error: " << error;
+ else
+ qDebug() << "elementNames: " << elementNames;
+
+ setupDone = true;
+ });
+}
+
+void Demo::createMaterials()
+{
+ m_presentation->createMaterials({QStringLiteral(":/presentation/materials/Copper.materialdef"),
+ QStringLiteral(":/presentation/materials/Red.materialdef")});
+}
+
+void Demo::createMeshes()
+{
+ Q3DSGeometry obj;
+
+ if (!parseObj(QStringLiteral(":/demo.obj"), obj))
+ qWarning("Failed to parse object");
+
+ QHash<QString, const Q3DSGeometry *> meshData;
+
+ meshData.insert(QStringLiteral("Suzanne"), &obj);
+
+ m_presentation->createMeshes(meshData);
+}
+
+void Demo::createElements()
+{
+ QRandomGenerator *rng = QRandomGenerator::system();
+ QVector< QHash<QString, QVariant> > properties;
+
+ for (int i = 0; i < m_elementData.size(); ++i) {
+ double theta = rng->bounded(2.0 * M_PI);
+
+ m_elementData[i].position = QVector3D(float(500.0 * qCos(theta)),
+ float(500.0 * qSin(theta)),
+ float(rng->bounded(-500, 10000)));
+ m_elementData[i].rotation = QVector3D(float(rng->bounded(360.0)),
+ float(rng->bounded(360.0)),
+ float(rng->bounded(360.0)));
+ m_elementData[i].delta = QVector3D(float(-1.0 + 2.0 * rng->generateDouble()),
+ float(-1.0 + 2.0 * rng->generateDouble()),
+ float(-1.0 + 2.0 * rng->generateDouble()));
+
+ QHash<QString, QVariant> data;
+
+ data.insert(QStringLiteral("name"), QStringLiteral("MyElement_%1").arg(i));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("Suzanne"));
+ data.insert(QStringLiteral("material"),
+ i % 2 == 0 ? QStringLiteral("materials/Red") :
+ QStringLiteral("materials/Copper"));
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(m_elementData[i].position));
+ data.insert(QStringLiteral("rotation"),
+ QVariant::fromValue<QVector3D>(m_elementData[i].rotation));
+
+ properties.push_back(data);
+ }
+
+ m_presentation->createElements(QStringLiteral("Scene.Layer"),
+ QStringLiteral("Slide1"), properties);
+}
+
+void Demo::animate()
+{
+ if (!setupDone)
+ return;
+
+ QRandomGenerator *rng = QRandomGenerator::system();
+
+ for (int i = 0; i < m_elementData.size(); ++i) {
+ QString e = QStringLiteral("Scene.Layer.MyElement_%1").arg(i);
+
+ float z = m_elementData[i].position.z() - 10;
+
+ if (z < -600) {
+ double theta = rng->bounded(2.0 * M_PI);
+
+ m_elementData[i].position = QVector3D(float(500.0 * qCos(theta)),
+ float(500.0 * qSin(theta)),
+ 10000.0);
+ } else {
+ m_elementData[i].position.setZ(z);
+ }
+
+ m_presentation->setAttribute(e, QStringLiteral("position.x"), m_elementData[i].position.x());
+ m_presentation->setAttribute(e, QStringLiteral("position.y"), m_elementData[i].position.y());
+ m_presentation->setAttribute(e, QStringLiteral("position.z"), m_elementData[i].position.z());
+
+ m_elementData[i].rotation.setX(m_elementData[i].rotation.x() + m_elementData[i].delta.x());
+ m_elementData[i].rotation.setY(m_elementData[i].rotation.y() + m_elementData[i].delta.y());
+ m_elementData[i].rotation.setZ(m_elementData[i].rotation.z() + m_elementData[i].delta.z());
+
+ m_presentation->setAttribute(e, QStringLiteral("rotation.x"), m_elementData[i].rotation.x());
+ m_presentation->setAttribute(e, QStringLiteral("rotation.y"), m_elementData[i].rotation.y());
+ m_presentation->setAttribute(e, QStringLiteral("rotation.z"), m_elementData[i].rotation.z());
+ }
+}
+
+bool Demo::parseObj(const QString &path, Q3DSGeometry &obj)
+{
+ QFile file(path);
+
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning("Failed to open %s", qPrintable(path));
+ return false;
+ }
+
+ QTextStream in(&file);
+
+ QVector<QVector3D> vertices;
+ QVector<QVector3D> normals;
+ QVector<QVector2D> texCoords;
+
+ struct Index
+ {
+ int v;
+ int vt;
+ int vn;
+ };
+
+ QVector< std::array<Index, 3> > faces;
+
+ vertices.clear();
+ normals.clear();
+ texCoords.clear();
+ faces.clear();
+
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+ QStringList fields = line.split(QLatin1Char(' '));
+ if (fields[0] == QLatin1String("v")) {
+ vertices.push_back(QVector3D(fields[1].toFloat(),
+ fields[2].toFloat(),
+ fields[3].toFloat()));
+ } else if (fields[0] == QLatin1String("vn")) {
+ normals.push_back(QVector3D(fields[1].toFloat(),
+ fields[2].toFloat(),
+ fields[3].toFloat()));
+ } else if (fields[0] == QLatin1String("vt")) {
+ texCoords.push_back(QVector2D(fields[1].toFloat(),
+ fields[2].toFloat()));
+ }
+ else if (fields[0] == QLatin1String("f")) {
+ if (fields.size() != 4) {
+ qWarning("Only triangle meshes supported");
+ return false;
+ }
+
+ auto parseIndex = [&](QStringList v) -> Index {
+ int vertex = v[0].toInt() - 1;
+ int texture = v[1].toInt() - 1;
+ int normal = v[2].toInt() - 1;
+ return Index({ vertex, texture, normal });
+ };
+
+ Index i = parseIndex(fields[1].split(QLatin1Char('/')));
+ Index j = parseIndex(fields[2].split(QLatin1Char('/')));
+ Index k = parseIndex(fields[3].split(QLatin1Char('/')));
+
+ faces.push_back({i, j, k});
+ }
+ }
+
+ struct Vertex
+ {
+ QVector3D position;
+ QVector3D normal;
+ QVector2D texture;
+ QVector3D textan;
+ QVector3D binorm;
+ };
+
+ QVector<QVector3D> textans;
+ QVector<QVector3D> binorms;
+
+ for (int n = 0; n < faces.size(); ++n) {
+ QVector3D v0 = vertices[faces[n][0].v];
+ QVector3D v1 = vertices[faces[n][1].v];
+ QVector3D v2 = vertices[faces[n][2].v];
+
+ QVector2D uv0 = texCoords[faces[n][0].vt];
+ QVector2D uv1 = texCoords[faces[n][1].vt];
+ QVector2D uv2 = texCoords[faces[n][2].vt];
+
+ QVector3D deltaPos1 = v1 - v0;
+ QVector3D deltaPos2 = v2 - v0;
+
+ QVector2D deltaUV1 = uv1 - uv0;
+ QVector2D deltaUV2 = uv2 - uv0;
+
+ float r = 1.0f / (deltaUV1.x() * deltaUV2.y() - deltaUV1.y() * deltaUV2.x());
+ QVector3D tangent = (deltaPos1 * deltaUV2.y() - deltaPos2 * deltaUV1.y()) * r;
+ QVector3D binorm = (deltaPos2 * deltaUV1.x() - deltaPos1 * deltaUV2.x()) * r;
+
+ textans.append(tangent);
+ binorms.append(binorm);
+ }
+
+ QVector<Vertex> vertexData;
+
+ for (int n = 0; n < faces.size(); ++n) {
+ for (int m = 0; m < 3; ++m) {
+ int v = faces[n][m].v;
+ int vt = faces[n][m].vt;
+ int vn = faces[n][m].vn;
+
+ vertexData.push_back({ vertices[v], normals[vn],
+ vt != -1 ? texCoords[vt] : QVector2D(0, 0),
+ textans[n], binorms[n] });
+ }
+ }
+
+ QByteArray vertexBuffer(reinterpret_cast<const char *>(vertexData.constData()),
+ vertexData.size() * int(sizeof(Vertex)));
+
+ obj.clear();
+ obj.setVertexData(vertexBuffer);
+ obj.addAttribute(Q3DSGeometry::Attribute::PositionSemantic);
+ obj.addAttribute(Q3DSGeometry::Attribute::NormalSemantic);
+ obj.addAttribute(Q3DSGeometry::Attribute::TexCoordSemantic);
+ obj.addAttribute(Q3DSGeometry::Attribute::TangentSemantic);
+ obj.addAttribute(Q3DSGeometry::Attribute::BinormalSemantic);
+
+ return true;
+}
diff --git a/examples/studio3d/dynamicelement/demo.h b/examples/studio3d/dynamicelement/demo.h
new file mode 100644
index 0000000..56f3dd5
--- /dev/null
+++ b/examples/studio3d/dynamicelement/demo.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEMO_H
+#define DEMO_H
+
+#include <QtCore/qobject.h>
+#include <QtStudio3D/q3dspresentation.h>
+#include <QtStudio3D/q3dsgeometry.h>
+#include <QtCore/qvector.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector2d.h>
+
+class Demo : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit Demo(Q3DSPresentation *presentation, QObject *parent = nullptr);
+ ~Demo() {}
+
+ Q_INVOKABLE void setup();
+ Q_INVOKABLE void animate();
+
+private:
+ void createMaterials();
+ void createMeshes();
+ void createElements();
+
+ bool parseObj(const QString &path, Q3DSGeometry &obj);
+
+ Q3DSPresentation *m_presentation = nullptr;
+
+ struct ElementData
+ {
+ QVector3D position;
+ QVector3D rotation;
+ QVector3D delta;
+ };
+
+ QVector<ElementData> m_elementData;
+ bool setupDone = false;
+};
+
+#endif
diff --git a/examples/studio3d/dynamicelement/demo.mtl b/examples/studio3d/dynamicelement/demo.mtl
new file mode 100644
index 0000000..70d3ba1
--- /dev/null
+++ b/examples/studio3d/dynamicelement/demo.mtl
@@ -0,0 +1,10 @@
+# Blender MTL File: 'None'
+# Material Count: 1
+
+newmtl None
+Ns 0
+Ka 0.000000 0.000000 0.000000
+Kd 0.8 0.8 0.8
+Ks 0.8 0.8 0.8
+d 1
+illum 2
diff --git a/examples/studio3d/dynamicelement/demo.obj b/examples/studio3d/dynamicelement/demo.obj
new file mode 100644
index 0000000..9f4c9be
--- /dev/null
+++ b/examples/studio3d/dynamicelement/demo.obj
@@ -0,0 +1,2979 @@
+# Blender v2.79 (sub 0) OBJ File: ''
+# www.blender.org
+mtllib demo.mtl
+o Suzanne
+v 43.750000 16.406250 76.562500
+v -43.750000 16.406250 76.562500
+v 50.000000 9.375000 68.750000
+v -50.000000 9.375000 68.750000
+v 54.687500 5.468750 57.812500
+v -54.687500 5.468750 57.812500
+v 35.156250 -2.343750 61.718750
+v -35.156250 -2.343750 61.718750
+v 35.156250 3.125000 71.875000
+v -35.156250 3.125000 71.875000
+v 35.156250 13.281250 78.125000
+v -35.156250 13.281250 78.125000
+v 27.343750 16.406250 79.687500
+v -27.343750 16.406250 79.687500
+v 20.312500 9.375000 74.218750
+v -20.312500 9.375000 74.218750
+v 15.625000 5.468750 64.843750
+v -15.625000 5.468750 64.843750
+v 7.812500 24.218750 65.625000
+v -7.812500 24.218750 65.625000
+v 14.062500 24.218750 74.218750
+v -14.062500 24.218750 74.218750
+v 24.218750 24.218750 79.687500
+v -24.218750 24.218750 79.687500
+v 27.343750 32.812500 79.687500
+v -27.343750 32.812500 79.687500
+v 20.312500 39.062500 74.218750
+v -20.312500 39.062500 74.218750
+v 15.625000 43.750000 64.843750
+v -15.625000 43.750000 64.843750
+v 35.156250 51.562500 61.718750
+v -35.156250 51.562500 61.718750
+v 35.156250 45.312500 71.875000
+v -35.156250 45.312500 71.875000
+v 35.156250 35.937500 78.125000
+v -35.156250 35.937500 78.125000
+v 43.750000 32.812500 76.562500
+v -43.750000 32.812500 76.562500
+v 50.000000 39.062500 68.750000
+v -50.000000 39.062500 68.750000
+v 54.687500 43.750000 57.812500
+v -54.687500 43.750000 57.812500
+v 62.500000 24.218750 56.250000
+v -62.500000 24.218750 56.250000
+v 56.250000 24.218750 67.187500
+v -56.250000 24.218750 67.187500
+v 46.875000 24.218750 75.781250
+v -46.875000 24.218750 75.781250
+v 47.656250 24.218750 77.343750
+v -47.656250 24.218750 77.343750
+v 44.531250 33.593750 78.125000
+v -44.531250 33.593750 78.125000
+v 35.156250 37.500000 80.468750
+v -35.156250 37.500000 80.468750
+v 26.562500 33.593750 82.031250
+v -26.562500 33.593750 82.031250
+v 22.656250 24.218750 82.031250
+v -22.656250 24.218750 82.031250
+v 26.562500 15.625000 82.031250
+v -26.562500 15.625000 82.031250
+v 35.156250 24.218750 82.812500
+v -35.156250 24.218750 82.812500
+v 35.156250 11.718750 80.468750
+v -35.156250 11.718750 80.468750
+v 44.531250 15.625000 78.125000
+v -44.531250 15.625000 78.125000
+v 0.000000 42.968750 74.218750
+v 0.000000 35.156250 82.031250
+v 0.000000 -67.968750 73.437500
+v 0.000000 -32.031250 78.125000
+v 0.000000 -18.750000 79.687500
+v 0.000000 -77.343750 71.875000
+v 0.000000 40.625000 60.156250
+v 0.000000 57.031250 57.031250
+v 0.000000 89.843750 -54.687500
+v 0.000000 56.250000 -85.156250
+v 0.000000 7.031250 -82.812500
+v 0.000000 -38.281250 -35.156250
+v 20.312500 -18.750000 56.250000
+v -20.312500 -18.750000 56.250000
+v 31.250000 -43.750000 57.031250
+v -31.250000 -43.750000 57.031250
+v 35.156250 -69.531250 57.031250
+v -35.156250 -69.531250 57.031250
+v 36.718750 -89.062500 53.125000
+v -36.718750 -89.062500 53.125000
+v 32.812500 -94.531250 52.343750
+v -32.812500 -94.531250 52.343750
+v 17.968750 -96.875000 55.468750
+v -17.968750 -96.875000 55.468750
+v 0.000000 -98.437500 57.812500
+v 43.750000 -14.062500 53.125000
+v -43.750000 -14.062500 53.125000
+v 63.281250 -3.906250 53.906250
+v -63.281250 -3.906250 53.906250
+v 82.812500 14.843750 44.531250
+v -82.812500 14.843750 44.531250
+v 85.937500 42.968750 59.375000
+v -85.937500 42.968750 59.375000
+v 71.093750 48.437500 62.500000
+v -71.093750 48.437500 62.500000
+v 49.218750 60.156250 68.750000
+v -49.218750 60.156250 68.750000
+v 32.031250 75.781250 73.437500
+v -32.031250 75.781250 73.437500
+v 15.625000 71.875000 75.781250
+v -15.625000 71.875000 75.781250
+v 6.250000 49.218750 75.000000
+v -6.250000 49.218750 75.000000
+v 16.406250 41.406250 77.343750
+v -16.406250 41.406250 77.343750
+v 12.500000 30.468750 76.562500
+v -12.500000 30.468750 76.562500
+v 20.312500 9.375000 74.218750
+v -20.312500 9.375000 74.218750
+v 37.500000 1.562500 70.312500
+v -37.500000 1.562500 70.312500
+v 49.218750 6.250000 67.187500
+v -49.218750 6.250000 67.187500
+v 62.500000 18.750000 64.843750
+v -62.500000 18.750000 64.843750
+v 64.062500 29.687500 64.843750
+v -64.062500 29.687500 64.843750
+v 60.156250 37.500000 66.406250
+v -60.156250 37.500000 66.406250
+v 42.968750 43.750000 71.875000
+v -42.968750 43.750000 71.875000
+v 25.000000 46.875000 75.781250
+v -25.000000 46.875000 75.781250
+v 0.000000 -76.562500 73.437500
+v 10.937500 -71.875000 73.437500
+v -10.937500 -71.875000 73.437500
+v 11.718750 -83.593750 71.093750
+v -11.718750 -83.593750 71.093750
+v 6.250000 -88.281250 69.531250
+v -6.250000 -88.281250 69.531250
+v 0.000000 -89.062500 68.750000
+v 0.000000 -19.531250 75.000000
+v 0.000000 -14.062500 74.218750
+v 10.156250 -14.843750 74.218750
+v -10.156250 -14.843750 74.218750
+v 12.500000 -22.656250 75.000000
+v -12.500000 -22.656250 75.000000
+v 8.593750 -28.906250 74.218750
+v -8.593750 -28.906250 74.218750
+v 39.843750 -4.687500 67.187500
+v -39.843750 -4.687500 67.187500
+v 61.718750 5.468750 62.500000
+v -61.718750 5.468750 62.500000
+v 72.656250 20.312500 60.156250
+v -72.656250 20.312500 60.156250
+v 74.218750 37.500000 65.625000
+v -74.218750 37.500000 65.625000
+v 68.750000 41.406250 72.656250
+v -68.750000 41.406250 72.656250
+v 43.750000 54.687500 79.687500
+v -43.750000 54.687500 79.687500
+v 31.250000 64.062500 83.593750
+v -31.250000 64.062500 83.593750
+v 20.312500 61.718750 85.156250
+v -20.312500 61.718750 85.156250
+v 10.156250 42.968750 84.375000
+v -10.156250 42.968750 84.375000
+v 12.500000 -10.156250 81.250000
+v -12.500000 -10.156250 81.250000
+v 21.093750 -44.531250 71.093750
+v -21.093750 -44.531250 71.093750
+v 25.000000 -70.312500 68.750000
+v -25.000000 -70.312500 68.750000
+v 26.562500 -82.031250 66.406250
+v -26.562500 -82.031250 66.406250
+v 23.437500 -91.406250 63.281250
+v -23.437500 -91.406250 63.281250
+v 16.406250 -92.968750 63.281250
+v -16.406250 -92.968750 63.281250
+v 0.000000 -94.531250 64.062500
+v 0.000000 4.687500 72.656250
+v 0.000000 21.093750 76.562500
+v 32.812500 47.656250 74.218750
+v -32.812500 47.656250 74.218750
+v 16.406250 14.062500 75.000000
+v -16.406250 14.062500 75.000000
+v 13.281250 21.093750 75.781250
+v -13.281250 21.093750 75.781250
+v 11.718750 -68.750000 73.437500
+v -11.718750 -68.750000 73.437500
+v 7.812500 -44.531250 75.000000
+v -7.812500 -44.531250 75.000000
+v 0.000000 -44.531250 75.000000
+v 0.000000 -32.812500 74.218750
+v 9.375000 -27.343750 78.125000
+v -9.375000 -27.343750 78.125000
+v 13.281250 -22.656250 79.687500
+v -13.281250 -22.656250 79.687500
+v 10.937500 -13.281250 78.125000
+v -10.937500 -13.281250 78.125000
+v 3.906250 -12.500000 78.125000
+v -3.906250 -12.500000 78.125000
+v 0.000000 -20.312500 82.812500
+v 4.687500 -14.843750 81.250000
+v -4.687500 -14.843750 81.250000
+v 9.375000 -15.625000 81.250000
+v -9.375000 -15.625000 81.250000
+v 10.937500 -22.656250 82.812500
+v -10.937500 -22.656250 82.812500
+v 7.812500 -25.000000 80.468750
+v -7.812500 -25.000000 80.468750
+v 0.000000 -28.906250 80.468750
+v 25.781250 -31.250000 55.468750
+v -25.781250 -31.250000 55.468750
+v 16.406250 -24.218750 71.093750
+v -16.406250 -24.218750 71.093750
+v 17.968750 -31.250000 71.093750
+v -17.968750 -31.250000 71.093750
+v 23.437500 -25.000000 55.468750
+v -23.437500 -25.000000 55.468750
+v 0.000000 -87.500000 68.750000
+v 4.687500 -86.718750 68.750000
+v -4.687500 -86.718750 68.750000
+v 9.375000 -82.031250 71.093750
+v -9.375000 -82.031250 71.093750
+v 9.375000 -74.218750 72.656250
+v -9.375000 -74.218750 72.656250
+v 0.000000 -78.125000 65.625000
+v 9.375000 -75.000000 66.406250
+v -9.375000 -75.000000 66.406250
+v 9.375000 -81.250000 64.062500
+v -9.375000 -81.250000 64.062500
+v 4.687500 -85.156250 63.281250
+v -4.687500 -85.156250 63.281250
+v 0.000000 -85.937500 63.281250
+v 17.187500 21.875000 78.125000
+v -17.187500 21.875000 78.125000
+v 18.750000 15.625000 77.343750
+v -18.750000 15.625000 77.343750
+v 33.593750 42.968750 75.781250
+v -33.593750 42.968750 75.781250
+v 27.343750 42.187500 77.343750
+v -27.343750 42.187500 77.343750
+v 42.187500 39.843750 77.343750
+v -42.187500 39.843750 77.343750
+v 56.250000 35.156250 69.531250
+v -56.250000 35.156250 69.531250
+v 58.593750 28.906250 68.750000
+v -58.593750 28.906250 68.750000
+v 57.812500 19.531250 67.968750
+v -57.812500 19.531250 67.968750
+v 47.656250 10.156250 71.875000
+v -47.656250 10.156250 71.875000
+v 37.500000 6.250000 74.218750
+v -37.500000 6.250000 74.218750
+v 22.656250 10.937500 78.125000
+v -22.656250 10.937500 78.125000
+v 17.968750 29.687500 78.125000
+v -17.968750 29.687500 78.125000
+v 21.093750 37.500000 78.125000
+v -21.093750 37.500000 78.125000
+v 23.437500 35.937500 75.781250
+v -23.437500 35.937500 75.781250
+v 19.531250 29.687500 75.781250
+v -19.531250 29.687500 75.781250
+v 24.218750 12.500000 75.781250
+v -24.218750 12.500000 75.781250
+v 37.500000 8.593750 72.656250
+v -37.500000 8.593750 72.656250
+v 46.093750 11.718750 70.312500
+v -46.093750 11.718750 70.312500
+v 54.687500 21.093750 67.187500
+v -54.687500 21.093750 67.187500
+v 55.468750 28.125000 67.187500
+v -55.468750 28.125000 67.187500
+v 53.125000 33.593750 67.968750
+v -53.125000 33.593750 67.968750
+v 41.406250 39.062500 75.000000
+v -41.406250 39.062500 75.000000
+v 28.125000 39.843750 76.562500
+v -28.125000 39.843750 76.562500
+v 33.593750 40.625000 75.000000
+v -33.593750 40.625000 75.000000
+v 20.312500 17.187500 75.000000
+v -20.312500 17.187500 75.000000
+v 19.531250 22.656250 75.000000
+v -19.531250 22.656250 75.000000
+v 10.937500 46.093750 60.937500
+v -10.937500 46.093750 60.937500
+v 19.531250 66.406250 61.718750
+v -19.531250 66.406250 61.718750
+v 33.593750 68.750000 59.375000
+v -33.593750 68.750000 59.375000
+v 48.437500 55.468750 55.468750
+v -48.437500 55.468750 55.468750
+v 67.968750 45.312500 49.218750
+v -67.968750 45.312500 49.218750
+v 79.687500 40.625000 46.093750
+v -79.687500 40.625000 46.093750
+v 77.343750 16.406250 37.500000
+v -77.343750 16.406250 37.500000
+v 60.156250 0.000000 41.406250
+v -60.156250 0.000000 41.406250
+v 43.750000 -9.375000 46.875000
+v -43.750000 -9.375000 46.875000
+v 0.000000 89.843750 28.906250
+v 0.000000 98.437500 -7.812500
+v 0.000000 -19.531250 -67.187500
+v 0.000000 -46.093750 18.750000
+v 0.000000 -97.656250 46.093750
+v 0.000000 -80.468750 34.375000
+v 0.000000 -57.031250 32.031250
+v 0.000000 -48.437500 28.125000
+v 85.156250 23.437500 5.468750
+v -85.156250 23.437500 5.468750
+v 85.937500 32.031250 -4.687500
+v -85.937500 32.031250 -4.687500
+v 77.343750 26.562500 -43.750000
+v -77.343750 26.562500 -43.750000
+v 46.093750 43.750000 -70.312500
+v -46.093750 43.750000 -70.312500
+v 73.437500 -4.687500 7.031250
+v -73.437500 -4.687500 7.031250
+v 59.375000 -12.500000 -16.406250
+v -59.375000 -12.500000 -16.406250
+v 64.062500 -0.781250 -42.968750
+v -64.062500 -0.781250 -42.968750
+v 33.593750 5.468750 -66.406250
+v -33.593750 5.468750 -66.406250
+v 23.437500 -35.156250 40.625000
+v -23.437500 -35.156250 40.625000
+v 17.968750 -41.406250 25.781250
+v -17.968750 -41.406250 25.781250
+v 28.906250 -71.093750 38.281250
+v -28.906250 -71.093750 38.281250
+v 25.000000 -50.000000 39.062500
+v -25.000000 -50.000000 39.062500
+v 32.812500 -91.406250 39.843750
+v -32.812500 -91.406250 39.843750
+v 14.062500 -75.781250 36.718750
+v -14.062500 -75.781250 36.718750
+v 12.500000 -53.906250 35.937500
+v -12.500000 -53.906250 35.937500
+v 16.406250 -94.531250 43.750000
+v -16.406250 -94.531250 43.750000
+v 21.875000 -28.125000 42.968750
+v -21.875000 -28.125000 42.968750
+v 21.093750 -22.656250 46.875000
+v -21.093750 -22.656250 46.875000
+v 20.312500 -17.187500 50.000000
+v -20.312500 -17.187500 50.000000
+v 21.093750 -39.062500 16.406250
+v -21.093750 -39.062500 16.406250
+v 29.687500 -31.250000 -26.562500
+v -29.687500 -31.250000 -26.562500
+v 34.375000 -14.843750 -53.906250
+v -34.375000 -14.843750 -53.906250
+v 45.312500 86.718750 -38.281250
+v -45.312500 86.718750 -38.281250
+v 45.312500 92.968750 -7.031250
+v -45.312500 92.968750 -7.031250
+v 45.312500 85.156250 23.437500
+v -45.312500 85.156250 23.437500
+v 46.093750 52.343750 42.968750
+v -46.093750 52.343750 42.968750
+v 72.656250 40.625000 33.593750
+v -72.656250 40.625000 33.593750
+v 63.281250 45.312500 28.125000
+v -63.281250 45.312500 28.125000
+v 64.062500 70.312500 5.468750
+v -64.062500 70.312500 5.468750
+v 79.687500 56.250000 12.500000
+v -79.687500 56.250000 12.500000
+v 79.687500 61.718750 -11.718750
+v -79.687500 61.718750 -11.718750
+v 64.062500 75.000000 -19.531250
+v -64.062500 75.000000 -19.531250
+v 64.062500 67.968750 -44.531250
+v -64.062500 67.968750 -44.531250
+v 79.687500 53.906250 -35.937500
+v -79.687500 53.906250 -35.937500
+v 61.718750 32.812500 -58.593750
+v -61.718750 32.812500 -58.593750
+v 48.437500 2.343750 -54.687500
+v -48.437500 2.343750 -54.687500
+v 82.031250 32.812500 -20.312500
+v -82.031250 32.812500 -20.312500
+v 40.625000 -17.187500 14.843750
+v -40.625000 -17.187500 14.843750
+v 42.968750 -19.531250 -21.093750
+v -42.968750 -19.531250 -21.093750
+v 89.062500 40.625000 -23.437500
+v -89.062500 40.625000 -23.437500
+v 77.343750 -14.062500 -12.500000
+v -77.343750 -14.062500 -12.500000
+v 103.906250 -10.156250 -32.812500
+v -103.906250 -10.156250 -32.812500
+v 128.125000 5.468750 -42.968750
+v -128.125000 5.468750 -42.968750
+v 135.156250 32.031250 -42.187500
+v -135.156250 32.031250 -42.187500
+v 123.437500 50.781250 -42.187500
+v -123.437500 50.781250 -42.187500
+v 102.343750 47.656250 -31.250000
+v -102.343750 47.656250 -31.250000
+v 101.562500 41.406250 -28.906250
+v -101.562500 41.406250 -28.906250
+v 118.750000 43.750000 -39.062500
+v -118.750000 43.750000 -39.062500
+v 126.562500 28.906250 -40.625000
+v -126.562500 28.906250 -40.625000
+v 121.093750 7.812500 -40.625000
+v -121.093750 7.812500 -40.625000
+v 103.125000 -3.906250 -30.468750
+v -103.125000 -3.906250 -30.468750
+v 82.812500 -7.031250 -13.281250
+v -82.812500 -7.031250 -13.281250
+v 92.187500 35.937500 -21.875000
+v -92.187500 35.937500 -21.875000
+v 94.531250 30.468750 -28.906250
+v -94.531250 30.468750 -28.906250
+v 88.281250 -2.343750 -21.093750
+v -88.281250 -2.343750 -21.093750
+v 103.906250 0.000000 -36.718750
+v -103.906250 0.000000 -36.718750
+v 118.750000 9.375000 -44.531250
+v -118.750000 9.375000 -44.531250
+v 123.437500 25.000000 -44.531250
+v -123.437500 25.000000 -44.531250
+v 117.187500 35.937500 -43.750000
+v -117.187500 35.937500 -43.750000
+v 102.343750 34.375000 -35.937500
+v -102.343750 34.375000 -35.937500
+v 84.375000 28.906250 -21.093750
+v -84.375000 28.906250 -21.093750
+v 83.593750 17.187500 -27.343750
+v -83.593750 17.187500 -27.343750
+v 75.781250 9.375000 -27.343750
+v -75.781250 9.375000 -27.343750
+v 82.031250 8.593750 -27.343750
+v -82.031250 8.593750 -27.343750
+v 84.375000 1.562500 -27.343750
+v -84.375000 1.562500 -27.343750
+v 81.250000 -1.562500 -27.343750
+v -81.250000 -1.562500 -27.343750
+v 72.656250 0.000000 -7.031250
+v -72.656250 0.000000 -7.031250
+v 71.875000 -2.343750 -17.187500
+v -71.875000 -2.343750 -17.187500
+v 71.875000 3.906250 -18.750000
+v -71.875000 3.906250 -18.750000
+v 79.687500 20.312500 -21.093750
+v -79.687500 20.312500 -21.093750
+v 89.062500 24.218750 -26.562500
+v -89.062500 24.218750 -26.562500
+v 89.062500 23.437500 -32.031250
+v -89.062500 23.437500 -32.031250
+v 81.250000 -1.562500 -32.031250
+v -81.250000 -1.562500 -32.031250
+v 85.156250 1.562500 -32.031250
+v -85.156250 1.562500 -32.031250
+v 82.812500 7.812500 -32.031250
+v -82.812500 7.812500 -32.031250
+v 76.562500 9.375000 -32.031250
+v -76.562500 9.375000 -32.031250
+v 84.375000 17.187500 -32.031250
+v -84.375000 17.187500 -32.031250
+v 103.906250 32.812500 -41.406250
+v -103.906250 32.812500 -41.406250
+v 118.750000 34.375000 -48.437500
+v -118.750000 34.375000 -48.437500
+v 125.781250 24.218750 -49.218750
+v -125.781250 24.218750 -49.218750
+v 121.093750 8.593750 -48.437500
+v -121.093750 8.593750 -48.437500
+v 104.687500 0.000000 -42.187500
+v -104.687500 0.000000 -42.187500
+v 88.281250 -1.562500 -26.562500
+v -88.281250 -1.562500 -26.562500
+v 95.312500 28.906250 -34.375000
+v -95.312500 28.906250 -34.375000
+v 89.062500 10.937500 -32.812500
+v -89.062500 10.937500 -32.812500
+v 93.750000 6.250000 -33.593750
+v -93.750000 6.250000 -33.593750
+v 100.000000 12.500000 -36.718750
+v -100.000000 12.500000 -36.718750
+v 96.093750 17.187500 -35.156250
+v -96.093750 17.187500 -35.156250
+v 101.562500 23.437500 -37.500000
+v -101.562500 23.437500 -37.500000
+v 105.468750 18.750000 -38.281250
+v -105.468750 18.750000 -38.281250
+v 110.937500 21.093750 -39.062500
+v -110.937500 21.093750 -39.062500
+v 108.593750 27.343750 -39.062500
+v -108.593750 27.343750 -39.062500
+v 102.343750 43.750000 -48.437500
+v -102.343750 43.750000 -48.437500
+v 125.000000 46.875000 -54.687500
+v -125.000000 46.875000 -54.687500
+v 136.718750 29.687500 -50.000000
+v -136.718750 29.687500 -50.000000
+v 131.250000 5.468750 -53.125000
+v -131.250000 5.468750 -53.125000
+v 103.906250 -8.593750 -49.218750
+v -103.906250 -8.593750 -49.218750
+v 78.906250 -12.500000 -32.812500
+v -78.906250 -12.500000 -32.812500
+v 85.937500 38.281250 -38.281250
+v -85.937500 38.281250 -38.281250
+vt 0.890955 0.590063
+vt 0.860081 0.560115
+vt 0.904571 0.559404
+vt 0.856226 0.850547
+vt 0.888398 0.821999
+vt 0.900640 0.853232
+vt 0.853018 0.521562
+vt 0.920166 0.524546
+vt 0.847458 0.888748
+vt 0.914672 0.888748
+vt 0.798481 0.569535
+vt 0.795104 0.838402
+vt 0.870622 0.589649
+vt 0.828900 0.590771
+vt 0.826436 0.818537
+vt 0.868067 0.821510
+vt 0.854402 0.604754
+vt 0.828171 0.633354
+vt 0.827598 0.775964
+vt 0.852534 0.805700
+vt 0.791018 0.645443
+vt 0.791018 0.762238
+vt 0.855181 0.668527
+vt 0.856142 0.742025
+vt 0.844839 0.707525
+vt 0.854107 0.625459
+vt 0.853157 0.785002
+vt 0.867508 0.642291
+vt 0.900375 0.666964
+vt 0.901223 0.745592
+vt 0.867293 0.768782
+vt 0.842358 0.702491
+vt 0.921180 0.713713
+vt 0.931889 0.636832
+vt 0.918898 0.699697
+vt 0.931368 0.777093
+vt 0.968213 0.770220
+vt 0.905882 0.627902
+vt 0.890474 0.641909
+vt 0.904990 0.784860
+vt 0.906232 0.605742
+vt 0.904357 0.807013
+vt 0.931250 0.820926
+vt 0.933717 0.593037
+vt 0.968392 0.645333
+vt 0.965038 0.841671
+vt 0.968392 0.573812
+vt 0.889591 0.593275
+vt 0.887178 0.818729
+vt 0.900583 0.804677
+vt 0.902359 0.607909
+vt 0.898822 0.786233
+vt 0.899781 0.626257
+vt 0.890219 0.770183
+vt 0.887351 0.775442
+vt 0.887842 0.636527
+vt 0.870376 0.775972
+vt 0.859881 0.623942
+vt 0.870908 0.635245
+vt 0.858859 0.786774
+vt 0.859664 0.608186
+vt 0.857942 0.802505
+vt 0.871664 0.593961
+vt 0.869299 0.817249
+vt 0.879400 0.616512
+vt 0.878029 0.795063
+vt 0.536419 0.062072
+vt 0.518916 0.050294
+vt 0.540260 0.053805
+vt 0.501452 0.062043
+vt 0.518925 0.059681
+vt 0.542788 0.064089
+vt 0.551930 0.058338
+vt 0.495083 0.064047
+vt 0.497626 0.053770
+vt 0.555073 0.061900
+vt 0.482805 0.061829
+vt 0.485955 0.058273
+vt 0.563812 0.076586
+vt 0.546290 0.072669
+vt 0.491565 0.072625
+vt 0.474014 0.076511
+vt 0.583135 0.108495
+vt 0.548333 0.084893
+vt 0.489507 0.084858
+vt 0.454527 0.108481
+vt 0.605512 0.165134
+vt 0.621513 0.227818
+vt 0.553118 0.209599
+vt 0.416514 0.229490
+vt 0.432024 0.165644
+vt 0.485339 0.210053
+vt 0.676379 0.233241
+vt 0.647395 0.200502
+vt 0.360308 0.235899
+vt 0.372747 0.256357
+vt 0.683908 0.279995
+vt 0.664761 0.253225
+vt 0.353696 0.284606
+vt 0.707254 0.310054
+vt 0.715342 0.265392
+vt 0.330721 0.316853
+vt 0.351187 0.317440
+vt 0.697446 0.332673
+vt 0.687515 0.311539
+vt 0.341964 0.339667
+vt 0.362723 0.329722
+vt 0.662817 0.372521
+vt 0.676824 0.323937
+vt 0.379297 0.378686
+vt 0.402772 0.362131
+vt 0.618316 0.375151
+vt 0.639050 0.357330
+vt 0.424583 0.379267
+vt 0.604826 0.397804
+vt 0.626842 0.395792
+vt 0.439252 0.401540
+vt 0.442396 0.381222
+vt 0.553095 0.390512
+vt 0.600808 0.377857
+vt 0.490934 0.391862
+vt 0.482938 0.358497
+vt 0.521923 0.386009
+vt 0.559674 0.357011
+vt 0.521086 0.343868
+vt 0.599845 0.344815
+vt 0.577279 0.340156
+vt 0.441977 0.347815
+vt 0.615546 0.342005
+vt 0.634472 0.332311
+vt 0.425972 0.345582
+vt 0.662406 0.312804
+vt 0.406362 0.336480
+vt 0.668440 0.297958
+vt 0.377061 0.317685
+vt 0.664101 0.277872
+vt 0.370304 0.302644
+vt 0.639236 0.253047
+vt 0.374100 0.281778
+vt 0.613992 0.242662
+vt 0.398938 0.255633
+vt 0.572941 0.258564
+vt 0.424464 0.244473
+vt 0.519760 0.248864
+vt 0.466409 0.259709
+vt 0.558527 0.316594
+vt 0.482619 0.317843
+vt 0.520277 0.294764
+vt 0.556923 0.291214
+vt 0.483433 0.292249
+vt 0.563905 0.272007
+vt 0.475886 0.273078
+vt 0.525483 0.068967
+vt 0.512375 0.068956
+vt 0.531231 0.073829
+vt 0.506626 0.073811
+vt 0.531019 0.087431
+vt 0.555621 0.121749
+vt 0.532669 0.090920
+vt 0.505177 0.090908
+vt 0.482177 0.121781
+vt 0.506827 0.087416
+vt 0.518981 0.151749
+vt 0.532042 0.127713
+vt 0.538112 0.158382
+vt 0.505828 0.127728
+vt 0.518941 0.128358
+vt 0.518925 0.093952
+vt 0.518927 0.085180
+vt 0.548362 0.173560
+vt 0.535214 0.166808
+vt 0.502799 0.166857
+vt 0.489683 0.173693
+vt 0.499851 0.158434
+vt 0.544281 0.193366
+vt 0.537959 0.175966
+vt 0.500100 0.176033
+vt 0.493996 0.193428
+vt 0.528757 0.191785
+vt 0.519841 0.200843
+vt 0.509219 0.191626
+vt 0.500890 0.187571
+vt 0.519132 0.185382
+vt 0.517577 0.190607
+vt 0.518998 0.159028
+vt 0.519016 0.165599
+vt 0.506910 0.171667
+vt 0.528222 0.186316
+vt 0.509787 0.186260
+vt 0.533528 0.184215
+vt 0.537248 0.187577
+vt 0.504547 0.184206
+vt 0.504604 0.176791
+vt 0.531131 0.171631
+vt 0.533449 0.176739
+vt 0.519099 0.179457
+vt 0.561572 0.167779
+vt 0.476363 0.167996
+vt 0.478371 0.149447
+vt 0.559475 0.149319
+vt 0.596138 0.133426
+vt 0.441395 0.133592
+vt 0.601169 0.147885
+vt 0.436337 0.148194
+vt 0.528933 0.084957
+vt 0.508915 0.084945
+vt 0.518925 0.083865
+vt 0.529036 0.075429
+vt 0.508820 0.075415
+vt 0.523751 0.070508
+vt 0.514106 0.070501
+vt 0.518928 0.067899
+vt 0.518929 0.069468
+vt 0.518928 0.074259
+vt 0.516297 0.074966
+vt 0.524236 0.076691
+vt 0.521560 0.074970
+vt 0.513619 0.076684
+vt 0.524601 0.079886
+vt 0.513252 0.079879
+vt 0.518926 0.079331
+vt 0.571787 0.277295
+vt 0.568351 0.292904
+vt 0.468070 0.278617
+vt 0.471978 0.294282
+vt 0.573085 0.311386
+vt 0.467790 0.313081
+vt 0.584855 0.327708
+vt 0.456477 0.329961
+vt 0.458737 0.268049
+vt 0.611720 0.255725
+vt 0.580734 0.266620
+vt 0.427062 0.257728
+vt 0.632494 0.262853
+vt 0.406068 0.265508
+vt 0.653658 0.279971
+vt 0.384904 0.283634
+vt 0.656064 0.297636
+vt 0.383015 0.301864
+vt 0.386858 0.314615
+vt 0.652752 0.310186
+vt 0.411556 0.327673
+vt 0.614408 0.331972
+vt 0.629040 0.323864
+vt 0.426727 0.335361
+vt 0.601033 0.333624
+vt 0.440344 0.336537
+vt 0.601799 0.328453
+vt 0.439372 0.331331
+vt 0.450408 0.323919
+vt 0.613335 0.327083
+vt 0.427623 0.330358
+vt 0.626851 0.320513
+vt 0.413648 0.324175
+vt 0.646248 0.306421
+vt 0.393381 0.310510
+vt 0.649541 0.296225
+vt 0.389662 0.300183
+vt 0.647785 0.283486
+vt 0.391040 0.287071
+vt 0.629829 0.267263
+vt 0.408893 0.269959
+vt 0.612641 0.261560
+vt 0.426254 0.263693
+vt 0.585166 0.270991
+vt 0.454369 0.272583
+vt 0.578124 0.281900
+vt 0.461798 0.283441
+vt 0.579548 0.309340
+vt 0.590644 0.321516
+vt 0.461204 0.311233
+vt 0.577524 0.293776
+vt 0.462754 0.295432
+vt 0.553209 0.433063
+vt 0.523031 0.433628
+vt 0.492809 0.434538
+vt 0.609819 0.431516
+vt 0.435860 0.435740
+vt 0.416915 0.400552
+vt 0.396518 0.425416
+vt 0.648174 0.419316
+vt 0.350292 0.396229
+vt 0.692106 0.388274
+vt 0.312756 0.350588
+vt 0.735879 0.312112
+vt 0.726332 0.341754
+vt 0.301067 0.320593
+vt 0.320452 0.270303
+vt 0.304876 0.261087
+vt 0.698172 0.216906
+vt 0.729900 0.256393
+vt 0.337414 0.219179
+vt 0.663103 0.190671
+vt 0.373474 0.191872
+vt 0.649444 0.022378
+vt 0.621440 0.048089
+vt 0.626908 0.015608
+vt 0.388827 0.021586
+vt 0.416419 0.047631
+vt 0.376796 0.075296
+vt 0.577206 0.032801
+vt 0.567460 0.000144
+vt 0.411318 0.015131
+vt 0.460782 0.032656
+vt 0.547413 0.041724
+vt 0.518922 0.024886
+vt 0.470636 0.000144
+vt 0.490511 0.041669
+vt 0.558059 0.053871
+vt 0.479842 0.053785
+vt 0.576951 0.057998
+vt 0.460920 0.057845
+vt 0.611687 0.078268
+vt 0.425932 0.077985
+vt 0.660451 0.076084
+vt 0.626663 0.111357
+vt 0.410618 0.111244
+vt 0.629482 0.130456
+vt 0.407648 0.130594
+vt 0.413741 0.147158
+vt 0.619303 0.159841
+vt 0.418035 0.160361
+vt 0.389677 0.201890
+vt 0.886245 0.121777
+vt 0.891780 0.036916
+vt 0.945900 0.079569
+vt 0.141314 0.112482
+vt 0.142277 0.021467
+vt 0.183115 0.092127
+vt 0.849114 0.099732
+vt 0.805584 0.010786
+vt 0.232648 0.003484
+vt 0.246353 0.076510
+vt 0.687018 0.077204
+vt 0.672384 0.022201
+vt 0.349875 0.075955
+vt 0.365979 0.020991
+vt 0.760215 0.193244
+vt 0.789046 0.233323
+vt 0.271553 0.193871
+vt 0.241255 0.236977
+vt 0.909112 0.183261
+vt 0.994525 0.167705
+vt 0.107928 0.179083
+vt 0.078961 0.060719
+vt 0.862868 0.338556
+vt 0.962901 0.344752
+vt 0.911671 0.402429
+vt 0.160557 0.356821
+vt 0.043968 0.367038
+vt 0.123776 0.315519
+vt 0.915360 0.259804
+vt 0.999856 0.254640
+vt 0.098965 0.266968
+vt 0.000144 0.259113
+vt 0.011829 0.155367
+vt 0.749542 0.334683
+vt 0.766337 0.300809
+vt 0.789162 0.313727
+vt 0.267408 0.310142
+vt 0.288183 0.346496
+vt 0.242992 0.325552
+vt 0.815314 0.276388
+vt 0.846174 0.293397
+vt 0.213065 0.285164
+vt 0.178537 0.304983
+vt 0.845007 0.256352
+vt 0.873517 0.265922
+vt 0.179662 0.263312
+vt 0.147089 0.274284
+vt 0.859075 0.228168
+vt 0.886999 0.233769
+vt 0.162803 0.231720
+vt 0.131514 0.237587
+vt 0.875030 0.184705
+vt 0.842355 0.195160
+vt 0.145224 0.182749
+vt 0.894128 0.301884
+vt 0.794286 0.364062
+vt 0.770185 0.379538
+vt 0.239776 0.382592
+vt 0.845499 0.449967
+vt 0.106400 0.432652
+vt 0.815858 0.445381
+vt 0.755700 0.418603
+vt 0.287033 0.442912
+vt 0.219260 0.477186
+vt 0.268122 0.398737
+vt 0.185281 0.484099
+vt 0.819845 0.468071
+vt 0.215894 0.503605
+vt 0.809631 0.233887
+vt 0.219168 0.237388
+vt 0.829287 0.219562
+vt 0.199067 0.222464
+vt 0.788458 0.080826
+vt 0.715482 0.139727
+vt 0.319538 0.139409
+vt 0.246666 0.114850
+vt 0.785486 0.152330
+vt 0.245969 0.151002
+vt 0.623495 0.146796
+vt 0.837382 0.156361
+vt 0.196622 0.155241
+vt 0.171653 0.132294
+vt 0.786480 0.117591
+vt 0.858171 0.137775
+vt 0.432388 0.894943
+vt 0.491058 0.881714
+vt 0.506166 0.904851
+vt 0.321637 0.893225
+vt 0.263032 0.878321
+vt 0.315867 0.868209
+vt 0.572792 0.860484
+vt 0.604825 0.879946
+vt 0.181486 0.854693
+vt 0.247207 0.901159
+vt 0.148729 0.873349
+vt 0.619962 0.791615
+vt 0.136063 0.784093
+vt 0.169745 0.787474
+vt 0.586396 0.793977
+vt 0.563786 0.739211
+vt 0.194086 0.733241
+vt 0.208656 0.740879
+vt 0.549027 0.746412
+vt 0.508270 0.697693
+vt 0.250811 0.693249
+vt 0.258399 0.707497
+vt 0.438641 0.680683
+vt 0.434803 0.658882
+vt 0.320962 0.677959
+vt 0.325318 0.656224
+vt 0.500314 0.711729
+vt 0.452955 0.700023
+vt 0.306136 0.696976
+vt 0.505666 0.730944
+vt 0.252524 0.726592
+vt 0.568148 0.787367
+vt 0.188269 0.781375
+vt 0.214575 0.750414
+vt 0.555495 0.826352
+vt 0.199850 0.820889
+vt 0.501231 0.844356
+vt 0.253846 0.840502
+vt 0.457832 0.840040
+vt 0.297562 0.837358
+vt 0.783193 0.187449
+vt 0.246955 0.187075
+vt 0.233625 0.175620
+vt 0.394766 0.686125
+vt 0.391039 0.611891
+vt 0.364838 0.684445
+vt 0.391747 0.862097
+vt 0.438797 0.870229
+vt 0.363377 0.861308
+vt 0.435018 0.718280
+vt 0.323658 0.715731
+vt 0.384658 0.710299
+vt 0.433669 0.729661
+vt 0.374400 0.708969
+vt 0.410995 0.747662
+vt 0.427812 0.742828
+vt 0.324726 0.727177
+vt 0.347028 0.745816
+vt 0.330270 0.740536
+vt 0.384657 0.795423
+vt 0.418086 0.784946
+vt 0.372270 0.794472
+vt 0.431333 0.817535
+vt 0.401605 0.841460
+vt 0.324790 0.815460
+vt 0.338952 0.783073
+vt 0.354026 0.840297
+vt 0.825107 0.209762
+vt 0.199767 0.214827
+vt 0.816266 0.203086
+vt 0.209828 0.206161
+vt 0.226485 0.183086
+vt 0.796021 0.176969
+vt 0.802192 0.184609
+vt 0.448505 0.804621
+vt 0.473386 0.824700
+vt 0.307886 0.802031
+vt 0.282357 0.821525
+vt 0.321237 0.777208
+vt 0.423718 0.754191
+vt 0.435868 0.779569
+vt 0.334089 0.752045
+vt 0.319919 0.747250
+vt 0.437950 0.749777
+vt 0.312907 0.729222
+vt 0.440995 0.724383
+vt 0.445392 0.731997
+vt 0.317510 0.721697
+vt 0.455277 0.713731
+vt 0.303460 0.710657
+vt 0.512485 0.828811
+vt 0.242975 0.824574
+vt 0.550942 0.811814
+vt 0.204839 0.806417
+vt 0.552139 0.787682
+vt 0.204331 0.782156
+vt 0.539407 0.764539
+vt 0.542850 0.755753
+vt 0.217774 0.759319
+vt 0.508439 0.743135
+vt 0.249419 0.738732
+vt 0.454776 0.761665
+vt 0.302729 0.758742
+vt 0.286960 0.745020
+vt 0.470841 0.748408
+vt 0.475403 0.783904
+vt 0.281439 0.780511
+vt 0.268291 0.766661
+vt 0.503673 0.787562
+vt 0.494476 0.802470
+vt 0.252972 0.783410
+vt 0.261790 0.798626
+vt 0.516802 0.807339
+vt 0.239243 0.802891
+vt 0.237920 0.787045
+vt 0.518562 0.791602
+vt 0.484068 0.628776
+vt 0.543385 0.683538
+vt 0.276936 0.625067
+vt 0.216123 0.678120
+vt 0.581052 0.726933
+vt 0.177176 0.720426
+vt 0.616701 0.759965
+vt 0.140379 0.752377
+vt 0.660647 0.741167
+vt 0.707492 0.759884
+vt 0.097038 0.732052
+vt 0.677256 0.670436
+vt 0.745511 0.652100
+vt 0.049526 0.748824
+vt 0.083564 0.662038
+vt 0.671403 0.592656
+vt 0.740843 0.572428
+vt 0.019409 0.639749
+vt 0.092820 0.589862
+vt 0.834705 0.206959
+vt 0.051216 0.522659
+vt 0.033664 0.564403
+vt 0.620420 0.565675
+vt 0.498072 0.552315
+vt 0.145041 0.562595
+vt 0.264218 0.550140
+vt 0.369913 0.610196
+vt 0.464579 0.342230
+vt 0.176788 0.196179
+vt 0.770572 0.444261
+vt 0.271364 0.473316
+vt 0.488870 0.770464
+vt 0.834578 0.206879
+vn 0.6617 -0.2026 0.7219
+vn -0.6617 -0.2026 0.7219
+vn 0.8268 -0.3051 0.4725
+vn -0.8268 -0.3051 0.4725
+vn 0.4076 -0.7905 0.4570
+vn -0.4076 -0.7905 0.4570
+vn 0.3791 -0.5163 0.7679
+vn -0.3791 -0.5163 0.7679
+vn -0.0859 -0.5222 0.8485
+vn 0.0859 -0.5222 0.8485
+vn -0.2664 -0.8487 0.4570
+vn 0.2664 -0.8487 0.4570
+vn -0.7824 -0.3294 0.5285
+vn 0.7606 -0.3400 0.5531
+vn -0.4706 -0.1981 0.8598
+vn 0.4706 -0.1981 0.8598
+vn -0.4649 0.1958 0.8634
+vn 0.4649 0.1958 0.8634
+vn -0.7656 0.3223 0.5568
+vn 0.7683 0.3293 0.5488
+vn -0.2560 0.8073 0.5317
+vn 0.2487 0.8249 0.5076
+vn -0.0821 0.6023 0.7940
+vn 0.1017 0.5518 0.8277
+vn 0.3329 0.5231 0.7846
+vn -0.3861 0.5446 0.7445
+vn 0.4246 0.7711 0.4745
+vn -0.4059 0.7641 0.5014
+vn 0.8251 0.2968 0.4808
+vn -0.8299 0.2940 0.4742
+vn 0.6888 0.1868 0.7005
+vn -0.6617 0.2026 0.7219
+vn 0.8400 0.3436 -0.4200
+vn -0.7816 0.3058 -0.5437
+vn 0.2074 0.8296 -0.5185
+vn -0.2037 0.8146 -0.5431
+vn -0.4056 0.7605 -0.5070
+vn 0.4381 0.7988 -0.4123
+vn -0.8642 0.3143 -0.3928
+vn 0.7861 0.3276 -0.5241
+vn -0.7782 -0.3537 -0.5188
+vn 0.7782 -0.3537 -0.5188
+vn -0.4381 -0.7988 -0.4123
+vn 0.4381 -0.7988 -0.4123
+vn 0.2037 -0.8146 -0.5431
+vn -0.2037 -0.8146 -0.5431
+vn 0.7683 -0.3293 -0.5488
+vn -0.7683 -0.3293 -0.5488
+vn 0.4000 -0.0623 0.9144
+vn -0.4000 -0.0623 0.9144
+vn 0.3069 -0.1754 0.9354
+vn -0.3069 -0.1754 0.9354
+vn 0.0945 -0.1835 0.9785
+vn -0.0945 -0.1835 0.9785
+vn -0.0624 -0.0283 0.9977
+vn 0.0624 -0.0283 0.9977
+vn -0.0624 0.0260 0.9977
+vn 0.0624 0.0260 0.9977
+vn 0.0996 0.1729 0.9799
+vn -0.0996 0.1729 0.9799
+vn 0.3036 0.1656 0.9383
+vn -0.3036 0.1656 0.9383
+vn 0.4002 0.0572 0.9147
+vn -0.4002 0.0572 0.9147
+vn 0.1367 -0.8748 0.4648
+vn -0.1054 -0.8433 0.5270
+vn 0.2303 -0.8656 0.4447
+vn -0.1916 -0.8620 0.4693
+vn 0.5788 -0.5049 0.6404
+vn -0.5788 -0.5049 0.6404
+vn 0.7763 -0.0633 0.6272
+vn -0.7763 -0.0633 0.6272
+vn 0.7471 0.1132 0.6550
+vn -0.7471 0.1132 0.6550
+vn 0.3747 -0.8345 0.4040
+vn -0.3747 -0.8345 0.4040
+vn 0.3557 -0.7290 0.5848
+vn -0.4177 -0.5751 0.7034
+vn 0.6947 -0.4197 0.5841
+vn -0.6947 -0.4197 0.5841
+vn 0.7028 -0.3915 0.5939
+vn -0.5537 -0.2978 0.7777
+vn 0.3127 0.3425 0.8860
+vn -0.8227 0.3606 0.4395
+vn 0.5091 0.6482 0.5663
+vn -0.5041 0.6448 0.5745
+vn 0.5977 0.5565 0.5771
+vn -0.5977 0.5565 0.5771
+vn -0.0486 0.6560 0.7532
+vn 0.0371 0.6685 0.7428
+vn -0.7104 0.2715 0.6494
+vn 0.7386 0.3768 0.5590
+vn -0.6013 0.5262 0.6013
+vn 0.5774 0.5774 0.5774
+vn 0.5070 -0.6281 0.5903
+vn -0.5364 -0.3230 0.7797
+vn 0.2226 -0.4694 0.8545
+vn -0.2226 -0.4694 0.8545
+vn -0.0348 -0.5792 0.8144
+vn 0.1073 -0.5010 0.8588
+vn -0.0899 -0.7843 0.6138
+vn 0.0770 -0.5759 0.8139
+vn 0.0547 -0.1695 0.9840
+vn -0.0279 -0.8645 0.5019
+vn 0.4260 -0.0609 0.9027
+vn -0.1687 -0.3128 0.9347
+vn 0.3352 -0.1828 0.9243
+vn -0.4350 -0.1812 0.8820
+vn 0.3579 -0.3068 0.8819
+vn -0.3223 -0.2762 0.9054
+vn 0.3069 0.2113 0.9280
+vn -0.4815 -0.2408 0.8427
+vn -0.1598 0.3903 0.9067
+vn 0.1598 0.3903 0.9067
+vn 0.6819 -0.2915 0.6709
+vn -0.1854 -0.4956 0.8485
+vn 0.0585 -0.0781 0.9952
+vn -0.0585 -0.0781 0.9952
+vn -0.0066 -0.2316 0.9728
+vn -0.0585 -0.0845 0.9947
+vn 0.1008 -0.7103 0.6966
+vn -0.1008 -0.7103 0.6966
+vn 0.1322 -0.5947 0.7930
+vn -0.1322 -0.5947 0.7930
+vn 0.3128 -0.1662 0.9352
+vn -0.3143 -0.3928 0.8642
+vn 0.3288 -0.0360 0.9437
+vn -0.3288 -0.0360 0.9437
+vn 0.3233 -0.0808 0.9429
+vn -0.3233 -0.0808 0.9429
+vn -0.0232 0.0511 0.9984
+vn 0.0000 0.0665 0.9978
+vn -0.0043 -0.0651 0.9979
+vn 0.0000 -0.0665 0.9978
+vn 0.0000 0.0000 1.0000
+vn 0.8447 -0.5335 0.0445
+vn -0.8447 -0.5335 0.0445
+vn 0.9500 0.2692 -0.1583
+vn -0.9500 0.2692 -0.1583
+vn 0.0693 0.9004 -0.4294
+vn -0.1018 0.9165 -0.3870
+vn -1.0000 0.0000 0.0000
+vn 0.6905 0.5492 0.4708
+vn 0.4071 -0.8956 0.1791
+vn -0.4319 -0.8639 0.2592
+vn 0.2873 -0.5747 0.7663
+vn -0.2873 -0.5747 0.7663
+vn -0.6326 0.5353 0.5596
+vn 0.6326 0.5353 0.5596
+vn 0.0862 0.7759 0.6250
+vn -0.0862 0.7759 0.6250
+vn 0.7532 0.2870 0.5918
+vn -0.7639 0.2971 0.5729
+vn 0.3416 -0.5409 0.7686
+vn -0.3416 -0.5409 0.7686
+vn 0.0502 0.2343 0.9709
+vn -0.0375 0.2247 0.9737
+vn -0.1304 -0.6087 0.7826
+vn 0.1304 -0.6087 0.7826
+vn -0.5059 0.0716 0.8596
+vn 0.5059 0.0716 0.8596
+vn -0.5774 -0.5774 0.5774
+vn 0.5774 -0.5774 0.5774
+vn 0.5460 -0.4310 0.7184
+vn -0.3319 0.0738 0.9404
+vn 0.3231 0.0311 0.9459
+vn -0.2815 0.0662 0.9573
+vn 0.7357 0.3910 0.5531
+vn -0.8753 0.2059 0.4376
+vn 0.8480 0.3180 0.4240
+vn -0.8973 0.1994 0.3938
+vn 0.8505 0.3798 0.3638
+vn -0.8505 0.3798 0.3638
+vn 0.1783 -0.4161 0.8917
+vn -0.2524 -0.8655 0.4327
+vn -0.1296 -0.1945 0.9723
+vn 0.1296 -0.1945 0.9723
+vn -0.4472 0.0000 0.8944
+vn 0.4472 0.0000 0.8944
+vn -0.1582 0.9494 0.2713
+vn 0.1582 0.9494 0.2713
+vn -0.6463 0.7337 0.2096
+vn 0.6463 0.7337 0.2096
+vn 1.0000 0.0000 0.0000
+vn 0.3051 -0.9450 0.1181
+vn -0.3051 -0.9450 0.1181
+vn 0.0217 -0.3031 0.9527
+vn -0.0217 -0.3031 0.9527
+vn 0.1353 -0.3479 0.9277
+vn -0.1353 -0.3479 0.9277
+vn -0.4681 -0.2239 0.8548
+vn 0.4681 -0.2239 0.8548
+vn -0.2710 0.0271 0.9622
+vn 0.2710 0.0271 0.9622
+vn -0.1717 -0.0090 0.9851
+vn 0.2595 0.1038 0.9601
+vn -0.4332 -0.4874 0.7581
+vn 0.6684 -0.4595 0.5849
+vn -0.1599 -0.8797 0.4478
+vn 0.1599 -0.8797 0.4478
+vn 0.3900 -0.5895 0.7074
+vn -0.3900 -0.5895 0.7074
+vn 0.6547 -0.4589 0.6007
+vn -0.6547 -0.4589 0.6007
+vn 0.5378 -0.1144 0.8353
+vn -0.5378 -0.1144 0.8353
+vn 0.5657 0.1197 0.8159
+vn -0.5774 0.1155 0.8083
+vn 0.4082 0.4082 0.8165
+vn -0.5214 0.6574 0.5441
+vn 0.1796 0.7882 0.5886
+vn -0.1796 0.7882 0.5886
+vn 0.1881 0.3387 0.9219
+vn -0.1881 0.3387 0.9219
+vn -0.0870 0.2756 0.9573
+vn 0.0870 0.2756 0.9573
+vn 0.2804 -0.2181 0.9348
+vn -0.3553 -0.5739 0.7379
+vn 0.3015 -0.3015 0.9045
+vn -0.3015 -0.3015 0.9045
+vn -0.3766 -0.8339 0.4035
+vn 0.0631 -0.3156 0.9468
+vn 0.0823 -0.7822 0.6175
+vn 0.2016 -0.9071 0.3696
+vn -0.3707 -0.2851 0.8839
+vn 0.3707 -0.2851 0.8839
+vn -0.2692 -0.0577 0.9614
+vn 0.4568 0.0508 0.8881
+vn -0.2797 0.5245 0.8042
+vn 0.2797 0.5245 0.8042
+vn -0.0213 0.5546 0.8319
+vn 0.0487 0.6815 0.7302
+vn 0.3778 0.6342 0.6746
+vn -0.3378 0.5221 0.7831
+vn 0.4988 0.5300 0.6858
+vn -0.4988 0.5300 0.6858
+vn 0.5425 -0.3391 0.7686
+vn -0.5425 -0.3391 0.7686
+vn 0.8305 -0.0615 0.5536
+vn -0.8305 -0.0615 0.5536
+vn 0.7814 0.1116 0.6140
+vn -0.7814 0.1116 0.6140
+vn -0.4338 0.8888 -0.1481
+vn 0.4338 0.8888 -0.1481
+vn -0.8515 0.3744 -0.3670
+vn 0.8515 0.3744 -0.3670
+vn -0.2664 0.8710 -0.4127
+vn 0.2197 0.8626 -0.4557
+vn 0.5932 0.7445 -0.3063
+vn -0.5914 0.7489 -0.2991
+vn 0.3714 0.8685 -0.3284
+vn -0.3653 0.8833 -0.2938
+vn 0.2901 0.9141 -0.2833
+vn -0.2901 0.9141 -0.2833
+vn 0.8873 0.1343 -0.4412
+vn -0.7964 0.1323 -0.5901
+vn 0.5108 -0.6649 -0.5450
+vn -0.5108 -0.6649 -0.5450
+vn 0.3695 -0.8566 -0.3601
+vn -0.3695 -0.8566 -0.3601
+vn 0.3617 -0.3858 -0.8487
+vn -0.1649 -0.6644 -0.7289
+vn 0.1952 -0.0976 -0.9759
+vn -0.3011 -0.0125 -0.9535
+vn -0.0107 -0.5633 -0.8262
+vn -0.2562 -0.3112 -0.9152
+vn 0.1533 -0.9649 -0.2134
+vn -0.1533 -0.9649 -0.2134
+vn 0.1260 -0.9624 -0.2406
+vn -0.1260 -0.9624 -0.2406
+vn 0.9396 0.1573 -0.3041
+vn -0.9396 0.1573 -0.3041
+vn 0.9278 0.1838 -0.3246
+vn -0.9278 0.1838 -0.3246
+vn 0.2192 0.0766 -0.9727
+vn -0.2192 0.0766 -0.9727
+vn 0.1211 -0.0530 -0.9912
+vn 0.1497 -0.3635 -0.9195
+vn 0.9094 0.1371 -0.3927
+vn -0.3706 -0.6780 -0.6349
+vn 0.9202 0.1355 -0.3672
+vn -0.9202 0.1355 -0.3672
+vn 0.9173 0.3440 -0.2007
+vn -0.9457 0.2673 -0.1850
+vn 0.9004 0.3642 -0.2380
+vn -0.9337 0.2813 -0.2215
+vn 0.8945 0.4337 0.1084
+vn -0.9501 0.2455 -0.1922
+vn 0.1596 -0.9577 -0.2394
+vn -0.1835 -0.7864 -0.5898
+vn 0.3693 -0.4712 -0.8010
+vn -0.3727 -0.4759 -0.7966
+vn 0.2986 -0.8236 -0.4821
+vn -0.3263 -0.8342 -0.4446
+vn 0.2995 -0.9442 -0.1368
+vn -0.2995 -0.9442 -0.1368
+vn 0.3287 -0.9163 -0.2291
+vn -0.3287 -0.9163 -0.2291
+vn 0.8305 0.3333 -0.4463
+vn -0.8642 -0.4737 0.1696
+vn 0.9166 -0.3740 0.1414
+vn -0.9166 -0.3740 0.1414
+vn 0.2950 -0.0454 -0.9544
+vn -0.4189 -0.2265 -0.8793
+vn 0.1272 0.9658 0.2260
+vn -0.1119 0.9626 0.2468
+vn 0.1320 0.9750 -0.1788
+vn -0.1320 0.9750 -0.1788
+vn 0.3878 0.6192 -0.6828
+vn -0.3878 0.6192 -0.6828
+vn 0.4951 0.8618 -0.1100
+vn -0.4951 0.8618 -0.1100
+vn 0.2561 0.6447 0.7202
+vn -0.2561 0.6447 0.7202
+vn 0.5966 0.7888 0.1479
+vn -0.5966 0.7888 0.1479
+vn 0.7125 0.6755 -0.1900
+vn -0.7125 0.6755 -0.1900
+vn 0.7104 0.1364 -0.6904
+vn -0.6304 0.2517 -0.7343
+vn 0.6823 0.2318 -0.6933
+vn -0.6823 0.2318 -0.6933
+vn 0.6574 0.7254 -0.2040
+vn -0.6574 0.7254 -0.2040
+vn 0.7289 0.6729 0.1262
+vn -0.7289 0.6729 0.1262
+vn 0.7791 0.4074 0.4764
+vn -0.7791 0.4074 0.4764
+vn 0.3669 0.8840 -0.2898
+vn -0.3238 0.9434 -0.0720
+vn 0.2854 0.6237 0.7277
+vn -0.1548 0.5080 0.8473
+vn -0.1681 0.1005 -0.9806
+vn 0.1681 0.1005 -0.9806
+vn 0.2925 0.5674 0.7697
+vn -0.2925 0.5674 0.7697
+vn -0.1616 0.1847 0.9694
+vn 0.1616 0.1847 0.9694
+vn 0.8681 0.0893 -0.4883
+vn -0.9340 0.2255 0.2773
+vn 0.9276 0.0762 0.3657
+vn -0.9276 0.0762 0.3657
+vn 0.9750 0.2169 0.0490
+vn -0.9750 0.2169 0.0490
+vn 0.9817 -0.0304 -0.1882
+vn -0.9956 0.0893 -0.0288
+vn 0.7466 -0.6646 0.0285
+vn -0.6374 -0.7651 0.0915
+vn 0.3723 -0.9243 0.0847
+vn -0.3720 -0.9244 0.0845
+vn 0.3986 -0.8754 0.2734
+vn -0.3986 -0.8754 0.2734
+vn 0.6328 -0.7642 0.1247
+vn -0.6328 -0.7642 0.1247
+vn 0.7325 -0.6368 0.2407
+vn -0.7325 -0.6368 0.2407
+vn 0.2637 -0.4499 0.8533
+vn -0.2637 -0.4499 0.8533
+vn 0.5881 -0.3070 -0.7483
+vn -0.5236 -0.3290 -0.7859
+vn 0.4694 -0.2400 -0.8498
+vn -0.5396 -0.3343 -0.7727
+vn 0.4463 -0.8452 -0.2941
+vn -0.2144 -0.8341 -0.5082
+vn 0.6973 -0.6610 -0.2771
+vn -0.7365 -0.6154 -0.2808
+vn 0.4972 -0.4408 -0.7473
+vn -0.4972 -0.4408 -0.7473
+vn 0.3691 0.2855 0.8844
+vn -0.3244 0.4867 0.8111
+vn 0.4467 0.0975 0.8894
+vn -0.4467 0.0975 0.8894
+vn 0.3188 0.1993 0.9266
+vn -0.1817 -0.0079 0.9833
+vn 0.2076 -0.0836 0.9746
+vn -0.2925 -0.0758 0.9533
+vn 0.3398 0.0824 0.9369
+vn -0.5847 -0.2198 0.7809
+vn 0.5957 -0.3850 0.7049
+vn -0.5957 -0.3850 0.7049
+vn 0.4843 0.5580 0.6738
+vn -0.4843 0.5580 0.6738
+vn -0.2675 0.8318 0.4864
+vn 0.2675 0.8318 0.4864
+vn -0.8576 0.2223 0.4637
+vn 0.7885 0.2366 0.5677
+vn -0.5257 -0.3579 0.7717
+vn 0.5242 -0.3548 0.7742
+vn 0.4663 -0.5991 0.6509
+vn -0.4390 -0.5252 0.7290
+vn 0.7104 -0.4567 0.5356
+vn -0.7104 -0.4567 0.5356
+vn 0.7507 -0.6131 -0.2461
+vn -0.6302 -0.7658 0.1282
+vn -0.1788 0.2923 0.9395
+vn 0.2175 0.2733 0.9370
+vn 0.9042 -0.3578 -0.2332
+vn -0.9042 -0.3578 -0.2332
+vn 0.0400 0.3399 0.9396
+vn -0.0400 0.3399 0.9396
+vn 0.2734 0.9064 0.3221
+vn -0.2734 0.9064 0.3221
+vn 0.4480 -0.4480 0.7737
+vn -0.7177 0.1689 0.6755
+vn 0.5534 -0.5534 0.6225
+vn -0.9008 -0.4075 0.1501
+vn 0.5724 -0.3122 0.7582
+vn -0.5815 -0.5217 0.6243
+vn 0.5597 -0.5533 0.6169
+vn -0.6138 -0.2571 0.7465
+vn 0.8271 0.5323 -0.1802
+vn -0.8271 0.5323 -0.1802
+vn 0.9227 -0.3765 -0.0825
+vn -0.8717 -0.4446 -0.2063
+vn 0.9972 -0.0181 -0.0725
+vn -0.9972 -0.0181 -0.0725
+vn 0.6895 -0.6644 0.2883
+vn -0.6895 -0.6644 0.2883
+vn 0.7815 -0.6176 0.0882
+vn -0.7930 -0.5947 0.1322
+vn 0.7022 -0.7022 0.1170
+vn -0.7022 -0.7022 0.1170
+vn 0.1240 0.9921 0.0207
+vn -0.2408 0.9631 -0.1204
+vn 0.9435 0.3145 0.1048
+vn -0.9251 0.3469 0.1542
+vn 0.6213 -0.7767 0.1036
+vn -0.6213 -0.7767 0.1036
+vn 0.0000 1.0000 0.0000
+vn 0.6197 -0.6899 0.3742
+vn -0.6197 -0.6899 0.3742
+vn 0.2752 -0.8808 0.3853
+vn -0.2752 -0.8808 0.3853
+vn -0.7929 -0.5252 -0.3089
+vn 0.7929 -0.5252 -0.3089
+vn -0.8096 0.2429 -0.5343
+vn 0.8538 0.2328 -0.4657
+vn -0.5621 0.8231 -0.0803
+vn 0.5433 0.6985 -0.4657
+vn -0.0071 0.9899 0.1414
+vn 0.1096 0.9939 -0.0157
+vn 0.1046 0.0392 0.9937
+vn -0.1738 0.0097 0.9847
+vn 0.2461 0.0852 0.9655
+vn -0.4134 0.0413 0.9096
+vn 0.3009 0.0926 0.9491
+vn -0.3009 0.0926 0.9491
+vn 0.2104 0.0124 0.9775
+vn -0.1220 0.0458 0.9915
+vn -0.0099 0.3867 0.9221
+vn 0.0099 0.3867 0.9221
+vn 0.3787 -0.0364 0.9248
+vn -0.4244 -0.0320 0.9049
+vn 0.2530 -0.1897 0.9487
+vn -0.2570 0.0723 0.9637
+vn -0.4870 0.6088 0.6262
+vn 0.2981 0.7454 0.5963
+vn 0.6693 0.1802 0.7208
+vn -0.6693 0.1802 0.7208
+vn 0.4388 -0.2008 0.8759
+vn -0.4723 -0.1986 0.8588
+vn 0.5786 -0.1334 0.8046
+vn -0.2975 -0.4062 0.8640
+vn 0.5002 0.2833 0.8182
+vn -0.5002 0.2833 0.8182
+vn 0.2980 0.5802 0.7580
+vn -0.2980 0.5802 0.7580
+vn 0.0929 -0.9912 -0.0944
+vn -0.0929 -0.9912 -0.0944
+vn 0.4688 -0.8715 0.1442
+vn -0.4688 -0.8715 0.1442
+vn 0.9309 -0.2541 0.2624
+vn -0.9264 -0.2460 0.2851
+vn 0.8465 0.5291 -0.0595
+vn -0.8267 0.5627 -0.0035
+vn -0.2511 0.9439 -0.2145
+vn 0.2146 0.9243 -0.3157
+vn -0.4841 0.8743 -0.0361
+vn 0.4196 0.8851 -0.2012
+vn -0.5256 -0.0030 -0.8507
+vn 0.5470 -0.0144 -0.8370
+vn -0.1466 0.0104 -0.9891
+vn 0.1466 0.0104 -0.9891
+vn 0.4046 0.0266 -0.9141
+vn -0.4046 0.0266 -0.9141
+vn -0.8073 0.5901 0.0041
+vn 0.7330 0.6786 0.0472
+vn 0.4200 -0.2291 -0.8781
+vn -0.4200 -0.2291 -0.8781
+vn -0.0687 -0.9943 -0.0818
+vn 0.0687 -0.9943 -0.0818
+vn 0.6713 -0.1971 0.7145
+vn -0.6713 -0.1971 0.7145
+vn 0.8326 -0.3017 0.4646
+vn -0.8326 -0.3017 0.4646
+vn 0.4258 -0.7967 0.4290
+vn -0.4258 -0.7967 0.4290
+vn 0.3265 -0.4954 0.8050
+vn -0.3265 -0.4954 0.8050
+vn -0.0649 -0.5714 0.8181
+vn 0.0649 -0.5714 0.8181
+vn -0.2738 -0.8315 0.4834
+vn 0.2738 -0.8315 0.4834
+vn -0.7606 -0.3400 0.5531
+vn 0.7824 -0.3294 0.5285
+vn -0.4658 -0.1863 0.8651
+vn 0.4658 -0.1863 0.8651
+vn -0.4983 0.1812 0.8478
+vn 0.4983 0.1812 0.8478
+vn -0.7683 0.3293 0.5488
+vn 0.7656 0.3223 0.5568
+vn -0.2487 0.8249 0.5076
+vn 0.2560 0.8073 0.5317
+vn -0.1017 0.5518 0.8277
+vn 0.0821 0.6023 0.7940
+vn 0.3861 0.5446 0.7445
+vn -0.3329 0.5231 0.7846
+vn 0.4059 0.7641 0.5014
+vn -0.4246 0.7711 0.4745
+vn 0.8299 0.2940 0.4742
+vn -0.8251 0.2968 0.4808
+vn 0.6617 0.2026 0.7219
+vn -0.6888 0.1868 0.7005
+vn 0.7816 0.3058 -0.5437
+vn -0.8400 0.3436 -0.4200
+vn 0.2037 0.8146 -0.5431
+vn -0.2074 0.8296 -0.5185
+vn -0.4381 0.7988 -0.4123
+vn 0.4056 0.7605 -0.5070
+vn -0.7861 0.3276 -0.5241
+vn 0.8642 0.3143 -0.3928
+vn -0.8519 -0.3408 -0.3976
+vn 0.8519 -0.3408 -0.3976
+vn -0.4056 -0.7605 -0.5070
+vn 0.4056 -0.7605 -0.5070
+vn 0.2074 -0.8296 -0.5185
+vn -0.2074 -0.8296 -0.5185
+vn 0.8297 -0.3734 -0.4149
+vn -0.8297 -0.3734 -0.4149
+vn 0.1054 -0.8433 0.5270
+vn -0.1367 -0.8748 0.4648
+vn 0.1916 -0.8620 0.4693
+vn -0.2303 -0.8656 0.4447
+vn 0.5959 -0.4256 0.6810
+vn -0.5959 -0.4256 0.6810
+vn 0.7563 -0.0299 0.6535
+vn -0.7563 -0.0299 0.6535
+vn 0.8069 0.0689 0.5866
+vn -0.8069 0.0689 0.5866
+vn 0.2334 -0.7779 0.5834
+vn -0.2334 -0.7779 0.5834
+vn 0.4177 -0.5751 0.7034
+vn -0.3557 -0.7290 0.5848
+vn 0.6872 -0.4191 0.5934
+vn -0.6872 -0.4191 0.5934
+vn 0.5537 -0.2978 0.7777
+vn -0.7028 -0.3915 0.5939
+vn 0.8227 0.3606 0.4395
+vn -0.3127 0.3425 0.8860
+vn 0.5041 0.6448 0.5745
+vn -0.5091 0.6482 0.5663
+vn 0.6155 0.4924 0.6155
+vn -0.6155 0.4924 0.6155
+vn -0.0371 0.6685 0.7428
+vn 0.0486 0.6560 0.7532
+vn -0.7386 0.3768 0.5590
+vn 0.7104 0.2715 0.6494
+vn -0.5774 0.5774 0.5774
+vn 0.6013 0.5262 0.6013
+vn 0.5364 -0.3230 0.7797
+vn -0.5070 -0.6281 0.5903
+vn 0.2181 -0.4685 0.8561
+vn -0.2181 -0.4685 0.8561
+vn -0.1073 -0.5010 0.8588
+vn 0.0348 -0.5792 0.8144
+vn -0.0770 -0.5759 0.8139
+vn 0.0899 -0.7843 0.6138
+vn 0.0279 -0.8645 0.5019
+vn -0.0547 -0.1695 0.9840
+vn 0.1687 -0.3128 0.9347
+vn -0.4260 -0.0609 0.9027
+vn 0.4350 -0.1812 0.8820
+vn -0.3352 -0.1828 0.9243
+vn 0.3223 -0.2762 0.9054
+vn -0.3579 -0.3068 0.8819
+vn 0.4815 -0.2408 0.8427
+vn -0.3069 0.2113 0.9280
+vn -0.0317 -0.1899 0.9813
+vn 0.0317 -0.1899 0.9813
+vn 0.1854 -0.4956 0.8485
+vn -0.6819 -0.2915 0.6709
+vn 0.2623 -0.3498 0.8994
+vn -0.2623 -0.3498 0.8994
+vn 0.0585 -0.0845 0.9947
+vn 0.0066 -0.2316 0.9728
+vn -0.0136 -0.6507 0.7592
+vn 0.0136 -0.6507 0.7592
+vn 0.2404 -0.5476 0.8014
+vn -0.2404 -0.5476 0.8014
+vn 0.3143 -0.3928 0.8642
+vn -0.3128 -0.1662 0.9352
+vn 0.2821 -0.0164 0.9592
+vn -0.2821 -0.0164 0.9592
+vn 0.3273 -0.1432 0.9340
+vn -0.3273 -0.1432 0.9340
+vn 0.0232 0.0511 0.9984
+vn 0.0043 -0.0651 0.9979
+vn 0.7826 -0.6087 -0.1304
+vn -0.7826 -0.6087 -0.1304
+vn 0.9448 0.1919 -0.2657
+vn -0.9448 0.1919 -0.2657
+vn 0.1018 0.9165 -0.3870
+vn -0.0693 0.9004 -0.4294
+vn -0.6905 0.5492 0.4708
+vn 0.4319 -0.8639 0.2592
+vn -0.4071 -0.8956 0.1791
+vn -0.6667 0.6667 0.3333
+vn 0.6667 0.6667 0.3333
+vn 0.1348 0.8086 0.5727
+vn -0.1348 0.8086 0.5727
+vn 0.7639 0.2971 0.5729
+vn -0.7532 0.2870 0.5918
+vn 0.4116 -0.8575 0.3087
+vn -0.4116 -0.8575 0.3087
+vn 0.0375 0.2247 0.9737
+vn -0.0502 0.2343 0.9709
+vn 0.1304 -0.2609 0.9565
+vn -0.1304 -0.2609 0.9565
+vn -0.0631 -0.8206 0.5681
+vn 0.0631 -0.8206 0.5681
+vn 0.7325 0.2817 0.6198
+vn -0.7325 0.2817 0.6198
+vn 0.3319 0.0738 0.9404
+vn -0.5460 -0.4310 0.7184
+vn 0.2815 0.0662 0.9573
+vn -0.3231 0.0311 0.9459
+vn 0.8753 0.2059 0.4376
+vn -0.7357 0.3910 0.5531
+vn 0.8973 0.1994 0.3938
+vn -0.8480 0.3180 0.4240
+vn 0.9586 0.0664 0.2767
+vn -0.9586 0.0664 0.2767
+vn 0.2524 -0.8655 0.4327
+vn -0.1783 -0.4161 0.8917
+vn -0.1751 -0.2043 0.9631
+vn 0.1751 -0.2043 0.9631
+vn -0.1219 -0.1829 0.9755
+vn 0.1219 -0.1829 0.9755
+vn -0.1562 0.3123 0.9370
+vn 0.1562 0.3123 0.9370
+vn -0.7238 0.6857 0.0762
+vn 0.7238 0.6857 0.0762
+vn 0.0478 -0.2870 0.9567
+vn -0.0478 -0.2870 0.9567
+vn -0.5488 -0.3293 0.7683
+vn 0.5488 -0.3293 0.7683
+vn -0.4945 -0.1130 0.8618
+vn 0.4945 -0.1130 0.8618
+vn -0.2595 0.1038 0.9601
+vn 0.1717 -0.0090 0.9851
+vn -0.6684 -0.4595 0.5849
+vn 0.4332 -0.4874 0.7581
+vn -0.1156 -0.6359 0.7631
+vn 0.1156 -0.6359 0.7631
+vn 0.4242 -0.6211 0.6590
+vn -0.4242 -0.6211 0.6590
+vn 0.4767 -0.3557 0.8039
+vn -0.4767 -0.3557 0.8039
+vn 0.5871 -0.0839 0.8052
+vn -0.5871 -0.0839 0.8052
+vn 0.5774 0.1155 0.8083
+vn -0.5657 0.1197 0.8159
+vn 0.5214 0.6574 0.5441
+vn -0.4082 0.4082 0.8165
+vn 0.3358 0.3478 0.8754
+vn -0.3358 0.3478 0.8754
+vn 0.1452 0.3774 0.9146
+vn -0.1452 0.3774 0.9146
+vn 0.0301 0.2306 0.9726
+vn -0.0301 0.2306 0.9726
+vn 0.3553 -0.5739 0.7379
+vn -0.2804 -0.2181 0.9348
+vn 0.2627 -0.2252 0.9382
+vn -0.2627 -0.2252 0.9382
+vn -0.0631 -0.3156 0.9468
+vn 0.3766 -0.8339 0.4035
+vn -0.2016 -0.9071 0.3696
+vn -0.0823 -0.7822 0.6175
+vn -0.3356 -0.2397 0.9110
+vn 0.3356 -0.2397 0.9110
+vn -0.4568 0.0508 0.8881
+vn 0.2692 -0.0577 0.9614
+vn -0.0247 0.4072 0.9130
+vn 0.0247 0.4072 0.9130
+vn -0.0487 0.6815 0.7302
+vn 0.0213 0.5546 0.8319
+vn 0.3378 0.5221 0.7831
+vn -0.3778 0.6342 0.6746
+vn 0.7895 -0.3158 0.5263
+vn -0.7895 -0.3158 0.5263
+vn 0.8070 -0.0807 0.5851
+vn -0.8070 -0.0807 0.5851
+vn 0.7868 0.1210 0.6052
+vn -0.7868 0.1210 0.6052
+vn -0.6357 0.6811 -0.3633
+vn 0.6357 0.6811 -0.3633
+vn -0.8507 0.3650 -0.3783
+vn 0.8507 0.3650 -0.3783
+vn -0.2197 0.8626 -0.4557
+vn 0.2664 0.8710 -0.4127
+vn 0.5914 0.7489 -0.2991
+vn -0.5932 0.7445 -0.3063
+vn 0.3653 0.8833 -0.2938
+vn -0.3714 0.8685 -0.3284
+vn 0.2760 0.9159 -0.2915
+vn -0.2760 0.9159 -0.2915
+vn 0.7964 0.1323 -0.5901
+vn -0.8873 0.1343 -0.4412
+vn 0.5442 -0.7524 -0.3712
+vn -0.5442 -0.7524 -0.3712
+vn 0.4027 -0.7323 -0.5492
+vn -0.4027 -0.7323 -0.5492
+vn 0.1649 -0.6644 -0.7289
+vn -0.3617 -0.3858 -0.8487
+vn 0.3011 -0.0125 -0.9535
+vn -0.1952 -0.0976 -0.9759
+vn 0.2562 -0.3112 -0.9152
+vn 0.0107 -0.5633 -0.8262
+vn 0.0779 -0.9948 -0.0663
+vn -0.0779 -0.9948 -0.0663
+vn 0.1094 -0.9718 -0.2089
+vn -0.1094 -0.9718 -0.2089
+vn 0.8150 -0.5621 -0.1405
+vn -0.8150 -0.5621 -0.1405
+vn 0.9358 0.1396 -0.3236
+vn -0.9358 0.1396 -0.3236
+vn 0.1132 -0.0274 -0.9932
+vn -0.1132 -0.0274 -0.9932
+vn -0.1497 -0.3635 -0.9195
+vn -0.1211 -0.0530 -0.9912
+vn 0.3706 -0.6780 -0.6349
+vn -0.9094 0.1371 -0.3927
+vn 0.9193 0.1393 -0.3682
+vn -0.9193 0.1393 -0.3682
+vn 0.9457 0.2673 -0.1850
+vn -0.9173 0.3440 -0.2007
+vn 0.9337 0.2813 -0.2215
+vn -0.9004 0.3642 -0.2380
+vn 0.9501 0.2455 -0.1922
+vn -0.8945 0.4337 0.1084
+vn 0.1835 -0.7864 -0.5898
+vn -0.1596 -0.9577 -0.2394
+vn 0.3727 -0.4759 -0.7966
+vn -0.3693 -0.4712 -0.8010
+vn 0.3263 -0.8342 -0.4446
+vn -0.2986 -0.8236 -0.4821
+vn 0.2620 -0.9574 -0.1217
+vn -0.2620 -0.9574 -0.1217
+vn 0.2996 -0.9443 -0.1362
+vn -0.2996 -0.9443 -0.1362
+vn 0.8642 -0.4737 0.1696
+vn -0.8305 0.3333 -0.4463
+vn 0.6869 -0.6358 0.3521
+vn -0.6869 -0.6358 0.3521
+vn 0.4189 -0.2265 -0.8793
+vn -0.2950 -0.0454 -0.9544
+vn 0.1119 0.9626 0.2468
+vn -0.1272 0.9658 0.2260
+vn 0.1208 0.9734 -0.1947
+vn -0.1208 0.9734 -0.1947
+vn 0.3140 0.5711 -0.7585
+vn -0.3140 0.5711 -0.7585
+vn 0.3231 0.9288 -0.1817
+vn -0.3231 0.9288 -0.1817
+vn 0.0452 0.7955 0.6043
+vn -0.0452 0.7955 0.6043
+vn 0.6144 0.7696 0.1738
+vn -0.6144 0.7696 0.1738
+vn 0.6935 0.6857 -0.2212
+vn -0.6935 0.6857 -0.2212
+vn 0.6304 0.2517 -0.7343
+vn -0.7104 0.1364 -0.6904
+vn 0.3179 0.5704 -0.7574
+vn -0.3179 0.5704 -0.7574
+vn 0.6289 0.7624 -0.1525
+vn -0.6289 0.7624 -0.1525
+vn 0.7088 0.6833 0.1752
+vn -0.7088 0.6833 0.1752
+vn 0.6885 0.3830 0.6158
+vn -0.6885 0.3830 0.6158
+vn 0.3238 0.9434 -0.0720
+vn -0.3669 0.8840 -0.2898
+vn 0.1548 0.5080 0.8473
+vn -0.2854 0.6237 0.7277
+vn -0.1819 0.1145 -0.9766
+vn 0.1819 0.1145 -0.9766
+vn -0.2638 0.9462 -0.1871
+vn 0.2638 0.9462 -0.1871
+vn 0.9340 0.2255 0.2773
+vn -0.8681 0.0893 -0.4883
+vn 0.9758 0.1241 0.1800
+vn -0.9758 0.1241 0.1800
+vn 0.9613 0.1472 -0.2330
+vn -0.9613 0.1472 -0.2330
+vn 0.9956 0.0893 -0.0288
+vn -0.9817 -0.0304 -0.1882
+vn 0.6374 -0.7651 0.0915
+vn -0.7466 -0.6646 0.0285
+vn 0.3720 -0.9244 0.0845
+vn -0.3723 -0.9243 0.0847
+vn 0.5281 -0.8354 0.1522
+vn -0.5281 -0.8354 0.1522
+vn 0.3070 -0.5237 0.7946
+vn -0.3070 -0.5237 0.7946
+vn 0.5236 -0.3290 -0.7859
+vn -0.5881 -0.3070 -0.7483
+vn 0.5396 -0.3343 -0.7727
+vn -0.4694 -0.2400 -0.8498
+vn 0.2144 -0.8341 -0.5082
+vn -0.4463 -0.8452 -0.2941
+vn 0.7365 -0.6154 -0.2808
+vn -0.6973 -0.6610 -0.2771
+vn 0.3244 0.4867 0.8111
+vn -0.3691 0.2855 0.8844
+vn 0.4649 0.2593 0.8465
+vn -0.4649 0.2593 0.8465
+vn 0.1817 -0.0079 0.9833
+vn -0.3188 0.1993 0.9266
+vn 0.2925 -0.0758 0.9533
+vn -0.2076 -0.0836 0.9746
+vn 0.5847 -0.2198 0.7809
+vn -0.3398 0.0824 0.9369
+vn 0.6509 -0.1939 0.7340
+vn -0.6509 -0.1939 0.7340
+vn 0.4075 0.7506 0.5201
+vn -0.4075 0.7506 0.5201
+vn -0.2655 0.8296 0.4911
+vn 0.2655 0.8296 0.4911
+vn -0.7885 0.2366 0.5677
+vn 0.8576 0.2223 0.4637
+vn -0.5242 -0.3548 0.7742
+vn 0.5257 -0.3579 0.7717
+vn 0.4390 -0.5252 0.7290
+vn -0.4663 -0.5991 0.6509
+vn 0.6888 -0.4428 0.5740
+vn -0.6888 -0.4428 0.5740
+vn 0.6302 -0.7658 0.1282
+vn -0.7507 -0.6131 -0.2461
+vn -0.2175 0.2733 0.9370
+vn 0.1788 0.2923 0.9395
+vn 0.9046 -0.3869 -0.1792
+vn -0.9046 -0.3869 -0.1792
+vn 0.1782 -0.0891 0.9800
+vn -0.1782 -0.0891 0.9800
+vn -0.2335 0.8972 0.3749
+vn 0.2335 0.8972 0.3749
+vn 0.7177 0.1689 0.6755
+vn -0.4480 -0.4480 0.7737
+vn 0.5313 0.5844 0.6134
+vn -0.5313 0.5844 0.6134
+vn 0.9008 -0.4075 0.1501
+vn -0.5534 -0.5534 0.6225
+vn 0.5815 -0.5217 0.6243
+vn -0.5724 -0.3122 0.7582
+vn 0.6138 -0.2571 0.7465
+vn -0.5597 -0.5533 0.6169
+vn 0.8779 -0.4788 0.0076
+vn -0.8779 -0.4788 0.0076
+vn 0.8717 -0.4446 -0.2063
+vn -0.9227 -0.3765 -0.0825
+vn 0.7661 -0.6363 0.0909
+vn -0.7661 -0.6363 0.0909
+vn 0.7930 -0.5947 0.1322
+vn -0.7815 -0.6176 0.0882
+vn 0.2408 0.9631 -0.1204
+vn -0.1240 0.9921 0.0207
+vn 0.9251 0.3469 0.1542
+vn -0.9435 0.3145 0.1048
+vn 0.7071 -0.7071 0.0000
+vn -0.7071 -0.7071 0.0000
+vn -0.0157 0.9898 0.1414
+vn 0.0157 0.9898 0.1414
+vn 0.6266 -0.7211 0.2956
+vn -0.6266 -0.7211 0.2956
+vn 0.2714 -0.9022 0.3353
+vn -0.2714 -0.9022 0.3353
+vn -0.8651 -0.4853 -0.1266
+vn 0.8651 -0.4853 -0.1266
+vn -0.8538 0.2328 -0.4657
+vn 0.8096 0.2429 -0.5343
+vn -0.5433 0.6985 -0.4657
+vn 0.5621 0.8231 -0.0803
+vn -0.1096 0.9939 -0.0157
+vn 0.0071 0.9899 0.1414
+vn 0.1738 0.0097 0.9847
+vn -0.1046 0.0392 0.9937
+vn 0.4134 0.0413 0.9096
+vn -0.2461 0.0852 0.9655
+vn 0.3228 -0.0461 0.9453
+vn -0.3228 -0.0461 0.9453
+vn 0.1220 0.0458 0.9915
+vn -0.2104 0.0124 0.9775
+vn 0.5679 0.1916 0.8005
+vn -0.5679 0.1916 0.8005
+vn 0.4244 -0.0320 0.9049
+vn -0.3787 -0.0364 0.9248
+vn 0.2570 0.0723 0.9637
+vn -0.2530 -0.1897 0.9487
+vn 0.1351 -0.0225 0.9906
+vn -0.1351 -0.0225 0.9906
+vn -0.2981 0.7454 0.5963
+vn 0.4870 0.6088 0.6262
+vn 0.5571 -0.1486 0.8171
+vn -0.5571 -0.1486 0.8171
+vn 0.4723 -0.1986 0.8588
+vn -0.4388 -0.2008 0.8759
+vn 0.2975 -0.4062 0.8640
+vn -0.5786 -0.1334 0.8046
+vn 0.5771 0.2164 0.7875
+vn -0.5771 0.2164 0.7875
+vn 0.0931 -0.9932 -0.0692
+vn -0.0931 -0.9932 -0.0692
+vn 0.5161 -0.8527 -0.0812
+vn -0.5161 -0.8527 -0.0812
+vn 0.9264 -0.2460 0.2851
+vn -0.9309 -0.2541 0.2624
+vn 0.8267 0.5627 -0.0035
+vn -0.8465 0.5291 -0.0595
+vn -0.2146 0.9243 -0.3157
+vn 0.2511 0.9439 -0.2145
+vn -0.4196 0.8851 -0.2012
+vn 0.4841 0.8743 -0.0361
+vn -0.5470 -0.0144 -0.8370
+vn 0.5256 -0.0030 -0.8507
+vn -0.2556 -0.0749 -0.9639
+vn 0.2556 -0.0749 -0.9639
+vn -0.7330 0.6786 0.0472
+vn 0.8073 0.5901 0.0041
+vn 0.6844 -0.1711 -0.7088
+vn -0.6844 -0.1711 -0.7088
+vn -0.3604 -0.8283 -0.4290
+vn 0.3604 -0.8283 -0.4290
+usemtl None
+s off
+f 47/1/1 3/2/1 45/3/1
+f 4/4/2 48/5/2 46/6/2
+f 45/3/3 5/7/3 43/8/3
+f 6/9/4 46/6/4 44/10/4
+f 3/2/5 7/11/5 5/7/5
+f 8/12/6 4/4/6 6/9/6
+f 1/13/7 9/14/7 3/2/7
+f 10/15/8 2/16/8 4/4/8
+f 11/17/9 15/18/9 9/14/9
+f 16/19/10 12/20/10 10/15/10
+f 9/14/11 17/21/11 7/11/11
+f 18/22/12 10/15/12 8/12/12
+f 21/23/13 17/21/13 15/18/13
+f 22/24/14 18/22/14 20/25/14
+f 13/26/15 21/23/15 15/18/15
+f 22/24/16 14/27/16 16/19/16
+f 23/28/17 27/29/17 21/23/17
+f 28/30/18 24/31/18 22/24/18
+f 27/29/19 19/32/19 21/23/19
+f 28/30/20 20/25/20 30/33/20
+f 33/34/21 29/35/21 27/29/21
+f 34/36/22 30/33/22 32/37/22
+f 35/38/23 27/29/23 25/39/23
+f 36/40/24 28/30/24 34/36/24
+f 37/41/25 33/34/25 35/38/25
+f 38/42/26 34/36/26 40/43/26
+f 39/44/27 31/45/27 33/34/27
+f 40/43/28 32/37/28 42/46/28
+f 45/3/29 41/47/29 39/44/29
+f 46/6/30 42/46/30 44/10/30
+f 47/1/31 39/44/31 37/41/31
+f 48/5/32 40/43/32 46/6/32
+f 37/41/33 49/48/33 47/1/33
+f 38/42/34 50/49/34 52/50/34
+f 35/38/35 51/51/35 37/41/35
+f 36/40/36 52/50/36 54/52/36
+f 25/39/37 53/53/37 35/38/37
+f 26/54/38 54/52/38 56/55/38
+f 23/28/39 55/56/39 25/39/39
+f 24/31/40 56/55/40 58/57/40
+f 23/28/41 59/58/41 57/59/41
+f 60/60/42 24/31/42 58/57/42
+f 13/26/43 63/61/43 59/58/43
+f 64/62/44 14/27/44 60/60/44
+f 11/17/45 65/63/45 63/61/45
+f 66/64/46 12/20/46 64/62/46
+f 1/13/47 49/48/47 65/63/47
+f 50/49/48 2/16/48 66/64/48
+f 61/65/49 65/63/49 49/48/49
+f 50/49/50 66/64/50 62/66/50
+f 63/61/51 65/63/51 61/65/51
+f 62/66/52 66/64/52 64/62/52
+f 61/65/53 59/58/53 63/61/53
+f 64/62/54 60/60/54 62/66/54
+f 61/65/55 57/59/55 59/58/55
+f 60/60/56 58/57/56 62/66/56
+f 61/65/57 55/56/57 57/59/57
+f 58/57/58 56/55/58 62/66/58
+f 61/65/59 53/53/59 55/56/59
+f 56/55/60 54/52/60 62/66/60
+f 61/65/61 51/51/61 53/53/61
+f 54/52/62 52/50/62 62/66/62
+f 61/65/63 49/48/63 51/51/63
+f 52/50/64 50/49/64 62/66/64
+f 174/67/65 91/68/65 89/69/65
+f 175/70/66 91/68/66 176/71/66
+f 172/72/67 89/69/67 87/73/67
+f 173/74/68 90/75/68 175/70/68
+f 85/76/69 172/72/69 87/73/69
+f 173/74/70 86/77/70 88/78/70
+f 83/79/71 170/80/71 85/76/71
+f 171/81/72 84/82/72 86/77/72
+f 81/83/73 168/84/73 83/79/73
+f 169/85/74 82/86/74 84/82/74
+f 79/87/75 146/88/75 164/89/75
+f 147/90/76 80/91/76 165/92/76
+f 94/93/77 146/88/77 92/94/77
+f 95/95/78 147/90/78 149/96/78
+f 94/93/79 150/97/79 148/98/79
+f 151/99/80 95/95/80 149/96/80
+f 98/100/81 150/97/81 96/101/81
+f 99/102/82 151/99/82 153/103/82
+f 100/104/83 152/105/83 98/100/83
+f 101/106/84 153/103/84 155/107/84
+f 102/108/85 154/109/85 100/104/85
+f 103/110/86 155/107/86 157/111/86
+f 102/108/87 158/112/87 156/113/87
+f 159/114/88 103/110/88 157/111/88
+f 106/115/89 158/112/89 104/116/89
+f 107/117/90 159/114/90 161/118/90
+f 108/119/91 160/120/91 106/115/91
+f 109/121/92 161/118/92 163/122/92
+f 67/123/93 162/124/93 108/119/93
+f 67/123/94 163/122/94 68/125/94
+f 128/126/95 162/124/95 110/127/95
+f 129/128/96 163/122/96 161/118/96
+f 128/126/97 158/112/97 160/120/97
+f 159/114/98 129/128/98 161/118/98
+f 156/113/99 179/129/99 126/130/99
+f 157/111/100 180/131/100 159/114/100
+f 154/109/101 126/130/101 124/132/101
+f 155/107/102 127/133/102 157/111/102
+f 152/105/103 124/132/103 122/134/103
+f 153/103/104 125/135/104 155/107/104
+f 150/97/105 122/134/105 120/136/105
+f 151/99/106 123/137/106 153/103/106
+f 148/98/107 120/136/107 118/138/107
+f 149/96/108 121/139/108 151/99/108
+f 146/88/109 118/138/109 116/140/109
+f 147/90/110 119/141/110 149/96/110
+f 164/89/111 116/140/111 114/142/111
+f 165/92/112 117/143/112 147/90/112
+f 114/142/113 177/144/113 164/89/113
+f 177/144/114 115/145/114 165/92/114
+f 162/124/115 112/146/115 110/127/115
+f 163/122/116 113/147/116 68/125/116
+f 112/146/117 178/148/117 183/149/117
+f 178/148/118 113/147/118 184/150/118
+f 181/151/119 178/148/119 177/144/119
+f 182/152/120 178/148/120 184/150/120
+f 135/153/121 176/71/121 174/67/121
+f 176/71/122 136/154/122 175/70/122
+f 133/155/123 174/67/123 172/72/123
+f 175/70/124 134/156/124 173/74/124
+f 133/155/125 170/80/125 131/157/125
+f 134/156/126 171/81/126 173/74/126
+f 166/158/127 185/159/127 168/84/127
+f 186/160/128 167/161/128 169/85/128
+f 131/157/129 168/84/129 185/159/129
+f 169/85/130 132/162/130 186/160/130
+f 190/163/131 187/164/131 144/165/131
+f 190/163/132 188/166/132 189/167/132
+f 187/164/133 69/168/133 185/159/133
+f 188/166/134 69/168/134 189/167/134
+f 131/157/135 69/168/135 130/169/135
+f 132/162/135 69/168/135 186/160/135
+f 142/170/136 191/171/136 144/165/136
+f 192/172/137 143/173/137 145/174/137
+f 140/175/138 193/176/138 142/170/138
+f 194/177/139 141/178/139 143/173/139
+f 197/179/140 140/175/140 139/180/140
+f 198/181/141 141/178/141 196/182/141
+f 71/183/142 139/180/142 138/184/142
+f 71/183/143 139/180/143 198/181/143
+f 144/165/144 70/185/144 190/163/144
+f 145/174/145 70/185/145 192/172/145
+f 191/171/146 208/186/146 70/185/146
+f 192/172/147 208/186/147 207/187/147
+f 71/183/148 200/188/148 197/179/148
+f 201/189/149 71/183/149 198/181/149
+f 197/179/150 202/190/150 195/191/150
+f 203/192/151 198/181/151 196/182/151
+f 202/190/152 193/176/152 195/191/152
+f 203/192/153 194/177/153 205/193/153
+f 193/176/154 206/194/154 191/171/154
+f 207/187/155 194/177/155 192/172/155
+f 204/195/156 200/188/156 199/196/156
+f 205/193/157 201/189/157 203/192/157
+f 199/196/158 206/194/158 204/195/158
+f 207/187/159 199/196/159 205/193/159
+f 139/180/160 164/89/160 177/144/160
+f 165/92/161 139/180/161 177/144/161
+f 140/175/162 211/197/162 164/89/162
+f 212/198/163 141/178/163 165/92/163
+f 144/165/164 211/197/164 142/170/164
+f 145/174/165 212/198/165 214/199/165
+f 187/164/166 213/200/166 144/165/166
+f 188/166/167 214/199/167 167/161/167
+f 209/201/168 166/158/168 81/83/168
+f 210/202/169 167/161/169 214/199/169
+f 215/203/170 213/200/170 209/201/170
+f 216/204/171 214/199/171 212/198/171
+f 79/87/172 211/197/172 215/203/172
+f 212/198/173 80/91/173 216/204/173
+f 130/169/174 222/205/174 131/157/174
+f 130/169/175 223/206/175 72/207/175
+f 133/155/176 222/205/176 220/208/176
+f 223/206/177 134/156/177 221/209/177
+f 135/153/178 220/208/178 218/210/178
+f 221/209/179 136/154/179 219/211/179
+f 137/212/135 218/210/135 217/213/135
+f 219/211/135 137/212/135 217/213/135
+f 218/210/180 231/214/180 217/213/180
+f 219/211/181 231/214/181 230/215/181
+f 218/210/182 227/216/182 229/217/182
+f 228/218/183 219/211/183 230/215/183
+f 220/208/142 225/219/142 227/216/142
+f 226/220/184 221/209/184 228/218/184
+f 72/207/185 225/219/185 222/205/185
+f 72/207/186 226/220/186 224/221/186
+f 224/221/187 229/217/187 225/219/187
+f 230/215/188 224/221/188 226/220/188
+f 225/219/189 229/217/189 227/216/189
+f 228/218/190 230/215/190 226/220/190
+f 183/149/191 234/222/191 232/223/191
+f 235/224/192 184/150/192 233/225/192
+f 112/146/193 232/223/193 254/226/193
+f 233/225/194 113/147/194 255/227/194
+f 112/146/195 256/228/195 110/127/195
+f 113/147/196 257/229/196 255/227/196
+f 114/142/197 234/222/197 181/151/197
+f 115/145/198 235/224/198 253/230/198
+f 114/142/199 250/231/199 252/232/199
+f 251/233/200 115/145/200 253/230/200
+f 116/140/201 248/234/201 250/231/201
+f 249/235/202 117/143/202 251/233/202
+f 118/138/203 246/236/203 248/234/203
+f 247/237/204 119/141/204 249/235/204
+f 120/136/205 244/238/205 246/236/205
+f 245/239/206 121/139/206 247/237/206
+f 124/132/207 244/238/207 122/134/207
+f 125/135/208 245/239/208 243/240/208
+f 126/130/209 242/241/209 124/132/209
+f 127/133/210 243/240/210 241/242/210
+f 126/130/211 236/243/211 240/244/211
+f 237/245/212 127/133/212 241/242/212
+f 179/129/213 238/246/213 236/243/213
+f 239/247/214 180/131/214 237/245/214
+f 128/126/215 256/228/215 238/246/215
+f 257/229/216 129/128/216 239/247/216
+f 256/228/217 276/248/217 238/246/217
+f 257/229/218 277/249/218 259/250/218
+f 236/243/219 276/248/219 278/251/219
+f 277/249/220 237/245/220 279/252/220
+f 236/243/221 274/253/221 240/244/221
+f 237/245/222 275/254/222 279/252/222
+f 240/244/223 272/255/223 242/241/223
+f 241/242/224 273/256/224 275/254/224
+f 244/238/225 272/255/225 270/257/225
+f 273/256/226 245/239/226 271/258/226
+f 244/238/227 268/259/227 246/236/227
+f 245/239/228 269/260/228 271/258/228
+f 248/234/229 268/259/229 266/261/229
+f 269/260/230 249/235/230 267/262/230
+f 248/234/231 264/263/231 250/231/231
+f 249/235/232 265/264/232 267/262/232
+f 250/231/233 262/265/233 252/232/233
+f 251/233/234 263/266/234 265/264/234
+f 234/222/235 262/265/235 280/267/235
+f 263/266/236 235/224/236 281/268/236
+f 256/228/237 260/269/237 258/270/237
+f 261/271/238 257/229/238 259/250/238
+f 254/226/239 282/272/239 260/269/239
+f 283/273/240 255/227/240 261/271/240
+f 232/223/241 280/267/241 282/272/241
+f 281/268/242 233/225/242 283/273/242
+f 67/123/243 284/274/243 73/275/243
+f 285/276/244 67/123/244 73/275/244
+f 108/119/245 286/277/245 284/274/245
+f 287/278/246 109/121/246 285/276/246
+f 104/116/247 286/277/247 106/115/247
+f 105/279/248 287/278/248 289/280/248
+f 102/108/249 288/281/249 104/116/249
+f 103/110/250 289/280/250 291/282/250
+f 100/104/251 290/283/251 102/108/251
+f 101/106/252 291/282/252 293/284/252
+f 100/104/253 294/285/253 292/286/253
+f 295/287/254 101/106/254 293/284/254
+f 96/101/255 294/285/255 98/100/255
+f 97/288/256 295/287/256 297/289/256
+f 96/101/257 298/290/257 296/291/257
+f 299/292/258 97/288/258 297/289/258
+f 94/93/259 300/293/259 298/290/259
+f 301/294/260 95/95/260 299/292/260
+f 309/295/261 338/296/261 308/297/261
+f 309/298/262 339/299/262 329/300/262
+f 308/297/263 336/301/263 307/302/263
+f 308/303/264 337/304/264 339/299/264
+f 307/302/265 340/305/265 306/306/265
+f 307/307/266 341/308/266 337/304/266
+f 89/69/267 306/306/267 340/305/267
+f 306/306/268 90/75/268 341/308/268
+f 87/73/269 340/305/269 334/309/269
+f 341/308/270 88/78/270 335/310/270
+f 85/76/271 334/309/271 330/311/271
+f 335/310/272 86/77/272 331/312/272
+f 83/79/273 330/311/273 332/313/273
+f 331/312/274 84/82/274 333/314/274
+f 330/311/275 338/296/275 332/313/275
+f 339/299/276 331/312/276 333/314/276
+f 334/309/277 336/301/277 330/311/277
+f 335/310/278 337/304/278 341/308/278
+f 332/313/279 328/315/279 326/316/279
+f 333/314/280 329/300/280 339/299/280
+f 81/83/281 332/313/281 326/316/281
+f 333/314/282 82/86/282 327/317/282
+f 342/318/283 215/203/283 209/201/283
+f 343/319/284 216/204/284 345/320/284
+f 326/316/285 209/201/285 81/83/285
+f 327/317/286 210/202/286 343/319/286
+f 215/203/287 346/321/287 79/87/287
+f 216/204/288 347/322/288 345/320/288
+f 346/321/289 92/94/289 79/87/289
+f 347/322/290 93/323/290 301/294/290
+f 324/324/291 304/325/291 77/326/291
+f 325/327/292 304/328/292 353/329/292
+f 352/330/293 78/331/293 304/325/293
+f 353/329/294 78/332/294 351/333/294
+f 78/331/295 348/334/295 305/335/295
+f 349/336/296 78/332/296 305/337/296
+f 305/335/297 328/315/297 309/295/297
+f 329/300/298 305/337/298 309/298/298
+f 328/315/299 342/318/299 326/316/299
+f 329/300/300 343/319/300 349/336/300
+f 296/291/301 318/338/301 310/339/301
+f 319/340/302 297/289/302 311/341/302
+f 316/342/303 77/326/303 76/343/303
+f 317/344/304 77/345/304 325/327/304
+f 358/346/305 303/347/305 302/348/305
+f 359/349/306 303/350/306 357/351/306
+f 303/347/307 354/352/307 75/353/307
+f 355/354/308 303/350/308 75/355/308
+f 75/353/309 316/342/309 76/343/309
+f 317/344/310 75/355/310 76/356/310
+f 292/357/311 362/358/311 364/359/311
+f 363/360/312 293/361/312 365/362/312
+f 364/359/313 368/363/313 366/364/313
+f 369/365/314 365/362/314 367/366/314
+f 366/364/315 370/367/315 372/368/315
+f 371/369/316 367/366/316 373/370/316
+f 372/368/317 376/371/317 374/372/317
+f 377/373/318 373/370/318 375/374/318
+f 378/375/319 376/371/319 314/376/319
+f 379/377/320 377/373/320 375/374/320
+f 316/342/321 374/372/321 378/375/321
+f 375/374/322 317/344/322 379/377/322
+f 354/352/323 372/368/323 374/372/323
+f 373/370/324 355/354/324 375/374/324
+f 356/378/325 366/364/325 372/368/325
+f 367/366/326 357/351/326 373/370/326
+f 358/346/327 364/359/327 366/364/327
+f 365/362/328 359/349/328 367/366/328
+f 292/357/329 360/379/329 290/380/329
+f 293/361/330 361/381/330 365/362/330
+f 360/379/331 302/348/331 74/382/331
+f 361/381/332 302/383/332 359/349/332
+f 284/384/333 288/385/333 290/380/333
+f 289/386/334 285/387/334 291/388/334
+f 284/384/335 360/379/335 74/382/335
+f 361/381/336 285/387/336 74/389/336
+f 73/390/337 284/384/337 74/382/337
+f 74/389/338 285/387/338 73/391/338
+f 296/291/339 362/358/339 294/285/339
+f 297/289/340 363/360/340 311/341/340
+f 310/339/341 368/363/341 362/358/341
+f 369/365/342 311/341/342 363/360/342
+f 312/392/343 370/367/343 368/363/343
+f 371/369/344 313/393/344 369/365/344
+f 376/371/345 382/394/345 314/376/345
+f 377/373/346 383/395/346 371/369/346
+f 350/396/347 384/397/347 348/334/347
+f 351/333/348 385/398/348 387/399/348
+f 384/397/349 320/400/349 318/338/349
+f 385/398/350 321/401/350 387/399/350
+f 298/290/351 384/397/351 318/338/351
+f 385/398/352 299/292/352 319/340/352
+f 300/293/353 342/318/353 384/397/353
+f 343/319/354 301/294/354 385/398/354
+f 342/318/355 348/334/355 384/397/355
+f 385/398/356 349/336/356 343/319/356
+f 300/293/357 346/321/357 344/402/357
+f 345/320/358 347/322/358 301/294/358
+f 322/403/359 378/375/359 314/376/359
+f 323/404/360 379/377/360 381/405/360
+f 378/375/361 324/324/361 316/342/361
+f 379/377/362 325/327/362 381/405/362
+f 386/406/363 322/403/363 320/400/363
+f 387/399/364 323/404/364 381/405/364
+f 352/330/365 386/406/365 350/396/365
+f 353/329/366 387/399/366 381/405/366
+f 324/324/367 380/407/367 352/330/367
+f 353/329/368 381/405/368 325/327/368
+f 388/408/369 402/409/369 400/410/369
+f 389/411/370 403/412/370 415/413/370
+f 400/410/371 404/414/371 398/415/371
+f 405/416/372 401/417/372 399/418/372
+f 404/414/373 396/419/373 398/415/373
+f 405/416/374 397/420/374 407/421/374
+f 406/422/375 394/423/375 396/419/375
+f 407/421/376 395/424/376 409/425/376
+f 408/426/377 392/427/377 394/423/377
+f 409/425/378 393/428/378 411/429/378
+f 392/427/379 412/430/379 390/431/379
+f 413/432/380 393/428/380 391/433/380
+f 410/434/381 418/435/381 412/430/381
+f 419/436/382 411/429/382 413/432/382
+f 408/426/383 420/437/383 410/434/383
+f 421/438/384 409/425/384 411/429/384
+f 424/439/385 408/426/385 406/422/385
+f 425/440/386 409/425/386 423/441/386
+f 426/442/387 406/422/387 404/414/387
+f 427/443/388 407/421/388 425/440/388
+f 428/444/389 404/414/389 402/409/389
+f 429/445/390 405/416/390 427/443/390
+f 402/409/391 416/446/391 428/444/391
+f 417/447/392 403/412/392 429/445/392
+f 320/400/393 442/448/393 318/338/393
+f 321/401/394 443/449/394 445/450/394
+f 390/431/395 444/451/395 320/452/395
+f 391/433/396 445/453/396 413/432/396
+f 310/339/397 442/448/397 312/392/397
+f 443/449/398 311/341/398 313/393/398
+f 382/454/399 414/455/399 388/408/399
+f 415/413/400 383/456/400 389/411/400
+f 412/430/401 440/457/401 444/451/401
+f 441/458/402 413/432/402 445/453/402
+f 446/459/403 440/457/403 438/460/403
+f 447/461/404 441/458/404 445/453/404
+f 434/462/135 438/460/135 436/463/135
+f 439/464/135 435/465/135 437/466/135
+f 448/467/405 434/462/405 432/468/405
+f 449/469/406 435/465/406 447/461/406
+f 448/467/407 450/470/407 430/471/407
+f 449/469/408 451/472/408 433/473/408
+f 430/471/409 416/446/409 414/455/409
+f 431/474/410 417/447/410 451/472/410
+f 312/392/411 430/475/411 382/394/411
+f 431/476/412 313/393/412 383/395/412
+f 442/448/413 448/477/413 312/392/413
+f 443/449/414 449/478/414 447/479/414
+f 442/448/415 444/480/415 446/481/415
+f 447/479/416 445/450/416 443/449/416
+f 416/446/417 452/482/417 476/483/417
+f 453/484/418 417/447/418 477/485/418
+f 432/468/419 452/482/419 450/470/419
+f 433/473/420 453/484/420 463/486/420
+f 432/468/421 460/487/421 462/488/421
+f 461/489/422 433/473/422 463/486/422
+f 436/463/423 460/487/423 434/462/423
+f 437/466/424 461/489/424 459/490/424
+f 438/460/425 458/491/425 436/463/425
+f 439/464/426 459/490/426 457/492/426
+f 438/460/427 454/493/427 456/494/427
+f 455/495/428 439/464/428 457/492/428
+f 440/457/429 474/496/429 454/493/429
+f 475/497/429 441/458/429 455/495/429
+f 428/444/430 476/483/430 464/498/430
+f 477/485/431 429/445/431 465/499/431
+f 426/442/432 464/498/432 466/500/432
+f 465/499/433 427/443/433 467/501/433
+f 424/439/434 466/500/434 468/502/434
+f 467/501/435 425/440/435 469/503/435
+f 424/439/436 470/504/436 422/505/436
+f 425/440/437 471/506/437 469/503/437
+f 422/505/438 472/507/438 420/437/438
+f 423/441/439 473/508/439 471/506/439
+f 420/437/440 474/496/440 418/435/440
+f 421/438/441 475/497/441 473/508/441
+f 456/494/442 478/509/442 458/491/442
+f 457/492/443 479/510/443 481/511/443
+f 480/512/444 484/513/444 478/509/444
+f 481/511/445 485/514/445 483/515/445
+f 484/513/446 488/516/446 486/517/446
+f 489/518/447 485/514/447 487/519/447
+f 488/516/448 492/520/448 486/517/448
+f 489/518/449 493/521/449 491/522/449
+f 464/498/450 486/517/450 492/520/450
+f 487/519/451 465/499/451 493/521/451
+f 484/513/452 476/483/452 452/482/452
+f 485/514/453 477/485/453 487/519/453
+f 462/488/454 484/513/454 452/482/454
+f 463/486/455 485/514/455 479/510/455
+f 458/491/135 462/488/135 460/487/135
+f 463/486/135 459/490/135 461/489/135
+f 474/496/456 456/494/456 454/493/456
+f 475/497/457 457/492/457 481/511/457
+f 472/507/458 480/512/458 474/496/458
+f 481/511/459 473/508/459 475/497/459
+f 488/516/460 472/507/460 470/504/460
+f 489/518/461 473/508/461 483/515/461
+f 490/523/462 470/504/462 468/502/462
+f 491/522/463 471/506/463 489/518/463
+f 466/500/464 490/523/464 468/502/464
+f 491/522/465 467/501/465 469/503/465
+f 464/498/466 492/520/466 466/500/466
+f 467/501/467 493/521/467 465/499/467
+f 392/427/468 504/524/468 502/525/468
+f 505/526/469 393/428/469 503/527/469
+f 394/423/470 502/525/470 500/528/470
+f 503/527/471 395/424/471 501/529/471
+f 394/423/472 498/530/472 396/419/472
+f 395/424/473 499/531/473 501/529/473
+f 396/419/474 496/532/474 398/533/474
+f 397/420/475 497/534/475 499/531/475
+f 398/533/476 494/535/476 400/536/476
+f 399/537/477 495/538/477 497/534/477
+f 400/536/478 506/539/478 388/540/478
+f 401/541/479 507/542/479 495/538/479
+f 502/525/480 506/539/480 494/535/480
+f 503/527/481 507/542/481 505/526/481
+f 494/535/482 500/528/482 502/525/482
+f 501/529/483 495/538/483 503/527/483
+f 496/532/484 498/530/484 500/528/484
+f 501/529/485 499/531/485 497/534/485
+f 382/394/486 506/543/486 314/376/486
+f 383/544/487 507/542/487 389/545/487
+f 314/546/488 504/524/488 322/547/488
+f 505/526/489 315/548/489 323/549/489
+f 320/452/490 504/524/490 390/431/490
+f 505/526/491 321/550/491 391/433/491
+f 47/1/492 1/13/492 3/2/492
+f 4/4/493 2/16/493 48/5/493
+f 45/3/494 3/2/494 5/7/494
+f 6/9/495 4/4/495 46/6/495
+f 3/2/496 9/14/496 7/11/496
+f 8/12/497 10/15/497 4/4/497
+f 1/13/498 11/17/498 9/14/498
+f 10/15/499 12/20/499 2/16/499
+f 11/17/500 13/26/500 15/18/500
+f 16/19/501 14/27/501 12/20/501
+f 9/14/502 15/18/502 17/21/502
+f 18/22/503 16/19/503 10/15/503
+f 21/23/504 19/32/504 17/21/504
+f 22/24/505 16/19/505 18/22/505
+f 13/26/506 23/28/506 21/23/506
+f 22/24/507 24/31/507 14/27/507
+f 23/28/508 25/39/508 27/29/508
+f 28/30/509 26/54/509 24/31/509
+f 27/29/510 29/35/510 19/32/510
+f 28/30/511 22/24/511 20/25/511
+f 33/34/512 31/45/512 29/35/512
+f 34/36/513 28/30/513 30/33/513
+f 35/38/514 33/34/514 27/29/514
+f 36/40/515 26/54/515 28/30/515
+f 37/41/516 39/44/516 33/34/516
+f 38/42/517 36/40/517 34/36/517
+f 39/44/518 41/47/518 31/45/518
+f 40/43/519 34/36/519 32/37/519
+f 45/3/520 43/8/520 41/47/520
+f 46/6/521 40/43/521 42/46/521
+f 47/1/522 45/3/522 39/44/522
+f 48/5/523 38/42/523 40/43/523
+f 37/41/524 51/51/524 49/48/524
+f 38/42/525 48/5/525 50/49/525
+f 35/38/526 53/53/526 51/51/526
+f 36/40/527 38/42/527 52/50/527
+f 25/39/528 55/56/528 53/53/528
+f 26/54/529 36/40/529 54/52/529
+f 23/28/530 57/59/530 55/56/530
+f 24/31/531 26/54/531 56/55/531
+f 23/28/532 13/26/532 59/58/532
+f 60/60/533 14/27/533 24/31/533
+f 13/26/534 11/17/534 63/61/534
+f 64/62/535 12/20/535 14/27/535
+f 11/17/536 1/13/536 65/63/536
+f 66/64/537 2/16/537 12/20/537
+f 1/13/538 47/1/538 49/48/538
+f 50/49/539 48/5/539 2/16/539
+f 174/67/540 176/71/540 91/68/540
+f 175/70/541 90/75/541 91/68/541
+f 172/72/542 174/67/542 89/69/542
+f 173/74/543 88/78/543 90/75/543
+f 85/76/544 170/80/544 172/72/544
+f 173/74/545 171/81/545 86/77/545
+f 83/79/546 168/84/546 170/80/546
+f 171/81/547 169/85/547 84/82/547
+f 81/83/548 166/158/548 168/84/548
+f 169/85/549 167/161/549 82/86/549
+f 79/87/550 92/94/550 146/88/550
+f 147/90/551 93/323/551 80/91/551
+f 94/93/552 148/98/552 146/88/552
+f 95/95/553 93/323/553 147/90/553
+f 94/93/554 96/101/554 150/97/554
+f 151/99/555 97/288/555 95/95/555
+f 98/100/556 152/105/556 150/97/556
+f 99/102/557 97/288/557 151/99/557
+f 100/104/558 154/109/558 152/105/558
+f 101/106/559 99/102/559 153/103/559
+f 102/108/560 156/113/560 154/109/560
+f 103/110/561 101/106/561 155/107/561
+f 102/108/562 104/116/562 158/112/562
+f 159/114/563 105/279/563 103/110/563
+f 106/115/564 160/120/564 158/112/564
+f 107/117/565 105/279/565 159/114/565
+f 108/119/566 162/124/566 160/120/566
+f 109/121/567 107/117/567 161/118/567
+f 67/123/568 68/125/568 162/124/568
+f 67/123/569 109/121/569 163/122/569
+f 128/126/570 160/120/570 162/124/570
+f 129/128/571 111/551/571 163/122/571
+f 128/126/572 179/129/572 158/112/572
+f 159/114/573 180/131/573 129/128/573
+f 156/113/574 158/112/574 179/129/574
+f 157/111/575 127/133/575 180/131/575
+f 154/109/576 156/113/576 126/130/576
+f 155/107/577 125/135/577 127/133/577
+f 152/105/578 154/109/578 124/132/578
+f 153/103/579 123/137/579 125/135/579
+f 150/97/580 152/105/580 122/134/580
+f 151/99/581 121/139/581 123/137/581
+f 148/98/582 150/97/582 120/136/582
+f 149/96/583 119/141/583 121/139/583
+f 146/88/584 148/98/584 118/138/584
+f 147/90/585 117/143/585 119/141/585
+f 164/89/586 146/88/586 116/140/586
+f 165/92/587 115/145/587 117/143/587
+f 114/142/588 181/151/588 177/144/588
+f 177/144/589 182/152/589 115/145/589
+f 162/124/590 68/125/590 112/146/590
+f 163/122/591 111/551/591 113/147/591
+f 112/146/592 68/125/592 178/148/592
+f 178/148/593 68/125/593 113/147/593
+f 181/151/594 183/149/594 178/148/594
+f 182/152/595 177/144/595 178/148/595
+f 135/153/596 137/212/596 176/71/596
+f 176/71/597 137/212/597 136/154/597
+f 133/155/598 135/153/598 174/67/598
+f 175/70/599 136/154/599 134/156/599
+f 133/155/600 172/72/600 170/80/600
+f 134/156/601 132/162/601 171/81/601
+f 166/158/602 187/164/602 185/159/602
+f 186/160/603 188/166/603 167/161/603
+f 131/157/604 170/80/604 168/84/604
+f 169/85/605 171/81/605 132/162/605
+f 190/163/132 189/167/132 187/164/132
+f 190/163/606 145/174/606 188/166/606
+f 187/164/134 189/167/134 69/168/134
+f 188/166/607 186/160/607 69/168/607
+f 131/157/135 185/159/135 69/168/135
+f 132/162/135 130/169/135 69/168/135
+f 142/170/608 193/176/608 191/171/608
+f 192/172/609 194/177/609 143/173/609
+f 140/175/610 195/191/610 193/176/610
+f 194/177/611 196/182/611 141/178/611
+f 197/179/612 195/191/612 140/175/612
+f 198/181/613 139/180/613 141/178/613
+f 71/183/614 197/179/614 139/180/614
+f 71/183/184 138/184/184 139/180/184
+f 144/165/615 191/171/615 70/185/615
+f 145/174/616 190/163/616 70/185/616
+f 191/171/146 206/194/146 208/186/146
+f 192/172/147 70/185/147 208/186/147
+f 71/183/617 199/196/617 200/188/617
+f 201/189/618 199/196/618 71/183/618
+f 197/179/619 200/188/619 202/190/619
+f 203/192/620 201/189/620 198/181/620
+f 202/190/621 204/195/621 193/176/621
+f 203/192/622 196/182/622 194/177/622
+f 193/176/623 204/195/623 206/194/623
+f 207/187/624 205/193/624 194/177/624
+f 204/195/625 202/190/625 200/188/625
+f 205/193/626 199/196/626 201/189/626
+f 199/196/627 208/186/627 206/194/627
+f 207/187/628 208/186/628 199/196/628
+f 139/180/629 140/175/629 164/89/629
+f 165/92/630 141/178/630 139/180/630
+f 140/175/631 142/170/631 211/197/631
+f 212/198/632 143/173/632 141/178/632
+f 144/165/633 213/200/633 211/197/633
+f 145/174/634 143/173/634 212/198/634
+f 187/164/635 166/158/635 213/200/635
+f 188/166/636 145/174/636 214/199/636
+f 209/201/637 213/200/637 166/158/637
+f 210/202/638 82/86/638 167/161/638
+f 215/203/639 211/197/639 213/200/639
+f 216/204/640 210/202/640 214/199/640
+f 79/87/641 164/89/641 211/197/641
+f 212/198/642 165/92/642 80/91/642
+f 130/169/643 72/207/643 222/205/643
+f 130/169/644 132/162/644 223/206/644
+f 133/155/645 131/157/645 222/205/645
+f 223/206/646 132/162/646 134/156/646
+f 135/153/647 133/155/647 220/208/647
+f 221/209/648 134/156/648 136/154/648
+f 137/212/649 135/153/649 218/210/649
+f 219/211/650 136/154/650 137/212/650
+f 218/210/180 229/217/180 231/214/180
+f 219/211/181 217/213/181 231/214/181
+f 218/210/651 220/208/651 227/216/651
+f 228/218/652 221/209/652 219/211/652
+f 220/208/142 222/205/142 225/219/142
+f 226/220/184 223/206/184 221/209/184
+f 72/207/185 224/221/185 225/219/185
+f 72/207/186 223/206/186 226/220/186
+f 224/221/653 231/214/653 229/217/653
+f 230/215/654 231/214/654 224/221/654
+f 183/149/655 181/151/655 234/222/655
+f 235/224/656 182/152/656 184/150/656
+f 112/146/657 183/149/657 232/223/657
+f 233/225/658 184/150/658 113/147/658
+f 112/146/659 254/226/659 256/228/659
+f 113/147/660 111/551/660 257/229/660
+f 114/142/661 252/232/661 234/222/661
+f 115/145/662 182/152/662 235/224/662
+f 114/142/663 116/140/663 250/231/663
+f 251/233/664 117/143/664 115/145/664
+f 116/140/665 118/138/665 248/234/665
+f 249/235/666 119/141/666 117/143/666
+f 118/138/667 120/136/667 246/236/667
+f 247/237/668 121/139/668 119/141/668
+f 120/136/669 122/134/669 244/238/669
+f 245/239/670 123/137/670 121/139/670
+f 124/132/671 242/241/671 244/238/671
+f 125/135/672 123/137/672 245/239/672
+f 126/130/673 240/244/673 242/241/673
+f 127/133/674 125/135/674 243/240/674
+f 126/130/675 179/129/675 236/243/675
+f 237/245/676 180/131/676 127/133/676
+f 179/129/677 128/126/677 238/246/677
+f 239/247/678 129/128/678 180/131/678
+f 128/126/679 110/127/679 256/228/679
+f 257/229/680 111/551/680 129/128/680
+f 256/228/681 258/270/681 276/248/681
+f 257/229/682 239/247/682 277/249/682
+f 236/243/683 238/246/683 276/248/683
+f 277/249/684 239/247/684 237/245/684
+f 236/243/685 278/251/685 274/253/685
+f 237/245/686 241/242/686 275/254/686
+f 240/244/687 274/253/687 272/255/687
+f 241/242/688 243/240/688 273/256/688
+f 244/238/689 242/241/689 272/255/689
+f 273/256/690 243/240/690 245/239/690
+f 244/238/691 270/257/691 268/259/691
+f 245/239/692 247/237/692 269/260/692
+f 248/234/693 246/236/693 268/259/693
+f 269/260/694 247/237/694 249/235/694
+f 248/234/695 266/261/695 264/263/695
+f 249/235/696 251/233/696 265/264/696
+f 250/231/697 264/263/697 262/265/697
+f 251/233/698 253/230/698 263/266/698
+f 234/222/235 252/232/235 262/265/235
+f 263/266/236 253/230/236 235/224/236
+f 256/228/699 254/226/699 260/269/699
+f 261/271/700 255/227/700 257/229/700
+f 254/226/701 232/223/701 282/272/701
+f 283/273/702 233/225/702 255/227/702
+f 232/223/703 234/222/703 280/267/703
+f 281/268/704 235/224/704 233/225/704
+f 67/123/705 108/119/705 284/274/705
+f 285/276/706 109/121/706 67/123/706
+f 108/119/707 106/115/707 286/277/707
+f 287/278/708 107/117/708 109/121/708
+f 104/116/709 288/281/709 286/277/709
+f 105/279/710 107/117/710 287/278/710
+f 102/108/711 290/283/711 288/281/711
+f 103/110/712 105/279/712 289/280/712
+f 100/104/713 292/286/713 290/283/713
+f 101/106/714 103/110/714 291/282/714
+f 100/104/715 98/100/715 294/285/715
+f 295/287/716 99/102/716 101/106/716
+f 96/101/717 296/291/717 294/285/717
+f 97/288/718 99/102/718 295/287/718
+f 96/101/719 94/93/719 298/290/719
+f 299/292/720 95/95/720 97/288/720
+f 94/93/721 92/94/721 300/293/721
+f 301/294/722 93/323/722 95/95/722
+f 309/295/723 328/315/723 338/296/723
+f 309/298/724 308/303/724 339/299/724
+f 308/297/725 338/296/725 336/301/725
+f 308/303/726 307/307/726 337/304/726
+f 307/302/727 336/301/727 340/305/727
+f 307/307/728 306/306/728 341/308/728
+f 89/69/729 91/68/729 306/306/729
+f 306/306/730 91/68/730 90/75/730
+f 87/73/731 89/69/731 340/305/731
+f 341/308/732 90/75/732 88/78/732
+f 85/76/733 87/73/733 334/309/733
+f 335/310/734 88/78/734 86/77/734
+f 83/79/735 85/76/735 330/311/735
+f 331/312/736 86/77/736 84/82/736
+f 330/311/737 336/301/737 338/296/737
+f 339/299/738 337/304/738 331/312/738
+f 334/309/739 340/305/739 336/301/739
+f 335/310/740 331/312/740 337/304/740
+f 332/313/741 338/296/741 328/315/741
+f 333/314/742 327/317/742 329/300/742
+f 81/83/743 83/79/743 332/313/743
+f 333/314/744 84/82/744 82/86/744
+f 342/318/745 344/402/745 215/203/745
+f 343/319/746 210/202/746 216/204/746
+f 326/316/747 342/318/747 209/201/747
+f 327/317/748 82/86/748 210/202/748
+f 215/203/749 344/402/749 346/321/749
+f 216/204/750 80/91/750 347/322/750
+f 346/321/751 300/293/751 92/94/751
+f 347/322/752 80/91/752 93/323/752
+f 324/324/753 352/330/753 304/325/753
+f 325/327/754 77/345/754 304/328/754
+f 352/330/755 350/396/755 78/331/755
+f 353/329/756 304/328/756 78/332/756
+f 78/331/757 350/396/757 348/334/757
+f 349/336/758 351/333/758 78/332/758
+f 305/335/759 348/334/759 328/315/759
+f 329/300/760 349/336/760 305/337/760
+f 328/315/761 348/334/761 342/318/761
+f 329/300/762 327/317/762 343/319/762
+f 296/291/763 298/290/763 318/338/763
+f 319/340/764 299/292/764 297/289/764
+f 316/342/765 324/324/765 77/326/765
+f 317/344/766 76/356/766 77/345/766
+f 358/346/767 356/378/767 303/347/767
+f 359/349/768 302/383/768 303/350/768
+f 303/347/769 356/378/769 354/352/769
+f 355/354/770 357/351/770 303/350/770
+f 75/353/771 354/352/771 316/342/771
+f 317/344/772 355/354/772 75/355/772
+f 292/357/773 294/285/773 362/358/773
+f 363/360/774 295/287/774 293/361/774
+f 364/359/775 362/358/775 368/363/775
+f 369/365/776 363/360/776 365/362/776
+f 366/364/777 368/363/777 370/367/777
+f 371/369/778 369/365/778 367/366/778
+f 372/368/779 370/367/779 376/371/779
+f 377/373/780 371/369/780 373/370/780
+f 378/375/781 374/372/781 376/371/781
+f 379/377/782 315/552/782 377/373/782
+f 316/342/783 354/352/783 374/372/783
+f 375/374/784 355/354/784 317/344/784
+f 354/352/785 356/378/785 372/368/785
+f 373/370/786 357/351/786 355/354/786
+f 356/378/787 358/346/787 366/364/787
+f 367/366/788 359/349/788 357/351/788
+f 358/346/789 360/379/789 364/359/789
+f 365/362/790 361/381/790 359/349/790
+f 292/357/791 364/359/791 360/379/791
+f 293/361/792 291/388/792 361/381/792
+f 360/379/793 358/346/793 302/348/793
+f 361/381/794 74/389/794 302/383/794
+f 284/384/795 286/553/795 288/385/795
+f 289/386/796 287/554/796 285/387/796
+f 284/384/797 290/380/797 360/379/797
+f 361/381/798 291/388/798 285/387/798
+f 296/291/799 310/339/799 362/358/799
+f 297/289/800 295/287/800 363/360/800
+f 310/339/801 312/392/801 368/363/801
+f 369/365/802 313/393/802 311/341/802
+f 312/392/803 382/394/803 370/367/803
+f 371/369/804 383/395/804 313/393/804
+f 376/371/805 370/367/805 382/394/805
+f 377/373/806 315/552/806 383/395/806
+f 350/396/807 386/406/807 384/397/807
+f 351/333/808 349/336/808 385/398/808
+f 384/397/809 386/406/809 320/400/809
+f 385/398/810 319/340/810 321/401/810
+f 298/290/811 300/293/811 384/397/811
+f 385/398/812 301/294/812 299/292/812
+f 300/293/813 344/402/813 342/318/813
+f 343/319/814 345/320/814 301/294/814
+f 322/403/815 380/407/815 378/375/815
+f 323/404/816 315/552/816 379/377/816
+f 378/375/817 380/407/817 324/324/817
+f 379/377/818 317/344/818 325/327/818
+f 386/406/819 380/407/819 322/403/819
+f 387/399/820 321/401/820 323/404/820
+f 352/330/821 380/407/821 386/406/821
+f 353/329/822 351/333/822 387/399/822
+f 388/408/823 414/455/823 402/409/823
+f 389/411/824 401/417/824 403/412/824
+f 400/410/825 402/409/825 404/414/825
+f 405/416/826 403/412/826 401/417/826
+f 404/414/827 406/422/827 396/419/827
+f 405/416/828 399/418/828 397/420/828
+f 406/422/829 408/426/829 394/423/829
+f 407/421/830 397/420/830 395/424/830
+f 408/426/831 410/434/831 392/427/831
+f 409/425/832 395/424/832 393/428/832
+f 392/427/833 410/434/833 412/430/833
+f 413/432/834 411/429/834 393/428/834
+f 410/434/835 420/437/835 418/435/835
+f 419/436/836 421/438/836 411/429/836
+f 408/426/837 422/505/837 420/437/837
+f 421/438/838 423/441/838 409/425/838
+f 424/439/839 422/505/839 408/426/839
+f 425/440/840 407/421/840 409/425/840
+f 426/442/841 424/439/841 406/422/841
+f 427/443/842 405/416/842 407/421/842
+f 428/444/843 426/442/843 404/414/843
+f 429/445/844 403/412/844 405/416/844
+f 402/409/845 414/455/845 416/446/845
+f 417/447/846 415/413/846 403/412/846
+f 320/400/847 444/480/847 442/448/847
+f 321/401/848 319/340/848 443/449/848
+f 390/431/849 412/430/849 444/451/849
+f 391/433/850 321/550/850 445/453/850
+f 310/339/851 318/338/851 442/448/851
+f 443/449/852 319/340/852 311/341/852
+f 382/454/853 430/471/853 414/455/853
+f 415/413/854 431/474/854 383/456/854
+f 412/430/855 418/435/855 440/457/855
+f 441/458/856 419/436/856 413/432/856
+f 446/459/857 444/451/857 440/457/857
+f 447/461/858 439/464/858 441/458/858
+f 434/462/859 446/459/859 438/460/859
+f 439/464/860 447/461/860 435/465/860
+f 448/467/861 446/459/861 434/462/861
+f 449/469/862 433/473/862 435/465/862
+f 448/467/863 432/468/863 450/470/863
+f 449/469/864 431/474/864 451/472/864
+f 430/471/865 450/470/865 416/446/865
+f 431/474/866 415/413/866 417/447/866
+f 312/392/867 448/477/867 430/475/867
+f 431/476/868 449/478/868 313/393/868
+f 442/448/869 446/481/869 448/477/869
+f 443/449/870 313/393/870 449/478/870
+f 416/446/871 450/470/871 452/482/871
+f 453/484/872 451/472/872 417/447/872
+f 432/468/873 462/488/873 452/482/873
+f 433/473/874 451/472/874 453/484/874
+f 432/468/421 434/462/421 460/487/421
+f 461/489/422 435/465/422 433/473/422
+f 436/463/875 458/491/875 460/487/875
+f 437/466/876 435/465/876 461/489/876
+f 438/460/877 456/494/877 458/491/877
+f 439/464/878 437/466/878 459/490/878
+f 438/460/879 440/457/879 454/493/879
+f 455/495/880 441/458/880 439/464/880
+f 440/457/881 418/435/881 474/496/881
+f 475/497/882 419/436/882 441/458/882
+f 428/444/883 416/446/883 476/483/883
+f 477/485/884 417/447/884 429/445/884
+f 426/442/885 428/444/885 464/498/885
+f 465/499/886 429/445/886 427/443/886
+f 424/439/887 426/442/887 466/500/887
+f 467/501/888 427/443/888 425/440/888
+f 424/439/889 468/502/889 470/504/889
+f 425/440/890 423/441/890 471/506/890
+f 422/505/891 470/504/891 472/507/891
+f 423/441/892 421/438/892 473/508/892
+f 420/437/893 472/507/893 474/496/893
+f 421/438/894 419/436/894 475/497/894
+f 456/494/895 480/512/895 478/509/895
+f 457/492/896 459/490/896 479/510/896
+f 480/512/897 482/555/897 484/513/897
+f 481/511/898 479/510/898 485/514/898
+f 484/513/899 482/555/899 488/516/899
+f 489/518/900 483/515/900 485/514/900
+f 488/516/901 490/523/901 492/520/901
+f 489/518/902 487/519/902 493/521/902
+f 464/498/903 476/483/903 486/517/903
+f 487/519/904 477/485/904 465/499/904
+f 484/513/905 486/517/905 476/483/905
+f 485/514/906 453/484/906 477/485/906
+f 462/488/907 478/509/907 484/513/907
+f 463/486/908 453/484/908 485/514/908
+f 458/491/909 478/509/909 462/488/909
+f 463/486/910 479/510/910 459/490/910
+f 474/496/911 480/512/911 456/494/911
+f 475/497/912 455/495/912 457/492/912
+f 472/507/913 482/555/913 480/512/913
+f 481/511/914 483/515/914 473/508/914
+f 488/516/915 482/555/915 472/507/915
+f 489/518/916 471/506/916 473/508/916
+f 490/523/917 488/516/917 470/504/917
+f 491/522/918 469/503/918 471/506/918
+f 466/500/919 492/520/919 490/523/919
+f 491/522/920 493/521/920 467/501/920
+f 392/427/921 390/431/921 504/524/921
+f 505/526/922 391/433/922 393/428/922
+f 394/423/923 392/427/923 502/525/923
+f 503/527/924 393/428/924 395/424/924
+f 394/423/925 500/528/925 498/530/925
+f 395/424/926 397/420/926 499/531/926
+f 396/419/927 498/530/927 496/532/927
+f 397/420/928 399/537/928 497/534/928
+f 398/533/929 496/532/929 494/535/929
+f 399/537/930 401/541/930 495/538/930
+f 400/536/931 494/535/931 506/539/931
+f 401/541/932 389/545/932 507/542/932
+f 502/525/933 504/524/933 506/539/933
+f 503/527/934 495/538/934 507/542/934
+f 494/535/935 496/532/935 500/528/935
+f 501/529/936 497/534/936 495/538/936
+f 382/394/937 388/556/937 506/543/937
+f 383/544/938 315/548/938 507/542/938
+f 314/546/939 506/539/939 504/524/939
+f 505/526/940 507/542/940 315/548/940
+f 320/452/941 322/547/941 504/524/941
+f 505/526/942 323/549/942 321/550/942
diff --git a/examples/studio3d/dynamicelement/dynamicelement.pro b/examples/studio3d/dynamicelement/dynamicelement.pro
new file mode 100644
index 0000000..1b804fd
--- /dev/null
+++ b/examples/studio3d/dynamicelement/dynamicelement.pro
@@ -0,0 +1,15 @@
+TEMPLATE = app
+
+QT += qml quick studio3d
+
+SOURCES += \
+ demo.cpp \
+ main.cpp
+
+HEADERS += \
+ demo.h
+
+RESOURCES += dynamicelement.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/studio3d/$$TARGET
+INSTALLS += target
diff --git a/examples/studio3d/dynamicelement/dynamicelement.qrc b/examples/studio3d/dynamicelement/dynamicelement.qrc
new file mode 100644
index 0000000..81c135b
--- /dev/null
+++ b/examples/studio3d/dynamicelement/dynamicelement.qrc
@@ -0,0 +1,14 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>presentation/presentations/presentation.uip</file>
+ <file>presentation/presentation.uia</file>
+ <file>presentation/maps/materials/shadow.png</file>
+ <file>presentation/maps/materials/spherical_checker.png</file>
+ <file>demo.mtl</file>
+ <file>demo.obj</file>
+ <file>presentation/materials/Red.materialdef</file>
+ <file>presentation/materials/Copper.materialdef</file>
+ <file>presentation/materials/copper.shader</file>
+ </qresource>
+</RCC>
diff --git a/examples/studio3d/dynamicelement/main.cpp b/examples/studio3d/dynamicelement/main.cpp
new file mode 100644
index 0000000..aa272a6
--- /dev/null
+++ b/examples/studio3d/dynamicelement/main.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QtQuick/QQuickView>
+#include <QtQuick/qquickitem.h>
+#include <QtQml/qqmlcontext.h>
+#include <qstudio3dglobal.h>
+#include "demo.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
+ QGuiApplication app(argc, argv);
+
+ QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat());
+
+ QQuickView viewer;
+ viewer.setSource(QStringLiteral("qrc:/main.qml"));
+
+ std::function<Q3DSPresentation *(QObject *obj)> findPresentation;
+ findPresentation = [&](QObject *obj) -> Q3DSPresentation * {
+ Q3DSPresentation *presentation = nullptr;
+ const auto children = obj->children();
+ for (auto &child : children) {
+ presentation = qobject_cast<Q3DSPresentation *>(child);
+ if (!presentation)
+ presentation = findPresentation(child);
+ if (presentation)
+ break;
+ }
+ return presentation;
+ };
+
+ Demo demo(findPresentation(viewer.rootObject()));
+ viewer.rootContext()->setContextProperty(QStringLiteral("_demo"), &demo);
+
+ viewer.setTitle(QStringLiteral("Dynamic Element Creation Example"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.resize(1280, 720);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/studio3d/dynamicelement/main.qml b/examples/studio3d/dynamicelement/main.qml
new file mode 100644
index 0000000..7fb8e2f
--- /dev/null
+++ b/examples/studio3d/dynamicelement/main.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Window 2.12
+import QtStudio3D.OpenGL 2.4
+import QtQuick.Dialogs 1.3
+
+Rectangle {
+ id: root
+
+ Studio3D {
+ id: s3d
+ anchors.fill: parent
+
+ Presentation {
+ id: s3dpres
+ source: "qrc:/presentation/presentation.uia"
+ }
+
+ ViewerSettings {
+ scaleMode: ViewerSettings.ScaleModeFill;
+ }
+
+ onPresentationReady: {
+ _demo.setup();
+ }
+
+ onFrameUpdate: {
+ _demo.animate();
+ }
+ }
+}
diff --git a/examples/studio3d/dynamicelement/presentation/maps/materials/shadow.png b/examples/studio3d/dynamicelement/presentation/maps/materials/shadow.png
new file mode 100644
index 0000000..599b1cc
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/maps/materials/shadow.png
Binary files differ
diff --git a/examples/studio3d/dynamicelement/presentation/maps/materials/spherical_checker.png b/examples/studio3d/dynamicelement/presentation/maps/materials/spherical_checker.png
new file mode 100644
index 0000000..e42394d
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/maps/materials/spherical_checker.png
Binary files differ
diff --git a/examples/studio3d/dynamicelement/presentation/materials/Copper.materialdef b/examples/studio3d/dynamicelement/presentation/materials/Copper.materialdef
new file mode 100644
index 0000000..b1866f7
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/materials/Copper.materialdef
@@ -0,0 +1,14 @@
+<MaterialData version="1.0">
+ <Property name="uEnvironmentTexture" type="Texture"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="uEnvironmentMappingEnabled">True</Property>
+ <Property name="uBakedShadowTexture" type="Texture"><![CDATA[./maps/materials/shadow.png]]></Property>
+ <Property name="uShadowMappingEnabled">False</Property>
+ <Property name="roughness">0</Property>
+ <Property name="metal_color">0.805 0.395 0.305 1</Property>
+ <Property name="sourcepath"><![CDATA[./materials/copper.shader]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="name"><![CDATA[materials/Copper]]></Property>
+ <Property name="type">CustomMaterial</Property>
+ <Property name="path"><![CDATA[/home/jakarppi/Work/ogl-runtime/examples/studio3d/dynamicelement/presentation/materials/Copper.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/examples/studio3d/dynamicelement/presentation/materials/Red.materialdef b/examples/studio3d/dynamicelement/presentation/materials/Red.materialdef
new file mode 100644
index 0000000..f93488b
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/materials/Red.materialdef
@@ -0,0 +1,25 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">1 0 0 1</Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="name"><![CDATA[materials/Red]]></Property>
+ <Property name="type">Material</Property>
+ <Property name="path"><![CDATA[/home/jakarppi/Work/ogl-runtime/examples/studio3d/dynamicelement/presentation/materials/Red.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/examples/studio3d/dynamicelement/presentation/materials/copper.shader b/examples/studio3d/dynamicelement/presentation/materials/copper.shader
new file mode 100644
index 0000000..cf9e1ad
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/materials/copper.shader
@@ -0,0 +1,178 @@
+<Material name="copper" version="1.0">
+ <MetaData >
+ <Property formalName="Environment Map" name="uEnvironmentTexture" description="Environment texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="environment" default="./maps/materials/spherical_checker.png" category="Material"/>
+ <Property formalName="Enable Environment" name="uEnvironmentMappingEnabled" description="Enable environment mapping" type="Boolean" default="True" category="Material"/>
+ <Property formalName="Baked Shadow Map" name="uBakedShadowTexture" description="Baked shadow texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="shadow" default="./maps/materials/shadow.png" category="Material"/>
+ <Property formalName="Shadow Mapping" name="uShadowMappingEnabled" description="Enable shadow mapping" type="Boolean" default="False" category="Material"/>
+ <Property formalName="Roughness" name="roughness" type="Float" min="0.000000" max="1.000000" default="0.000000" description="Roughness of the material.\n0 = fully specular\n1 = fully diffuse" category="Material"/>
+ <Property formalName="Metal Color" name="metal_color" type="Color" default="0.805 0.395 0.305" description="Color of the material" category="Material"/>
+ </MetaData>
+ <Shaders type="GLSL" version="330">
+ <Shader>
+ <Shared> </Shared>
+<VertexShader>
+ </VertexShader>
+ <FragmentShader>
+
+// add enum defines
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QT3DS_ENABLE_UV0 1
+#define QT3DS_ENABLE_WORLD_POSITION 1
+#define QT3DS_ENABLE_TEXTAN 1
+#define QT3DS_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+ vec4 base;
+ vec4 layer;
+ mat3 tanFrame;
+};
+
+
+// temporary declarations
+ vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "luminance.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "fresnelLayer.glsllib"
+
+bool evalTwoSided()
+{
+ return( false );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+ return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, roughness, roughness, scatter_reflect );
+
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, roughness, roughness );
+
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QT3DS_ENABLE_LIGHT_PROBE
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, roughness, roughness, scatter_reflect );
+
+#else
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, roughness, roughness );
+
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+ return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QT3DS_ENABLE_LIGHT_PROBE
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+ return( false ? 1.0 : luminance( vec3( 1, 1, 1 ) ) );
+}
+
+float evalCutout()
+{
+ return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+ return( normal );
+}
+
+void computeTemporaries()
+{
+ tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+ vec4 color;
+ color = fresnelLayer( normal, vec3( 25.65, 25.65, 25.65 ), 1.000000, metal_color.rgb, layers[0].layer, layers[0].base, alpha );
+ return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+ // clear layers
+ layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+ layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+ layers[0].tanFrame = orthoNormalize( mat3( tangent, cross(normal, tangent), normal ) );
+}
+
+ </FragmentShader>
+ </Shader>
+ </Shaders>
+<Passes >
+ <ShaderKey value="4"/>
+ <LayerKey count="1"/>
+ <Pass >
+ </Pass>
+</Passes>
+</Material>
diff --git a/examples/studio3d/dynamicelement/presentation/presentation.uia b/examples/studio3d/dynamicelement/presentation/presentation.uia
new file mode 100644
index 0000000..fa976db
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/presentation.uia
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8'?>
+<application xmlns="http://qt.io/qt3dstudio/uia">
+ <assets initial="presentation">
+ <presentation id="presentation" src="presentations/presentation.uip"/>
+ </assets>
+</application>
diff --git a/examples/studio3d/dynamicelement/presentation/presentations/presentation.uip b/examples/studio3d/dynamicelement/presentation/presentations/presentation.uip
new file mode 100644
index 0000000..cb1bd1e
--- /dev/null
+++ b/examples/studio3d/dynamicelement/presentation/presentations/presentation.uip
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="6" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="1920" presentationHeight="1080" maintainAspect="False" preferKtx="False" >
+ <CustomColors count="16" >#ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
+ </ProjectSettings>
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" variants="" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" position="0 0 -600" />
+ <State id="Scene-Slide1" name="Slide1" />
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/examples/studio3d/qmldatainput/qml/qmldatainput/main.qml b/examples/studio3d/qmldatainput/qml/qmldatainput/main.qml
index 8267b01..32963ab 100644
--- a/examples/studio3d/qmldatainput/qml/qmldatainput/main.qml
+++ b/examples/studio3d/qmldatainput/qml/qmldatainput/main.qml
@@ -94,7 +94,7 @@ Item {
+ (modelData.max !== 0 ? "\n range min: " + modelData.min
+ "\n range max: " + modelData.max
: "")
- + " \n metadata keys: [" + modelData.metadataKeys() + "]"
+ + " \n metadata keys: [" + modelData.metadataKeys + "]"
font.pointSize: 6
}
}
@@ -113,10 +113,6 @@ Item {
property string inputString: ""
property variant inputVariant: 0
- onPresentationLoaded: {
- diList.updateModel();
- }
-
// A changing property to demonstrate DataInput
NumberAnimation {
target: studio3D
@@ -179,6 +175,10 @@ Item {
id: presentation
source: "qrc:/presentation/datainput.uia"
+
+ onDataInputsReady: {
+ diList.updateModel();
+ }
DataInput {
// Name must match the data input name specified in the presentation
name: "rangeInput"
diff --git a/examples/studio3d/simpleqml/main.qml b/examples/studio3d/simpleqml/main.qml
index 06321a7..ed0278e 100644
--- a/examples/studio3d/simpleqml/main.qml
+++ b/examples/studio3d/simpleqml/main.qml
@@ -70,9 +70,13 @@ Rectangle {
anchors.fill: parent
property string textValue: "hello world"
+ ViewerSettings {
+ id: viewerSettings
+ }
+
Presentation {
id: s3dpres
- source: "qrc:/presentation/barrel.uip"
+ source: "qrc:/presentation/barrel.uia"
onCustomSignalEmitted: customSignalName.text = Date.now() + ": " + name
onSlideEntered: slideEnter.text = "Entered slide " + name + "(index " + index + ") on " + elementPath
onSlideExited: slideExit.text = "Exited slide " + name + "(index " + index + ") on " + elementPath
@@ -169,7 +173,11 @@ Rectangle {
}
Button {
text: "Reload"
- onClicked: s3dpres.reload()
+ onClicked: {
+ var src = s3dpres.source
+ s3dpres.source = ""
+ s3dpres.source = src
+ }
focusPolicy: Qt.NoFocus
}
Button {
@@ -185,9 +193,10 @@ Rectangle {
}
Button {
text: "Toggle camera"
+ property bool eyeball: true
onClicked: {
- var v = s3dpres.getAttribute("Scene.Layer.Camera", "eyeball")
- s3dpres.setAttribute("Scene.Layer.Camera", "eyeball", !v)
+ eyeball = !eyeball
+ s3dpres.setAttribute("Scene.Layer.Camera", "eyeball", eyeball)
}
focusPolicy: Qt.NoFocus
}
@@ -258,11 +267,11 @@ Rectangle {
Button {
id: profTogBtn
- text: "Toggle profile UI"
+ text: "Toggle render stats"
anchors.right: parent.right
anchors.bottom: parent.bottom
focusPolicy: Qt.NoFocus
- onClicked: s3dpres.profileUiVisible = !s3dpres.profileUiVisible
+ onClicked: viewerSettings.showRenderStats = !viewerSettings.showRenderStats
}
Slider {
id: profUiScale
diff --git a/examples/studio3d/simpleqml/presentation/barrel.uia b/examples/studio3d/simpleqml/presentation/barrel.uia
index d936e42..209d13a 100644
--- a/examples/studio3d/simpleqml/presentation/barrel.uia
+++ b/examples/studio3d/simpleqml/presentation/barrel.uia
@@ -1,16 +1,16 @@
-<?xml version="1.0" encoding="UTF-8" ?>
+<?xml version='1.0' encoding='UTF-8'?>
<application>
- <assets initial="barrel">
- <dataInput name="di_text" type="String"/>
- <presentation id="barrel" src="barrel.uip"/>
- </assets>
- <statemachine ref="#logic">
- <visual-states>
- <state ref="Initial">
- <enter>
- <goto-slide element="main:Scene" rel="next"/>
- </enter>
- </state>
- </visual-states>
- </statemachine>
+ <assets initial="barrel">
+ <presentation id="barrel" src="barrel.uip"/>
+ <dataInput metadata="" name="di_text" type="String"/>
+ </assets>
+ <statemachine ref="#logic">
+ <visual-states>
+ <state ref="Initial">
+ <enter>
+ <goto-slide rel="next" element="main:Scene"/>
+ </enter>
+ </state>
+ </visual-states>
+ </statemachine>
</application>
diff --git a/examples/studio3d/simpleqml/presentation/barrel.uip b/examples/studio3d/simpleqml/presentation/barrel.uip
index 48b4edc..7b9b2fb 100644
--- a/examples/studio3d/simpleqml/presentation/barrel.uip
+++ b/examples/studio3d/simpleqml/presentation/barrel.uip
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<UIP version="6" >
<Project >
- <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" preferKtx="False" >
<CustomColors count="16" >#ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
</ProjectSettings>
<Graph >
<Scene id="Scene" >
- <Layer id="Layer" >
+ <Layer id="Layer" variants="" >
<Camera id="Camera" />
<Light id="Light" />
- <Model id="Barrel" >
+ <Model id="Barrel" variants="" >
<Material id="Material" >
<Image id="Material_diffusemap" />
<Image id="Material_normalmap" />
@@ -17,8 +17,8 @@
<Image id="Material_specularmap" />
</Material>
</Model>
- <Text id="Text" />
- <Text id="Text2" />
+ <Text id="Text" variants="" />
+ <Text id="Text2" variants="" />
</Layer>
</Scene>
</Graph>
@@ -34,14 +34,14 @@
<AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 5 -302 100 100 10 0 100 100</AnimationTrack>
<AnimationTrack property="rotation.z" type="EaseInOut" >0 0 100 100 5 0 100 100 10 0 100 100</AnimationTrack>
</Add>
- <Add ref="#Material" bumpamount="0" diffuse="1 1 1" diffusemap="#Material_diffusemap" emissivemap="#Material_emissivemap" fresnelPower="25" normalmap="#Material_normalmap" specularamount="4" specularmap="#Material_specularmap" specularmodel="Default" specularroughness="0.001" >
+ <Add ref="#Material" bumpamount="0" diffuse="1 1 1 1" diffusemap="#Material_diffusemap" emissivemap="#Material_emissivemap" fresnelPower="25" normalmap="#Material_normalmap" specularamount="4" specularmap="#Material_specularmap" specularmodel="Default" specularroughness="0.001" >
<AnimationTrack property="bumpamount" type="EaseInOut" >0 0 100 100 5 1 100 100</AnimationTrack>
</Add>
<Add ref="#Material_diffusemap" sourcepath=".\maps\barrel_barrel_Diffuse.png" />
<Add ref="#Material_normalmap" sourcepath=".\maps\barrel_barrel_Normal.png" />
<Add ref="#Material_emissivemap" sourcepath=".\maps\barrel_barrel_Emissive.png" />
<Add ref="#Material_specularmap" sourcepath=".\maps\barrel_barrel_Specular.png" />
- <Add ref="#Text" name="Text" font="Arimo-Regular" position="-486.418 297.128 50.5569" textcolor="0 1 0" textstring="Barrel!" tracking="0" >
+ <Add ref="#Text" name="Text" font="Arimo-Regular" position="-486.418 297.128 50.5569" textcolor="0 1 0 1" textstring="Barrel!" tracking="0" >
<AnimationTrack property="opacity" type="EaseInOut" >0 100 100 100 5.009 43.75 100 100 10 100 100 100</AnimationTrack>
<AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 4.997 0 100 100 5.009 0 100 100 10 0 100 100</AnimationTrack>
<AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 4.997 0 100 100 5.009 0 100 100 10 360 100 100</AnimationTrack>
@@ -50,7 +50,7 @@
<AnimationTrack property="textcolor.y" type="EaseInOut" >0 1 100 100 5.009 0.235294 100 100 10 1 100 100</AnimationTrack>
<AnimationTrack property="textcolor.z" type="EaseInOut" >0 0 100 100 5.009 0.333333 100 100 10 0 100 100</AnimationTrack>
</Add>
- <Add ref="#Text2" name="Text2" controlledproperty="di_text textstring" font="Arimo-Regular" position="435.899 267.025 0" />
+ <Add ref="#Text2" name="Text2" controlledproperty="$di_text textstring" font="Arimo-Regular" position="437.342 256.921 0" />
</State>
</State>
</Logic>
diff --git a/examples/studio3d/studio3d.pro b/examples/studio3d/studio3d.pro
index f51add1..05213bd 100644
--- a/examples/studio3d/studio3d.pro
+++ b/examples/studio3d/studio3d.pro
@@ -5,5 +5,6 @@ SUBDIRS += \
qtHaveModule(quick) {
SUBDIRS += simpleqml \
- qmldatainput
+ qmldatainput \
+ dynamicelement
}
diff --git a/ogl-runtime.pro b/ogl-runtime.pro
index e4bac15..44d9fd6 100644
--- a/ogl-runtime.pro
+++ b/ogl-runtime.pro
@@ -1,32 +1,25 @@
requires(!ios)
-requires(!integrity)
-requires(!qnx)
requires(!tvos)
requires(!watchos)
requires(!winrt)
requires(!wasm)
-ios|integrity|qnx|tvos|watchos|winrt|wasm|*-icc*: {
- message("WARNING, target excluded from ogl-runtime")
+integrity {
+ CHECK_INTEGRITY_DIR = $$(INTEGRITY_DIR)
+}
+
+ios|tvos|watchos|winrt|wasm|*-icc*|contains(CHECK_INTEGRITY_DIR, .*int1144$) {
+ message("WARNING, target not supported by ogl-runtime")
#Exclude non-working cross-compile targets, see:
- # QT3DS-3645 ogl-runtime doesn't compile on INTEGRITY_11_04 in CI
# QT3DS-3647 ogl-runtime doesn't compile on TvOS_ANY in CI
# QT3DS-3648 ogl-runtime doesn't compile on WatchOS_ANY in CI
# QT3DS-3646 ogl-runtime doesn't compile on IOS_ANY in CI
# QT3DS-3649 ogl-runtime doesn't compile on WinRT in CI
# QT3DS-3650 ogl-runtime doesn't compile on WebAssembly in CI
- # QT3DS-3652 ogl-runtime doesn't compile on QNX in CI
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS += src_dummy
} else {
- contains(QMAKE_TARGET.os, WinRT)|contains(QMAKE_TARGET.os, TvOS)|contains(QMAKE_TARGET.os, IOS)|contains(QMAKE_TARGET.os, WatchOS)|contains(QMAKE_TARGET.os, INTEGRITY)|contains(QMAKE_TARGET.os, QNX) {
- message("WARNING, target OS excluded from ogl-runtime")
- TEMPLATE = subdirs
- CONFIG += ordered
- SUBDIRS += src_dummy
- } else {
- load(qt_parts)
- requires(qtHaveModule(opengl))
- }
+ load(qt_parts)
+ requires(qtHaveModule(opengl))
}
diff --git a/src/3rdparty/EASTL b/src/3rdparty/EASTL
-Subproject e4b2f453fd3cb3176922af9ab6bc79ddafc12c4
+Subproject 31697c758f2ed19bd7c6bbe61f1b91f9e12035b
diff --git a/src/api/studio3d/doc/doc.pri b/src/api/studio3d/doc/doc.pri
new file mode 100644
index 0000000..ec30e40
--- /dev/null
+++ b/src/api/studio3d/doc/doc.pri
@@ -0,0 +1,9 @@
+build_online_docs: \
+ QMAKE_DOCS = $$PWD/online/qtstudio3d.qdocconf
+else: \
+ QMAKE_DOCS = $$PWD/qtstudio3d.qdocconf
+
+OTHER_FILES += \
+ $$PWD/src/*.qdoc \
+ $$PWD/src/*.html \
+ $$PWD/src/images/*.png \
diff --git a/src/api/studio3d/doc/online/qtstudio3d.qdocconf b/src/api/studio3d/doc/online/qtstudio3d.qdocconf
new file mode 100644
index 0000000..a1dd74d
--- /dev/null
+++ b/src/api/studio3d/doc/online/qtstudio3d.qdocconf
@@ -0,0 +1,2 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults-online-commercial.qdocconf)
+include(../qt3dstudio-opengl-runtime-project.qdocconf)
diff --git a/src/api/studio3d/doc/qt3dstudio-opengl-runtime-project.qdocconf b/src/api/studio3d/doc/qt3dstudio-opengl-runtime-project.qdocconf
new file mode 100644
index 0000000..ece96a5
--- /dev/null
+++ b/src/api/studio3d/doc/qt3dstudio-opengl-runtime-project.qdocconf
@@ -0,0 +1,63 @@
+project = QtStudio3D
+description = Qt 3D Studio OpenGL Runtime Reference
+version = $QT_VERSION
+# url is relative to the parent project
+url = openglruntime
+
+moduleheader = QtStudio3D
+
+sourcedirs += ./src \
+ ../.. \
+ ../../../qmlstreamer
+
+headerdirs += ../.. \
+ ../../../qmlstreamer
+
+imagedirs += ./src/images
+
+depends = qtcore qtgui qtwidgets qtqml qtquick qtquickcontrols qt3dstudio qt3dstudioruntime2 qtdoc qmake
+
+qhp.projects = QtStudio3D
+
+qhp.QtStudio3D.file = qtstudio3d.qhp
+qhp.QtStudio3D.namespace = io.qt.qtstudio3d.$QT_VERSION_TAG
+qhp.QtStudio3D.virtualFolder = qtstudio3d
+qhp.QtStudio3D.indexTitle = Qt 3D Studio OpenGL Runtime
+qhp.QtStudio3D.indexRoot =
+
+qhp.QtStudio3D.filterAttributes = qtstudio3d $QT_VER
+qhp.QtStudio3D.customFilters.Qt.name = QtStudio3D $QT_VER
+qhp.QtStudio3D.customFilters.Qt.filterAttributes = qtstudio3d $QT_VER
+
+qhp.QtStudio3D.subprojects = qmltypes classes
+
+qhp.QtStudio3D.subprojects.qmltypes.title = QML Types
+qhp.QtStudio3D.subprojects.qmltypes.indexTitle = Qt 3D Studio OpenGL Runtime QML Types
+qhp.QtStudio3D.subprojects.qmltypes.selectors = qmltype
+qhp.QtStudio3D.subprojects.qmltypes.sortPages = true
+
+qhp.QtStudio3D.subprojects.classes.title = C++ Classes
+qhp.QtStudio3D.subprojects.classes.indexTitle = Qt 3D Studio OpenGL Runtime C++ Classes
+qhp.QtStudio3D.subprojects.classes.selectors = class namespace doc:headerfile
+qhp.QtStudio3D.subprojects.classes.sortPages = true
+
+# Add an .html file with sidebar content, used in the online style
+HTML.stylesheets += style/qt5-sidebar.html
+
+navigation.homepage = "Qt 3D Studio OpenGL Runtime"
+navigation.hometitle = "Qt 3D Studio OpenGL Runtime"
+navigation.hometitle = "OpenGL Runtime"
+navigation.landingpage = "Qt 3D Studio OpenGL Runtime"
+navigation.landingtitle = OpenGL Runtime
+navigation.cppclassespage = Qt 3D Studio OpenGL Runtime C++ Classes
+navigation.qmltypespage = Qt 3D Studio OpenGL Runtime QML Types
+buildversion = "Qt 3D Studio OpenGL Runtime $QT_VER Manual"
+
+macro.RUNTIME = Qt 3D Studio OpenGL Runtime
+
+#TODO: adjust these once we have runtime-specific examples
+# examplesinstallpath = studio3d
+# exampledirs += ../examples/studio3d
+
+Cpp.ignoretokens += Q3DSV_EXPORT Q_STUDIO3D_EXPORT
+depends += qt3d
diff --git a/src/api/studio3d/doc/qtstudio3d.qdocconf b/src/api/studio3d/doc/qtstudio3d.qdocconf
new file mode 100644
index 0000000..9b76104
--- /dev/null
+++ b/src/api/studio3d/doc/qtstudio3d.qdocconf
@@ -0,0 +1,2 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include(qt3dstudio-opengl-runtime-project.qdocconf)
diff --git a/src/api/studio3d/doc/src/attributenames.html b/src/api/studio3d/doc/src/attributenames.html
new file mode 100644
index 0000000..fca55df
--- /dev/null
+++ b/src/api/studio3d/doc/src/attributenames.html
@@ -0,0 +1,911 @@
+\raw HTML
+<table id='scripting-attributes'>
+<tbody></tbody>
+<tr><th colspan="4">Scenes</td></tr>
+<tr>
+<td class='formal'>Name</td>
+<td class='scripting'>name</td>
+<td class='type'>string</td>
+</tr>
+<tr>
+<td class='formal'>Enable Background Color</td>
+<td class='scripting'>bgcolorenable</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Background Color R</td>
+<td class='scripting'>backgroundcolor.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Background Color G</td>
+<td class='scripting'>backgroundcolor.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Background Color B</td>
+<td class='scripting'>backgroundcolor.b</td>
+<td class='type'>number</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Elements other than Scenes</td></tr>
+<tr>
+<td class='formal'>Element Name</td>
+<td class='scripting'>name</td>
+<td class='type'>string</td>
+</tr>
+<tr>
+<td class='formal'>(Eyeball)</td>
+<td class='scripting'>eyeball</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Timebar Start</td>
+<td class='scripting'>starttime</td>
+<td class='type'>number</td>
+<td class='note'>
+in integer milliseconds
+</td>
+</tr>
+<tr>
+<td class='formal'>Timebar End</td>
+<td class='scripting'>endtime</td>
+<td class='type'>number</td>
+<td class='note'>
+in integer milliseconds
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Layers</td></tr>
+<tr>
+<td class='formal'>Disable Depth Test</td>
+<td class='scripting'>disabledepthtest</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Progressive AA</td>
+<td class='scripting'>progressiveaa</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'None'</code>, <code>'2x'</code>, <code>'4x'</code>, <code>'8x'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Multisample AA</td>
+<td class='scripting'>multisampleaa</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'None'</code>, <code>'2x'</code>, <code>'4x'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Temporal AA</td>
+<td class='scripting'>temporalaa</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Layer Background</td>
+<td class='scripting'>background</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Transparent'</code>, <code>'Unspecified'</code>, <code>'SolidColor'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Background Color R</td>
+<td class='scripting'>backgroundcolor.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Background Color G</td>
+<td class='scripting'>backgroundcolor.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Background Color B</td>
+<td class='scripting'>backgroundcolor.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Blend Type</td>
+<td class='scripting'>blendtype</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Normal'</code>, <code>'Screen'</code>, <code>'Multiply'</code>, <code>'Add'</code>, <code>'*Overlay'</code>, <code>'*ColorBurn'</code>, <code>'*ColorDodge'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Horizontal Fields</td>
+<td class='scripting'>horzfields</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Left/Width'</code>, <code>'Left/Right'</code>, <code>'Width/Right'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Left</td>
+<td class='scripting'>left</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Left Units</td>
+<td class='scripting'>leftunits</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'pixels'</code>, <code>'percent'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Width</td>
+<td class='scripting'>width</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Width Units</td>
+<td class='scripting'>widthunits</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'pixels'</code>, <code>'percent'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Right</td>
+<td class='scripting'>right</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Right Units</td>
+<td class='scripting'>rightunits</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'pixels'</code>, <code>'percent'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Vertical Fields</td>
+<td class='scripting'>vertfields</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Top/Height'</code>, <code>'Top/Bottom'</code>, <code>'Height/Bottom'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Top</td>
+<td class='scripting'>top</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Top Units</td>
+<td class='scripting'>topunits</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'pixels'</code>, <code>'percent'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Height</td>
+<td class='scripting'>height</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Height Units</td>
+<td class='scripting'>heightunits</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'pixels'</code>, <code>'percent'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Bottom</td>
+<td class='scripting'>bottom</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Bottom Units</td>
+<td class='scripting'>bottomunits</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'pixels'</code>, <code>'percent'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Ambient Occlusion</td>
+<td class='scripting'>aostrength</td>
+<td class='type'>number</td>
+<td class='note'>
+values between 0 and 100
+</td>
+</tr>
+<tr>
+<td class='formal'>AO Distance</td>
+<td class='scripting'>aodistance</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>AO Softness</td>
+<td class='scripting'>aosoftness</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>AO Threshold</td>
+<td class='scripting'>aobias</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>AO Sampling Rate</td>
+<td class='scripting'>aosamplerate</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>AO Dithering</td>
+<td class='scripting'>aodither</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Strength</td>
+<td class='scripting'>shadowstrength</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Distance</td>
+<td class='scripting'>shadowdist</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Softness</td>
+<td class='scripting'>shadowsoftness</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Threshold</td>
+<td class='scripting'>shadowbias</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Light Probe</td>
+<td class='scripting'>lightprobe</td>
+<td class='type'>image element</td>
+</tr>
+<tr>
+<td class='formal'>IBL Horizon Cutoff</td>
+<td class='scripting'>probehorizon</td>
+<td class='type'>number</td>
+<td class='note'>
+values from -1 (no horizon) to -0.001 (hard edge)
+</td>
+</tr>
+<tr>
+<td class='formal'>Sub-Presentation</td>
+<td class='scripting'>sourcepath</td>
+<td class='type'>string</td>
+<td class='note'>
+id of the sub-presentation to display
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Nodes</td></tr>
+<tr>
+<td class='formal'>Position X</td>
+<td class='scripting'>position.x</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Position Y</td>
+<td class='scripting'>position.y</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Position Z</td>
+<td class='scripting'>position.z</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Rotation X</td>
+<td class='scripting'>rotation.x</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Rotation Y</td>
+<td class='scripting'>rotation.y</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Rotation Z</td>
+<td class='scripting'>rotation.z</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Scale X</td>
+<td class='scripting'>scale.x</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Scale Y</td>
+<td class='scripting'>scale.y</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Scale Z</td>
+<td class='scripting'>scale.z</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Pivot X</td>
+<td class='scripting'>pivot.x</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Pivot Y</td>
+<td class='scripting'>pivot.y</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Pivot Z</td>
+<td class='scripting'>pivot.z</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Opacity</td>
+<td class='scripting'>opacity</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'></td>
+<td class='scripting'>orientation</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Left Handed'</code>, <code>'Right Handed'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'></td>
+<td class='scripting'>rotationorder</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'XYZ'</code>, <code>'YZX'</code>, <code>'ZXY'</code>, <code>'XZY'</code>, <code>'YXZ'</code>, <code>'ZYX'</code>, <code>'XYZr'</code>, <code>'YZXr'</code>, <code>'ZXYr'</code>, <code>'XZYr'</code>, <code>'YXZr'</code>, <code>'ZYXr'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'></td>
+<td class='scripting'>ignoresparent</td>
+<td class='type'>boolean</td>
+<td class='note'>
+prevents parent transformation from being applied [ignored as of 2.0]
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Aliases</td></tr>
+<tr>
+<td class='formal'>Reference</td>
+<td class='scripting'>referencednode</td>
+<td class='type'>string</td>
+<td class='note'>
+relative or absolute element path
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Cameras</td></tr>
+<tr>
+<td class='formal'>Orthographic</td>
+<td class='scripting'>orthographic</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Field of View</td>
+<td class='scripting'>fov</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Clipping Start</td>
+<td class='scripting'>clipnear</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Clipping End</td>
+<td class='scripting'>clipfar</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Runtime Scale Mode</td>
+<td class='scripting'>scalemode</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Fit'</code>, <code>'Same Size'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Runtime Scale Anchor</td>
+<td class='scripting'>scaleanchor</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Center'</code>, <code>'NW'</code>, <code>'N'</code>, <code>'NE'</code>, <code>'E'</code>, <code>'SE'</code>, <code>'S'</code>, <code>'SW'</code>, <code>'W'</code>
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Lights</td></tr>
+<tr>
+<td class='formal'>Scope</td>
+<td class='scripting'>scope</td>
+<td class='type'>string</td>
+<td class='note'>
+full path to the element
+</td>
+</tr>
+<tr>
+<td class='formal'>Light Type</td>
+<td class='scripting'>lighttype</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Directional'</code>, <code>'Point'</code>, <code>'Area'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Light Color R</td>
+<td class='scripting'>lightdiffuse.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Light Color G</td>
+<td class='scripting'>lightdiffuse.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Light Color B</td>
+<td class='scripting'>lightdiffuse.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Color R</td>
+<td class='scripting'>lightspecular.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Color G</td>
+<td class='scripting'>lightspecular.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Color B</td>
+<td class='scripting'>lightspecular.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Ambient Color R</td>
+<td class='scripting'>lightambient.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Ambient Color G</td>
+<td class='scripting'>lightambient.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Ambient Color B</td>
+<td class='scripting'>lightambient.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Brightness</td>
+<td class='scripting'>brightness</td>
+<td class='type'>number</td>
+<td class='note'>
+only applies to point lights
+</td>
+</tr>
+<tr>
+<td class='formal'>Linear Fade</td>
+<td class='scripting'>linearfade</td>
+<td class='type'>number</td>
+<td class='note'>
+only applies to point lights
+</td>
+</tr>
+<tr>
+<td class='formal'>Exponential Fade</td>
+<td class='scripting'>expfade</td>
+<td class='type'>number</td>
+<td class='note'>
+only applies to point lights
+</td>
+</tr>
+<tr>
+<td class='formal'>Cast Shadows?</td>
+<td class='scripting'>castshadow</td>
+<td class='type'>boolean</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Darkness</td>
+<td class='scripting'>shdwfactor</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Softness</td>
+<td class='scripting'>shdwfilter</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Resolution</td>
+<td class='scripting'>shdwmapres</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'256'</code>, <code>'512'</code>, <code>'1024'</code>, <code>'2048'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Depth Bias</td>
+<td class='scripting'>shdwbias</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Shadow Far Clip</td>
+<td class='scripting'>shdwmapfar</td>
+<td class='type'>number</td>
+<tr>
+<td class='formal'>Shadow Field of View</td>
+<td class='scripting'>shdwmapfov</td>
+<td class='type'>number</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Groups</td></tr>
+<tr>
+<td class='formal'>Import</td>
+<td class='scripting'>sourcepath</td>
+<td class='type'>string</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Text</td></tr>
+<tr>
+<td class='formal'>Text String</td>
+<td class='scripting'>textstring</td>
+<td class='type'>string</td>
+</tr>
+<tr>
+<td class='formal'>Text Color R</td>
+<td class='scripting'>textcolor.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Text Color G</td>
+<td class='scripting'>textcolor.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Text Color B</td>
+<td class='scripting'>textcolor.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Font</td>
+<td class='scripting'>font</td>
+<td class='type'>string</td>
+</tr>
+<tr>
+<td class='formal'>Font Size</td>
+<td class='scripting'>size</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Horizontal Alignment</td>
+<td class='scripting'>horzalign</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Left'</code>, <code>'Center'</code>, <code>'Right'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Vertical Alignment</td>
+<td class='scripting'>vertalign</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Top'</code>, <code>'Middle'</code>, <code>'Bottom'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Leading</td>
+<td class='scripting'>leading</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Tracking</td>
+<td class='scripting'>tracking</td>
+<td class='type'>number</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Models</td></tr>
+<tr>
+<td class='formal'>Mesh</td>
+<td class='scripting'>sourcepath</td>
+<td class='type'>string</td>
+</tr>
+<tr>
+<td class='formal'>Tessellation Mode</td>
+<td class='scripting'>tessellation</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'None'</code>, <code>'Linear'</code>, <code>'Phong'</code>, <code>'NPatch'</code> [ignored as of 2.0]
+</td>
+</tr>
+<tr>
+<td class='formal'>Edge Tessellation</td>
+<td class='scripting'>edgetess</td>
+<td class='type'>number</td>
+<td class='note'>
+[ignored as of 2.0]
+</td>
+</tr>
+<tr>
+<td class='formal'>Inner Tessellation</td>
+<td class='scripting'>innertess</td>
+<td class='type'>number</td>
+<td class='note'>
+[ignored as of 2.0]
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Standard Materials</td></tr>
+<tr>
+<td class='formal'>Lighting</td>
+<td class='scripting'>shaderlighting</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Vertex'</code>, <code>'Pixel'</code>, <code>'None'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Blending Mode</td>
+<td class='scripting'>blendmode</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Normal'</code>, <code>'Screen'</code>, <code>'Multiply'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Diffuse Color R</td>
+<td class='scripting'>diffuse.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Diffuse Color G</td>
+<td class='scripting'>diffuse.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Diffuse Color B</td>
+<td class='scripting'>diffuse.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Diffuse Map</td>
+<td class='scripting'>diffusemap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Diffuse Map 2</td>
+<td class='scripting'>diffusemap2</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Diffuse Map 3</td>
+<td class='scripting'>diffusemap3</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Specular Reflection</td>
+<td class='scripting'>specularreflection</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Specular Tint R</td>
+<td class='scripting'>speculartint.r</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Tint G</td>
+<td class='scripting'>speculartint.g</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Tint B</td>
+<td class='scripting'>speculartint.b</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Amount</td>
+<td class='scripting'>specularamount</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Map</td>
+<td class='scripting'>specularmap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Specular Model</td>
+<td class='scripting'>specularmodel</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Default'</code>, <code>'KGGX'</code>, <code>'KWard'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>Fresnel Power</td>
+<td class='scripting'>fresnelPower</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Index of Refraction</td>
+<td class='scripting'>ior</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Specular Roughness</td>
+<td class='scripting'>specularroughness</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Bump Map</td>
+<td class='scripting'>bumpmap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Normal Map</td>
+<td class='scripting'>normalmap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Bump Amount</td>
+<td class='scripting'>bumpamount</td>
+<td class='type'>number</td>
+<td class='note'>
+affects both bump and normal maps
+</td>
+</tr>
+<tr>
+<td class='formal'>Displacement Map</td>
+<td class='scripting'>displacementmap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Displacement Amount</td>
+<td class='scripting'>displaceamount</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Opacity</td>
+<td class='scripting'>opacity</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Opacity Map</td>
+<td class='scripting'>opacitymap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tr>
+<td class='formal'>Emissive Power</td>
+<td class='scripting'>emissivepower</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Emissive Map</td>
+<td class='scripting'>emissivemap</td>
+<td class='type'>image element</td>
+<td class='note'>
+to change the image set the <code>sourcepath</code> attribute on the image element
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Material References</td></tr>
+<tr>
+<td class='formal'>Referenced Material</td>
+<td class='scripting'>referencedmaterial</td>
+<td class='type'>string</td>
+<td class='note'>
+relative or absolute element path
+</td>
+</tr>
+<tbody></tbody>
+<tr><th colspan="4">Images</td></tr>
+<tr>
+<td class='formal'>U Repeat</td>
+<td class='scripting'>scaleu</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>V Repeat</td>
+<td class='scripting'>scalev</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Texture Mapping</td>
+<td class='scripting'>mappingmode</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'UV Mapping'</code>, <code>'Environmental Mapping'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>U Tiling</td>
+<td class='scripting'>tilingmodehorz</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Tiled'</code>, <code>'Mirrored'</code>, <code>'No Tiling'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>V Tiling</td>
+<td class='scripting'>tilingmodevert</td>
+<td class='type'>string</td>
+<td class='note'>
+values: <code>'Tiled'</code>, <code>'Mirrored'</code>, <code>'No Tiling'</code>
+</td>
+</tr>
+<tr>
+<td class='formal'>UV Rotation</td>
+<td class='scripting'>rotationuv</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>U Position</td>
+<td class='scripting'>positionu</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>V Position</td>
+<td class='scripting'>positionv</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>U Pivot</td>
+<td class='scripting'>pivotu</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>V Pivot</td>
+<td class='scripting'>pivotv</td>
+<td class='type'>number</td>
+</tr>
+<tr>
+<td class='formal'>Sub-Presentation</td>
+<td class='scripting'>subpresentation</td>
+<td class='type'>string</td>
+<td class='note'>
+id of the sub-presentation to display
+</td>
+</tr>
+<tr>
+<td class='formal'>Source Path</td>
+<td class='scripting'>sourcepath</td>
+<td class='type'>string</td>
+<td class='note'>
+path to the image
+</td>
+</tr>
+</table>
+\endraw
diff --git a/src/api/studio3d/doc/src/attributenames.qdoc b/src/api/studio3d/doc/src/attributenames.qdoc
new file mode 100644
index 0000000..e499f17
--- /dev/null
+++ b/src/api/studio3d/doc/src/attributenames.qdoc
@@ -0,0 +1,71 @@
+!/****************************************************************************
+**
+** Copyright (C) 1993-2009 NVIDIA Corporation.
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Pull in attributenames.html into qdoc. Note that attributenames.html is
+// manually maintained since 2.0 and is not auto-generated.
+
+/*!
+ \page qt3dstudio-opengl-runtime-attribute-names.html
+ \title Attribute Names
+ \keyword Attributes
+
+ Below is a list of the attributes that can be set on the various scene
+ objects via Q3DSPresentation::setAttribute() or Q3DSElement::setAttribute().
+
+ \note vector (e.g. a group's or model's \c rotation) and color (e.g. a
+ material's \c diffuse) attributes allow setting/getting all components in
+ one operation, and are mapped to QVector3D and QColor, respectively.
+
+ \note As of Qt 3D Studio 2.1 not all properties can be changed on the fly at
+ run time. As a general rule attributes that are animatable in the Qt 3D
+ Studio application are freely changeable by the applications during run time
+ as well.
+
+ \note When possible, applications are recommended to rely on the \c{data
+ input} functionality of Qt 3D Studio instead. This avoids the need to refer
+ to hard-coded attribute names, and instead allows the designers to expose
+ the interesting attributes with arbitrary data input names to the
+ application developers, thus offering a fixed, well-known interface from the
+ 3D presentation to the application code. See \l Q3DSDataInput, \l DataInput,
+ \l Q3DSDataOutput, and \l DataOutput for more information.
+
+ \include attributenames.html
+
+ Custom materials and effects have their custom set of properties that are
+ defined in the \c{.material} or \c{.effect} file. For example, an instances
+ of an effect with the following metadata will have an attribute \c HBlurBias
+ with the type \c number that can be set and queried as if it was a built-in
+ attribute.
+
+ \badcode
+ <Effect>
+ <MetaData>
+ <Property name="HBlurBias" formalName="Horizontal Blur" min="0" max="10" default="2" description="Amount of corona horizontally."/>
+ ...
+ \endcode
+*/
diff --git a/src/api/studio3d/doc/src/building-embedded.qdoc b/src/api/studio3d/doc/src/building-embedded.qdoc
new file mode 100644
index 0000000..ddd8b59
--- /dev/null
+++ b/src/api/studio3d/doc/src/building-embedded.qdoc
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Building \RUNTIME for Embedded Linux
+\page building-opengl-runtime-embedded-linux.html
+
+Before you build the \RUNTIME for Embedded Linux, you will need to install Qt for Embedded Linux.
+
+\section1 Install Qt for Embedded Linux
+Follow the Installation guide for your specific target device.
+
+\section1 Build the \RUNTIME
+
+\list 1
+ \li
+ Clone the \RUNTIME repository from
+ \l {https://code.qt.io/cgit/qt3dstudio/ogl-runtime.git}.
+ You can clone the repo with the \c {git clone} command:
+ \badcode
+ git clone git://code.qt.io/qt3dstudio/ogl-runtime.git
+ \endcode
+
+ \note If you want to use the HTTPS protocol, you can clone the \RUNTIME repo with the
+ following command:
+ \badcode
+ git clone https://code.qt.io/qt3dstudio/ogl-runtime.git
+ \endcode
+ \li
+ Run the following \c{git submodule} command:
+ \badcode
+ git submodule update --init --recursive
+ \endcode
+ \li
+ Open \c{ogl-runtime.pro} in Qt Creator. \c{ogl-runtime.pro} is located in the root of the
+ cloned repository.
+
+ \image ogl-runtime-pro.png
+ \li
+ Select the desired prebuilt Embedded Linux component and select \uicontrol{Configure Project}.
+
+ \image embedded-linux.png
+ \li
+ Add a build step with argument \c{install}.
+
+ \image embedded-linux-2.png
+ \li
+ From the menu, select \uicontrol{Build > Build Project "opengl-runtime"}.
+\endlist
+
+\section1 Deploy the \RUNTIME
+
+Follow the
+\l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html}{Installation guide}
+for your specific target device.
+
+*/
diff --git a/src/api/studio3d/doc/src/building-integrity.qdoc b/src/api/studio3d/doc/src/building-integrity.qdoc
new file mode 100644
index 0000000..fb09a10
--- /dev/null
+++ b/src/api/studio3d/doc/src/building-integrity.qdoc
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Building \RUNTIME for GHS Integrity
+\page building-opengl-runtime-integrity.html
+
+Before you build the \RUNTIME for Integrity, you will need to build
+\l{https://doc.qt.io/qt-5/integrity.html}{Qt for Integrity}.
+Then, follow the steps below:
+
+\list 1
+ \li
+ Clone the OpenGL Runtime repository from
+ \l {https://code.qt.io/cgit/qt3dstudio/ogl-runtime.git/}. You can clone the repo with the git
+ clone command:
+
+ \badcode
+ git clone git://code.qt.io/qt3dstudio/ogl-runtime.git
+ \endcode
+
+ \note If you want to use the HTTPS protocol, you can clone the \RUNTIME repo with the
+ following command:
+ \badcode
+ git clone https://code.qt.io/qt3dstudio/ogl-runtime.git
+ \endcode
+ \li
+ Run the following \c{git submodule} command:
+ \badcode
+ git submodule update --init --recursive
+ \endcode
+ \li
+ In the root folder of the cloned repo, run the \c qmake command:
+ \badcode
+ qmake
+ \endcode
+ \li
+ Next, run the \c make command:
+ \badcode
+ make
+ \endcode
+\endlist
+
+For deployment, see the \l {https://doc.qt.io/qt-5/integrity.html}{Qt for Integrity} documentation.
+
+*/
diff --git a/src/api/studio3d/doc/src/building-opengl-runtime.qdoc b/src/api/studio3d/doc/src/building-opengl-runtime.qdoc
new file mode 100644
index 0000000..b9d95b5
--- /dev/null
+++ b/src/api/studio3d/doc/src/building-opengl-runtime.qdoc
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Building the \RUNTIME
+\page building-opengl-runtime.html
+
+\section1 Build Instructions
+
+\list
+ \li
+ \l {Building \RUNTIME for Embedded Linux}
+ \li
+ \l {Building \RUNTIME for GHS Integrity}
+ \li
+ \l {Building \RUNTIME for QNX}
+\endlist
+
+*/
diff --git a/src/api/studio3d/doc/src/building-qnx.qdoc b/src/api/studio3d/doc/src/building-qnx.qdoc
new file mode 100644
index 0000000..fba04ce
--- /dev/null
+++ b/src/api/studio3d/doc/src/building-qnx.qdoc
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Building \RUNTIME for QNX
+\page building-opengl-runtime-qnx.html
+
+Before you build the \RUNTIME for QNX, you will need to install Qt for QNX and Qt 3D Studio.
+
+\section1 Install Qt for QNX
+
+\list 1
+ \li
+ Download and install QNX SDP 7.0 from the \l {http://www.qnx.com}{QNX software center}.
+ \li
+ Run the Qt online installer. You can get it from \l {https://www.qt.io/download}.
+ \li
+ Select the desired prebuilt QNX component, select \uicontrol Next.
+
+ \image qt-installer-qnx-prebuild.png
+ \li
+ Select the folder where your QNX SDP is installed.
+
+ \image qnx-sdp-folder.png
+ \li
+ Press \uicontrol Next, then press \uicontrol Install. The Qt Creator will now run.
+\endlist
+
+\section1 Build Qt 3D Studio
+
+\list 1
+ \li
+ Clone the Qt 3D Studio repository from \l {https://code.qt.io/qt3dstudio/qt3dstudio.git}.
+ You can clone the repo with the \c {git clone} command:
+
+ \badcode
+ git clone git://code.qt.io/qt3dstudio/qt3dstudio.git
+ \endcode
+
+ \note If you want to use the HTTPS protocol, you can clone the Qt 3D Studio with the following
+ command:
+
+ \badcode
+ git clone https://code.qt.io/qt3dstudio/qt3dstudio.
+ \endcode
+ \li
+ Run the following \c{git submodule} command:
+ \badcode
+ git submodule update --init --recursive
+ \endcode
+ \li
+ Open \c {qt3dstudio.pro} in the Qt Creator. \c {qt3dstudio.pro} is located in the root of the
+ cloned repository.
+
+ \image qt3dstudio-pro.png
+ \li
+ Select desired prebuilt QNX Component.
+
+ \image select-prebuilt-qnx-component.png
+ \li
+ Press \uicontrol{Configure Project}.
+ \li
+ Select the \uicontrol Project tab and \uicontrol{Build Settings}.
+ \li
+ Add a build step with the argument \c install.
+
+ \image add-build-step.png
+ \li
+ From the menu, select \uicontrol{Build > Build Project "qt3dstudio"}.
+\endlist
+
+\section1 Build the \RUNTIME
+
+\list 1
+ \li
+ Clone the \RUNTIME repository from
+ \l{https://code.qt.io/cgit/qt3dstudio/ogl-runtime.git}.
+ You can clone the repo with the \c {git clone} command:
+ \badcode
+ git clone git://code.qt.io/qt3dstudio/ogl-runtime.git
+ \endcode
+
+ \note If you want to use the HTTPS protocol, you can clone the \RUNTIME repo with
+ the following command:
+
+ \badcode
+ git clone https://code.qt.io/qt3dstudio/ogl-runtime.git
+ \endcode
+ \li
+ Run the following \ {git submodule} command:
+
+ \badcode
+ git submodule update --init --recursive
+ \endcode
+ \li
+ Open \c {ogl-runtime.pro} in Qt Creator. \c {ogl-runtime.pro} is located in the root of the
+ cloned repository.
+
+ \image ogl-runtime-pro.png
+ \li
+ Select the desired prebuilt QNX component and select \uicontrol{Configure Project}.
+
+ \image qnx-prebuild.png
+ \li
+ Add a build step with argument \c install.
+
+ \image add-build-step-qnx.png
+ \li
+ From the menu, select \uicontrol{Build > Build Project "opengl-runtime"}.
+ \li
+ The \RUNTIME is installed to the same folder where you have installed the QNX prebuilt
+ components. For example \c{~/Qt5.12/5.12.3/qnx7_x86_64/}.
+\endlist
+
+\section1 Deploy the \RUNTIME
+
+To deploy to the target device, follow the steps below:
+
+\list 1
+ \li
+ In Qt Creator, select \uicontrol{Tools > Options} from the menu.
+ \li
+ Select the \uicontrol Devices tab.
+
+ \image devices-tab.png
+ \li
+ Select \uicontrol Add.
+ \li
+ Select QNX Device, then press \uicontrol {Start Wizard}.
+
+ \image add-qnx-device.png
+ \li
+ Select \uicontrol {Deploy Qt Libraries}. This will also deploy Qt and Qt 3D Studio binaries
+ and libraries.
+\endlist
+
+*/
diff --git a/src/api/studio3d/doc/src/copyright.qdoc b/src/api/studio3d/doc/src/copyright.qdoc
new file mode 100644
index 0000000..bd431cd
--- /dev/null
+++ b/src/api/studio3d/doc/src/copyright.qdoc
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page copyright-notices.html
+\title Copyright Notices
+\section1 Third-party Licenses
+
+The following table lists parts (modules) of \RUNTIME that
+incorporate code licensed under third-party open-source licenses:
+
+\annotatedlist attributions-qtstudio3d
+
+*/
diff --git a/src/api/studio3d/doc/src/embedded.qdoc b/src/api/studio3d/doc/src/embedded.qdoc
new file mode 100644
index 0000000..b468070
--- /dev/null
+++ b/src/api/studio3d/doc/src/embedded.qdoc
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qt3dstudio-opengl-runtime-embedded.html
+ \title Using the Runtime on Embedded Devices
+
+*/
diff --git a/src/api/studio3d/doc/src/examples.qdoc b/src/api/studio3d/doc/src/examples.qdoc
new file mode 100644
index 0000000..f7a78b4
--- /dev/null
+++ b/src/api/studio3d/doc/src/examples.qdoc
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \title Examples
+ \ingroup examples
+ \page qt3dstudio-opengl-runtime-examples.html
+
+ Included in the \RUNTIME you will find a set of examples. These are
+ located in the \c {examples} folder in the installation folder.
+
+ \section1 More Examples
+
+ You can find more examples from
+ \l{https://git.qt.io/public-demos/qt3dstudio}, these examples are more
+ visually appealing and suitable to use as demos for example.
+*/
diff --git a/src/api/studio3d/doc/src/gettingstarted.qdoc b/src/api/studio3d/doc/src/gettingstarted.qdoc
new file mode 100644
index 0000000..9289b54
--- /dev/null
+++ b/src/api/studio3d/doc/src/gettingstarted.qdoc
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qt3dstudio-opengl-runtime-gettingstarted.html
+ \title Getting Started
+
+ The \RUNTIME provides C++ and QML APIs for integrating Qt 3D
+ Studio scenes into Qt applications, as well as the viewer application that
+ is used in combination with the Qt 3D Studio application during the design
+ phase.
+
+ Below is an example scene in the Qt 3D Studio application.
+
+ \image intro-editor.png
+
+ During the design phase, the standalone viewer is typically launched from
+ the editor several times to check and verify the presentation in the
+ runtime.
+
+ \image intro-viewer.png
+
+ Once the design is done and the \c{.uia}, \c{.uip}, and other asset files
+ are available, these can be loaded, rendered, and manipulated in Qt
+ applications. This is done via the APIs provided in the \c studio3d
+ module and the \c QtStudio3D.OpenGL QML plugin.
+
+ Below is the same scene loaded into a simple Qt Quick application
+ (the \l{Qt 3D Studio Runtime: Simple QML Example}{simpleqml
+ example}) that composes the 3D content with the other Qt Quick
+ items, for example the ones provided by \l{Qt Quick Controls
+ 2}. In addition to displaying the presentation, the application
+ can also control many aspects of it (slides, timeline, object
+ properties) and can react on certain conditions, such as when a 3D
+ object is clicked on (picked) by mouse or touch input.
+
+ \image intro-app.png
+
+ \section1 Rendering Scenes
+
+ APIs are provided for the following Qt UI technologies:
+
+ \list
+
+ \li Qt Quick: here applications import QtStudio3D.OpenGL \QtVer which
+ provides the \l [QML] Studio3D QML type, a Qt Quick item that can be
+ added to Qt Quick scenes. Under the hood this is similar to adding a
+ \l [QML] Scene3D (when working directly with the lower level Qt 3D
+ framework) or a custom item based on \l QQuickFramebufferObject into
+ the scene.
+
+ \li QWindow or offscreen render targets (OpenGL texture): Q3DSSurfaceViewer
+ can be used both to render to an on-screen QWindow, as well as off-screen
+ into an OpenGL texture. The latter allows reading back and saving the
+ frames, to generate pre-rendered video sequences for example.
+
+ \endlist
+
+ \section1 Manipulating Scenes
+
+ Rendering Qt 3D Studio scenes is only part of the story since many scenes
+ are not static and will not just display all their contents as they were
+ done by designers in the Qt 3D Studio application. Rather, properties of
+ scene objects (for example, the rotation property of a 3D model, or the
+ diffuse color of the material associated with such a model) may need to be
+ changed dynamically, at run time. The timeline or the current slide may
+ also need to be adjusted based on the user's actions or other application
+ state.
+
+ Above functionality is exposed via the following types:
+
+ \table
+ \header
+ \li C++ Class
+ \li QML Type
+ \row
+ \li Q3DSPresentation
+ \li \l [QML] Presentation
+ \row
+ \li Q3DSElement
+ \li \l Element
+ \row
+ \li Q3DSSceneElement
+ \li \l [QML] SceneElement
+ \row
+ \li Q3DSDataInput
+ \li \l [QML] DataInput
+
+ \endtable
+
+ Advanced scene manipulation (for example, dynamically spawning and
+ removing objects in a 3D scene) will be introduced in future versions.
+*/
diff --git a/src/api/studio3d/doc/src/images/add-build-step-qnx.png b/src/api/studio3d/doc/src/images/add-build-step-qnx.png
new file mode 100644
index 0000000..8406b39
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/add-build-step-qnx.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/add-build-step.png b/src/api/studio3d/doc/src/images/add-build-step.png
new file mode 100644
index 0000000..d047bb7
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/add-build-step.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/add-qnx-device.png b/src/api/studio3d/doc/src/images/add-qnx-device.png
new file mode 100644
index 0000000..c1f5aca
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/add-qnx-device.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/customsignal.png b/src/api/studio3d/doc/src/images/customsignal.png
new file mode 100644
index 0000000..eb0e0ba
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/customsignal.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/devices-tab.png b/src/api/studio3d/doc/src/images/devices-tab.png
new file mode 100644
index 0000000..10f2884
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/devices-tab.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/embedded-linux-2.png b/src/api/studio3d/doc/src/images/embedded-linux-2.png
new file mode 100644
index 0000000..d46da08
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/embedded-linux-2.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/embedded-linux.png b/src/api/studio3d/doc/src/images/embedded-linux.png
new file mode 100644
index 0000000..b8e0efb
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/embedded-linux.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/intro-app.png b/src/api/studio3d/doc/src/images/intro-app.png
new file mode 100644
index 0000000..3658190
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/intro-app.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/intro-editor.png b/src/api/studio3d/doc/src/images/intro-editor.png
new file mode 100644
index 0000000..52e5a69
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/intro-editor.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/intro-viewer.png b/src/api/studio3d/doc/src/images/intro-viewer.png
new file mode 100644
index 0000000..f964b58
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/intro-viewer.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/ogl-runtime-pro.png b/src/api/studio3d/doc/src/images/ogl-runtime-pro.png
new file mode 100644
index 0000000..d49dbdf
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/ogl-runtime-pro.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/qnx-prebuild.png b/src/api/studio3d/doc/src/images/qnx-prebuild.png
new file mode 100644
index 0000000..09ce65d
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/qnx-prebuild.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/qnx-sdp-folder.png b/src/api/studio3d/doc/src/images/qnx-sdp-folder.png
new file mode 100644
index 0000000..269374a
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/qnx-sdp-folder.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/qt-installer-qnx-prebuild.png b/src/api/studio3d/doc/src/images/qt-installer-qnx-prebuild.png
new file mode 100644
index 0000000..8dc7389
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/qt-installer-qnx-prebuild.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/qt3dstudio-pro.png b/src/api/studio3d/doc/src/images/qt3dstudio-pro.png
new file mode 100644
index 0000000..8d8a5d5
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/qt3dstudio-pro.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/select-prebuilt-qnx-component.png b/src/api/studio3d/doc/src/images/select-prebuilt-qnx-component.png
new file mode 100644
index 0000000..4ef68fe
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/select-prebuilt-qnx-component.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/images/twolayers.png b/src/api/studio3d/doc/src/images/twolayers.png
new file mode 100644
index 0000000..2f4b66f
--- /dev/null
+++ b/src/api/studio3d/doc/src/images/twolayers.png
Binary files differ
diff --git a/src/api/studio3d/doc/src/index.qdoc b/src/api/studio3d/doc/src/index.qdoc
new file mode 100644
index 0000000..1888a87
--- /dev/null
+++ b/src/api/studio3d/doc/src/index.qdoc
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\title \RUNTIME
+\page qt3dstudio-opengl-runtime-index.html
+
+\section1 Table of Contents
+
+\list
+ \li \l {Getting Started}
+ \li \l {System and Application Requirements}
+ \li \l {Building the \RUNTIME}
+ \li \l {\RUNTIME C++ Classes}
+ \li \l {\RUNTIME QML Types}
+ \li \l {Attribute Names}{Scene Object Attribute List}
+ \li \l {Examples}
+ \li \l {Copyright Notices}
+\endlist
+
+*/
diff --git a/src/api/studio3d/doc/src/mobile.qdoc b/src/api/studio3d/doc/src/mobile.qdoc
new file mode 100644
index 0000000..2ede51a
--- /dev/null
+++ b/src/api/studio3d/doc/src/mobile.qdoc
@@ -0,0 +1,32 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qt3dstudio-opengl-runtime-mobile.html
+ \title Using the OpenGL Runtime on Android/iOS Devices
+
+*/
diff --git a/src/api/studio3d/doc/src/module.qdoc b/src/api/studio3d/doc/src/module.qdoc
new file mode 100644
index 0000000..98b134e
--- /dev/null
+++ b/src/api/studio3d/doc/src/module.qdoc
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \module OpenGLRuntime
+ \title \RUNTIME C++ Classes
+ \ingroup modules
+
+ \brief The \RUNTIME provides a number of C++ classes to
+ integrate and control Qt 3D Studio presentations in Qt applications.
+
+ To include the definitions of the module's classes, use the following directive:
+
+ \code
+ #include <QtStudio3D>
+ \endcode
+
+ To link against the module, add this line to your \l qmake \c .pro file:
+
+ \badcode
+ QT += studio3d
+ \endcode
+
+ \section1 Integrating
+
+ The main class is \l Q3DSSurfaceViewer. Q3DSSurfaceViewer allows targeting a QWindow or an
+ offscreen render target (an OpenGL texture).
+
+ \note Qt applications based on QML and Qt Quick will rather want to use the
+ \l Studio3D type from \l {\RUNTIME QML Types}.
+
+ \section1 Controlling
+
+ Each \l Q3DSSurfaceViewer instance exposes a \l
+ Q3DSPresentation. This, possibly in combination with \l Q3DSDataInput or
+ \l Q3DSElement objects, allows:
+
+ \list
+
+ \li changing scene object properties (for example, the transform of a
+ model, colors and other settings of a material, etc.),
+
+ \li changing slides (thus starting the relevant animations and applying the
+ scene object property changes associated with the new slide),
+
+ \li and controlling the timeline (the current playback position for the
+ key-frame based animations) both on the main scene and on individual
+ Component nodes.
+
+ \endlist
+
+ \section1 Classes
+*/
+
+/*!
+ \qmlmodule QtStudio3D.OpenGL \QtVer
+ \title \RUNTIME QML Types
+ \ingroup qmlmodules
+
+ \brief QML Types for the \RUNTIME module.
+
+ The \RUNTIME provides a number of QML types to integrate and
+ control Qt 3D Studio presentations in Qt Quick applications. These types
+ can be imported into your application using the following import statement
+ in your \c{.qml} file:
+
+ \qml \QtVer
+ import QtStudio3D.OpenGL \1
+ \endqml
+
+ The main type for embedding a Qt 3D Studio presentations into a Qt Quick
+ scene is \l Studio3D. Many of the other types correspond to a C++ class in
+ the API offered to non-QML based applications, providing the same level of
+ control described in \l{\RUNTIME C++ Classes}{the C++ reference}.
+
+ There are also QML types that offer functionality not available via the C++
+ classes. The \l SubPresentationSettings type allows defining \c{QML
+ sub-presentations} (live Qt Quick scenes composed into the 3D scene either
+ as Qt 3D Studio layers or as texture maps) in-line, inside a Studio3D
+ element, without having to deploy them as separate \c .qml files.
+
+ \note the \l Behavior type is to be used by \c{behavior scripts} (\c .qml
+ snippets associated with scene objects during the design phase in Qt 3D
+ Studio) and is not available in the main application code.
+
+ \section1 QML Types
+*/
diff --git a/src/api/studio3d/doc/src/requirements.qdoc b/src/api/studio3d/doc/src/requirements.qdoc
new file mode 100644
index 0000000..f93483c
--- /dev/null
+++ b/src/api/studio3d/doc/src/requirements.qdoc
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qt3dstudio-opengl-runtime-requirements.html
+ \title System and Application Requirements
+
+ \section1 OpenGL Requirements
+
+ Qt 3D Studio requires OpenGL or OpenGL ES. The recommended minimum versions
+ are \c{3.3 core profile} and \c{3.0}, respectively.
+
+ When it comes to OpenGL ES, a limited subset of the functionality is
+ available when running on plain \c{OpenGL ES 2.0} implementations. In
+ practice this means losing shadow mapping, image based lighting, and many
+ other advanced features and is therefore not recommended. On the other hand,
+ this allows bringing up Qt 3D Studio scenes on boards like the Raspberry Pi
+ (with the original proprietary graphics stack) or the Beaglebone Black, or
+ in hypervisor-based virtualized environments where the GPU virtualization
+ only supports GLES 2.0, and can therefore still be valuable in certain
+ special situations.
+
+ Non-native implementations, like \c ANGLE or software implementations like
+ \c{Mesa's llvmpipe} may work but are not tested and can fail in unexpected
+ ways.
+
+ \section1 Application Integration Notes
+
+ \section2 C++
+
+ A typical Qt C++ application using the \RUNTIME is expected to
+ query and honor the runtime's \c{ideal surface format}. This way the OpenGL
+ contexts will all be created with the OpenGL version and profile that best
+ match the runtime's needs:
+
+ \code
+ #include <Q3DSSurfaceViewer> // or <q3dsruntimeglobal.h> if only Q3DS::surfaceFormat() is interesting for main()
+
+ int main(int argc, char *argv[])
+ {
+ QApplication app(argc, argv);
+
+ QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat());
+
+ Q3DSSurfaceViewer w;
+ ...
+ return app.exec();
+ }
+ \endcode
+
+ To enable using Qt 3D Studio headers and libraries in the application, add
+ the \c studio3d module in the application's \c{.pro} file:
+
+ \badcode
+ QT += studio3d
+ \endcode
+
+ \section2 QML/Qt Quick
+
+ When no C++ classes are used, the \c studio3d module can be omitted
+ in the \c{.pro}. To use the \l Studio3D element in QML code, it is
+ enough to add the corresponding import statement:
+
+ \qml
+ import QtStudio3D.OpenGL \QtVer
+ \endqml
+
+ It is nonetheless strongly recommended to set the the default surface format
+ as shown above. Make sure the
+ \c{QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat())} call is made
+ after constructing QGuiApplication but before the first QQuickWindow or
+ QQuickView. When this is not possible, for example because the QML contents
+ is hosted in an application that has no knowledge of the Qt Quick scene's 3D
+ needs, Studio3D may still be usable but this may be dependent on the OpenGL
+ implementation and the context versions it offers, and is therefore more fragile.
+*/
diff --git a/src/api/studio3d/doc/src/toc.qdoc b/src/api/studio3d/doc/src/toc.qdoc
new file mode 100644
index 0000000..979f084
--- /dev/null
+++ b/src/api/studio3d/doc/src/toc.qdoc
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\contentspage \RUNTIME
+\page qt3dstudio-opengl-runtime-toc.html
+\title \RUNTIME TOC
+
+\omit
+This file is used for generating a TOC in a .qch file.
+\endomit
+
+\list
+ \li \l {\RUNTIME}{Overview}
+\endlist
+*/
diff --git a/src/api/studio3d/doc/style/qt5-sidebar.html b/src/api/studio3d/doc/style/qt5-sidebar.html
new file mode 100644
index 0000000..435d52a
--- /dev/null
+++ b/src/api/studio3d/doc/style/qt5-sidebar.html
@@ -0,0 +1,26 @@
+<div class="sectionlist normallist">
+ <div>
+ <a name="reference"></a>
+ <h2 id="reference">Qt 3D OpenGL Studio Runtime</h2>
+ </div>
+ <div class="indexboxcont indexboxbar">
+ <ul>
+ <li><a href="qt3dstudio-opengl-runtime-index.html">Home</a></li>
+ <li><a href="qt3dstudio-opengl-runtime-gettingstarted.html">Getting Started</a></li>
+ <li><a href="qtstudio3d-opengl-qmlmodule.html">QML API Reference</a></li>
+ <li><a href="openglruntime-module.html">C++ API Reference</a></li>
+ <li><a href="copyright-notices.html">Copyright Notices</a></li>
+ </ul>
+ </div>
+</div>
+<div class="sectionlist normallist">
+ <div>
+ <a name="reference"></a>
+ <h2 id="reference">Qt 3D Studio</h2>
+ </div>
+ <div class="indexboxcont indexboxbar">
+ <ul>
+ <li><a href="../index.html">Home</a></li>
+ </ul>
+ </div>
+</div>
diff --git a/src/api/studio3d/q3dscommandqueue.cpp b/src/api/studio3d/q3dscommandqueue.cpp
index c6071aa..e9eed29 100644
--- a/src/api/studio3d/q3dscommandqueue.cpp
+++ b/src/api/studio3d/q3dscommandqueue.cpp
@@ -61,6 +61,7 @@ CommandQueue::CommandQueue()
, m_showRenderStats(false)
, m_matteColor(Qt::black)
, m_delayedLoading(false)
+ , m_matteEnabled(false)
, m_size(0)
{
qRegisterMetaType<CommandType>();
@@ -207,6 +208,7 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue)
m_globalAnimationTimeChanged
= m_globalAnimationTimeChanged || fromQueue.m_globalAnimationTimeChanged;
m_delayedLoadingChanged = m_delayedLoadingChanged || fromQueue.m_delayedLoadingChanged;
+ m_matteEnabledChanged = m_matteEnabledChanged || fromQueue.m_matteEnabledChanged;
if (fromQueue.m_visibleChanged)
m_visible = fromQueue.m_visible;
@@ -226,6 +228,8 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue)
m_globalAnimationTime = fromQueue.m_globalAnimationTime;
if (fromQueue.m_delayedLoadingChanged)
m_delayedLoading = fromQueue.m_delayedLoading;
+ if (fromQueue.m_matteEnabledChanged)
+ m_matteEnabled = fromQueue.m_matteEnabled;
// Pending queue may be synchronized multiple times between queue processing, so let's append
// to the existing queue rather than clearing it.
@@ -304,6 +308,7 @@ void CommandQueue::clear(bool deleteCommandData)
m_variantListChanged = false;
m_globalAnimationTimeChanged = false;
m_delayedLoadingChanged = false;
+ m_matteEnabledChanged = false;
if (deleteCommandData) {
for (int i = 0; i < m_size; ++i) {
diff --git a/src/api/studio3d/q3dscommandqueue_p.h b/src/api/studio3d/q3dscommandqueue_p.h
index 12d1b7e..effb72e 100644
--- a/src/api/studio3d/q3dscommandqueue_p.h
+++ b/src/api/studio3d/q3dscommandqueue_p.h
@@ -142,6 +142,7 @@ public:
bool m_variantListChanged;
bool m_globalAnimationTimeChanged;
bool m_delayedLoadingChanged;
+ bool m_matteEnabledChanged;
bool m_visible;
Q3DSViewerSettings::ScaleMode m_scaleMode;
@@ -152,6 +153,7 @@ public:
QStringList m_variantList;
qint64 m_globalAnimationTime;
bool m_delayedLoading;
+ bool m_matteEnabled;
void clear(bool deleteCommandData);
int size() const { return m_size; }
diff --git a/src/api/studio3d/q3dsdatainput.cpp b/src/api/studio3d/q3dsdatainput.cpp
index a15f9fb..2a52963 100644
--- a/src/api/studio3d/q3dsdatainput.cpp
+++ b/src/api/studio3d/q3dsdatainput.cpp
@@ -38,9 +38,10 @@ QT_BEGIN_NAMESPACE
/*!
\qmltype DataInput
\instantiates Q3DSDataInput
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\brief Controls a data input entry in a Qt 3D Studio presentation.
+
This class is a convenience class for controlling a data input in a presentation.
DataInput provides a clean contract between the presentation design and the code.
It hides the presentation details from the code while providing a contractual access
@@ -49,11 +50,40 @@ QT_BEGIN_NAMESPACE
multiple aspects of the design (e.g. DataInput for speed can change the color of
the speedometer, angle of the needle).
+ As an example:
+
+ \qml
+ Studio3D {
+ ...
+ Presentation {
+ id: presentation
+ ...
+ property string text: ""
+ DataInput {
+ name: "inputForSomeTextNode"
+ value: presentation.text
+ }
+ }
+ }
+
+ Button {
+ onClicked: presentation.text = "Hello World"
+ }
+ \endqml
+
+ The example assumes that a data input connection was made in Qt 3D Studio
+ presentation using Qt 3D Studio editor between the \c textstring property of
+ target property and a data input name \c inputForSomeTextNode. As the value
+ is now set via a property, the full set of QML property bindings techniques
+ are available.
+
\note There is a performance cost for each registered DataInput, so try to avoid
creating unnecessary DataInputs.
- \sa Presentation, DataOutput, Presentation::slideExited, Presentation::slideEntered
- \sa Presentation::customSignalEmitted
+ \sa Presentation, DataOutput
+ \sa {QtStudio3D.OpenGL::Presentation::slideExited()}{Presentation.slideExited()}
+ \sa {QtStudio3D.OpenGL::Presentation::slideEntered()}{Presentation.slideEntered()}
+ \sa {QtStudio3D.OpenGL::Presentation::customSignalEmitted()}{Presentation.customSignalEmitted()}
*/
/*!
@@ -82,6 +112,10 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \dontdocument QMetaTypeId
+*/
+
+/*!
\internal
*/
Q3DSDataInput::Q3DSDataInput(QObject *parent)
@@ -101,6 +135,8 @@ Q3DSDataInput::Q3DSDataInput(const QString &name, QObject *parent)
}
/*!
+ \fn Q3DSDataInput::Q3DSDataInput(Q3DSPresentation *presentation, const QString &name, QObject *parent)
+
Constructs a Q3DSDataInput instance and initializes the \a name. The
constructed instance is automatically associated with the specified \a
presentation. An optional \a parent object can be specified.
@@ -257,6 +293,8 @@ bool Q3DSDataInput::isValid() const
}
/*!
+ \qmlmethod string DataInput::metadata(string key)
+
Returns the metadata defined for this datainput with metadata \a key.
Metadata is user-defined key-value table that can be used, for example, to better describe the
@@ -265,8 +303,8 @@ bool Q3DSDataInput::isValid() const
\note Datainput metadata is read-only.
*/
+
/*!
- \qmlmethod string DataInput::metadata
Returns the metadata defined for this datainput with metadata \a key.
Metadata is user-defined key-value table that can be used, for example, to better describe the
@@ -290,13 +328,6 @@ QString Q3DSDataInput::metadata(const QString &key) const
\sa metadata
*/
-/*!
- \qmlmethod var DataInput::metadataKeys
- Returns the metadata keys defined for this datainput.
-
- \note Datainput metadata is read-only.
- \sa metadata
- */
QStringList Q3DSDataInput::metadataKeys() const
{
if (!d_ptr->m_presentation)
@@ -360,50 +391,6 @@ void Q3DSDataInputPrivate::setCommandQueue(CommandQueue *queue)
setValue(m_value);
}
-
-/*!
- \qmltype DataInput
- \instantiates Q3DSDataInput
- \inqmlmodule QtStudio3D
- \ingroup OpenGLRuntime
-
- \brief Controls a data input entry in a Qt 3D Studio presentation.
-
- This type is a convenience for controlling a data in a presentation. Its functionality is
- equivalent to \c{Presentation::setDataInputValue()}, however it has a big advantage
- of being able to use QML property bindings, thus avoiding the need to having to resort
- to a JavaScript function call for every value change.
-
- As an example:
-
- \qml
- Studio3D {
- ...
- Presentation {
- id: presentation
- ...
- property string text: ""
- DataInput {
- name: "inputForSomeTextNode"
- value: presentation.text
- }
- }
- }
-
- Button {
- onClicked: presentation.text = "Hello World"
- }
- \endqml
-
- The example assumes that a data input connection was made in Qt 3D Studio
- presentation using Qt 3D Studio editor between the \c textstring property of
- target property and a data input name \c inputForSomeTextNode. As the value
- is now set via a property, the full set of QML property bindings techniques
- are available.
-
- \sa Studio3D, Presentation
-*/
-
/*!
\qmlproperty string DataInput::name
@@ -448,4 +435,12 @@ void Q3DSDataInputPrivate::setCommandQueue(CommandQueue *queue)
\note This value is read-only.
*/
+/*!
+ \qmlproperty list<string> DataInput::metadataKeys
+
+ Contains the metadata keys specified for this datainput.
+
+ \note This value is read-only.
+*/
+
QT_END_NAMESPACE
diff --git a/src/api/studio3d/q3dsdatainput.h b/src/api/studio3d/q3dsdatainput.h
index 3617dcd..3f81c65 100644
--- a/src/api/studio3d/q3dsdatainput.h
+++ b/src/api/studio3d/q3dsdatainput.h
@@ -48,6 +48,7 @@ class Q_STUDIO3D_EXPORT Q3DSDataInput : public QObject
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
Q_PROPERTY(float max READ max CONSTANT)
Q_PROPERTY(float min READ min CONSTANT)
+ Q_PROPERTY(QStringList metadataKeys READ metadataKeys CONSTANT)
public:
explicit Q3DSDataInput(QObject *parent = nullptr);
explicit Q3DSDataInput(const QString &name, QObject *parent = nullptr);
@@ -69,7 +70,7 @@ public:
bool isValid() const;
Q_INVOKABLE QString metadata(const QString &key) const;
- Q_INVOKABLE QStringList metadataKeys() const;
+ QStringList metadataKeys() const;
public Q_SLOTS:
void setName(const QString &name);
diff --git a/src/api/studio3d/q3dsdataoutput.cpp b/src/api/studio3d/q3dsdataoutput.cpp
index 3cb13a0..9ca0d03 100644
--- a/src/api/studio3d/q3dsdataoutput.cpp
+++ b/src/api/studio3d/q3dsdataoutput.cpp
@@ -34,9 +34,10 @@
/*!
\qmltype DataOutput
\instantiates Q3DSDataOutput
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\brief Provides notifications from data output entries in Qt 3D Studio presentation.
+
This class is a convenience class for listening for changes in the Qt 3D Studio
presentation attributes. DataOutput provides a clean contract between the presentation
design and the code. It hides the presentation details from the code while providing a
@@ -59,6 +60,7 @@
\inmodule OpenGLRuntime
\since Qt 3D Studio 2.4
\brief Provides notifications from data output entries in Qt 3D Studio presentation.
+
This class is a convenience class for listening for changes in the Qt 3D Studio
presentation attributes. DataOutput provides a clean contract between the presentation
design and the code. It hides the presentation details from the code while providing a
@@ -66,8 +68,8 @@
(e.g. movement of an element in the presentation due to timeline animation).
DataOutput can be attached to same attributes in the design as DataInput is, including
- presentation timeline. Only excaption is slide changes Slide changes are already notified
- through \c{Q3DSPresentation::slideEntered} and \c{Q3DSPresentation::slideExited} signals.
+ presentation timeline. Only exception is slide changes (slide changes are already notified
+ through \c{Q3DSPresentation::slideEntered} and \c{Q3DSPresentation::slideExited} signals).
\note There is a performance cost for each registered DataOutput, so try to avoid
creating unnecessary DataOutputs.
@@ -135,7 +137,8 @@ void Q3DSDataOutput::setName(const QString &name)
}
/*!
- \qmlproperty DataOutput::value
+ \qmlproperty var DataOutput::value
+ \readonly
Contains the read-only value of the controlled data output element in the
presentation.
@@ -161,17 +164,17 @@ QVariant Q3DSDataOutput::value() const
}
/*!
- * \qmlsignal DataOutput::valueChanged
- Emitted when the value of the observed DataOutput has changed in the
- presentation.
- \param newValue The new value of the observed DataOutput.
+ \qmlsignal DataOutput::valueChanged(var newValue)
+
+ Emitted when the value of the observed DataOutput has changed to
+ \a newValue in the presentation.
*/
/*!
- \fn Q3DSDataOutput::valueChanged
- Emitted when the value of the observed DataOutput has changed in the
- presentation.
- \param newValue The new value of the observed DataOutput.
+ \fn Q3DSDataOutput::valueChanged(const QVariant &newValue)
+
+ Emitted when the value of the observed DataOutput has changed to
+ \a newValue in the presentation.
*/
/*!
diff --git a/src/api/studio3d/q3dselement.cpp b/src/api/studio3d/q3dselement.cpp
index 16ae110..5731001 100644
--- a/src/api/studio3d/q3dselement.cpp
+++ b/src/api/studio3d/q3dselement.cpp
@@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE
/*!
\qmltype Element
\instantiates Q3DSElement
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\brief Control type for elements in a Qt 3D Studio presentation.
@@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
\inmodule OpenGLRuntime
\since Qt 3D Studio 2.0
- \brief Controls a scene object (node) in a Qt 3D Studio presentation.
+ \brief Controls a scene object (element) in a Qt 3D Studio presentation.
This class is provided for backwards compatibility. We recommend using
DataInput and DataOutput APIs for contractual and clean API between
@@ -74,7 +74,7 @@ QT_BEGIN_NAMESPACE
object (such as, model, material, camera, layer) in a Qt 3D Studio
presentation.
- \sa Q3DSWidget, Q3DSSurfaceViewer, Q3DSSceneElement
+ \sa Q3DSSurfaceViewer, Q3DSSceneElement
*/
/*!
diff --git a/src/api/studio3d/q3dsgeometry.cpp b/src/api/studio3d/q3dsgeometry.cpp
index bfc66a9..f4b650a 100644
--- a/src/api/studio3d/q3dsgeometry.cpp
+++ b/src/api/studio3d/q3dsgeometry.cpp
@@ -31,51 +31,239 @@
QT_BEGIN_NAMESPACE
+/*!
+ \class Q3DSGeometry
+ \inmodule OpenGLRuntime
+ \since Qt 3D Studio 2.4
+
+ \brief Represents a mesh geometry.
+
+ This class describes the mesh geometry for dynamic mesh creation.
+ The geometry consists of a vertex buffer and an optional index buffer.
+ Geometry attributes are used to define how the data in these buffers should be interpreted.
+
+ For example, create a simple textured pyramid geometry:
+
+ \badcode
+ // A vertex in vertex buffer consists of position, normal, and texture coordinates
+ struct Vertex {
+ QVector3D position;
+ QVector3D normal;
+ QVector2D uv;
+ };
+
+ // The vertex buffer
+ QVector<Vertex> vertices;
+
+ // Creates a triangle into the vertex buffer
+ auto createTriangle = [&](const QVector3D &xyz1, const QVector2D &uv1,
+ const QVector3D &xyz2, const QVector2D &uv2,
+ const QVector3D &xyz3, const QVector2D &uv3) {
+ QVector3D n = QVector3D::crossProduct(xyz2 - xyz1, xyz3 - xyz1).normalized();
+ vertices.append({xyz1, n, uv1});
+ vertices.append({xyz2, n, uv2});
+ vertices.append({xyz3, n, uv3});
+ };
+
+ // Pyramid corner coordinates in local space
+ QVector3D xyz[5] = {{0, 0, 50}, {50, 50, -50}, {50, -50, -50}, {-50, -50, -50}, {-50, 50, -50}};
+
+ // Possible texture coordinates for triangle corners
+ QVector2D uv[4] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
+
+ // Pyramid consists of four side triangles and a bottom quad made of two triangles
+ createTriangle(xyz[0], uv[0], xyz[1], uv[1], xyz[2], uv[2]);
+ createTriangle(xyz[0], uv[0], xyz[2], uv[1], xyz[3], uv[2]);
+ createTriangle(xyz[0], uv[0], xyz[3], uv[1], xyz[4], uv[2]);
+ createTriangle(xyz[0], uv[0], xyz[4], uv[1], xyz[1], uv[2]);
+ createTriangle(xyz[1], uv[0], xyz[4], uv[2], xyz[3], uv[1]);
+ createTriangle(xyz[1], uv[0], xyz[3], uv[3], xyz[2], uv[2]);
+
+ // Make a byte array out of the vertex buffer
+ QByteArray vertexBuffer(reinterpret_cast<const char *>(vertices.constData()),
+ vertices.size() * int(sizeof(Vertex)));
+
+ // Create the geometry. Triangle is the default primitive type, so we don't specify it.
+ // The order of the added attributes must match the order of the attribute data in the
+ // vertex buffer.
+ Q3DSGeometry pyramid;
+ pyramid.setVertexData(vertexBuffer);
+ pyramid.addAttribute(Q3DSGeometry::Attribute::PositionSemantic);
+ pyramid.addAttribute(Q3DSGeometry::Attribute::NormalSemantic);
+ pyramid.addAttribute(Q3DSGeometry::Attribute::TexCoordSemantic);
+ \endcode
+
+ \sa Q3DSPresentation::createMesh
+ */
+
+/*!
+ \enum Q3DSGeometry::PrimitiveType
+
+ This enumeration specifies the possible rendering primitives for the geometry.
+ For more information about rendering primitives and how they affect the vertex data,
+ see OpenGL documentation.
+
+ \value UnknownType Primitive type is unknown.
+ \value Points Geometry uses point primitives.
+ \value LineStrip Geometry uses line strip primitives.
+ \value LineLoop Geometry uses line loop primitives.
+ \value Lines Geometry uses line primitives.
+ \value TriangleStrip Geometry uses triangle strip primitives.
+ \value TriangleFan Geometry uses triangle fan primitives.
+ \value Triangles Geometry uses triangle primitives. This is the default primitive type.
+ \value Patches Geometry uses patch primitives.
+*/
+
+/*!
+ \enum Q3DSGeometry::Attribute::Semantic
+
+ This enumeration specifies the possible attribute semantics for the geometry.
+ The attribute semantic indicates the purpose of the attribute.
+
+ \value UnknownSemantic Attribute semantic is unknown.
+ \value IndexSemantic Attribute specifies index buffer data type.
+ \value PositionSemantic Attribute specifies vertex position attribute
+ (\c{attr_pos} in shaders).
+ Attribute has three components.
+ \value NormalSemantic Attribute specifies vertex normal attribute
+ (\c{attr_norm} in shaders).
+ Attribute has three components.
+ \value TexCoordSemantic Attribute specifies vertex texture coordinate attribute
+ (\c{attr_uv0} in shaders).
+ Attribute has two components.
+ \value TangentSemantic Attribute specifies vertex tangent attribute
+ (\c{attr_textan} in shaders).
+ Attribute has three components.
+ \value BinormalSemantic Attribute specifies vertex binormal attribute
+ (\c{attr_binormal} in shaders).
+ Attribute has three components.
+*/
+
+/*!
+ \enum Q3DSGeometry::Attribute::ComponentType
+
+ This enumeration specifies the possible attribute component types for the geometry.
+ The attribute component type indicates how the attribute component data should be interpreted.
+
+ \value DefaultType Use the default type for the attribute.
+ \value U8Type Component data is unsigned 8 bit integer.
+ \value I8Type Component data is signed 8 bit integer.
+ \value U16Type Component data is unsigned 16 bit integer.
+ \value I16Type Component data is signed 16 bit integer.
+ \value U32Type Component data is unsigned 32 bit integer.
+ Default component type for attributes with IndexSemantic.
+ \value I32Type Component data is signed 32 bit integer.
+ \value U64Type Component data is unsigned 64 bit integer.
+ \value I64Type Component data is signed 64 bit integer.
+ \value F16Type Component data is 16 bit float.
+ \value F32Type Component data is 32 bit float.
+ Default component type for attributes with a semantic other than IndexSemantic.
+ \value F64Type Component data is 64 bit float.
+*/
+
+/*!
+ Constructs a new Q3DSGeometry instance.
+ */
Q3DSGeometry::Q3DSGeometry()
: d_ptr(new Q3DSGeometryPrivate(this))
{
}
+/*!
+ Destructor.
+ */
Q3DSGeometry::~Q3DSGeometry()
{
delete d_ptr;
}
+/*!
+ Sets the vertex buffer to \a data. The \a data must contain all attribute data in interleaved
+ format. You must also add attributes to the geometry to specify how the vertex buffer
+ data should be interpreted.
+
+ \sa addAttribute
+ \sa vertexBuffer
+ */
void Q3DSGeometry::setVertexData(const QByteArray &data)
{
d_ptr->m_meshData.m_vertexBuffer = data;
}
+/*!
+ Sets the index buffer to \a data.
+ You must also add an attribute with \c IndexSemantic to the geometry.
+
+ \sa addAttribute
+ \sa indexBuffer
+ \sa Attribute::Semantic
+ */
void Q3DSGeometry::setIndexData(const QByteArray &data)
{
d_ptr->m_meshData.m_indexBuffer = data;
}
+/*!
+ Returns the currently set vertex buffer data.
+
+ \sa setVertexData
+ */
const QByteArray &Q3DSGeometry::vertexBuffer() const
{
return d_ptr->m_meshData.m_vertexBuffer;
}
+/*!
+ This is an overloaded function.
+ */
QByteArray &Q3DSGeometry::vertexBuffer()
{
return d_ptr->m_meshData.m_vertexBuffer;
}
+/*!
+ Returns the currently set index buffer data.
+
+ \sa setIndexData
+ */
const QByteArray &Q3DSGeometry::indexBuffer() const
{
return d_ptr->m_meshData.m_indexBuffer;
}
+/*!
+ This is an overloaded function.
+ */
QByteArray &Q3DSGeometry::indexBuffer()
{
return d_ptr->m_meshData.m_indexBuffer;
}
+/*!
+ Returns the number of attributes set to this geometry.
+
+ \sa addAttribute
+ */
int Q3DSGeometry::attributeCount() const
{
return d_ptr->m_meshData.m_attributeCount;
}
+/*!
+ Sets an attribute to this geometry. The geometry attributes specify how the data in vertex and
+ index buffers should be interpreted. Each attribute is composed of a \a semantic, which
+ indicates which vertex attribute this attribute refers to and \a componentType, which indicates
+ the data type of each component of the attribute data. The \a semantic also determines
+ the component count in vertex buffer for the attribute. The component count is two for
+ TexCoordSemantic and three for other vertex buffer semantics.
+ Component count for index buffer is always one.
+
+ For example, PositionSemantic specifies the vertex position in local space, so it is composed
+ of three components: x, y, and z-coordinates.
+
+ The order of addAttribute calls must match the order of the attributes in vertex data.
+ The order is relevant as it is used to calculate the offset and stride of each attribute.
+ */
void Q3DSGeometry::addAttribute(Q3DSGeometry::Attribute::Semantic semantic,
Q3DSGeometry::Attribute::ComponentType componentType)
{
@@ -98,11 +286,20 @@ void Q3DSGeometry::addAttribute(Q3DSGeometry::Attribute::Semantic semantic,
d_ptr->m_meshData.m_stride = d_ptr->getNextAttributeOffset();
}
+/*!
+ This is an overloaded function.
+ */
void Q3DSGeometry::addAttribute(const Q3DSGeometry::Attribute &att)
{
addAttribute(att.semantic, att.componentType);
}
+/*!
+ Returns an added attribute with index \a idx.
+
+ \sa addAttribute
+ \sa attributeCount
+ */
Q3DSGeometry::Attribute Q3DSGeometry::attribute(int idx) const
{
Attribute att;
@@ -113,16 +310,31 @@ Q3DSGeometry::Attribute Q3DSGeometry::attribute(int idx) const
return att;
}
+/*!
+ Returns the primitive type of this geometry.
+
+ \sa setPrimitiveType
+ */
Q3DSGeometry::PrimitiveType Q3DSGeometry::primitiveType() const
{
return static_cast<Q3DSGeometry::PrimitiveType>(d_ptr->m_meshData.m_primitiveType);
}
+/*!
+ Sets the primitive type of this geometry to \a type.
+
+ \sa primitiveType
+ */
void Q3DSGeometry::setPrimitiveType(Q3DSGeometry::PrimitiveType type)
{
d_ptr->m_meshData.m_primitiveType = static_cast<Q3DSViewer::MeshData::PrimitiveType>(type);
}
+/*!
+ Removes all added attributes and buffers and resets the geometry to an uninitialized state.
+
+ \sa primitiveType
+ */
void Q3DSGeometry::clear()
{
d_ptr->m_meshData.clear();
diff --git a/src/api/studio3d/q3dspresentation.cpp b/src/api/studio3d/q3dspresentation.cpp
index c07922c..cd9ecfa 100644
--- a/src/api/studio3d/q3dspresentation.cpp
+++ b/src/api/studio3d/q3dspresentation.cpp
@@ -79,9 +79,54 @@ QT_BEGIN_NAMESPACE
information is available regardless.
\note This class should not be instantiated directly when working with the
- C++ APIs. Q3DSSurfaceViewer and Q3DSWidget create a Q3DSPresentation
+ C++ APIs. Q3DSSurfaceViewer creates a Q3DSPresentation
instance implicitly. This can be queried via
- Q3DSSurfaceViewer::presentation() or Q3DSWidget::presentation().
+ Q3DSSurfaceViewer::presentation().
+ */
+
+/*!
+ \qmltype Presentation
+ \instantiates Q3DSPresentationItem
+ \inqmlmodule QtStudio3D.OpenGL
+ \ingroup OpenGLRuntime
+ \inherits Q3DSPresentation
+ \keyword Studio3D
+
+ \brief Represents a Qt 3D Studio presentation.
+
+ This item provides properties and methods for controlling a
+ presentation.
+
+ Qt 3D Studio supports multiple presentations in one project. There
+ is always a main presentation and zero or more
+ sub-presentations. The sub-presentations are composed into the
+ main presentations either as contents of Qt 3D Studio layers or as
+ texture maps.
+
+ In the filesystem each presentation corresponds to one \c{.uip}
+ presentation file. When present, the \c{.uia} project file ties
+ these together by specifying a name for each of the
+ (sub-)presentations and specifies which one is the main one.
+
+ The \c{.uia} project also defines \l{DataInput}s and
+ \l{DataOutput}s that are exported by the presentations.
+ \l{DataInput}s provide a way to provide input to the presentation
+ to e.g. control a timeline of a subpresentation from code.
+ \l{DataOutput}s provide a way to get notified when an attribute
+ is changed in the presentation by animation timeline,
+ by behavior scripts or by a \l{DataInput}.
+
+ The Presentation type handles child objects of the types \l Element, \l
+ SceneElement, \l DataInput, \l DataOutput, and \l SubPresentationSettings specially. These
+ will get automatically associated with the presentation and can control
+ certain aspects of it from that point on.
+
+ From the API point of view Presentation corresponds to the
+ main presentation. The source property can refer either to a
+ \c{.uia} or \c{.uip} file. When specifying a file with \c{.uip}
+ extension and a \c{.uia} is present with the same name, the
+ \c{.uia} is loaded automatically and thus sub-presentation
+ information is available regardless.
*/
/*!
@@ -299,7 +344,7 @@ Q3DSDataOutput *Q3DSPresentation::registeredDataOutput(const QString &name) cons
interface to set a datainput value using datainput name, or call Q3DSDataInput::setValue
directly for a specific datainput.
- \sa setDataInputValue
+ \sa setDataInputValue()
\sa Q3DSDataInput
*/
QVector<Q3DSDataInput *> Q3DSPresentation::dataInputs() const
@@ -327,7 +372,7 @@ QVector<Q3DSDataInput *> Q3DSPresentation::dataInputs() const
interface to set a datainput value using datainput name, or call Q3DSDataInput::setValue
directly for a specific datainput.
- \sa setDataInputValue
+ \sa setDataInputValue()
\sa Q3DSDataInput
*/
QVariantList Q3DSPresentation::getDataInputs() const
@@ -342,19 +387,19 @@ QVariantList Q3DSPresentation::getDataInputs() const
}
/*!
+ \qmlmethod var Presentation::getDataInputs(string metadataKey)
Returns a list of datainputs defined for this presentation that have the specified
\a metadataKey.
- \sa setDataInputValue
- \sa Q3DSDataInput
+ \sa DataInput
*/
/*!
- \qmlmethod var Presentation::getDataInputs
Returns a list of datainputs defined for this presentation that have the specified
\a metadataKey.
- \sa DataInput
+ \sa setDataInputValue()
+ \sa Q3DSDataInput
*/
QVariantList Q3DSPresentation::getDataInputs(const QString &metadataKey) const
{
@@ -371,7 +416,7 @@ QVariantList Q3DSPresentation::getDataInputs(const QString &metadataKey) const
Returns a list of datainputs defined for this presentation that have the specified
\a metadataKey.
- \sa setDataInputValue
+ \sa setDataInputValue()
\sa Q3DSDataInput
*/
QVector<Q3DSDataInput *> Q3DSPresentation::dataInputs(const QString &metadataKey) const
@@ -405,7 +450,7 @@ QVector<Q3DSDataOutput *> Q3DSPresentation::dataOutputs() const
\c{valueChanged()} signal in the required \l{DataOutput}s to get notified
when the value tracked by the DataOutput is changed.
- \sa SDataOutput
+ \sa Q3DSDataOutput
*/
/*!
* \brief Q3DSPresentation::getDataOutputs Returns \l{DataOutput}s.
@@ -465,16 +510,44 @@ void Q3DSPresentation::setDelayedLoading(bool enable)
}
/*!
- \qmlmethod Presentation::preloadSlide
- Preloads slide resources to memory. All resources required by the given slide will be
- loaded in the background. This function has effect only when delayed loading is enabled.
- \param elementPath
+ \qmlmethod Presentation::preloadSlide(string elementPath)
+
+ Preloads slide resources identified by \a elementPath to memory. All resources required
+ by the given slide will load in the background.
+
+ \a elementPath is the identifier of a slide in a presentation and component.
+
+ The presentation, component and slide are separated by ":", for example
+ My-presentation:Scene.Layer.Speedometer:Main-slide.
+
+ If \a elementPath does not contain any ":", then it specifies the name of a slide in the
+ main presentation and main component. If it contains one ":", it specifies component:slide
+ in the main presentation, and if it contains two ":", it
+ specifies presentation:component:slide.
+
+ If you want to indicate the main slide in a sub-presentation, you will need to specify the
+ full path. For example My-sub-presentation:Scene:Main-slide.
+
+ This function has effect only when delayed loading is enabled.
*/
/*!
- \brief Q3DSPresentation::preloadSlide
- Preloads slide resources to memory. All resources required by the given slide will be
- loaded in the background. This function has effect only when delayed loading is enabled.
- \param elementPath
+ Preloads slide resources identified by \a elementPath to memory. All resources required
+ by the given slide will load in the background.
+
+ \a elementPath is the identifier of a slide in a presentation and component.
+
+ The presentation, component and slide are separated by ":", for example
+ My-presentation:Scene.Layer.Speedometer:Main-slide.
+
+ If \a elementPath does not contain any ":", then it specifies the name of a slide in the
+ main presentation and main component. If it contains one ":", it specifies component:slide
+ in the main presentation, and if it contains two ":", it
+ specifies presentation:component:slide.
+
+ If you want to indicate the main slide in a sub-presentation, you will need to specify the
+ full path. For example My-sub-presentation:Scene:Main-slide.
+
+ This function has effect only when delayed loading is enabled.
*/
void Q3DSPresentation::preloadSlide(const QString &elementPath)
{
@@ -485,17 +558,45 @@ void Q3DSPresentation::preloadSlide(const QString &elementPath)
}
/*!
- \qmlmethod Presentation::unloadSlide
- Unloads slide resources from memory. If the slide is current, then the resources are unloaded
- when the slide is changed. This function has effect only when delayed loading is enabled.
- \param elementPath
+ \qmlmethod Presentation::unloadSlide(string elementPath)
+
+ Unloads slide resources identified by \a elementPath from memory. If the
+ slide is current, the resources are unloaded when the slide is changed.
+
+ \a elementPath is the identifier of a slide in a presentation and component.
+
+ The presentation, component and slide are separated by ":", for example
+ my-presentation:Scene.Layer.Speedometer:Main-slide.
+
+ If \a elementPath does not contain any ":", then it specifies the name of a slide in the
+ main presentation and main component. If it contains one ":", it specifies component:slide
+ in the main presentation, and if it contains two ":", it
+ specifies presentation:component:slide.
+
+ If you want to indicate the main slide in a sub-presentation, you will need to specify the
+ full path. For example My-sub-presentation:Scene:Main-slide.
+
+ This function has effect only when delayed loading is enabled.
*/
/*!
- \brief Q3DSPresentation::unloadSlide
- Unloads slide resources from memory. If the slide is current, then the resources are unloaded
- when the slide is changed. This function has effect only when delayed loading is enabled.
- \param elementPath
+ Unloads slide resources identified by \a elementPath from memory. If the
+ slide is current, the resources are unloaded when the slide is changed.
+
+ \a elementPath is the identifier of a slide in a presentation and component.
+
+ The presentation, component and slide are separated by ":", for example
+ My-presentation:speedometer:main-slide.
+
+ If \a elementPath does not contain any ":", then it specifies the name of a slide in the
+ main presentation and main component. If it contains one ":", it specifies component:slide
+ in the main presentation, and if it contains two ":", it
+ specifies presentation:Scene.Layer.Speedometer:Main-slide.
+
+ If you want to indicate the main slide in a sub-presentation, you will need to specify the
+ full path. For example My-sub-presentation:Scene:Main-slide.
+
+ This function has effect only when delayed loading is enabled.
*/
void Q3DSPresentation::unloadSlide(const QString &elementPath)
{
@@ -506,7 +607,7 @@ void Q3DSPresentation::unloadSlide(const QString &elementPath)
}
/*!
- This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ This function is for backwards compatibility. We recommend using \l{DataInput}s to control
slide changes. \l{DataInput} provides stronger contract between the design and
code as it avoids use of elementPath (a reference to design's internal structure).
@@ -531,7 +632,7 @@ void Q3DSPresentation::goToSlide(const QString &elementPath, unsigned int index)
}
/*!
- This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ This function is for backwards compatibility. We recommend using \l{DataInput}s to control
slide changes. \l{DataInput} provides stronger contract between the design and
code as it avoids use of elementPath (a reference to design's internal structure).
@@ -557,7 +658,7 @@ void Q3DSPresentation::goToSlide(const QString &elementPath, const QString &name
}
/*!
- This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ This function is for backwards compatibility. We recommend using \l{DataInput}s to control
slide changes. \l{DataInput} provides stronger contract between the design and
code as it avoids use of elementPath (a reference to design's internal structure).
@@ -584,12 +685,12 @@ void Q3DSPresentation::goToSlide(const QString &elementPath, bool next, bool wra
}
/*!
- This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ This function is for backwards compatibility. We recommend using \l{DataInput}s to control
slide changes. \l{DataInput} provides stronger contract between the design and
code as it avoids use of elementPath (a reference to design's internal structure).
Moves the timeline for a time context (a Scene or a Component element) to a
- specific position. The position is given in seconds in \a timeSeconds.
+ specific position. The position is given in seconds in \a time.
If \a elementPath points to a time context, that element is
controlled. For all other element types the time context owning
@@ -624,7 +725,7 @@ void Q3DSPresentation::goToTime(const QString &elementPath, float time)
}
/*!
- This API is for backwards compatibility. We recommend using \l{DataInput}s to control
+ This function is for backwards compatibility. We recommend using \l{DataInput}s to control
attributes in the presentation. \l{DataInput} provides stronger contract between the
design and code as it avoids use of elementPath (a reference to design's
internal structure).
@@ -778,12 +879,18 @@ void Q3DSPresentation::setDataInputValue(const QString &name, const QVariant &va
The element is ready for use once elementsCreated() signal is received for it.
- \sa createElements
- \sa createMaterial
- \sa createMesh
- \sa elementsCreated
- \sa setAttribute
- \sa dataInputs
+ \note If your application is creating and deleting a lot of elements, it is recommended that
+ you reuse previously deleted element names when creating new elements.
+ This is because the internal string table implementation of Qt 3D Studio ogl-runtime doesn't
+ support removing strings for performance reasons, so always using new unique names
+ will leak memory.
+
+ \sa createElements()
+ \sa createMaterial()
+ \sa createMesh()
+ \sa elementsCreated()
+ \sa setAttribute()
+ \sa dataInputs()
*/
void Q3DSPresentation::createElement(const QString &parentElementPath, const QString &slideName,
const QHash<QString, QVariant> &properties)
@@ -798,8 +905,8 @@ void Q3DSPresentation::createElement(const QString &parentElementPath, const QSt
specified with \a slideName. Element properties are specified in \a properties.
For more details, see createElement().
- \sa createElement
- \sa elementsCreated
+ \sa createElement()
+ \sa elementsCreated()
*/
void Q3DSPresentation::createElements(const QString &parentElementPath, const QString &slideName,
const QVector<QHash<QString, QVariant>> &properties)
@@ -820,8 +927,8 @@ void Q3DSPresentation::createElements(const QString &parentElementPath, const QS
Deleting elements is supported only for elements that have been dynamically created with
createElement() or createElements().
- \sa deleteElements
- \sa createElement
+ \sa deleteElements()
+ \sa createElement()
*/
void Q3DSPresentation::deleteElement(const QString &elementPath)
{
@@ -835,7 +942,7 @@ void Q3DSPresentation::deleteElement(const QString &elementPath)
Deleting elements is supported only for elements that have been dynamically created with
createElement() or createElements().
- \sa deleteElement
+ \sa deleteElement()
*/
void Q3DSPresentation::deleteElements(const QStringList &elementPaths)
{
@@ -852,6 +959,7 @@ void Q3DSPresentation::deleteElements(const QStringList &elementPaths)
/*!
\qmlproperty list<string> Presentation::createdElements
+ \readonly
This property contains a list of all dynamically created elements on this presentation.
@@ -859,8 +967,8 @@ void Q3DSPresentation::deleteElements(const QStringList &elementPaths)
\note Elements can only be dynamically created via C++ API.
- \sa createElement
- \sa createElements
+ \sa createElement()
+ \sa createElements()
*/
/*!
@@ -870,8 +978,8 @@ void Q3DSPresentation::deleteElements(const QStringList &elementPaths)
This property is read-only.
- \sa createElement
- \sa createElements
+ \sa createElement()
+ \sa createElements()
*/
QStringList Q3DSPresentation::createdElements() const
{
@@ -898,15 +1006,21 @@ QStringList Q3DSPresentation::createdElements() const
The material is ready for use once materialsCreated() signal is received for it.
+ \note If your application is creating and deleting a lot of materials, it is recommended that
+ you reuse previously deleted material names when creating new materials.
+ This is because the internal string table implementation of Qt 3D Studio ogl-runtime doesn't
+ support removing strings for performance reasons, so always using new unique names
+ will leak memory.
+
\note Creating materials that utilise custom shaders with mipmapped textures can in some cases
corrupt the textures on other elements if the same textures are already used by existing basic
materials in the scene, as basic materials do not create mipmaps for their textures.
Typical symptom of this is black texture on another element after creating a new element using
the custom material.
- \sa createMaterials
- \sa createElement
- \sa materialsCreated
+ \sa createMaterials()
+ \sa createElement()
+ \sa materialsCreated()
*/
void Q3DSPresentation::createMaterial(const QString &materialDefinition,
const QString &subPresId)
@@ -923,8 +1037,8 @@ void Q3DSPresentation::createMaterial(const QString &materialDefinition,
For more details, see createMaterial().
- \sa createMaterial
- \sa materialsCreated
+ \sa createMaterial()
+ \sa materialsCreated()
*/
void Q3DSPresentation::createMaterials(const QStringList &materialDefinitions,
const QString &subPresId)
@@ -947,8 +1061,8 @@ void Q3DSPresentation::createMaterials(const QStringList &materialDefinitions,
Deleting materials is supported only for materials that have been dynamically created with
createMaterial() or createMaterials().
- \sa deleteMaterials
- \sa createMaterial
+ \sa deleteMaterials()
+ \sa createMaterial()
*/
void Q3DSPresentation::deleteMaterial(const QString &materialName)
{
@@ -965,7 +1079,7 @@ void Q3DSPresentation::deleteMaterial(const QString &materialName)
Deleting materials is supported only for materials that have been dynamically created with
createMaterial() or createMaterials().
- \sa deleteMaterial
+ \sa deleteMaterial()
*/
void Q3DSPresentation::deleteMaterials(const QStringList &materialNames)
{
@@ -982,6 +1096,7 @@ void Q3DSPresentation::deleteMaterials(const QStringList &materialNames)
/*!
\qmlproperty list<string> Presentation::createdMaterials
+ \readonly
This property contains a list of all dynamically created materials on this presentation.
@@ -989,8 +1104,8 @@ void Q3DSPresentation::deleteMaterials(const QStringList &materialNames)
\note Materials can only be dynamically created via C++ API.
- \sa createMaterial
- \sa createMaterials
+ \sa createMaterial()
+ \sa createMaterials()
*/
/*!
@@ -1000,8 +1115,8 @@ void Q3DSPresentation::deleteMaterials(const QStringList &materialNames)
This property is read-only.
- \sa createMaterial
- \sa createMaterials
+ \sa createMaterial()
+ \sa createMaterials()
*/
QStringList Q3DSPresentation::createdMaterials() const
{
@@ -1014,9 +1129,9 @@ QStringList Q3DSPresentation::createdMaterials() const
The mesh is ready for use once meshesCreated() signal is received for it.
- \sa createElement
- \sa createMeshes
- \sa meshesCreated
+ \sa createElement()
+ \sa createMeshes()
+ \sa meshesCreated()
*/
void Q3DSPresentation::createMesh(const QString &meshName, const Q3DSGeometry &geometry)
{
@@ -1031,8 +1146,14 @@ void Q3DSPresentation::createMesh(const QString &meshName, const Q3DSGeometry &g
The ownership of supplied geometries stays with the caller.
- \sa createMesh
- \sa meshesCreated
+ \note If your application is creating and deleting a lot of meshes, it is recommended that
+ you reuse previously deleted mesh names when creating new materials.
+ This is because the internal string table implementation of \RUNTIME doesn't
+ support removing strings for performance reasons, so always using new unique names
+ will leak memory.
+
+ \sa createMesh()
+ \sa meshesCreated()
*/
void Q3DSPresentation::createMeshes(const QHash<QString, const Q3DSGeometry *> &meshData)
{
@@ -1058,8 +1179,8 @@ void Q3DSPresentation::createMeshes(const QHash<QString, const Q3DSGeometry *> &
Deleting meshes is supported only for meshes that have been dynamically created with
createMesh() or createMeshes().
- \sa deleteMeshes
- \sa createMesh
+ \sa deleteMeshes()
+ \sa createMesh()
*/
void Q3DSPresentation::deleteMesh(const QString &meshName)
{
@@ -1073,7 +1194,7 @@ void Q3DSPresentation::deleteMesh(const QString &meshName)
Deleting meshes is supported only for meshes that have been dynamically created with
createMesh() or createMeshes().
- \sa deleteMesh
+ \sa deleteMesh()
*/
void Q3DSPresentation::deleteMeshes(const QStringList &meshNames)
{
@@ -1090,6 +1211,7 @@ void Q3DSPresentation::deleteMeshes(const QStringList &meshNames)
/*!
\qmlproperty list<string> Presentation::createdMeshes
+ \readonly
This property contains a list of all dynamically created meshes on this presentation.
@@ -1097,8 +1219,8 @@ void Q3DSPresentation::deleteMeshes(const QStringList &meshNames)
\note Meshes can only be dynamically created via C++ API.
- \sa createMesh
- \sa createMeshes
+ \sa createMesh()
+ \sa createMeshes()
*/
/*!
@@ -1108,8 +1230,8 @@ void Q3DSPresentation::deleteMeshes(const QStringList &meshNames)
This property is read-only.
- \sa createMesh
- \sa createMeshes
+ \sa createMesh()
+ \sa createMeshes()
*/
QStringList Q3DSPresentation::createdMeshes() const
{
@@ -1213,125 +1335,171 @@ void Q3DSPresentation::keyReleaseEvent(QKeyEvent *e)
}
}
-// #TODO: QT3DS-3562 Most Presentation signals missing documentation
/*!
- * \qmlsignal Presentation::slideEntered
- * Emitted when
- * \param elementPath
- * \param index
- * \param name
+ \qmlsignal Presentation::slideEntered(string elementPath, int index, string name)
+
+ Emitted when a slide in a presentation or component is entered. \a elementPath
+ specifies the slide path. \a index and \a name contain the index and
+ the name of the entered slide.
+
+ This signal is emitted for each component, meaning that it can be emitted multiple
+ times on one slide change.
*/
/*!
- * \fn Q3DSPresentation::slideEntered
- * Emitted when
- * \param elementPath
- * \param index
- * \param name
+ \fn Q3DSPresentation::slideEntered(const QString &elementPath, unsigned int index, const QString &name)
+
+ Emitted when a slide in a presentation or component is entered. \a elementPath
+ specifies the slide path. \a index and \a name contain the index and
+ the name of the entered slide.
+
+ This signal is emitted for each component, meaning that it can be emitted multiple
+ times on one slide change.
*/
/*!
- * \qmlsignal Presentation::slideExited
- * Emitted when
- * \param elementPath
- * \param index
- * \param name
+ \qmlsignal Presentation::slideExited(string elementPath, int index, string name)
+
+ Emitted when a slide in a presentation or component is exited. \a elementPath
+ specifies the slide path. \a index and \a name contain the index and
+ the name of the exited slide.
+
+ This signal is emitted for each component, meaning that it can be emitted multiple
+ times on one slide change.
*/
/*!
- * \fn Q3DSPresentation::slideExited
- * Emitted when
- * \param elementPath
- * \param index
- * \param name
- */
+ \fn Q3DSPresentation::slideExited(const QString &elementPath, unsigned int index, const QString &name)
+
+ Emitted when a slide in a presentation or component is exited. \a elementPath
+ specifies the slide path. \a index and \a name contain the index and
+ the name of the exited slide.
+
+ This signal is emitted for each component, meaning that it can be emitted multiple
+ times on one slide change.
+*/
/*!
- * \fn Q3DSPresentation::dataInputsReady
- * Emitted when \l{DataInput}s in the Studio project have been parsed and data inputs are available
- * through dataInputs() and getDataInputs() methods.
- */
+ \fn Q3DSPresentation::dataInputsReady()
+
+ Emitted when \l{DataInput}s in the Studio project have been parsed and data inputs are available
+ through dataInputs() and getDataInputs() methods.
+*/
/*!
- * \fn Q3DSPresentation::dataOutputsReady
- * Emitted when \l{DataOutput}s in the Studio project have been parsed and data outputs are available
- * through dataOutputs() and getDataOutputs() methods.
+ \fn Q3DSPresentation::dataOutputsReady()
+
+ Emitted when \l{DataOutput}s in the Studio project have been parsed and data outputs are available
+ through dataOutputs() and getDataOutputs() methods.
*/
/*!
- * \qmlsignal Presentation::customSignalEmitted
- * Emitted when
- * \param elementPath
- * \param name
+ \qmlsignal Presentation::customSignalEmitted(string elementPath, string name)
+
+ Emitted when an action with the \c{Emit Signal}
+ handler is executed in the Qt 3D Studio presentation. \a
+ elementPath specifies \c{Target Object}, and \a name specifies \c{Signal Name}.
+
+ Connecting to this signal offers a way of reacting upon certain
+ events in the Qt 3D Studio presentation.
+
+ \image customsignal.png
+
+ In this example, pressing or tapping on the Cluster object will result in
+ emitting \c{customSignalEmitted("Cluster", "clusterPressed")}.
*/
/*!
- * \fn Q3DSPresentation::customSignalEmitted
- * Emitted when
- * \param elementPath
- * \param name
+ \fn Q3DSPresentation::customSignalEmitted(const QString &elementPath, const QString &name)
+
+ Emitted when an action with the \c{Emit Signal}
+ handler is executed in the Qt 3D Studio presentation. \a
+ elementPath specifies \c{Target Object}, and \a name specifies \c{Signal Name}.
+
+ Connecting to this signal offers a way of reacting upon certain
+ events in the Qt 3D Studio presentation.
+
+ \image customsignal.png
+
+ In this example, pressing or tapping on the Cluster object will result in
+ emitting \c{customSignalEmitted("Cluster", "clusterPressed")}.
*/
/*!
- \qmlsignal Presentation::elementsCreated
+ \qmlsignal Presentation::elementsCreated(list<string> elementPaths, string error)
+
Emitted when one or more elements have been created in response to createElement()
or createElements() calls. The \a elementPaths list contains the element paths of the created
- elements. If creation failed, \a error string indicates the reason.
+ elements.
+
+ If creation failed, \a error string indicates the reason.
- \sa createElement
- \sa createElements
+ \sa createElement()
+ \sa createElements()
*/
/*!
- \fn Q3DSPresentation::elementsCreated
+ \fn Q3DSPresentation::elementsCreated(const QStringList &elementPaths, const QString &error)
+
Emitted when one or more elements have been created in response to createElement()
or createElements() calls. The \a elementPaths list contains the element paths of the created
elements. If creation failed, \a error string indicates the reason.
- \sa createElement
- \sa createElements
+ \sa createElement()
+ \sa createElements()
*/
/*!
- \qmlsignal Presentation::materialsCreated
+ \qmlsignal Presentation::materialsCreated(list<string> materialNames, string error)
+
Emitted when one or more materials have been created in response to createMaterial()
or createMaterials() calls. The \a materialNames list contains the names of the created
materials. If the material is created into a subpresentation, the name is prefixed with
subpresentation ID followed by a colon.
+
If creation failed, \a error string indicates the reason.
- \sa createMaterial
- \sa createMaterials
+ \sa createMaterial()
+ \sa createMaterials()
*/
/*!
- \fn Q3DSPresentation::materialsCreated
+ \fn Q3DSPresentation::materialsCreated(const QStringList &materialNames, const QString &error)
+
Emitted when one or more materials have been created in response to createMaterial()
or createMaterials() calls. The \a materialNames list contains the names of the created
- materials. If creation failed, \a error string indicates the reason.
+ materials.
+
+ If creation failed, \a error string indicates the reason.
- \sa createMaterial
- \sa createMaterials
+ \sa createMaterial()
+ \sa createMaterials()
*/
/*!
- \qmlsignal Presentation::meshesCreated
+ \qmlsignal Presentation::meshesCreated(list<string> meshNames, string error)
+
Emitted when one or more meshes have been created in response to createMesh()
or createMeshes() calls. The \a meshNames list contains the names of the created
- meshes. If creation failed, \a error string indicates the reason.
+ meshes.
+
+ If creation failed, \a error string indicates the reason.
- \sa createMesh
- \sa createMeshes
+ \sa createMesh()
+ \sa createMeshes()
*/
/*!
- \fn Q3DSPresentation::meshesCreated
+ \fn Q3DSPresentation::meshesCreated(const QStringList &meshNames, const QString &error)
+
Emitted when one or more meshes have been created in response to createMesh()
or createMeshes() calls. The \a meshNames list contains the names of the created
- meshes. If creation failed, \a error string indicates the reason.
+ meshes.
+
+ If creation failed, \a error string indicates the reason.
- \sa createMesh
- \sa createMeshes
+ \sa createMesh()
+ \sa createMeshes()
*/
/*!
diff --git a/src/api/studio3d/q3dssceneelement.cpp b/src/api/studio3d/q3dssceneelement.cpp
index 3f860d6..8de03eb 100644
--- a/src/api/studio3d/q3dssceneelement.cpp
+++ b/src/api/studio3d/q3dssceneelement.cpp
@@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE
/*!
\qmltype SceneElement
\instantiates Q3DSSceneElement
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\brief Controls the special Scene or Component scene objects in a Qt 3D
Studio presentation.
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
\note The functionality of Q3DSSceneElement is equivalent to
Q3DSPresentation::goToTime() and Q3DSPresentation::goToSlide().
- \sa Q3DSPresentation, Q3DSWidget, Q3DSSurfaceViewer, Q3DSElement
+ \sa Q3DSPresentation, Q3DSSurfaceViewer, Q3DSElement
*/
/*!
@@ -156,11 +156,10 @@ void Q3DSSceneElement::setCurrentSlideIndex(int currentSlideIndex)
}
/*!
- \property int SceneElement::previousSlideIndex
+ \qmlproperty int SceneElement::previousSlideIndex
+ \readonly
Holds the index of the previously active slide of the tracked time context.
-
- Note: This property is read-only.
*/
/*!
\property Q3DSSceneElement::previousSlideIndex
@@ -224,11 +223,10 @@ void Q3DSSceneElement::setCurrentSlideName(const QString &currentSlideName)
}
/*!
- \qmlmproperty string SceneElement::previousSlideName
+ \qmlproperty string SceneElement::previousSlideName
+ \readonly
Holds the name of the previously active slide of the tracked time context.
-
- Note: This property is read-only.
*/
/*!
\property Q3DSSceneElement::previousSlideName
@@ -257,7 +255,7 @@ void Q3DSSceneElement::goToSlide(bool next, bool wrap)
/*!
Moves the timeline for a time context (a Scene or a Component element) to a
- specific position. The position is given in seconds in \a timeSeconds.
+ specific position. The position is given in seconds in \a time.
*/
void Q3DSSceneElement::goToTime(float time)
{
diff --git a/src/api/studio3d/q3dssurfaceviewer.cpp b/src/api/studio3d/q3dssurfaceviewer.cpp
index 32ffb99..899d771 100644
--- a/src/api/studio3d/q3dssurfaceviewer.cpp
+++ b/src/api/studio3d/q3dssurfaceviewer.cpp
@@ -94,7 +94,6 @@ QT_BEGIN_NAMESPACE
}
\endcode
- \sa Q3DSWidget
*/
/*!
@@ -259,8 +258,6 @@ bool Q3DSSurfaceViewer::isRunning() const
return d_ptr->m_viewerApp != nullptr;
}
-// #TODO QT3DS-3534
-
/*!
\property Q3DSSurfaceViewer::presentationId
*/
diff --git a/src/api/studio3d/q3dsviewersettings.cpp b/src/api/studio3d/q3dsviewersettings.cpp
index 187729a..9403a32 100644
--- a/src/api/studio3d/q3dsviewersettings.cpp
+++ b/src/api/studio3d/q3dsviewersettings.cpp
@@ -40,11 +40,11 @@ QT_BEGIN_NAMESPACE
/*!
\qmltype ViewerSettings
\instantiates Q3DSViewerSettings
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\brief Qt 3D Studio presentation viewer settings.
- This type provides properties to define presentation independent viewer settings.
+ This type provides properties to define presentation-independent viewer settings.
\note ViewerSettings are only applicable when \l Studio3D is used in the
default mode, showing the final, composed image from the Qt 3D Studio
@@ -60,13 +60,12 @@ QT_BEGIN_NAMESPACE
\brief Qt 3D Studio presentation viewer settings.
- Q3DSViewerSettings provides properties to define presentation independent
+ Q3DSViewerSettings provides properties to define presentation-independent
viewer settings.
\note This class should not be instantiated directly when working with the
- C++ APIs. Q3DSSurfaceViewer and Q3DSWidget create a Q3DSViewerSettings
- instance implicitly. This can be queried via Q3DSSurfaceViewer::settings()
- or Q3DSWidget::settings().
+ C++ APIs. Q3DSSurfaceViewer creates a Q3DSViewerSettings
+ instance implicitly. This can be queried via Q3DSSurfaceViewer::settings().
*/
/*!
@@ -156,11 +155,15 @@ void Q3DSViewerSettings::setShowRenderStats(bool show)
}
}
-/*!
- \qmlproperty ViewerSettings::shadeMode
+/*
+ //! TODO
+ \internal
+ \qmlproperty enumeration ViewerSettings::shadeMode
*/
-/*!
+/*
+ // TODO
+ \internal
\property Q3DSViewerSettings::shadeMode
*/
Q3DSViewerSettings::ShadeMode Q3DSViewerSettings::shadeMode() const
@@ -226,20 +229,49 @@ void Q3DSViewerSettings::setScaleMode(Q3DSViewerSettings::ScaleMode mode)
}
/*!
- \qmmlmethod ViewerSettings::save
+ \qmlproperty bool ViewerSettings::matteEnabled
+
+ Specifies if the empty area around the presentation (applicable when
+ scaleMode is set to ScaleModeCenter or ScaleModeFit) should be filled with
+ a custom color.
+
+ The default value is \c false.
+ */
+/*!
+ \property Q3DSViewerSettings::matteEnabled
+
+ Specifies if the empty area around the presentation (applicable when
+ scaleMode is set to ScaleModeCenter or ScaleModeFit) should be filled with
+ a custom color.
+
+ The default value is \c false.
+
+ \sa matteColor
+ */
+bool Q3DSViewerSettings::matteEnabled() const
+{
+ return d_ptr->m_matteEnabled;
+}
+
+void Q3DSViewerSettings::setMatteEnabled(bool enabled)
+{
+ if (d_ptr->m_matteEnabled != enabled) {
+ d_ptr->setMatteEnabled(enabled);
+ Q_EMIT matteEnabledChanged(enabled);
+ }
+}
+
+
+/*!
+ \qmlmethod ViewerSettings::save(string group, string organization, string application)
+
Persistently saves the viewer \l{QSettings}{settings} using \a group, \a organization and
\a application.
- \param group
- \param organization
- \param application
*/
+
/*!
- * \brief Q3DSViewerSettings::save Persistently saves the viewer \l{QSettings}{settings}
Persistently saves the viewer \l{QSettings}{settings} using \a group, \a organization and
\a application.
- \param group
- \param organization
- \param application
*/
void Q3DSViewerSettings::save(const QString &group, const QString &organization,
const QString &application)
@@ -248,20 +280,14 @@ void Q3DSViewerSettings::save(const QString &group, const QString &organization,
}
/*!
- \qmlmethod ViewerSettings::load
+ \qmlmethod ViewerSettings::load(string group, string organization, string application)
Loads previously saved viewer \l{QSettings}{settings} using \a group, \a organization and
\a application.
- \param group
- \param organization
- \param application
*/
+
/*!
- * \brief Q3DSViewerSettings::load Loads previously saved viewer \l{QSettings}{settings}
Loads previously saved viewer \l{QSettings}{settings} using \a group, \a organization and
\a application.
- \param group
- \param organization
- \param application
*/
void Q3DSViewerSettings::load(const QString &group, const QString &organization,
const QString &application)
@@ -276,6 +302,7 @@ Q3DSViewerSettingsPrivate::Q3DSViewerSettingsPrivate(Q3DSViewerSettings *q)
, m_commandQueue(nullptr)
, m_matteColor(Qt::black)
, m_showRenderStats(false)
+ , m_matteEnabled(false)
, m_shadeMode(Q3DSViewerSettings::ShadeModeShaded)
, m_scaleMode(Q3DSViewerSettings::ScaleModeCenter)
, m_savedSettings(nullptr)
@@ -290,6 +317,7 @@ void Q3DSViewerSettingsPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app)
{
m_viewerApp = app;
if (m_viewerApp) {
+ setMatteEnabled(m_matteEnabled);
setMatteColor(m_matteColor);
setShowRenderStats(m_showRenderStats);
setShadeMode(m_shadeMode);
@@ -301,6 +329,7 @@ void Q3DSViewerSettingsPrivate::setCommandQueue(CommandQueue *queue)
{
m_commandQueue = queue;
if (m_commandQueue) {
+ setMatteEnabled(m_matteEnabled);
setMatteColor(m_matteColor);
setShowRenderStats(m_showRenderStats);
setShadeMode(m_shadeMode);
@@ -317,6 +346,7 @@ void Q3DSViewerSettingsPrivate::save(const QString &group, const QString &organi
m_savedSettings->setValue(QStringLiteral("showRenderStats"), m_showRenderStats);
m_savedSettings->setValue(QStringLiteral("shadeMode"), m_shadeMode);
m_savedSettings->setValue(QStringLiteral("scaleMode"), m_scaleMode);
+ m_savedSettings->setValue(QStringLiteral("matteEnabled"), m_matteEnabled);
}
void Q3DSViewerSettingsPrivate::load(const QString &group, const QString &organization,
@@ -330,6 +360,7 @@ void Q3DSViewerSettingsPrivate::load(const QString &group, const QString &organi
m_savedSettings->value(QStringLiteral("shadeMode")).toInt()));
q_ptr->setScaleMode(Q3DSViewerSettings::ScaleMode(
m_savedSettings->value(QStringLiteral("scaleMode")).toInt()));
+ q_ptr->setMatteEnabled(m_savedSettings->value(QStringLiteral("matteEnabled")).toBool());
}
void Q3DSViewerSettingsPrivate::setMatteColor(const QColor &color)
@@ -343,6 +374,17 @@ void Q3DSViewerSettingsPrivate::setMatteColor(const QColor &color)
}
}
+void Q3DSViewerSettingsPrivate::setMatteEnabled(bool enabled)
+{
+ m_matteEnabled = enabled;
+ if (m_viewerApp) {
+ m_viewerApp->setMatteColor(enabled);
+ } else if (m_commandQueue) {
+ m_commandQueue->m_matteEnabled = enabled;
+ m_commandQueue->m_matteEnabledChanged = true;
+ }
+}
+
void Q3DSViewerSettingsPrivate::setShowRenderStats(bool show)
{
m_showRenderStats = show;
diff --git a/src/api/studio3d/q3dsviewersettings.h b/src/api/studio3d/q3dsviewersettings.h
index 5d7abf6..7199e1c 100644
--- a/src/api/studio3d/q3dsviewersettings.h
+++ b/src/api/studio3d/q3dsviewersettings.h
@@ -45,9 +45,7 @@ class Q_STUDIO3D_EXPORT Q3DSViewerSettings : public QObject
Q_ENUMS(ShadeMode)
Q_ENUMS(ScaleMode)
-// #TODO: QT3DS-3542 Q3DSViewerSettings API is missing property matteEnabled compared to 2.3
-// Q_PROPERTY(bool matteEnabled READ matteEnabled WRITE setMatteEnabled NOTIFY matteEnabledChanged)
-
+ Q_PROPERTY(bool matteEnabled READ matteEnabled WRITE setMatteEnabled NOTIFY matteEnabledChanged)
Q_PROPERTY(QColor matteColor READ matteColor WRITE setMatteColor NOTIFY matteColorChanged)
Q_PROPERTY(bool showRenderStats READ isShowRenderStats WRITE setShowRenderStats NOTIFY showRenderStatsChanged)
Q_PROPERTY(ScaleMode scaleMode READ scaleMode WRITE setScaleMode NOTIFY scaleModeChanged)
@@ -67,6 +65,7 @@ public:
explicit Q3DSViewerSettings(QObject *parent = nullptr);
~Q3DSViewerSettings();
+ bool matteEnabled() const;
QColor matteColor() const;
bool isShowRenderStats() const;
ScaleMode scaleMode() const;
@@ -77,11 +76,13 @@ public:
const QString &application = QString());
public Q_SLOTS:
+ void setMatteEnabled(bool enabled);
void setMatteColor(const QColor &color);
void setShowRenderStats(bool show);
void setScaleMode(ScaleMode mode);
Q_SIGNALS:
+ void matteEnabledChanged(bool enabled);
void matteColorChanged(const QColor &color);
void showRenderStatsChanged(bool show);
void shadeModeChanged(ShadeMode mode);
diff --git a/src/api/studio3d/q3dsviewersettings_p.h b/src/api/studio3d/q3dsviewersettings_p.h
index 48fbae3..4628241 100644
--- a/src/api/studio3d/q3dsviewersettings_p.h
+++ b/src/api/studio3d/q3dsviewersettings_p.h
@@ -62,6 +62,7 @@ public:
void save(const QString &group, const QString &organization, const QString &application);
void load(const QString &group, const QString &organization, const QString &application);
+ void setMatteEnabled(bool enabled);
void setMatteColor(const QColor &color);
void setShowRenderStats(bool show);
void setShadeMode(Q3DSViewerSettings::ShadeMode mode);
@@ -78,6 +79,7 @@ private:
CommandQueue *m_commandQueue; // Not owned
QColor m_matteColor;
bool m_showRenderStats;
+ bool m_matteEnabled;
Q3DSViewerSettings::ShadeMode m_shadeMode;
Q3DSViewerSettings::ScaleMode m_scaleMode;
QSettings *m_savedSettings;
diff --git a/src/api/studio3d/studio3d.pro b/src/api/studio3d/studio3d.pro
index 8b9fbb0..6749a57 100644
--- a/src/api/studio3d/studio3d.pro
+++ b/src/api/studio3d/studio3d.pro
@@ -3,6 +3,8 @@ TARGET = QtStudio3D
include($$PWD/../../commoninclude.pri)
QT += opengl widgets qml
+include($$PWD/doc/doc.pri)
+
qtHaveModule(multimedia) {
DEFINES += PLATFORM_HAS_QT_MULTIMEDIA_LIB
QT += multimedia
diff --git a/src/api/studio3dqml/plugins.qmltypes b/src/api/studio3dqml/plugins.qmltypes
new file mode 100644
index 0000000..bb8f052
--- /dev/null
+++ b/src/api/studio3dqml/plugins.qmltypes
@@ -0,0 +1,438 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtStudio3D.OpenGL 2.4'
+
+Module {
+ dependencies: ["QtQuick 2.12"]
+ Component {
+ name: "Q3DSDataInput"
+ prototype: "QObject"
+ exports: ["QtStudio3D.OpenGL/DataInput 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "name"; type: "string" }
+ Property { name: "value"; type: "QVariant" }
+ Property { name: "max"; type: "float"; isReadonly: true }
+ Property { name: "min"; type: "float"; isReadonly: true }
+ Property { name: "metadataKeys"; type: "QStringList"; isReadonly: true }
+ Method {
+ name: "setName"
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "setValue"
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "metadata"
+ type: "string"
+ Parameter { name: "key"; type: "string" }
+ }
+ }
+ Component {
+ name: "Q3DSDataOutput"
+ prototype: "QObject"
+ exports: ["QtStudio3D.OpenGL/DataOutput 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "name"; type: "string" }
+ Property { name: "value"; type: "QVariant"; isReadonly: true }
+ Signal {
+ name: "nameChanged"
+ Parameter { name: "newName"; type: "string" }
+ }
+ Signal {
+ name: "valueChanged"
+ Parameter { name: "newValue"; type: "QVariant" }
+ }
+ Method {
+ name: "setName"
+ Parameter { name: "name"; type: "string" }
+ }
+ }
+ Component {
+ name: "Q3DSElement"
+ prototype: "QObject"
+ exports: ["QtStudio3D.OpenGL/Element 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "elementPath"; type: "string" }
+ Signal {
+ name: "elementPathChanged"
+ Parameter { name: "elementPath"; type: "string" }
+ }
+ Method {
+ name: "setElementPath"
+ Parameter { name: "elementPath"; type: "string" }
+ }
+ Method {
+ name: "setAttribute"
+ Parameter { name: "attributeName"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "fireEvent"
+ Parameter { name: "eventName"; type: "string" }
+ }
+ }
+ Component {
+ name: "Q3DSPresentation"
+ prototype: "QObject"
+ Property { name: "source"; type: "QUrl" }
+ Property { name: "variantList"; type: "QStringList" }
+ Property { name: "delayedLoading"; type: "bool" }
+ Property { name: "createdElements"; type: "QStringList"; isReadonly: true }
+ Property { name: "createdMaterials"; type: "QStringList"; isReadonly: true }
+ Property { name: "createdMeshes"; type: "QStringList"; isReadonly: true }
+ Signal {
+ name: "variantListChanged"
+ Parameter { name: "variantList"; type: "QStringList" }
+ }
+ Signal {
+ name: "sourceChanged"
+ Parameter { name: "source"; type: "QUrl" }
+ }
+ Signal {
+ name: "slideEntered"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "index"; type: "uint" }
+ Parameter { name: "name"; type: "string" }
+ }
+ Signal {
+ name: "slideExited"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "index"; type: "uint" }
+ Parameter { name: "name"; type: "string" }
+ }
+ Signal { name: "dataInputsReady" }
+ Signal { name: "dataOutputsReady" }
+ Signal {
+ name: "customSignalEmitted"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "name"; type: "string" }
+ }
+ Signal {
+ name: "delayedLoadingChanged"
+ Parameter { name: "enable"; type: "bool" }
+ }
+ Signal {
+ name: "elementsCreated"
+ Parameter { name: "elementPaths"; type: "QStringList" }
+ Parameter { name: "error"; type: "string" }
+ }
+ Signal {
+ name: "materialsCreated"
+ Parameter { name: "materialNames"; type: "QStringList" }
+ Parameter { name: "error"; type: "string" }
+ }
+ Signal {
+ name: "meshesCreated"
+ Parameter { name: "meshNames"; type: "QStringList" }
+ Parameter { name: "error"; type: "string" }
+ }
+ Method {
+ name: "setSource"
+ Parameter { name: "source"; type: "QUrl" }
+ }
+ Method {
+ name: "setVariantList"
+ Parameter { name: "variantList"; type: "QStringList" }
+ }
+ Method {
+ name: "goToSlide"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "index"; type: "uint" }
+ }
+ Method {
+ name: "goToSlide"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "goToSlide"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "next"; type: "bool" }
+ Parameter { name: "wrap"; type: "bool" }
+ }
+ Method {
+ name: "goToTime"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "time"; type: "float" }
+ }
+ Method {
+ name: "setAttribute"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "attributeName"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method {
+ name: "setPresentationActive"
+ Parameter { name: "id"; type: "string" }
+ Parameter { name: "active"; type: "bool" }
+ }
+ Method {
+ name: "fireEvent"
+ Parameter { name: "elementPath"; type: "string" }
+ Parameter { name: "eventName"; type: "string" }
+ }
+ Method {
+ name: "setGlobalAnimationTime"
+ Parameter { name: "milliseconds"; type: "qlonglong" }
+ }
+ Method {
+ name: "setDataInputValue"
+ Parameter { name: "name"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ Parameter { name: "valueRole"; type: "Q3DSDataInput::ValueRole" }
+ }
+ Method {
+ name: "setDataInputValue"
+ Parameter { name: "name"; type: "string" }
+ Parameter { name: "value"; type: "QVariant" }
+ }
+ Method { name: "getDataInputs"; type: "QVariantList" }
+ Method {
+ name: "getDataInputs"
+ type: "QVariantList"
+ Parameter { name: "metadataKey"; type: "string" }
+ }
+ Method { name: "getDataOutputs"; type: "QVariantList" }
+ Method {
+ name: "preloadSlide"
+ Parameter { name: "elementPath"; type: "string" }
+ }
+ Method {
+ name: "unloadSlide"
+ Parameter { name: "elementPath"; type: "string" }
+ }
+ }
+ Component {
+ name: "Q3DSPresentationItem"
+ defaultProperty: "qmlChildren"
+ prototype: "Q3DSPresentation"
+ exports: ["QtStudio3D.OpenGL/Presentation 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "qmlChildren"; type: "QObject"; isList: true; isReadonly: true }
+ Method {
+ name: "appendQmlChildren"
+ Parameter { name: "list"; type: "QObject"; isList: true; isPointer: true }
+ Parameter { name: "obj"; type: "QObject"; isPointer: true }
+ }
+ }
+ Component {
+ name: "Q3DSQmlStream"
+ defaultProperty: "item"
+ prototype: "QObject"
+ exports: ["QtStudio3D.OpenGL/QmlStream 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "presentationId"; type: "string" }
+ Property { name: "item"; type: "QQuickItem"; isPointer: true }
+ Signal {
+ name: "presentationIdChanged"
+ Parameter { name: "presentationId"; type: "string" }
+ }
+ Signal {
+ name: "itemChanged"
+ Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
+ }
+ Method {
+ name: "setPresentationId"
+ Parameter { name: "presentationId"; type: "string" }
+ }
+ Method {
+ name: "setItem"
+ Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
+ }
+ }
+ Component {
+ name: "Q3DSSceneElement"
+ prototype: "Q3DSElement"
+ exports: ["QtStudio3D.OpenGL/SceneElement 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "currentSlideIndex"; type: "int" }
+ Property { name: "previousSlideIndex"; type: "int"; isReadonly: true }
+ Property { name: "currentSlideName"; type: "string" }
+ Property { name: "previousSlideName"; type: "string"; isReadonly: true }
+ Signal {
+ name: "currentSlideIndexChanged"
+ Parameter { name: "currentSlideIndex"; type: "int" }
+ }
+ Signal {
+ name: "previousSlideIndexChanged"
+ Parameter { name: "previousSlideIndex"; type: "int" }
+ }
+ Signal {
+ name: "currentSlideNameChanged"
+ Parameter { name: "currentSlideName"; type: "string" }
+ }
+ Signal {
+ name: "previousSlideNameChanged"
+ Parameter { name: "previousSlideName"; type: "string" }
+ }
+ Method {
+ name: "setCurrentSlideIndex"
+ Parameter { name: "currentSlideIndex"; type: "int" }
+ }
+ Method {
+ name: "setCurrentSlideName"
+ Parameter { name: "currentSlideName"; type: "string" }
+ }
+ Method {
+ name: "goToSlide"
+ Parameter { name: "next"; type: "bool" }
+ Parameter { name: "wrap"; type: "bool" }
+ }
+ Method {
+ name: "goToTime"
+ Parameter { name: "time"; type: "float" }
+ }
+ }
+ Component {
+ name: "Q3DSStudio3D"
+ defaultProperty: "data"
+ prototype: "QQuickFramebufferObject"
+ exports: ["QtStudio3D.OpenGL/Studio3D 2.4"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "EventIgnoreFlags"
+ values: {
+ "EnableAllEvents": 0,
+ "IgnoreMouseEvents": 1,
+ "IgnoreWheelEvents": 2,
+ "IgnoreKeyboardEvents": 4,
+ "IgnoreAllInputEvents": 7
+ }
+ }
+ Property { name: "running"; type: "bool"; isReadonly: true }
+ Property { name: "presentation"; type: "Q3DSPresentationItem"; isReadonly: true; isPointer: true }
+ Property { name: "viewerSettings"; type: "Q3DSViewerSettings"; isReadonly: true; isPointer: true }
+ Property { name: "error"; type: "string"; isReadonly: true }
+ Property { name: "ignoredEvents"; type: "EventIgnoreFlags" }
+ Signal { name: "frameUpdate" }
+ Signal {
+ name: "runningChanged"
+ Parameter { name: "initialized"; type: "bool" }
+ }
+ Signal {
+ name: "errorChanged"
+ Parameter { name: "error"; type: "string" }
+ }
+ Signal { name: "presentationReady" }
+ Signal { name: "presentationLoaded" }
+ Method { name: "reset" }
+ }
+ Component {
+ name: "Q3DSSubPresentationSettings"
+ prototype: "QObject"
+ exports: ["QtStudio3D.OpenGL/SubPresentationSettings 2.4"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "qmlStreams"; type: "Q3DSQmlStream"; isList: true; isReadonly: true }
+ }
+ Component {
+ name: "Q3DSViewerSettings"
+ prototype: "QObject"
+ exports: ["QtStudio3D.OpenGL/ViewerSettings 2.4"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "ShadeMode"
+ values: {
+ "ShadeModeShaded": 0,
+ "ShadeModeShadedWireframe": 1
+ }
+ }
+ Enum {
+ name: "ScaleMode"
+ values: {
+ "ScaleModeFit": 0,
+ "ScaleModeFill": 1,
+ "ScaleModeCenter": 2
+ }
+ }
+ Property { name: "matteEnabled"; type: "bool" }
+ Property { name: "matteColor"; type: "QColor" }
+ Property { name: "showRenderStats"; type: "bool" }
+ Property { name: "scaleMode"; type: "ScaleMode" }
+ Signal {
+ name: "matteEnabledChanged"
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ Signal {
+ name: "matteColorChanged"
+ Parameter { name: "color"; type: "QColor" }
+ }
+ Signal {
+ name: "showRenderStatsChanged"
+ Parameter { name: "show"; type: "bool" }
+ }
+ Signal {
+ name: "shadeModeChanged"
+ Parameter { name: "mode"; type: "ShadeMode" }
+ }
+ Signal {
+ name: "scaleModeChanged"
+ Parameter { name: "mode"; type: "ScaleMode" }
+ }
+ Method {
+ name: "setMatteEnabled"
+ Parameter { name: "enabled"; type: "bool" }
+ }
+ Method {
+ name: "setMatteColor"
+ Parameter { name: "color"; type: "QColor" }
+ }
+ Method {
+ name: "setShowRenderStats"
+ Parameter { name: "show"; type: "bool" }
+ }
+ Method {
+ name: "setScaleMode"
+ Parameter { name: "mode"; type: "ScaleMode" }
+ }
+ Method {
+ name: "save"
+ Parameter { name: "group"; type: "string" }
+ Parameter { name: "organization"; type: "string" }
+ Parameter { name: "application"; type: "string" }
+ }
+ Method {
+ name: "save"
+ Parameter { name: "group"; type: "string" }
+ Parameter { name: "organization"; type: "string" }
+ }
+ Method {
+ name: "save"
+ Parameter { name: "group"; type: "string" }
+ }
+ Method {
+ name: "load"
+ Parameter { name: "group"; type: "string" }
+ Parameter { name: "organization"; type: "string" }
+ Parameter { name: "application"; type: "string" }
+ }
+ Method {
+ name: "load"
+ Parameter { name: "group"; type: "string" }
+ Parameter { name: "organization"; type: "string" }
+ }
+ Method {
+ name: "load"
+ Parameter { name: "group"; type: "string" }
+ }
+ }
+ Component {
+ name: "QQuickFramebufferObject"
+ defaultProperty: "data"
+ prototype: "QQuickItem"
+ Property { name: "textureFollowsItemSize"; type: "bool" }
+ Property { name: "mirrorVertically"; type: "bool" }
+ Signal {
+ name: "textureFollowsItemSizeChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "mirrorVerticallyChanged"
+ Parameter { type: "bool" }
+ }
+ }
+}
diff --git a/src/api/studio3dqml/q3dspresentationitem.cpp b/src/api/studio3dqml/q3dspresentationitem.cpp
index 6372f2f..4eb7c96 100644
--- a/src/api/studio3dqml/q3dspresentationitem.cpp
+++ b/src/api/studio3dqml/q3dspresentationitem.cpp
@@ -37,50 +37,6 @@
QT_BEGIN_NAMESPACE
-/*!
- \qmltype Presentation
- \instantiates Q3DSPresentationItem
- \inqmlmodule QtStudio3D
- \ingroup OpenGLRuntime
- \inherits Q3DSPresentation
- \keyword Studio3D
-
- \brief Represents a Qt 3D Studio presentation.
-
- This item provides properties and methods for controlling a
- presentation.
-
- Qt 3D Studio supports multiple presentations in one project. There
- is always a main presentation and zero or more
- sub-presentations. The sub-presentations are composed into the
- main presentations either as contents of Qt 3D Studio layers or as
- texture maps.
-
- In the filesystem each presentation corresponds to one \c{.uip}
- presentation file. When present, the \c{.uia} project file ties
- these together by specifying a name for each of the
- (sub-)presentations and specifies which one is the main one.
-
- The \c{.uia} project also defines \l{DataInput}s and
- \l{DataOutput}s that are exported by the presentations.
- \l{DataInput}s provide a way to provide input to the presentation
- to e.g. control a timeline of a subpresentation from code.
- \l{DataOutput}s provide a way to get notified when an attribute
- is changed in the presentation by animation timeline,
- by behavior scripts or by a \l{DataInput}.
-
- The Presentation type handles child objects of the types \l Element, \l
- SceneElement, \l DataInput, and \l SubPresentationSettings specially. These
- will get automatically associated with the presentation and can control
- certain aspects of it from that point on.
-
- From the API point of view Presentation corresponds to the
- main presentation. The source property can refer either to a
- \c{.uia} or \c{.uip} file. When specifying a file with \c{.uip}
- extension and a \c{.uia} is present with the same name, the
- \c{.uia} is loaded automatically and thus sub-presentation
- information is available regardless.
- */
Q3DSPresentationItem::Q3DSPresentationItem(QObject *parent)
: Q3DSPresentation(parent)
, m_subPresentationSettings(nullptr)
diff --git a/src/api/studio3dqml/q3dsrenderer.cpp b/src/api/studio3dqml/q3dsrenderer.cpp
index 7366d6a..e3fce5c 100644
--- a/src/api/studio3dqml/q3dsrenderer.cpp
+++ b/src/api/studio3dqml/q3dsrenderer.cpp
@@ -48,7 +48,8 @@ using namespace Q3DSViewer;
QT_BEGIN_NAMESPACE
-Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor)
+Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor,
+ QElapsedTimer *startupTimer)
: m_visibleFlag(visibleFlag)
, m_initElements(false)
, m_runtime(0)
@@ -58,8 +59,9 @@ Q3DSRenderer::Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisi
, m_visitor(assetVisitor)
, m_settings(new Q3DSViewerSettings(this))
, m_presentation(new Q3DSPresentation(this))
+ , m_startupTimer(startupTimer)
{
- m_startupTimer.start();
+
}
Q3DSRenderer::~Q3DSRenderer()
@@ -170,7 +172,7 @@ void Q3DSRenderer::draw()
bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
{
- m_runtime = &Q3DSViewerApp::Create(nullptr, new Qt3DSAudioPlayerImpl(), &m_startupTimer);
+ m_runtime = &Q3DSViewerApp::Create(nullptr, new Qt3DSAudioPlayerImpl(), m_startupTimer);
Q_ASSERT(m_runtime);
// Connect presentation ready signal before initializing the app
@@ -286,6 +288,8 @@ void Q3DSRenderer::processCommands()
m_settings->setShowRenderStats(m_commands.m_showRenderStats);
if (m_commands.m_delayedLoadingChanged)
this->m_runtime->setDelayedLoading(m_commands.m_delayedLoading);
+ if (m_commands.m_matteEnabledChanged)
+ this->m_runtime->setMatteEnabled(m_commands.m_matteEnabled);
if (m_commands.m_globalAnimationTimeChanged)
m_presentation->setGlobalAnimationTime(m_commands.m_globalAnimationTime);
diff --git a/src/api/studio3dqml/q3dsrenderer_p.h b/src/api/studio3dqml/q3dsrenderer_p.h
index 6d044ff..8927f34 100644
--- a/src/api/studio3dqml/q3dsrenderer_p.h
+++ b/src/api/studio3dqml/q3dsrenderer_p.h
@@ -59,7 +59,8 @@ class Q3DSRenderer : public QObject,
Q_OBJECT
public:
- Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor);
+ Q3DSRenderer(bool visibleFlag, qt3ds::Qt3DSAssetVisitor *assetVisitor,
+ QElapsedTimer *startupTimer);
~Q3DSRenderer();
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
@@ -102,7 +103,7 @@ protected:
Q3DSViewerSettings *m_settings;
Q3DSPresentation *m_presentation;
QString m_error;
- QElapsedTimer m_startupTimer;
+ QElapsedTimer *m_startupTimer;
};
QT_END_NAMESPACE
diff --git a/src/api/studio3dqml/q3dsstudio3d.cpp b/src/api/studio3dqml/q3dsstudio3d.cpp
index 5a46089..38d32d4 100644
--- a/src/api/studio3dqml/q3dsstudio3d.cpp
+++ b/src/api/studio3dqml/q3dsstudio3d.cpp
@@ -40,13 +40,14 @@
#include <QtCore/qdebug.h>
#include <QtCore/qfileinfo.h>
#include <QtQuick/qquickwindow.h>
+#include <QtQml/qqmlcontext.h>
QT_BEGIN_NAMESPACE
/*!
\qmltype Studio3D
\instantiates Q3DSStudio3D
- \inqmlmodule QtStudio3D
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\inherits Item
\keyword Studio3D
@@ -151,6 +152,8 @@ Q3DSStudio3D::Q3DSStudio3D()
connect(this, &Q3DSStudio3D::visibleChanged, this, &Q3DSStudio3D::handleVisibleChanged);
updateEventMasks();
+ m_startupTimer.reset(new QElapsedTimer());
+ m_startupTimer->restart();
}
Q3DSStudio3D::~Q3DSStudio3D()
@@ -171,10 +174,13 @@ Q3DSPresentationItem *Q3DSStudio3D::presentation() const
return m_presentation;
}
-// #TODO: QT3DS-3566 viewerSettings is missing documentation
/*!
\qmlproperty ViewerSettings Studio3D::viewerSettings
+ Accessor for the viewerSettings. Applications are expected to create a single
+ ViewerSettings child object for Studio3D. If this is omitted, ViewerSettings
+ is created automatically.
+
This property is read-only.
*/
Q3DSViewerSettings *Q3DSStudio3D::viewerSettings() const
@@ -271,7 +277,12 @@ void Q3DSStudio3D::componentComplete()
m_presentation->d_ptr->setCommandQueue(&m_pendingCommands);
// Ensure qml stream proxy gets created on main thread
- m_presentation->d_ptr->streamProxy();
+ QQmlContext *ctx = QQmlEngine::contextForObject(this);
+ m_presentation->d_ptr->streamProxy()->setEngine(ctx->engine());
+
+ QObject::connect(m_presentation, &Q3DSPresentationItem::sourceChanged, [this]() {
+ m_startupTimer->restart();
+ });
QQuickFramebufferObject::componentComplete();
}
@@ -291,6 +302,8 @@ void Q3DSStudio3D::handleWindowChanged(QQuickWindow *window)
connect(window, &QQuickWindow::afterAnimating, this, &Q3DSStudio3D::tick);
// Call update after the frame is handled to queue another frame
connect(window, &QQuickWindow::afterSynchronizing, this, &Q3DSStudio3D::update);
+
+ reset();
}
/*!
@@ -310,9 +323,9 @@ void Q3DSStudio3D::reset()
{
// Fake a source change to trigger a reloading of the presentation
m_pendingCommands.m_sourceChanged = true;
- m_pendingCommands.m_source = m_presentation->source();
+ m_pendingCommands.m_source = m_presentation ? m_presentation->source() : QString();
m_pendingCommands.m_variantListChanged = true;
- m_pendingCommands.m_variantList = m_presentation->variantList();
+ m_pendingCommands.m_variantList = m_presentation ? m_presentation->variantList() : QStringList();
}
/*!
@@ -366,7 +379,8 @@ QQuickFramebufferObject::Renderer *Q3DSStudio3D::createRenderer() const
// It is "illegal" to create a connection between the renderer
// and the plugin, and vice-versa. The only valid time the two
// may communicate is during Q3DSRenderer::synchronize().
- Q3DSRenderer *renderer = new Q3DSRenderer(isVisible(), m_presentation->d_ptr->streamProxy());
+ Q3DSRenderer *renderer = new Q3DSRenderer(isVisible(), m_presentation->d_ptr->streamProxy(),
+ m_startupTimer.get());
connect(renderer, &Q3DSRenderer::enterSlide,
m_presentation->d_ptr, &Q3DSPresentationPrivate::handleSlideEntered);
diff --git a/src/api/studio3dqml/q3dsstudio3d_p.h b/src/api/studio3dqml/q3dsstudio3d_p.h
index eed8459..0fa91d6 100644
--- a/src/api/studio3dqml/q3dsstudio3d_p.h
+++ b/src/api/studio3dqml/q3dsstudio3d_p.h
@@ -45,6 +45,7 @@
#include <QtStudio3D/private/q3dscommandqueue_p.h>
#include <QtGui/qopenglframebufferobject.h>
#include <QtQuick/qquickframebufferobject.h>
+#include <QtCore/qelapsedtimer.h>
QT_BEGIN_NAMESPACE
@@ -128,6 +129,7 @@ protected:
CommandQueue m_pendingCommands;
qreal m_pixelRatio;
QString m_error;
+ QScopedPointer<QElapsedTimer> m_startupTimer;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSStudio3D::EventIgnoreFlags)
diff --git a/src/dm/systems/Qt3DSDMStringTable.h b/src/dm/systems/Qt3DSDMStringTable.h
index 7f1e945..fb38b0b 100644
--- a/src/dm/systems/Qt3DSDMStringTable.h
+++ b/src/dm/systems/Qt3DSDMStringTable.h
@@ -31,6 +31,7 @@
#define QT3DS_IMPORT_STRINGTABLE_H
#include <string>
+#include <memory>
#include <EABase/eabase.h>
#include "foundation/Qt3DSPreprocessor.h"
diff --git a/src/engine/Qt3DSRenderRuntimeBindingImplRenderer.cpp b/src/engine/Qt3DSRenderRuntimeBindingImplRenderer.cpp
index b41c83b..0451570 100644
--- a/src/engine/Qt3DSRenderRuntimeBindingImplRenderer.cpp
+++ b/src/engine/Qt3DSRenderRuntimeBindingImplRenderer.cpp
@@ -167,6 +167,7 @@ struct SRenderer : public Q3DStudio::ITegraApplicationRenderEngine
}
void SetMatteColor(Option<QT3DSVec4> inColor) override { m_Context->SetMatteColor(inColor); }
+ void setMatteEnabled(bool enabled) override { m_Context->setMatteEnabled(enabled); };
virtual void PushState() { m_StateStack.push_back(m_Viewport); }
virtual void PopState()
{
diff --git a/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp b/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp
index a4b3bc7..c0b72a6 100644
--- a/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp
+++ b/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp
@@ -1236,21 +1236,22 @@ struct SDynamicObjectTranslatorContext : public STranslatorContext
{
}
~SDynamicObjectTranslatorContext() {}
- void AddEffectExtendedProperty(const qt3ds::render::dynamic::SPropertyDefinition &thePropDef,
- const char *inExtension, Q3DStudio::EAttributeType inType,
- Qt3DSString &ioStringBuilder, QT3DSU32 inOffset, QT3DSU32 dataOffset)
- {
- ioStringBuilder.fromUtf8(thePropDef.m_Name.c_str());
- ioStringBuilder.append(inExtension);
- Q3DStudio::INT32 theHash = Q3DStudio::CHash::HashAttribute(
- ioStringBuilder.toUtf8().constData());
+ void AddEffectExtendedProperty(const QByteArray &baseName,
+ const QByteArray &extension, Q3DStudio::EAttributeType inType,
+ QByteArray &ioStringBuilder, QT3DSU32 inOffset,
+ QT3DSU32 dataOffset)
+ {
+ ioStringBuilder = baseName;
+ ioStringBuilder.append(extension);
+ Q3DStudio::INT32 theHash = Q3DStudio::CHash::HashAttribute(ioStringBuilder.constData());
m_PropertyHashes.insert(
eastl::make_pair(theHash, SEffectPropertyEntry(inType, inOffset, dataOffset)));
}
void BuildPropertyHashes(NVConstDataRef<qt3ds::render::dynamic::SPropertyDefinition> inProperties)
{
if (m_PropertyHashes.size() == 0) {
- qt3ds::foundation::Qt3DSString theNameBuilder;
+ QByteArray nameBuilder;
+ QByteArray baseName;
for (QT3DSU32 idx = 0, end = inProperties.size(); idx < end; ++idx) {
const qt3ds::render::dynamic::SPropertyDefinition &thePropDef = inProperties[idx];
switch (thePropDef.m_DataType) {
@@ -1276,35 +1277,62 @@ struct SDynamicObjectTranslatorContext : public STranslatorContext
}
break;
case qt3ds::render::NVRenderShaderDataTypes::QT3DSVec2:
- AddEffectExtendedProperty(thePropDef, ".x", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 0);
- AddEffectExtendedProperty(thePropDef, ".y", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, sizeof(QT3DSF32));
+ baseName = QString::fromUtf8(thePropDef.m_Name.c_str()).toUtf8();
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".x"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT, nameBuilder, idx, 0);
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".y"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT, nameBuilder, idx,
+ sizeof(QT3DSF32));
break;
case qt3ds::render::NVRenderShaderDataTypes::QT3DSVec3:
- AddEffectExtendedProperty(thePropDef, ".x", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 0);
- AddEffectExtendedProperty(thePropDef, ".y", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, sizeof(QT3DSF32));
- AddEffectExtendedProperty(thePropDef, ".z", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 2 * sizeof(QT3DSF32));
-
- AddEffectExtendedProperty(thePropDef, ".r", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 0);
- AddEffectExtendedProperty(thePropDef, ".g", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, sizeof(QT3DSF32));
- AddEffectExtendedProperty(thePropDef, ".b", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 2 * sizeof(QT3DSF32));
+ baseName = QString::fromUtf8(thePropDef.m_Name.c_str()).toUtf8();
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".x"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 0);
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".y"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, sizeof(QT3DSF32));
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".z"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 2 * sizeof(QT3DSF32));
+
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".r"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 0);
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".g"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, sizeof(QT3DSF32));
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".b"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 2 * sizeof(QT3DSF32));
break;
case qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4:
- AddEffectExtendedProperty(thePropDef, ".x", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 0);
- AddEffectExtendedProperty(thePropDef, ".y", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, sizeof(QT3DSF32));
- AddEffectExtendedProperty(thePropDef, ".z", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 2 * sizeof(QT3DSF32));
- AddEffectExtendedProperty(thePropDef, ".w", Q3DStudio::ATTRIBUTETYPE_FLOAT,
- theNameBuilder, idx, 3 * sizeof(QT3DSF32));
+ baseName = QString::fromUtf8(thePropDef.m_Name.c_str()).toUtf8();
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".x"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 0);
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".y"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, sizeof(QT3DSF32));
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".z"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 2 * sizeof(QT3DSF32));
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".w"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 3 * sizeof(QT3DSF32));
+
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".r"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 0);
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".g"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, sizeof(QT3DSF32));
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".b"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 2 * sizeof(QT3DSF32));
+ AddEffectExtendedProperty(baseName, QByteArrayLiteral(".a"),
+ Q3DStudio::ATTRIBUTETYPE_FLOAT,
+ nameBuilder, idx, 3 * sizeof(QT3DSF32));
break;
case qt3ds::render::NVRenderShaderDataTypes::NVRenderTexture2DPtr:
case qt3ds::render::NVRenderShaderDataTypes::NVRenderImage2DPtr:
diff --git a/src/engine/Qt3DSRuntimeView.cpp b/src/engine/Qt3DSRuntimeView.cpp
index c1f3b3d..90a2562 100644
--- a/src/engine/Qt3DSRuntimeView.cpp
+++ b/src/engine/Qt3DSRuntimeView.cpp
@@ -260,6 +260,7 @@ CRuntimeView::~CRuntimeView()
bool CRuntimeView::BeginLoad(const QString &sourcePath, const QStringList &variantList)
{
bool theResult = false;
+ m_startupTime = -1;
// boot up the application
BootupPreGraphicsInitObjects();
@@ -372,7 +373,7 @@ void CRuntimeView::Render()
m_Application->UpdateAndRender();
- if (m_startupTime < 0 && m_startupTimer) {
+ if (m_startupTime < 0 && m_startupTimer && m_startupTimer->isValid()) {
m_startupTime = m_startupTimer->elapsed();
m_startupTimer->invalidate();
}
diff --git a/src/engine/Qt3DSRuntimeView.h b/src/engine/Qt3DSRuntimeView.h
index 22d8cba..7d86022 100644
--- a/src/engine/Qt3DSRuntimeView.h
+++ b/src/engine/Qt3DSRuntimeView.h
@@ -143,6 +143,7 @@ public:
virtual ITegraRenderStateManager &GetTegraRenderStateManager() = 0;
virtual qt3ds::render::NVRenderContext &GetRenderContext() = 0;
virtual void SetMatteColor(qt3ds::foundation::Option<qt3ds::QT3DSVec4> inColor) = 0;
+ virtual void setMatteEnabled(bool enable) = 0;
virtual void EnableRenderRotation(bool inEnable) = 0;
virtual void SetWriteOutShaderCache(bool inWriteOutShaderCache) = 0;
virtual void Release() = 0;
diff --git a/src/foundation/Qt3DSFoundation.cpp b/src/foundation/Qt3DSFoundation.cpp
index 8687cd6..b08ca19 100644
--- a/src/foundation/Qt3DSFoundation.cpp
+++ b/src/foundation/Qt3DSFoundation.cpp
@@ -44,6 +44,15 @@
#ifdef _WIN32
#pragma warning(disable : 4996) // intentionally suppressing this warning message
#endif
+
+namespace qt3ds {
+void Qt3DSAssert(const char *exp, const char *file, int line, bool *ignore)
+{
+ Q_UNUSED(ignore)
+ qCritical() << "Assertion thrown: " << file << " " << line << " " << exp;
+}
+}
+
namespace qt3ds {
namespace foundation {
using namespace intrinsics;
diff --git a/src/foundation/Qt3DSPreprocessor.h b/src/foundation/Qt3DSPreprocessor.h
index 371d3e6..98b60c6 100644
--- a/src/foundation/Qt3DSPreprocessor.h
+++ b/src/foundation/Qt3DSPreprocessor.h
@@ -175,29 +175,20 @@ static linking
no definition - this will allow DLLs and libraries to use the exported API from PhysXCommon
*/
+#include <qglobal.h>
#if defined(QT3DS_WINDOWS) && !defined(__CUDACC__)
#if defined QT3DS_FOUNDATION_EXPORTS
-#define QT3DS_FOUNDATION_API __declspec(dllexport)
+#define QT3DS_FOUNDATION_API Q_DECL_EXPORT
#elif defined QT3DS_FOUNDATION_NO_EXPORTS
#define QT3DS_FOUNDATION_API
#else
-#define QT3DS_FOUNDATION_API __declspec(dllimport)
+#define QT3DS_FOUNDATION_API Q_DECL_IMPORT
#endif
#else
#define QT3DS_FOUNDATION_API
#endif
-
-#if defined(QT3DS_AUTOTESTS_ENABLED)
-#include <qglobal.h>
-#if defined(QT3DS_BUILDING_LIBRARY)
-#define QT3DS_AUTOTEST_EXPORT Q_DECL_EXPORT
-#else
-#define QT3DS_AUTOTEST_EXPORT Q_DECL_IMPORT
-#endif
-#else
-#define QT3DS_AUTOTEST_EXPORT
-#endif
+#define QT3DS_AUTOTEST_EXPORT QT3DS_FOUNDATION_API
/**
Calling convention
diff --git a/src/foundation/StringTable.cpp b/src/foundation/StringTable.cpp
index 47130dc..7833639 100644
--- a/src/foundation/StringTable.cpp
+++ b/src/foundation/StringTable.cpp
@@ -38,6 +38,8 @@
#include "foundation/SerializationTypes.h"
#include "foundation/Qt3DSMutex.h"
+#include <QtCore/qhash.h>
+
using namespace qt3ds;
using namespace qt3ds::foundation;
using namespace eastl;
@@ -317,6 +319,16 @@ public:
return theFind->second;
}
+ SCharAndHandle justFindStrDontRegister(SCharAndHash hashCode)
+ {
+ if (isTrivial(hashCode.m_Data))
+ return SCharAndHandle();
+ TMapType::iterator theFind = m_HashToStrMap.find(hashCode);
+ if (theFind == m_HashToStrMap.end())
+ return SCharAndHandle();
+ return theFind->second;
+ }
+
const CRegisteredString FindStr(SCharAndHash hashCode)
{
SCharAndHandle result = DoFindStr(hashCode);
@@ -527,6 +539,8 @@ struct SStringTableMutexScope
#define STRING_TABLE_MULTITHREADED_METHOD SStringTableMutexScope __locker(m_MultithreadMutex)
+static const QT3DSU32 dynHandleBase = 0x80000000;
+
class StringTable : public IStringTable
{
typedef nvhash_map<SCharAndHash, QT3DSU32> TMapType;
@@ -539,6 +553,18 @@ class StringTable : public IStringTable
TWideStr m_WideConvertBuffer;
Mutex m_MultithreadMutexBacker;
Mutex *m_MultithreadMutex;
+
+ struct DynamicString
+ {
+ QByteArray str;
+ int refCount = 0;
+ };
+
+ QHash<QT3DSU32, DynamicString *> m_dynamicFreeHandlesMap;
+ QHash<QT3DSU32, DynamicString *> m_dynamicUsedHandlesMap;
+ QHash<QByteArray, QT3DSU32> m_dynamicStringToHandleMap;
+ QT3DSU32 m_nextFreeDynamicHandle = dynHandleBase;
+
// Data that will be written out to the file.
public:
@@ -554,7 +580,11 @@ public:
{
}
- virtual ~StringTable() override {}
+ virtual ~StringTable() override
+ {
+ qDeleteAll(m_dynamicFreeHandlesMap);
+ qDeleteAll(m_dynamicUsedHandlesMap);
+ }
QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_FileData.m_Allocator.m_Allocator)
@@ -630,10 +660,59 @@ public:
return m_FileData.FindStrHandle(str);
}
+ CStringHandle getDynamicHandle(const QByteArray &str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ QT3DSU32 handle = m_dynamicStringToHandleMap.value(str, 0);
+ DynamicString *theStr = nullptr;
+
+ if (!handle) {
+ handle = m_FileData.justFindStrDontRegister(str.constData()).m_Handle;
+ if (!handle) {
+ if (m_dynamicFreeHandlesMap.isEmpty()) {
+ handle = ++m_nextFreeDynamicHandle;
+ theStr = new DynamicString;
+ } else {
+ auto first = m_dynamicFreeHandlesMap.begin();
+ handle = first.key();
+ theStr = first.value();
+ m_dynamicFreeHandlesMap.erase(first);
+ }
+ theStr->str = str;
+ m_dynamicStringToHandleMap.insert(str, handle);
+ m_dynamicUsedHandlesMap.insert(handle, theStr);
+ } else {
+ return CStringHandle::ISwearThisHasBeenRegistered(handle);
+ }
+ } else {
+ theStr = m_dynamicUsedHandlesMap.value(handle);
+ }
+ ++theStr->refCount;
+ return CStringHandle::ISwearThisHasBeenRegistered(handle);
+ }
+
+ void releaseDynamicHandle(QT3DSU32 strHandle) override
+ {
+ DynamicString *str = m_dynamicUsedHandlesMap.value(strHandle);
+ if (str) {
+ --str->refCount;
+ if (str->refCount == 0) {
+ m_dynamicUsedHandlesMap.remove(strHandle);
+ m_dynamicFreeHandlesMap.insert(strHandle, str);
+ m_dynamicStringToHandleMap.remove(str->str);
+ }
+ }
+ }
+
CRegisteredString HandleToStr(QT3DSU32 strHandle) override
{
STRING_TABLE_MULTITHREADED_METHOD;
- return m_FileData.FindStrByHandle(strHandle);
+ if (strHandle >= dynHandleBase) {
+ DynamicString *str = m_dynamicUsedHandlesMap.value(strHandle);
+ return CRegisteredString::ISwearThisHasBeenRegistered(str->str.constData());
+ } else {
+ return m_FileData.FindStrByHandle(strHandle);
+ }
}
const wchar_t *GetWideStr(CRegisteredString theStr)
diff --git a/src/foundation/StringTable.h b/src/foundation/StringTable.h
index d46c111..8f7fa84 100644
--- a/src/foundation/StringTable.h
+++ b/src/foundation/StringTable.h
@@ -248,6 +248,8 @@ namespace foundation {
virtual CRegisteredString RegisterStr(const char32_t *str) = 0;
virtual CStringHandle GetHandle(Qt3DSBCharPtr str) = 0;
+ virtual CStringHandle getDynamicHandle(const QByteArray &str) = 0;
+ virtual void releaseDynamicHandle(QT3DSU32 strHandle) = 0;
virtual CRegisteredString HandleToStr(QT3DSU32 strHandle) = 0;
virtual CRegisteredString RegisterStr(const wchar_t *str) = 0;
diff --git a/src/foundation/qt/formatdiscovery.cpp b/src/foundation/qt/formatdiscovery.cpp
index 7ea762b..0a4bcbd 100644
--- a/src/foundation/qt/formatdiscovery.cpp
+++ b/src/foundation/qt/formatdiscovery.cpp
@@ -104,22 +104,22 @@ static QSurfaceFormat findIdealGLESVersion()
return fmt;
}
+static QSurfaceFormat s_f;
+
QSurfaceFormat surfaceFormat()
{
- static const QSurfaceFormat f = [] {
- QSurfaceFormat fmt;
+ if (s_f.renderableType() == QSurfaceFormat::DefaultRenderableType) {
// works in dynamic gl builds too because there's a qguiapp already
// this requirement is also a problem, see QT3DS-3603
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
- fmt = findIdealGLVersion();
+ s_f = findIdealGLVersion();
else
- fmt = findIdealGLESVersion();
- fmt.setDepthBufferSize(24);
- fmt.setStencilBufferSize(8);
+ s_f = findIdealGLESVersion();
+ s_f.setDepthBufferSize(24);
+ s_f.setStencilBufferSize(8);
// Ignore MSAA here as that is a per-layer setting.
- return fmt;
- }();
- return f;
+ }
+ return s_f;
}
} // End namespace Q3DS
diff --git a/src/ogl-runtime-dylib/ogl-runtime-dylib.pro b/src/ogl-runtime-dylib/ogl-runtime-dylib.pro
index 6cafa4c..264830f 100644
--- a/src/ogl-runtime-dylib/ogl-runtime-dylib.pro
+++ b/src/ogl-runtime-dylib/ogl-runtime-dylib.pro
@@ -28,7 +28,7 @@ HEADERS += \
../viewer/Qt3DSViewerApp.h \
../viewer/Qt3DSViewerTimer.h
-linux|qnx|mingw {
+linux|qnx {
BEGIN_ARCHIVE = -Wl,--whole-archive
END_ARCHIVE = -Wl,--no-whole-archive
}
@@ -46,9 +46,17 @@ STATICRUNTIME = \
QMAKE_LFLAGS += $$STATICRUNTIME
LIBS += -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
} else {
- LIBS += \
- $$STATICRUNTIME \
- -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+ mingw {
+ LIBS += \
+ -lqt3dsruntimestatic$$qtPlatformTargetSuffix() \
+ -lEASTL$$qtPlatformTargetSuffix() \
+ -lQT3DSDM$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+ } else {
+ LIBS += \
+ $$STATICRUNTIME \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+ }
}
win32 {
diff --git a/src/ogl-runtime-static/ogl-runtime-static.pro b/src/ogl-runtime-static/ogl-runtime-static.pro
index 8b2c95a..09b6c89 100644
--- a/src/ogl-runtime-static/ogl-runtime-static.pro
+++ b/src/ogl-runtime-static/ogl-runtime-static.pro
@@ -17,6 +17,17 @@ DEFINES += QT3DS_BUILDING_LIBRARY DISABLE_MESH_OPTIMIZATION
QT += qml
QT += quick-private
+mingw {
+ win32 {
+ LIBS += \
+ -lWs2_32 \
+ }
+ LIBS += \
+ -lEASTL$$qtPlatformTargetSuffix() \
+ -lQT3DSDM$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+}
+
# Foundation
SOURCES += \
../foundation/ConvertUTF.cpp \
diff --git a/src/qmlstreamer/q3dsqmlstream.cpp b/src/qmlstreamer/q3dsqmlstream.cpp
index e1b9e85..c0dc6a2 100644
--- a/src/qmlstreamer/q3dsqmlstream.cpp
+++ b/src/qmlstreamer/q3dsqmlstream.cpp
@@ -32,7 +32,7 @@
/*!
\qmltype QmlStream
\instantiates Q3DSQmlStream
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
\brief Allows streaming of QML as subpresentation.
@@ -43,12 +43,10 @@
\inmodule OpenGLRuntime
\since Qt 3D Studio 2.0
\brief Allows streaming of QML as subpresentation.
- \param parent
*/
/*!
- * \brief Q3DSQmlStream::Q3DSQmlStream Constructor
- * \param parent Optional parent object.
+ Constructs a Q3DSQmlStream object with \a parent as parent.
*/
Q3DSQmlStream::Q3DSQmlStream(QObject *parent)
: QObject(parent)
@@ -56,9 +54,6 @@ Q3DSQmlStream::Q3DSQmlStream(QObject *parent)
{
}
-/*!
- * \brief Q3DSQmlStream::~Q3DSQmlStream Destructor.
- */
Q3DSQmlStream::~Q3DSQmlStream()
{
}
diff --git a/src/qmlstreamer/q3dsqmlsubpresentationsettings.cpp b/src/qmlstreamer/q3dsqmlsubpresentationsettings.cpp
index bde5ad3..664b9e4 100644
--- a/src/qmlstreamer/q3dsqmlsubpresentationsettings.cpp
+++ b/src/qmlstreamer/q3dsqmlsubpresentationsettings.cpp
@@ -33,9 +33,9 @@
/*!
\qmltype SubPresentationSettings
\instantiates Q3DSSubPresentationSettings
- \inqmlmodule Qt3DStudio
+ \inqmlmodule QtStudio3D.OpenGL
\ingroup OpenGLRuntime
- \brief
+ \brief Settings for subpresentations.
\sa Studio3D, Presentation, QmlStream
*/
@@ -44,7 +44,6 @@
\inmodule OpenGLRuntime
\since Qt 3D Studio 2.0
\brief Settings for subpresentations.
- \param parent
\sa Q3DSPresentation, Q3DSQmlStream
*/
@@ -71,6 +70,9 @@ QQmlListProperty<Q3DSQmlStream> Q3DSSubPresentationSettings::qmlStreams()
return QQmlListProperty<Q3DSQmlStream>(this, m_list);
}
+/*!
+ Returns the list of QML streams to be used as subpresentations.
+*/
QList<Q3DSQmlStream *> Q3DSSubPresentationSettings::qmlStreamsList()
{
return m_list;
diff --git a/src/runtime/Qt3DSActivationManager.cpp b/src/runtime/Qt3DSActivationManager.cpp
index 3d05274..1449f6e 100644
--- a/src/runtime/Qt3DSActivationManager.cpp
+++ b/src/runtime/Qt3DSActivationManager.cpp
@@ -45,6 +45,7 @@
#include "foundation/Qt3DSMutex.h"
#include "foundation/Qt3DSSync.h"
#include "Qt3DSRenderThreadPool.h"
+#include "foundation/Qt3DSSimpleTypes.h"
using namespace qt3ds::runtime;
using namespace qt3ds::runtime::element;
@@ -405,7 +406,9 @@ struct STimeContext
if (inNode.DoesParticipateInTimeGraph()) {
UpdateNodeElementInformation(inNode);
if (inNode.IsUserActive()) {
- inGlobalMin = NVMax(inNode.m_ActivationManagerNode.m_StartTime, inGlobalMin);
+ // Start time does not get updated if the element doesn't have ATTRIBUTE_STARTTIME.
+ if (inNode.m_ActivationManagerNode.m_StartTime != QT3DS_MAX_U32)
+ inGlobalMin = NVMax(inNode.m_ActivationManagerNode.m_StartTime, inGlobalMin);
inGlobalMax = NVMin(inNode.m_ActivationManagerNode.m_StopTime, inGlobalMax);
if (inGlobalMin < inGlobalMax) {
GetTimeEventForTime(inGlobalMin, STimeEvent::Start)
diff --git a/src/runtime/Qt3DSApplication.cpp b/src/runtime/Qt3DSApplication.cpp
index baa94dd..d215e2f 100644
--- a/src/runtime/Qt3DSApplication.cpp
+++ b/src/runtime/Qt3DSApplication.cpp
@@ -338,8 +338,10 @@ struct STextureUploadRenderTask : public IRenderTask, public IImageLoadListener
sourcePaths.push_back(m_bufferManager.GetStringTable().RegisterStr(s));
QT3DSU32 id = m_batchLoader.LoadImageBatch(sourcePaths, CRegisteredString(),
this, m_type, m_preferKtx, false);
- if (id)
+ if (id) {
m_batches[id] = m_uploadSet;
+ m_uploadSet.clear();
+ }
}
if (!m_uploadWaitSet.isEmpty()) {
nvvector<CRegisteredString> sourcePaths(m_bufferManager.GetStringTable().GetAllocator(),
@@ -351,9 +353,11 @@ struct STextureUploadRenderTask : public IRenderTask, public IImageLoadListener
if (id) {
m_batchLoader.BlockUntilLoaded(id);
m_bufferManager.loadSet(m_uploadWaitSet);
+ m_uploadWaitSet.clear();
}
}
- m_bufferManager.unloadSet(m_deleteSet);
+ if (!m_deleteSet.isEmpty())
+ m_bufferManager.unloadSet(m_deleteSet);
}
void add(const QSet<QString> &set, bool wait)
{
@@ -1619,8 +1623,10 @@ struct SApp : public IApplication
// else assume main presentation and component:slide
}
component = presentation->GetRoot();
- if (!componentName.isNull() && componentName != component->m_Name)
- component = component->FindChild(CHash::HashString(qPrintable(componentName)));
+ if (!componentName.isNull() && componentName != component->m_Name) {
+ component = CQmlElementHelper::GetElement(*this, presentation,
+ qPrintable(componentName), nullptr);
+ }
if (!component) {
qCWarning(WARNING) << "Could not find slide: " << elementPath;
return false;
diff --git a/src/runtime/Qt3DSApplication.h b/src/runtime/Qt3DSApplication.h
index f38b182..510845e 100644
--- a/src/runtime/Qt3DSApplication.h
+++ b/src/runtime/Qt3DSApplication.h
@@ -89,6 +89,11 @@ struct DataInOutAttribute
QByteArray elementPath;
QVector<QByteArray> attributeName;
Q3DStudio::EAttributeType propertyType = Q3DStudio::ATTRIBUTETYPE_NONE;
+
+ bool operator==(const DataInOutAttribute &inOther) const {
+ return (inOther.elementPath == elementPath && inOther.attributeName == attributeName
+ && inOther.propertyType == propertyType);
+ }
};
enum DataInOutType {
diff --git a/src/runtime/Qt3DSElementSystem.cpp b/src/runtime/Qt3DSElementSystem.cpp
index d8e1833..f77bac5 100644
--- a/src/runtime/Qt3DSElementSystem.cpp
+++ b/src/runtime/Qt3DSElementSystem.cpp
@@ -162,11 +162,17 @@ struct SElementAllocator : public qt3ds::runtime::IElementAllocator
m_TempPropertyDescs.clear();
bool participatesInTimeGraph = false;
GetIgnoredProperties();
+ const bool isImage = inType == m_StringTable.RegisterStr("Image");
for (QT3DSU32 idx = 0, end = inPropertyDescriptions.size(); idx < end; ++idx) {
QT3DSU32 nameHash = inPropertyDescriptions[idx].first.GetNameHash();
- if (nameHash == Q3DStudio::ATTRIBUTE_STARTTIME
- || nameHash == Q3DStudio::ATTRIBUTE_ENDTIME)
+ // Make image instances explicitly not participate in the timegraph. This way their
+ // default start/end time does not have impact into lifetimes of their parents.
+ // This fixes QT3DS-3669 where image default end time overrode parent endtime when
+ // element active status was considered.
+ if ((nameHash == Q3DStudio::ATTRIBUTE_STARTTIME
+ || nameHash == Q3DStudio::ATTRIBUTE_ENDTIME) && !isImage) {
participatesInTimeGraph = true;
+ }
if (eastl::find(m_IgnoredProperties.begin(), m_IgnoredProperties.end(),
inPropertyDescriptions[idx].first.m_Name)
== m_IgnoredProperties.end()) {
@@ -637,36 +643,44 @@ void SElement::SetAttribute(const Q3DStudio::TAttributeHash inKey,
const Q3DStudio::UVariant inValue)
{
Option<TPropertyDescAndValuePtr> existing = FindProperty(inKey);
- if (existing.hasValue() == false)
+ if (existing.hasValue() == false) {
+ if (Q3DStudio::ATTRIBUTE_EYEBALL == inKey)
+ SetFlag(Q3DStudio::ELEMENTFLAG_EXPLICITACTIVE, inValue.m_INT32 ? true : false);
return;
+ }
SetAttribute(*existing, inValue);
}
-void SElement::SetAttribute(TPropertyDescAndValuePtr inKey, const Q3DStudio::UVariant inValue)
+void SElement::SetAttribute(TPropertyDescAndValuePtr inKey, const Q3DStudio::UVariant inValue,
+ bool forceSet)
{
Q3DStudio::EAttributeType theType = inKey.first.m_Type;
Q3DStudio::UVariant *currentValue = inKey.second;
QT3DSU32 attHash = inKey.first.GetNameHash();
- switch (theType) {
- case Q3DStudio::ATTRIBUTETYPE_FLOAT: // Early return
- if (fabs(currentValue->m_FLOAT - inValue.m_FLOAT) < SmallestDifference())
- return;
- break;
- case Q3DStudio::ATTRIBUTETYPE_FLOAT3: // Early return
- if (fabs(currentValue->m_FLOAT3[0] - inValue.m_FLOAT3[0]) < SmallestDifference()
- && fabs(currentValue->m_FLOAT3[1] - inValue.m_FLOAT3[1]) < SmallestDifference()
- && fabs(currentValue->m_FLOAT3[2] - inValue.m_FLOAT3[2]) < SmallestDifference()) {
- return;
+ if (!forceSet) {
+ switch (theType) {
+ case Q3DStudio::ATTRIBUTETYPE_FLOAT: // Early return
+ if (fabs(currentValue->m_FLOAT - inValue.m_FLOAT) < SmallestDifference())
+ return;
+ break;
+ case Q3DStudio::ATTRIBUTETYPE_FLOAT3: // Early return
+ if (fabs(currentValue->m_FLOAT3[0] - inValue.m_FLOAT3[0]) < SmallestDifference()
+ && fabs(currentValue->m_FLOAT3[1] - inValue.m_FLOAT3[1]) < SmallestDifference()
+ && fabs(currentValue->m_FLOAT3[2] - inValue.m_FLOAT3[2]) < SmallestDifference()) {
+ return;
+ }
+ break;
+ case Q3DStudio::ATTRIBUTETYPE_STRING:
+ if (currentValue->m_StringHandle == inValue.m_StringHandle)
+ return;
+ m_BelongedPresentation->GetStringTable().releaseDynamicHandle(
+ currentValue->m_StringHandle);
+ break;
+ default: // Early return
+ if (Q3DStudio::ATTRIBUTE_EYEBALL != attHash && currentValue->m_INT32 == inValue.m_INT32)
+ return;
+ break;
}
- break;
- case Q3DStudio::ATTRIBUTETYPE_STRING:
- if (currentValue->m_StringHandle == inValue.m_StringHandle)
- return;
- break;
- default: // Early return
- if (currentValue->m_INT32 == inValue.m_INT32)
- return;
- break;
}
*currentValue = inValue;
@@ -764,10 +778,19 @@ void SElement::SetFlag(Q3DStudio::EElementFlag inFlag, bool inValue)
bool existing = m_Flags & inFlag;
if (existing != inValue && HasActivityZone()) {
m_Flags.clearOrSet(inValue, inFlag);
- if (inFlag == Q3DStudio::ELEMENTFLAG_EXPLICITACTIVE)
+ if (inFlag == Q3DStudio::ELEMENTFLAG_EXPLICITACTIVE) {
GetActivityZone().UpdateItemInfo(*this);
- else if (inFlag == Q3DStudio::ELEMENTFLAG_SCRIPTCALLBACKS)
+ if (IsComponent()) {
+ SElement *parent = m_Parent;
+ // Get out parent component
+ while (parent && parent->m_Parent && !parent->IsComponent())
+ parent = parent->m_Parent;
+ if (parent)
+ parent->GetActivityZone().UpdateItemInfo(*parent);
+ }
+ } else if (inFlag == Q3DStudio::ELEMENTFLAG_SCRIPTCALLBACKS) {
GetActivityZone().UpdateItemScriptStatus(*this);
+ }
SetDirty();
}
}
diff --git a/src/runtime/Qt3DSElementSystem.h b/src/runtime/Qt3DSElementSystem.h
index 12ebebd..6e61a02 100644
--- a/src/runtime/Qt3DSElementSystem.h
+++ b/src/runtime/Qt3DSElementSystem.h
@@ -322,7 +322,8 @@ namespace runtime {
void SetAttribute(const Q3DStudio::TAttributeHash inKey,
const Q3DStudio::UVariant inValue);
// Triggers updating various subcomponents without requiring a new property lookup.
- void SetAttribute(TPropertyDescAndValuePtr inKey, const Q3DStudio::UVariant inNewValue);
+ void SetAttribute(TPropertyDescAndValuePtr inKey, const Q3DStudio::UVariant inNewValue,
+ bool forceSet = false);
// Q3DStudio::CHash::HashAttribute
Option<QT3DSU32> FindPropertyIndex(QT3DSU32 inNameHash) const;
diff --git a/src/runtime/Qt3DSQmlElementHelper.cpp b/src/runtime/Qt3DSQmlElementHelper.cpp
index 9b58a73..0a13a1f 100644
--- a/src/runtime/Qt3DSQmlElementHelper.cpp
+++ b/src/runtime/Qt3DSQmlElementHelper.cpp
@@ -150,10 +150,11 @@ TElement *CQmlElementHelper::GetElement(qt3ds::runtime::IApplication &inApplicat
}
bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttName,
- const void *value, bool inDelay)
+ const void *value)
{
SAttributeKey theAttributeKey;
theAttributeKey.m_Hash = CHash::HashAttribute(theAttName);
+ bool force = false;
// Early out for our single 'read only' attribute
if (ATTRIBUTE_URI == theAttributeKey.m_Hash) {
@@ -165,7 +166,8 @@ bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttNam
Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> thePropertyInfo =
theElement->FindProperty(theAttributeKey.m_Hash);
- if (!thePropertyInfo.hasValue()) {
+ // Do not create property for eyeball, it uses the explicit activity flag
+ if (!thePropertyInfo.hasValue() && theAttributeKey.m_Hash != Q3DStudio::ATTRIBUTE_EYEBALL) {
// if not search in the dynamic properties
thePropertyInfo = theElement->FindDynamicProperty(theAttributeKey.m_Hash);
if (!thePropertyInfo.hasValue()) {
@@ -178,10 +180,15 @@ bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttNam
theElement->GetBelongedPresentation()->GetApplication().GetMetaData();
thePropertyInfo = theElemAllocator.CreateDynamicProperty(
theMetaData, *theElement, theStringTable.RegisterStr(theAttName));
+ force = true;
}
}
- if (thePropertyInfo.hasValue()) {
+ if (theAttributeKey.m_Hash == Q3DStudio::ATTRIBUTE_EYEBALL) {
+ UVariant theNewValue;
+ theNewValue.m_INT32 = *(INT32 *)value;
+ theElement->SetAttribute(theAttributeKey.m_Hash, theNewValue);
+ } else if (thePropertyInfo.hasValue()) {
UVariant theNewValue;
QString name(thePropertyInfo->first.m_Name.c_str());
EAttributeType theAttributeType = thePropertyInfo->first.m_Type;
@@ -203,8 +210,8 @@ bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttNam
case ATTRIBUTETYPE_STRING:
theNewValue.m_StringHandle =
- theElement->GetBelongedPresentation()->GetStringTable().GetHandle(
- (const char *)value);
+ theElement->GetBelongedPresentation()->GetStringTable().getDynamicHandle(
+ QByteArray(static_cast<const char *>(value)));
break;
case ATTRIBUTETYPE_POINTER:
@@ -239,15 +246,7 @@ bool CQmlElementHelper::SetAttribute(TElement *theElement, const char *theAttNam
break;
}
- if (inDelay) {
- UVariant arg1;
- arg1.m_INT32 = theAttributeKey.m_Hash;
- theElement->GetBelongedPresentation()->FireCommand(
- COMMAND_SETPROPERTY, theElement, &arg1, &theNewValue, ATTRIBUTETYPE_HASH,
- theAttributeType);
- } else {
- theElement->SetAttribute(*thePropertyInfo, theNewValue);
- }
+ theElement->SetAttribute(*thePropertyInfo, theNewValue, force);
} else {
return false;
}
@@ -266,7 +265,10 @@ bool CQmlElementHelper::GetAttribute(TElement *inElement, const char *inAttribut
if (!thePropertyInfo.hasValue())
thePropertyInfo = inElement->FindDynamicProperty(theAttributeKey.m_Hash);
- if (thePropertyInfo.hasValue()) {
+ if (theAttributeKey.m_Hash == Q3DStudio::ATTRIBUTE_EYEBALL) {
+ INT32 val = inElement->IsExplicitActive() ? 1 : 0;
+ *(INT32 *)value = val;
+ } else if (thePropertyInfo.hasValue()) {
UVariant *theValuePtr = thePropertyInfo->second;
EAttributeType theAttributeType = thePropertyInfo->first.m_Type;
switch (theAttributeType) {
diff --git a/src/runtime/Qt3DSQmlElementHelper.h b/src/runtime/Qt3DSQmlElementHelper.h
index ec36c8e..c7b2b08 100644
--- a/src/runtime/Qt3DSQmlElementHelper.h
+++ b/src/runtime/Qt3DSQmlElementHelper.h
@@ -48,8 +48,7 @@ public:
IPresentation *inDefaultPresentation, const char *inPath,
TElement *inStartElement = NULL);
- static bool SetAttribute(TElement *inElement, const char *inAttribute, const void *value,
- bool inDelay);
+ static bool SetAttribute(TElement *inElement, const char *inAttribute, const void *value);
static bool GetAttribute(TElement *inElement, const char *inAttribute, void *value);
};
}
diff --git a/src/runtime/Qt3DSQmlEngine.cpp b/src/runtime/Qt3DSQmlEngine.cpp
index ac958ea..b9b2067 100644
--- a/src/runtime/Qt3DSQmlEngine.cpp
+++ b/src/runtime/Qt3DSQmlEngine.cpp
@@ -389,6 +389,9 @@ private:
QMap<QString, QQmlComponent *> m_components;
QVector<Q3DSQmlScript *> m_scripts;
+ QSet<int> m_availableIds;
+ QHash<TElement *, int> m_elementIdMap;
+
public:
CQmlEngineImpl(NVFoundationBase &fnd, ITimeProvider &inTimeProvider);
@@ -474,10 +477,14 @@ private:
TElement *getTarget(const char *component);
void listAllElements(TElement *root, QList<TElement *> &elements);
void initializeDataInputsInPresentation(CPresentation &presentation, bool isPrimary,
+ bool isDynamicAdd = false,
QList<TElement *> inElements = QList<TElement *>());
void initializeDataOutputsInPresentation(CPresentation &presentation, bool isPrimary);
+ void removeDataInputControl(const QVector<TElement *> &inElements);
// Splits down vector attributes to components as Runtime does not really
// handle vectors at this level anymore
+ bool getAttributeVector4(QVector<QByteArray> &outAttVec, const QByteArray &attName,
+ TElement *elem);
bool getAttributeVector3(QVector<QByteArray> &outAttVec, const QByteArray &attName,
TElement *elem);
bool getAttributeVector2(QVector<QByteArray> &outAttVec, const QByteArray &attName,
@@ -532,6 +539,8 @@ private:
void notifyMaterialCreation(const QStringList &materialNames, const QString &error);
void deleteElements(const QVector<TElement *> &elements,
qt3ds::render::IQt3DSRenderer *renderer);
+ int getAvailableId();
+ void releaseId(int id);
};
CQmlEngineImpl::CQmlEngineImpl(NVFoundationBase &fnd, ITimeProvider &)
@@ -595,7 +604,7 @@ void CQmlEngineImpl::SetAttribute(TElement *target, const char *attName, const c
{
QML_ENGINE_MULTITHREAD_PROTECT_METHOD;
if (target) {
- bool success = CQmlElementHelper::SetAttribute(target, attName, value, false);
+ bool success = CQmlElementHelper::SetAttribute(target, attName, value);
if (!success) {
qCCritical(qt3ds::INVALID_OPERATION)
<< "CQmlEngineImpl::SetAttribute: "
@@ -611,7 +620,7 @@ void CQmlEngineImpl::SetAttribute(const char *element, const char *attName, cons
TElement *theTarget = getTarget(element);
if (theTarget) {
- bool success = CQmlElementHelper::SetAttribute(theTarget, attName, value, false);
+ bool success = CQmlElementHelper::SetAttribute(theTarget, attName, value);
if (!success) {
qCCritical(qt3ds::INVALID_OPERATION)
<< "CQmlEngineImpl::SetAttribute: "
@@ -929,8 +938,6 @@ void CQmlEngineImpl::SetDataInputValue(
}
}
-static int _idCounter = 0;
-
void CQmlEngineImpl::createElements(const QString &parentElementPath, const QString &slideName,
const QVector<QHash<QString, QVariant>> &properties,
qt3ds::render::IQt3DSRenderer *renderer)
@@ -944,13 +951,15 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr
elementPaths.reserve(properties.size());
QVector<QHash<QString, QVariant>> theProperties = properties;
const QString namePropName = QStringLiteral("name");
+ QVector<int> idNumbers(theProperties.size());
for (int i = 0; i < theProperties.size(); ++i) {
auto &props = theProperties[i];
QString newElementName = props.value(namePropName).toString();
+ idNumbers[i] = getAvailableId();
if (newElementName.isEmpty()) {
// The id number on generated name will match generated graph object identifiers
- newElementName = QStringLiteral("NewElement_%1").arg(_idCounter + i + 1);
+ newElementName = QStringLiteral("NewElement_%1").arg(idNumbers[i]);
props.insert(namePropName, newElementName);
}
elementPaths << parentElementPath + QLatin1Char('.') + newElementName;
@@ -959,8 +968,11 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr
TElement *parentElement = nullptr;
auto handleError = [&]() {
- if (!error.isEmpty())
+ if (!error.isEmpty()) {
+ for (int id : qAsConst(idNumbers))
+ releaseId(id);
deleteElements(createdElements, renderer);
+ }
notifyElementCreation(elementPaths, error);
};
@@ -1012,8 +1024,8 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr
parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_ENDTIME, attValue);
const int parentEndTime = int(attValue.m_INT32);
- for (const auto &currentProps : qAsConst(theProperties)) {
- ++_idCounter;
+ for (int i = 0; i < theProperties.size(); ++i) {
+ const auto &currentProps = theProperties[i];
++elementIndex;
// Remove properties requiring custom handling
@@ -1200,7 +1212,7 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr
NVAllocatorCallback &allocator = presentation->GetScene()->allocator();
SModel *newObject = QT3DS_NEW(allocator, SModel)();
newObject->m_Id = strTable.RegisterStr((QByteArrayLiteral("__newObj_")
- + QByteArray::number(_idCounter)).constData());
+ + QByteArray::number(idNumbers[i])).constData());
parentObject.AddChild(*newObject);
Qt3DSTranslator::CreateTranslatorForElement(newElem, *newObject, allocator);
@@ -1210,7 +1222,7 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr
SReferencedMaterial *newMaterial = QT3DS_NEW(allocator, SReferencedMaterial)();
newMaterial->m_Id = strTable.RegisterStr(
(QByteArrayLiteral("__newMat_")
- + QByteArray::number(_idCounter)).constData());
+ + QByteArray::number(idNumbers[i])).constData());
newMaterial->m_ReferencedMaterial = referencedMaterial;
newObject->AddMaterial(*newMaterial);
}
@@ -1233,10 +1245,11 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr
newElem.GetActivityZone().UpdateItemInfo(newElem);
createdElements << &newElem;
+ m_elementIdMap.insert(&newElem, idNumbers[i]);
}
bool isPrimary = presentation == m_Application->GetPrimaryPresentation() ? true : false;
- initializeDataInputsInPresentation(*presentation, isPrimary, createdElements.toList());
+ initializeDataInputsInPresentation(*presentation, isPrimary, true, createdElements.toList());
renderer->ChildrenUpdated(parentObject);
@@ -1311,10 +1324,16 @@ void CQmlEngineImpl::createMaterials(const QString &subPresId,
};
QVector<MaterialInfo *> materialInfos;
QVector<TElement *> createdElements;
+ QVector<int> idNumbers(materialDefinitions.size());
+ for (int i = 0; i < materialDefinitions.size(); ++i)
+ idNumbers[i] = getAvailableId();
auto handleError = [&]() {
- if (!error.isEmpty())
+ if (!error.isEmpty()) {
+ for (int id : qAsConst(idNumbers))
+ releaseId(id);
deleteElements(createdElements, renderer);
+ }
QStringList materialNames;
QString prefix;
if (!subPresId.isEmpty())
@@ -1365,7 +1384,8 @@ void CQmlEngineImpl::createMaterials(const QString &subPresId,
if (!container)
container = createMaterialContainer(rootElement, presentation);
- for (auto &materialInfo : materialInfos) {
+ for (int i = 0; i < materialInfos.size(); ++i) {
+ const auto &materialInfo = materialInfos[i];
if (materialInfo->materialName.isEmpty() || materialInfo->materialProps.isEmpty()) {
error = QObject::tr("Invalid material definition: '%1'")
.arg(materialInfo->materialDefinition);
@@ -1570,7 +1590,7 @@ void CQmlEngineImpl::createMaterials(const QString &subPresId,
// Create render object for the material
qt3ds::render::SGraphObject *newMaterial = nullptr;
CRegisteredString newMatId = strTable.RegisterStr(
- (QByteArrayLiteral("__newMat_") + QByteArray::number(++_idCounter))
+ (QByteArrayLiteral("__newMat_") + QByteArray::number(idNumbers[i]))
.constData());
if (isCustomMaterial) {
newMaterial = customMaterialSystem->CreateCustomMaterial(matClass, allocator);
@@ -1647,15 +1667,18 @@ void CQmlEngineImpl::createMaterials(const QString &subPresId,
qt3ds::render::SImage *newImageObj
= QT3DS_NEW(allocator, qt3ds::render::SImage)();
+ const int imageId = getAvailableId();
newImageObj->m_Id = strTable.RegisterStr(
(QByteArrayLiteral("__newImage_")
- + QByteArray::number(++_idCounter)).constData());
+ + QByteArray::number(imageId)).constData());
qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement(
*imageElem, *newImageObj, allocator);
+ m_elementIdMap.insert(imageElem, imageId);
}
}
- createdElements << &newMatElem;
}
+ createdElements << &newMatElem;
+ m_elementIdMap.insert(&newMatElem, idNumbers[i]);
qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement(newMatElem, *newMaterial,
allocator);
@@ -2030,7 +2053,7 @@ void CQmlEngineImpl::listAllElements(TElement *root, QList<TElement *> &elements
// Initializes datainput bindings in the presentation starting by default from the root element.
// If inElements is specified, only parses the specified elements.
void CQmlEngineImpl::initializeDataInputsInPresentation(CPresentation &presentation,
- bool isPrimary,
+ bool isPrimary, bool isDynamicAdd,
QList<TElement *> inElements)
{
QList<TElement *> elements;
@@ -2079,6 +2102,24 @@ void CQmlEngineImpl::initializeDataInputsInPresentation(CPresentation &presentat
TElement *component = &element->GetComponentParent();
ctrlElem.elementPath.append(component->m_Path);
} else if (diMap[controllerName].type
+ == qt3ds::runtime::DataInOutTypeVector4) {
+ // special handling for vector datatype to handle
+ // expansion from <propertyname> to <propertyname>.x .y .z .w
+ QVector<QByteArray> attVec;
+ bool success = getAttributeVector4(
+ attVec, ctrlElem.attributeName.first().constData(),
+ element);
+ if (!attVec.empty() && success) {
+ ctrlElem.attributeName = attVec;
+ ctrlElem.elementPath.append(element->m_Path);
+ ctrlElem.propertyType = ATTRIBUTETYPE_FLOAT4;
+ } else {
+ qWarning() << __FUNCTION__ << "Property "
+ << ctrlElem.attributeName.first()
+ << " was not expanded to vector";
+ ctrlElem.propertyType = ATTRIBUTETYPE_NONE;
+ }
+ } else if (diMap[controllerName].type
== qt3ds::runtime::DataInOutTypeVector3) {
// special handling for vector datatype to handle
// expansion from <propertyname> to <propertyname>.x .y .z
@@ -2152,41 +2193,46 @@ void CQmlEngineImpl::initializeDataInputsInPresentation(CPresentation &presentat
diDef.controlledAttributes.append(ctrlElem);
// #TODO: Remove below once QT3DS-3510 has been implemented in the editor
- // Note, in this temp implementation only the LAST of multiple attributes
- // will be notified from the object under the DataInput name..
- qt3ds::runtime::DataInputDef inDef = diMap[controllerName];
- qt3ds::runtime::DataOutputDef &doDef = doMap[controllerName];
- doDef.observedAttribute = ctrlElem;
- doDef.type = inDef.type;
- doDef.min = inDef.min;
- doDef.max = inDef.max;
-
- if (ctrlElem.propertyType == ATTRIBUTETYPE_DATAINPUT_TIMELINE) {
- // Find the TElement for the @timeline attrib
- TElement *target = nullptr;
- QStringList split
- = QString(ctrlElem.elementPath).split(QLatin1Char(':'));
- if (split.size() > 1) {
- target = CQmlElementHelper::GetElement(
- *m_Application,
- m_Application->GetPresentationById(
- split.at(0).toStdString().c_str()),
- split.at(1).toStdString().c_str(), nullptr);
+ // Skip data output modification when adding dynamic elements,
+ // as that would break the previous binding
+ if (!isDynamicAdd) {
+ // Note, in this temp implementation only the LAST of multiple attrs
+ // will be notified from the object under the DataInput name..
+ qt3ds::runtime::DataInputDef inDef = diMap[controllerName];
+ qt3ds::runtime::DataOutputDef &doDef = doMap[controllerName];
+ doDef.observedAttribute = ctrlElem;
+ doDef.type = inDef.type;
+ doDef.min = inDef.min;
+ doDef.max = inDef.max;
+
+ if (ctrlElem.propertyType == ATTRIBUTETYPE_DATAINPUT_TIMELINE) {
+ // Find the TElement for the @timeline attrib
+ TElement *target = nullptr;
+ QStringList split
+ = QString(ctrlElem.elementPath).split(QLatin1Char(':'));
+ if (split.size() > 1) {
+ target = CQmlElementHelper::GetElement(
+ *m_Application,
+ m_Application->GetPresentationById(
+ split.at(0).toStdString().c_str()),
+ split.at(1).toStdString().c_str(), nullptr);
+ } else {
+ target = CQmlElementHelper::GetElement(
+ *m_Application,
+ m_Application->GetPrimaryPresentation(),
+ split.at(0).toStdString().c_str(), nullptr);
+ }
+
+ doDef.timelineComponent = static_cast<TComponent *>(target);
+ } else if (ctrlElem.propertyType == ATTRIBUTETYPE_DATAINPUT_SLIDE) {
+ // Slide notifications are already done with separate signal
+ // No need to process
} else {
- target = CQmlElementHelper::GetElement(
- *m_Application,
- m_Application->GetPrimaryPresentation(),
- split.at(0).toStdString().c_str(), nullptr);
+ // Other than slide or timeline are handled by CPresentation
+ CRegisteredString rString = strTable.RegisterStr(
+ ctrlElem.elementPath);
+ elementPathToDataOutputDefMap.insertMulti(rString, doDef);
}
-
- doDef.timelineComponent = static_cast<TComponent *>(target);
- } else if (ctrlElem.propertyType == ATTRIBUTETYPE_DATAINPUT_SLIDE) {
- // Slide notifications are already done with separate signal
- // No need to process
- } else {
- // Other than slide or timeline attributes are handled by CPresentation
- CRegisteredString rString = strTable.RegisterStr(ctrlElem.elementPath);
- elementPathToDataOutputDefMap.insertMulti(rString, doDef);
}
// #TODO: Remove above once QT3DS-3510 has been implemented in the editor
}
@@ -2196,7 +2242,8 @@ void CQmlEngineImpl::initializeDataInputsInPresentation(CPresentation &presentat
}
// #TODO: Remove below once QT3DS-3510 has been implemented in the editor
- presentation.AddToDataOutputMap(elementPathToDataOutputDefMap);
+ if (!isDynamicAdd)
+ presentation.AddToDataOutputMap(elementPathToDataOutputDefMap);
// #TODO: Remove above once QT3DS-3510 has been implemented in the editor
}
@@ -2292,11 +2339,61 @@ void CQmlEngineImpl::initializeDataOutputsInPresentation(CPresentation &presenta
presentation.AddToDataOutputMap(elementPathToDataOutputDefMap);
}
+// Remove datainput control from listed elements and update internal control map. Should be used
+// when elements having a datainput controller are removed in order to avoid invalid entries.
+void CQmlEngineImpl::removeDataInputControl(const QVector<TElement *> &inElements)
+{
+ const qt3ds::runtime::DataInputMap diMap(m_Application->dataInputMap());
+
+ // Have to do nasty triple-nested search loop as the datainput map is organized around
+ // datainputs for fast lookups in setDataInputValue, not around control targets.
+ QVector<QPair<QString, qt3ds::runtime::DataInOutAttribute>> elemAttrsToRemove;
+ QMapIterator<QString, qt3ds::runtime::DataInputDef> diMapIter(diMap);
+
+ for (const auto &elem : inElements) {
+ while (diMapIter.hasNext()) {
+ diMapIter.next();
+ for (const auto &inOutAttr : qAsConst(diMapIter.value().controlledAttributes)) {
+ if (inOutAttr.elementPath == QByteArray(elem->m_Path))
+ elemAttrsToRemove.append({diMapIter.key(), inOutAttr});
+ }
+ }
+ diMapIter.toFront();
+ }
+
+ for (const auto &attr : qAsConst(elemAttrsToRemove))
+ m_Application->dataInputMap()[attr.first].controlledAttributes.removeAll(attr.second);
+}
+
// Bit clumsy way of getting from "position" to "position .x .y .z" and enabling datainput
// support for vectorized types. UIP parser has already thrown away all vector
// type attributes and at this point we are operating with scalar components only.
// We check if this element has a property attName.x or attName.r to find out it
// we should expand property attName to XYZ or RGB vector
+bool CQmlEngineImpl::getAttributeVector4(QVector<QByteArray> &outAttVec,
+ const QByteArray &attName,
+ TElement *elem)
+{
+ auto hashName = Q3DStudio::CHash::HashAttribute(attName + ".x");
+
+ if (!elem->FindProperty(hashName).isEmpty()) {
+ outAttVec.append(attName + ".x");
+ outAttVec.append(attName + ".y");
+ outAttVec.append(attName + ".z");
+ outAttVec.append(attName + ".w");
+ return true;
+ }
+ hashName = Q3DStudio::CHash::HashAttribute(attName + ".r");
+ if (!elem->FindProperty(hashName).isEmpty()) {
+ outAttVec.append(attName + ".r");
+ outAttVec.append(attName + ".g");
+ outAttVec.append(attName + ".b");
+ outAttVec.append(attName + ".a");
+ return true;
+ }
+ return false;
+}
+
bool CQmlEngineImpl::getAttributeVector3(QVector<QByteArray> &outAttVec,
const QByteArray &attName,
TElement *elem)
@@ -2615,6 +2712,9 @@ void CQmlEngineImpl::deleteElements(const QVector<TElement *> &elements,
// Recursive deleter for translators and graph objects
std::function<void(TElement *)> deleteRenderObjects;
deleteRenderObjects = [&](TElement *elem) {
+ if (m_elementIdMap.contains(elem))
+ releaseId(m_elementIdMap.take(elem));
+
TElement *child = elem->m_Child;
while (child) {
TElement *sibling = child->m_Sibling;
@@ -2633,6 +2733,10 @@ void CQmlEngineImpl::deleteElements(const QVector<TElement *> &elements,
model->m_FirstMaterial);
QT3DS_FREE(allocator, material);
}
+ } else if (type == qt3ds::render::GraphObjectTypes::Image) {
+ auto image = static_cast<qt3ds::render::SImage *>(&translator->RenderObject());
+ if (image->m_LoadedTextureData)
+ image->m_LoadedTextureData->m_callbacks.removeOne(image);
}
QT3DS_FREE(allocator, &translator->RenderObject());
QT3DS_FREE(allocator, translator);
@@ -2664,6 +2768,29 @@ void CQmlEngineImpl::deleteElements(const QVector<TElement *> &elements,
}
for (auto parentNode : qAsConst(parentNodes))
renderer->ChildrenUpdated(*parentNode);
+
+ removeDataInputControl(elements);
+}
+
+int CQmlEngineImpl::getAvailableId()
+{
+ static int _idCounter = 0;
+
+ int id = -1;
+ if (m_availableIds.isEmpty()) {
+ id = ++_idCounter;
+ } else {
+ auto first = m_availableIds.begin();
+ id = *first;
+ m_availableIds.erase(first);
+ }
+
+ return id;
+}
+
+void CQmlEngineImpl::releaseId(int id)
+{
+ m_availableIds.insert(id);
}
template<typename TDataType>
diff --git a/src/runtimerender/Qt3DSDistanceFieldRenderer.cpp b/src/runtimerender/Qt3DSDistanceFieldRenderer.cpp
index 8c1b28a..f28e545 100644
--- a/src/runtimerender/Qt3DSDistanceFieldRenderer.cpp
+++ b/src/runtimerender/Qt3DSDistanceFieldRenderer.cpp
@@ -91,20 +91,32 @@ void Q3DSDistanceFieldRenderer::EndFrame()
// Remove meshes for glyphs that weren't rendered last frame
NVAllocatorCallback &alloc = m_context->GetAllocator();
- QHash<size_t, Q3DSDistanceFieldMesh>::const_iterator it = m_meshCache.constBegin();
- while (it != m_meshCache.constEnd()) {
- const size_t glyphHash = it.key();
- const Q3DSDistanceFieldMesh &mesh = it.value();
+ QHash<size_t, QHash<Q3DSDistanceFieldGlyphCache::TextureInfo *, GlyphInfo>>::const_iterator
+ glyphIt = m_glyphCache.constBegin();
+ while (glyphIt != m_glyphCache.constEnd()) {
+ const size_t textHash = glyphIt.key();
+ if (!m_renderedTexts.contains(textHash))
+ m_glyphCache.erase(glyphIt++);
+ else
+ glyphIt++;
+ }
+
+ QHash<size_t, Q3DSDistanceFieldMesh>::const_iterator meshIt = m_meshCache.constBegin();
+ while (meshIt != m_meshCache.constEnd()) {
+ const size_t glyphHash = meshIt.key();
+ const Q3DSDistanceFieldMesh &mesh = meshIt.value();
if (!m_renderedGlyphs.contains(glyphHash)) {
NVDelete(alloc, mesh.vertexBuffer);
NVDelete(alloc, mesh.indexBuffer);
NVDelete(alloc, mesh.inputAssembler);
- m_meshCache.erase(it++);
+ m_meshCache.erase(meshIt++);
} else {
- it++;
+ meshIt++;
}
}
+
m_renderedGlyphs.clear();
+ m_renderedTexts.clear();
}
QHash<Q3DSDistanceFieldGlyphCache::TextureInfo *, GlyphInfo>
@@ -611,6 +623,8 @@ static QVector<T> fillIndexBuffer(uint quadCount)
void Q3DSDistanceFieldRenderer::buildShaders()
{
+ if (m_shader.program)
+ return;
IShaderProgramGenerator &gen = m_context->GetShaderProgramGenerator();
gen.BeginProgram();
IShaderStageGenerator &vertexGenerator(*gen.GetStage(ShaderGeneratorStages::Vertex));
@@ -682,12 +696,12 @@ void Q3DSDistanceFieldRenderer::buildShaders()
Q3DSDistanceFieldMesh Q3DSDistanceFieldRenderer::buildMesh(const GlyphInfo &glyphInfo,
bool shadow)
{
- static NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry entries[] = {
NVRenderVertexBufferEntry("vCoord", NVRenderComponentTypes::QT3DSF32, 3),
NVRenderVertexBufferEntry("tCoord", NVRenderComponentTypes::QT3DSF32, 2, 3 * sizeof(float))
};
- static NVRenderVertexBufferEntry shadowEntries[] = {
+ NVRenderVertexBufferEntry shadowEntries[] = {
NVRenderVertexBufferEntry("vCoord", NVRenderComponentTypes::QT3DSF32, 3),
NVRenderVertexBufferEntry("tCoord", NVRenderComponentTypes::QT3DSF32, 2,
3 * sizeof(float)),
@@ -948,6 +962,8 @@ void Q3DSDistanceFieldRenderer::renderText(SText &text, const QT3DSMat44 &mvp)
m_renderedGlyphs += glyphHashValue;
}
+ m_renderedTexts += textHashValue;
+
text.m_Bounds = NVBounds3(minimum, maximum);
}
@@ -961,7 +977,6 @@ void Q3DSDistanceFieldRenderer::setContext(IQt3DSRenderContext &context)
{
m_context = &context;
m_glyphCacheManager.setContext(context);
- buildShaders();
}
ITextRendererCore &ITextRendererCore::createDistanceFieldRenderer(NVFoundationBase &fnd)
diff --git a/src/runtimerender/Qt3DSDistanceFieldRenderer.h b/src/runtimerender/Qt3DSDistanceFieldRenderer.h
index 3af19a9..a64fddd 100644
--- a/src/runtimerender/Qt3DSDistanceFieldRenderer.h
+++ b/src/runtimerender/Qt3DSDistanceFieldRenderer.h
@@ -153,6 +153,7 @@ private:
Q3DSDistanceFieldShader m_shader;
Q3DSDistanceFieldDropShadowShader m_dropShadowShader;
QVector<size_t> m_renderedGlyphs;
+ QVector<size_t> m_renderedTexts;
QStringList m_systemDirs;
QStringList m_projectDirs;
diff --git a/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp b/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp
index 4b74c51..2612b7c 100644
--- a/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp
+++ b/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp
@@ -292,10 +292,8 @@ public:
SRenderTextureAtlasDetails RenderText(const STextRenderInfo &inText) override
{
- qt3ds::foundation::IStringTable &theStringTable(m_RenderContext->GetStringTable());
-
- const wchar_t *wText = theStringTable.GetWideStr(inText.m_Text);
- QT3DSU32 length = (QT3DSU32)wcslen(wText);
+ const QString wText = QString::fromUtf8(inText.m_Text);
+ QT3DSU32 length = QT3DSU32(wText.length());
if (length) {
STextAtlasFont *pFont = m_TextFont;
@@ -307,13 +305,13 @@ public:
// we construct triangles here
// which means character count x 6 vertices x 5 floats
QT3DSF32 *vertexData =
- (QT3DSF32 *)QT3DS_ALLOC(m_Foundation.getAllocator(),
- length * 6 * 5 * sizeof(QT3DSF32),
- "Qt3DSOnscreenTextRenderer");
+ static_cast<QT3DSF32 *>(QT3DS_ALLOC(m_Foundation.getAllocator(),
+ length * 6 * 5 * sizeof(QT3DSF32),
+ "Qt3DSOnscreenTextRenderer"));
QT3DSF32 *bufPtr = vertexData;
if (vertexData) {
for (size_t i = 0; i < length; ++i) {
- pEntry = &pFont->m_AtlasEntries.find(wText[i])->second;
+ pEntry = &pFont->m_AtlasEntries.find(wText[uint(i)].unicode())->second;
if (pEntry) {
x1 = advance + pEntry->m_xOffset;
diff --git a/src/runtimerender/Qt3DSRenderContextCore.cpp b/src/runtimerender/Qt3DSRenderContextCore.cpp
index 33e1bf6..b5f9bc9 100644
--- a/src/runtimerender/Qt3DSRenderContextCore.cpp
+++ b/src/runtimerender/Qt3DSRenderContextCore.cpp
@@ -249,6 +249,7 @@ struct SRenderContext : public IQt3DSRenderContext
bool m_IsInSubPresentation;
Option<QT3DSVec4> m_SceneColor;
Option<QT3DSVec4> m_MatteColor;
+ bool m_matteEnabled;
RenderRotationValues::Enum m_Rotation;
NVScopedRefCounted<NVRenderFrameBuffer> m_RotationFBO;
NVScopedRefCounted<NVRenderTexture2D> m_RotationTexture;
@@ -276,14 +277,15 @@ struct SRenderContext : public IQt3DSRenderContext
, m_ResourceManager(IResourceManager::CreateResourceManager(ctx))
, m_ShaderCache(IShaderCache::CreateShaderCache(ctx, *m_InputStreamFactory, *m_PerfTimer))
, m_ThreadPool(inCore.GetThreadPool())
- , m_RenderList(IRenderList::CreateRenderList(ctx.GetFoundation()))
, m_PerFrameAllocator(ctx.GetAllocator())
+ , m_RenderList(IRenderList::CreateRenderList(ctx.GetFoundation()))
, m_FrameCount(0)
, mRefCount(0)
, m_WindowDimensions(800, 480)
, m_ScaleMode(ScaleModes::ExactSize)
, m_WireframeMode(false)
, m_IsInSubPresentation(false)
+ , m_matteEnabled(false)
, m_Rotation(RenderRotationValues::NoRotation)
, m_ContextRenderTarget(NULL)
, m_PresentationScale(0, 0)
@@ -420,6 +422,10 @@ struct SRenderContext : public IQt3DSRenderContext
void SetSceneColor(Option<QT3DSVec4> inSceneColor) override { m_SceneColor = inSceneColor; }
void SetMatteColor(Option<QT3DSVec4> inMatteColor) override { m_MatteColor = inMatteColor; }
+ void setMatteEnabled(bool enable) override
+ {
+ m_matteEnabled = enable;
+ }
void SetWindowDimensions(const QSize &inWindowDimensions) override
{
@@ -697,11 +703,17 @@ struct SRenderContext : public IQt3DSRenderContext
m_RenderContext->SetScissorTestEnabled(false);
}
{
- QT3DSVec4 theClearColor;
- if (m_MatteColor.hasValue())
+ QT3DSVec4 theClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ if (m_MatteColor.hasValue() && m_matteEnabled)
theClearColor = m_MatteColor;
- else
+ else if (m_SceneColor.hasValue())
theClearColor = m_SceneColor;
+ //premultiply the clear color
+ if (theClearColor.w < 1.0f) {
+ theClearColor.x *= theClearColor.w;
+ theClearColor.y *= theClearColor.w;
+ theClearColor.z *= theClearColor.w;
+ }
m_RenderContext->SetClearColor(theClearColor);
m_RenderContext->Clear(qt3ds::render::NVRenderClearValues::Color);
}
@@ -721,7 +733,13 @@ struct SRenderContext : public IQt3DSRenderContext
m_RotationDepthBuffer = NULL;
}
if (m_SceneColor.hasValue() && m_SceneColor.getValue().w != 0.0f) {
- m_RenderContext->SetClearColor(m_SceneColor);
+ QT3DSVec4 theClearColor = m_SceneColor;
+ if (theClearColor.w < 1.0f) {
+ theClearColor.x *= theClearColor.w;
+ theClearColor.y *= theClearColor.w;
+ theClearColor.z *= theClearColor.w;
+ }
+ m_RenderContext->SetClearColor(theClearColor);
m_RenderContext->Clear(qt3ds::render::NVRenderClearValues::Color);
}
} else {
@@ -752,7 +770,13 @@ struct SRenderContext : public IQt3DSRenderContext
}
m_RenderContext->SetRenderTarget(m_RotationFBO);
if (m_SceneColor.hasValue()) {
- m_RenderContext->SetClearColor(m_SceneColor);
+ QT3DSVec4 theClearColor = m_SceneColor;
+ if (theClearColor.w < 1.0f) {
+ theClearColor.x *= theClearColor.w;
+ theClearColor.y *= theClearColor.w;
+ theClearColor.z *= theClearColor.w;
+ }
+ m_RenderContext->SetClearColor(theClearColor);
m_RenderContext->Clear(qt3ds::render::NVRenderClearValues::Color);
}
}
diff --git a/src/runtimerender/Qt3DSRenderContextCore.h b/src/runtimerender/Qt3DSRenderContextCore.h
index 302571d..027d1f9 100644
--- a/src/runtimerender/Qt3DSRenderContextCore.h
+++ b/src/runtimerender/Qt3DSRenderContextCore.h
@@ -145,6 +145,7 @@ namespace render {
virtual void SetInSubPresentation(bool inValue) = 0;
virtual void SetSceneColor(Option<QT3DSVec4> inSceneColor) = 0;
virtual void SetMatteColor(Option<QT3DSVec4> inMatteColor) = 0;
+ virtual void setMatteEnabled(bool enable) = 0;
// Render screen aligned 2D text at x,y
virtual void RenderText2D(QT3DSF32 x, QT3DSF32 y, qt3ds::foundation::Option<qt3ds::QT3DSVec3> inColor,
diff --git a/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp b/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp
index aaf799f..a6fb9ee 100644
--- a/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp
+++ b/src/runtimerender/Qt3DSRenderCustomMaterialSystem.cpp
@@ -1975,7 +1975,7 @@ struct SMaterialSystem : public ICustomMaterialSystem
// TODO - return more information, specifically about transparency (object is transparent,
// object is completely transparent
bool PrepareForRender(const SModel & /*inModel*/, const SRenderSubset & /*inSubset*/,
- SCustomMaterial &inMaterial, bool clearMaterialDirtyFlags) override
+ SCustomMaterial &inMaterial) override
{
SMaterialClass *theMaterialClass = GetMaterialClass(inMaterial.m_ClassName);
if (theMaterialClass == NULL) {
@@ -1990,8 +1990,6 @@ struct SMaterialSystem : public ICustomMaterialSystem
inMaterial.m_hasVolumetricDF = false;
bool wasDirty = inMaterial.IsDirty() || theMaterialClass->m_AlwaysDirty;
- if (clearMaterialDirtyFlags)
- inMaterial.UpdateDirtyForFrame();
return wasDirty;
}
diff --git a/src/runtimerender/Qt3DSRenderCustomMaterialSystem.h b/src/runtimerender/Qt3DSRenderCustomMaterialSystem.h
index 6fe522f..478d2e3 100644
--- a/src/runtimerender/Qt3DSRenderCustomMaterialSystem.h
+++ b/src/runtimerender/Qt3DSRenderCustomMaterialSystem.h
@@ -111,7 +111,7 @@ namespace render {
// Returns true if the material is dirty and thus will produce a different render result
// than previously. This effects things like progressive AA.
virtual bool PrepareForRender(const SModel &inModel, const SRenderSubset &inSubset,
- SCustomMaterial &inMaterial, bool inClearDirty) = 0;
+ SCustomMaterial &inMaterial) = 0;
virtual bool RenderDepthPrepass(const QT3DSMat44 &inMVP, const SCustomMaterial &inMaterial,
const SRenderSubset &inSubset) = 0;
diff --git a/src/runtimerender/graphobjects/Qt3DSRenderScene.cpp b/src/runtimerender/graphobjects/Qt3DSRenderScene.cpp
index 7917bd7..7049035 100644
--- a/src/runtimerender/graphobjects/Qt3DSRenderScene.cpp
+++ b/src/runtimerender/graphobjects/Qt3DSRenderScene.cpp
@@ -37,8 +37,8 @@ using namespace qt3ds::render;
SScene::SScene()
: SGraphObject(GraphObjectTypes::Scene)
- , m_Presentation(NULL)
- , m_FirstChild(NULL)
+ , m_Presentation(nullptr)
+ , m_FirstChild(nullptr)
, m_ClearColor(0.0f)
, m_UseClearColor(true)
, m_Dirty(true)
@@ -47,7 +47,7 @@ SScene::SScene()
void SScene::AddChild(SLayer &inLayer)
{
- if (m_FirstChild == NULL)
+ if (m_FirstChild == nullptr)
m_FirstChild = &inLayer;
else
GetLastChild()->m_NextSibling = &inLayer;
@@ -71,6 +71,7 @@ bool SScene::PrepareForRender(const QT3DSVec2 &inViewportDimensions, IQt3DSRende
// We need to iterate through the layers in reverse order and ask them to render.
bool wasDirty = m_Dirty;
m_Dirty = false;
+
if (m_FirstChild) {
wasDirty |=
inContext.GetRenderer().PrepareLayerForRender(*m_FirstChild, inViewportDimensions,
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp
index 0b3f665..10f62c3 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp
@@ -236,6 +236,20 @@ namespace render {
if (theRenderData) {
theRenderData->PrepareForRender();
+ if (id) {
+ if (m_initialPrepareData.contains(theLayer)) {
+ // Copy dirty state from the initial since the graph is
+ // not dirty for subsequent calls
+ auto &flags = theRenderData->m_LayerPrepResult->m_Flags;
+ const auto &initialFlags
+ = m_initialPrepareData[theLayer]->m_LayerPrepResult->m_Flags;
+ flags.SetWasDirty(flags.WasDirty() || initialFlags.WasDirty());
+ flags.SetLayerDataDirty(flags.WasLayerDataDirty()
+ || initialFlags.WasLayerDataDirty());
+ } else {
+ m_initialPrepareData.insert(theLayer, theRenderData);
+ }
+ }
retval = retval || theRenderData->m_LayerPrepResult->m_Flags.WasDirty();
} else {
QT3DS_ASSERT(false);
@@ -495,6 +509,14 @@ namespace render {
for (QT3DSU32 idx = 0, end = m_LastFrameLayers.size(); idx < end; ++idx)
m_LastFrameLayers[idx]->ResetForFrame();
m_LastFrameLayers.clear();
+ m_initialPrepareData.clear();
+ for (auto *obj : qAsConst(m_materialClearDirty)) {
+ if (obj->m_Type == GraphObjectTypes::DefaultMaterial)
+ static_cast<SDefaultMaterial *>(obj)->m_Dirty.UpdateDirtyForFrame();
+ else if (obj->m_Type == GraphObjectTypes::CustomMaterial)
+ static_cast<SCustomMaterial *>(obj)->UpdateDirtyForFrame();
+ }
+ m_materialClearDirty.clear();
m_BeginFrameViewport = m_qt3dsContext.GetRenderList().GetViewport();
}
void Qt3DSRendererImpl::EndFrame()
@@ -1141,6 +1163,11 @@ namespace render {
inImage.m_TextureData.m_Texture->GenerateMipmaps();
}
+ void Qt3DSRendererImpl::addMaterialDirtyClear(SGraphObject *obj)
+ {
+ m_materialClearDirty.insert(obj);
+ }
+
bool NodeContainsBoneRoot(SNode &childNode, QT3DSI32 rootID)
{
for (SNode *childChild = childNode.m_FirstChild; childChild != NULL;
@@ -1851,9 +1878,11 @@ namespace render {
ITextTextureAtlas *theTextureAtlas = m_qt3dsContext.GetTextureAtlas();
QSize theWindow = m_qt3dsContext.GetWindowDimensions();
- const wchar_t *wText = m_StringTable->GetWideStr(text);
+ // Use dynamic strings to avoid memory leakage
+ QByteArray theText(text);
+ CStringHandle textHandle = m_StringTable->getDynamicHandle(theText);
STextRenderInfo theInfo;
- theInfo.m_Text = m_StringTable->RegisterStr(wText);
+ theInfo.m_Text = m_StringTable->HandleToStr(textHandle);
theInfo.m_FontSize = 20;
// text scale 2% of screen we don't scale Y though because it becomes unreadable
theInfo.m_ScaleX = (theWindow.width() / 100.0f) * 1.5f / (theInfo.m_FontSize);
@@ -1894,6 +1923,7 @@ namespace render {
QT3DS_FREE(m_Context->GetAllocator(),
theRenderTextDetails.first.m_Vertices.begin());
}
+ m_StringTable->releaseDynamicHandle(textHandle);
}
}
}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h
index 906afd6..6311a2d 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h
@@ -292,6 +292,9 @@ namespace render {
bool m_LayerGPuProfilingEnabled;
SShaderDefaultMaterialKeyProperties m_DefaultMaterialShaderKeyProperties;
+ QHash<SLayer *, SLayerRenderData *> m_initialPrepareData;
+ QSet<SGraphObject *> m_materialClearDirty;
+
public:
Qt3DSRendererImpl(IQt3DSRenderContext &ctx);
virtual ~Qt3DSRendererImpl();
@@ -402,6 +405,7 @@ namespace render {
void BeginLayerRender(SLayerRenderData &inLayer);
void EndLayerRender();
void PrepareImageForIbl(SImage &inImage);
+ void addMaterialDirtyClear(SGraphObject *obj);
NVRenderShaderProgram *CompileShader(CRegisteredString inName, const char8_t *inVert,
const char8_t *inFrame);
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
index 362a602..69c79ff 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
@@ -1281,9 +1281,8 @@ namespace render {
// If the user has disabled all layer caching this has the side effect of disabling the
// progressive AA algorithm.
if (thePrepResult.m_Flags.WasLayerDataDirty()
- || thePrepResult.m_Flags.WasDirty()
- || m_Renderer.IsLayerCachingEnabled() == false
- || thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ || thePrepResult.m_Flags.WasDirty()
+ || m_Renderer.IsLayerCachingEnabled() == false) {
m_ProgressiveAAPassIndex = 0;
m_NonDirtyTemporalAAPassIndex = 0;
needsRender = true;
@@ -1490,8 +1489,15 @@ namespace render {
theRenderContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport,
theNewViewport);
QT3DSVec4 clearColor(0.0f);
- if (m_Layer.m_Background == LayerBackground::Color)
+ if (m_Layer.m_Background == LayerBackground::Color) {
clearColor = m_Layer.m_ClearColor;
+ // Framebuffer holds premultiplied colors so the clearcolor must be premultiplied
+ if (clearColor.w < 1.0f) {
+ clearColor.x *= clearColor.w;
+ clearColor.y *= clearColor.w;
+ clearColor.z *= clearColor.w;
+ }
+ }
NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
theRenderContext, &NVRenderContext::GetClearColor, &NVRenderContext::SetClearColor,
@@ -1776,9 +1782,16 @@ namespace render {
theContext.SetScissorRect(
m_LayerPrepResult->GetLayerToPresentationScissorRect().ToIntegerRect());
if (m_Layer.m_Background == LayerBackground::Color) {
+ QT3DSVec4 clearColor = m_Layer.m_ClearColor;
+ // Framebuffer holds premultiplied colors so the clearcolor must be premultiplied
+ if (clearColor.w < 1.0f) {
+ clearColor.x *= clearColor.w;
+ clearColor.y *= clearColor.w;
+ clearColor.z *= clearColor.w;
+ }
NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
theContext, &NVRenderContext::GetClearColor, &NVRenderContext::SetClearColor,
- m_Layer.m_ClearColor);
+ clearColor);
theContext.Clear(NVRenderClearValues::Color);
}
RenderToViewport();
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
index 8afa3c0..6dcd4c9 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
@@ -388,6 +388,7 @@ namespace render {
Q3DSDistanceFieldRenderer *distanceFieldText
= static_cast<Q3DSDistanceFieldRenderer *>(
m_Renderer.GetQt3DSContext().getDistanceFieldRenderer());
+ distanceFieldText->buildShaders();
theRenderable = RENDER_FRAME_NEW(SDistanceFieldRenderable)(
theFlags, inText.GetGlobalPos(), inText, inText.m_Bounds, theMVP,
*distanceFieldText);
@@ -500,10 +501,8 @@ namespace render {
if (theMaterial != NULL && theMaterial->m_Type == GraphObjectTypes::DefaultMaterial) {
SDefaultMaterial *theDefaultMaterial = static_cast<SDefaultMaterial *>(theMaterial);
- // Don't clear dirty flags if the material was referenced.
- bool clearMaterialFlags = theMaterial == inPath.m_Material;
SDefaultMaterialPreparationResult prepResult(PrepareDefaultMaterialForRender(
- *theDefaultMaterial, theFlags, subsetOpacity, clearMaterialFlags));
+ *theDefaultMaterial, theFlags, subsetOpacity));
theFlags = prepResult.m_RenderableFlags;
if (inPath.m_PathType == PathTypes::Geometry) {
@@ -545,7 +544,8 @@ namespace render {
// Don't clear dirty flags if the material was referenced.
// bool clearMaterialFlags = theMaterial == inPath.m_Material;
SDefaultMaterialPreparationResult prepResult(
- PrepareCustomMaterialForRender(*theCustomMaterial, theFlags, subsetOpacity));
+ PrepareCustomMaterialForRender(*theCustomMaterial, theFlags, subsetOpacity,
+ retval));
theFlags = prepResult.m_RenderableFlags;
if (inPath.m_PathType == PathTypes::Geometry) {
@@ -660,8 +660,7 @@ namespace render {
}
SDefaultMaterialPreparationResult SLayerRenderPreparationData::PrepareDefaultMaterialForRender(
- SDefaultMaterial &inMaterial, SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity,
- bool inClearDirtyFlags)
+ SDefaultMaterial &inMaterial, SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity)
{
SDefaultMaterial *theMaterial = &inMaterial;
SDefaultMaterialPreparationResult retval(GenerateLightingKey(theMaterial->m_Lighting));
@@ -675,8 +674,6 @@ namespace render {
renderableFlags |= RenderPreparationResultFlagValues::Dirty;
}
subsetOpacity *= theMaterial->m_Opacity;
- if (inClearDirtyFlags)
- theMaterial->m_Dirty.UpdateDirtyForFrame();
SRenderableImage *firstImage = NULL;
@@ -780,11 +777,14 @@ namespace render {
retval.m_FirstImage = firstImage;
if (retval.m_RenderableFlags.IsDirty())
retval.m_Dirty = true;
+ if (retval.m_Dirty)
+ m_Renderer.addMaterialDirtyClear(&inMaterial);
return retval;
}
SDefaultMaterialPreparationResult SLayerRenderPreparationData::PrepareCustomMaterialForRender(
- SCustomMaterial &inMaterial, SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity)
+ SCustomMaterial &inMaterial, SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity,
+ bool alreadyDirty)
{
SDefaultMaterialPreparationResult retval(GenerateLightingKey(
DefaultMaterialLighting::FragmentLighting)); // always fragment lighting
@@ -836,6 +836,8 @@ namespace render {
#undef CHECK_IMAGE_AND_PREPARE
retval.m_FirstImage = firstImage;
+ if (retval.m_Dirty || alreadyDirty)
+ m_Renderer.addMaterialDirtyClear(&inMaterial);
return retval;
}
@@ -926,10 +928,6 @@ namespace render {
subsetDirty | (theSubset.m_WireframeMode != inModel.m_WireframeMode);
inModel.m_WireframeMode = false;
}
- // Only clear flags on the materials in this direct hierarchy. Do not clear them of
- // this
- // references materials in another hierarchy.
- bool clearMaterialDirtyFlags = theMaterialObject == theSourceMaterialObject;
if (theMaterialObject == NULL)
continue;
@@ -938,8 +936,8 @@ namespace render {
SDefaultMaterial &theMaterial(
static_cast<SDefaultMaterial &>(*theMaterialObject));
SDefaultMaterialPreparationResult theMaterialPrepResult(
- PrepareDefaultMaterialForRender(theMaterial, renderableFlags, subsetOpacity,
- clearMaterialDirtyFlags));
+ PrepareDefaultMaterialForRender(theMaterial, renderableFlags,
+ subsetOpacity));
SShaderDefaultMaterialKey theGeneratedKey = theMaterialPrepResult.m_MaterialKey;
subsetOpacity = theMaterialPrepResult.m_Opacity;
SRenderableImage *firstImage(theMaterialPrepResult.m_FirstImage);
@@ -968,11 +966,11 @@ namespace render {
ICustomMaterialSystem &theMaterialSystem(
qt3dsContext.GetCustomMaterialSystem());
subsetDirty |= theMaterialSystem.PrepareForRender(
- theModelContext.m_Model, theSubset, theMaterial, clearMaterialDirtyFlags);
+ theModelContext.m_Model, theSubset, theMaterial);
SDefaultMaterialPreparationResult theMaterialPrepResult(
PrepareCustomMaterialForRender(theMaterial, renderableFlags,
- subsetOpacity));
+ subsetOpacity, subsetDirty));
SShaderDefaultMaterialKey theGeneratedKey = theMaterialPrepResult.m_MaterialKey;
subsetOpacity = theMaterialPrepResult.m_Opacity;
SRenderableImage *firstImage(theMaterialPrepResult.m_FirstImage);
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h
index 5b8d6e1..4a4415f 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h
@@ -313,12 +313,12 @@ namespace render {
SDefaultMaterialPreparationResult
PrepareDefaultMaterialForRender(SDefaultMaterial &inMaterial,
- SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity,
- bool inClearMaterialFlags);
+ SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity);
SDefaultMaterialPreparationResult
PrepareCustomMaterialForRender(SCustomMaterial &inMaterial,
- SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity);
+ SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity,
+ bool alreadyDirty);
bool PrepareModelForRender(SModel &inModel, const QT3DSMat44 &inViewProjection,
const Option<SClippingFrustum> &inClipFrustum,
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp
index a3d3fab..eb560aa 100644
--- a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp
@@ -2399,7 +2399,6 @@ namespace render {
fragmentGenerator.Append("void main() {");
fragmentGenerator.Append("\tvec2 theCoords = uv_coords;\n");
fragmentGenerator.Append("\tvec4 theLayerTexture = texture2D( layer_image, theCoords );\n");
- fragmentGenerator.Append("\tif( theLayerTexture.a == 0.0 ) discard;\n");
fragmentGenerator.Append("\tfragOutput = theLayerTexture;\n");
fragmentGenerator.Append("}");
NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
diff --git a/src/viewer/Qt3DSViewerApp.cpp b/src/viewer/Qt3DSViewerApp.cpp
index 3199124..1402ef0 100644
--- a/src/viewer/Qt3DSViewerApp.cpp
+++ b/src/viewer/Qt3DSViewerApp.cpp
@@ -48,14 +48,6 @@
#include <mach-o/dyld.h>
#endif
-namespace qt3ds {
-void Qt3DSAssert(const char *exp, const char *file, int line, bool *ignore)
-{
- Q_UNUSED(ignore)
- qCritical() << "Assertion thrown: " << file << " " << line << " " << exp;
-}
-}
-
#ifndef EASTL_DEBUG_BREAK
void EASTL_DEBUG_BREAK()
{
@@ -833,6 +825,12 @@ void Q3DSViewerApp::setMatteColor(const QColor &color)
}
}
+void Q3DSViewerApp::setMatteEnabled(bool enable)
+{
+ if (m_Impl.m_view && m_Impl.m_view->GetTegraRenderEngine())
+ m_Impl.m_view->GetTegraRenderEngine()->setMatteEnabled(enable);
+}
+
void Q3DSViewerApp::setShowOnScreenStats(bool inShow)
{
if (m_Impl.m_view && m_Impl.m_view->GetTegraRenderEngine())
diff --git a/src/viewer/Qt3DSViewerApp.h b/src/viewer/Qt3DSViewerApp.h
index 06fdeef..3086d55 100644
--- a/src/viewer/Qt3DSViewerApp.h
+++ b/src/viewer/Qt3DSViewerApp.h
@@ -477,6 +477,7 @@ public:
void preloadSlide(const QString &slide);
void unloadSlide(const QString &slide);
void setDelayedLoading(bool enable);
+ void setMatteEnabled(bool enabled);
private:
/*
diff --git a/testres.qrc b/testres.qrc
deleted file mode 100644
index 79643b8..0000000
--- a/testres.qrc
+++ /dev/null
@@ -1,14 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file alias="aluminium.shader">Content/Material Library/aluminum.shader</file>
- <file alias="asphalt.shader">Content/Material Library/asphalt.shader</file>
- <file alias="concrete.shader">Content/Material Library/concrete.shader</file>
- <file alias="copper.shader">Content/Material Library/copper.shader</file>
- <file alias="porcelain.shader">Content/Material Library/porcelain.shader</file>
- <file alias="simple_glass.shader">Content/Material Library/simple_glass.shader</file>
- <file alias="Desaturate.effect">Content/Effect Library/Desaturate.effect</file>
- <file alias="Gaussian Blur.effect">Content/Effect Library/Gaussian Blur.effect</file>
- <file alias="Sepia.effect">Content/Effect Library/Sepia.effect</file>
- <file alias="Bloom.effect">Content/Effect Library/Bloom.effect</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
new file mode 100644
index 0000000..9c21cc1
--- /dev/null
+++ b/tests/auto/auto.pro
@@ -0,0 +1,10 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+#!macos:!win32: SUBDIRS += \
+# qtextras
+
+# TODO: Re-enable these tests after confirming CI can build & run them
+# runtime \
+# viewer \
+# studio3d
diff --git a/tests/auto/qtextras/qt3dsqmlstream/qt3dsqmlstream.pro b/tests/auto/qtextras/qt3dsqmlstream/qt3dsqmlstream.pro
new file mode 100644
index 0000000..57aab92
--- /dev/null
+++ b/tests/auto/qtextras/qt3dsqmlstream/qt3dsqmlstream.pro
@@ -0,0 +1,18 @@
+TEMPLATE = app
+CONFIG += testcase
+include($$PWD/../../../../commonplatform.pri)
+
+TARGET = tst_qt3dsqmlstream
+
+QT += testlib quick
+
+SOURCES += tst_qt3dsqmlstream.cpp
+
+INCLUDEPATH += \
+ $$PWD/../../../../src/qmlstreamer
+
+LIBS += \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+ANDROID_EXTRA_LIBS = \
+ libqt3dsqmlstreamer.so
diff --git a/tests/auto/qtextras/qt3dsqmlstream/tst_qt3dsqmlstream.cpp b/tests/auto/qtextras/qt3dsqmlstream/tst_qt3dsqmlstream.cpp
new file mode 100644
index 0000000..71de525
--- /dev/null
+++ b/tests/auto/qtextras/qt3dsqmlstream/tst_qt3dsqmlstream.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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/QtTest>
+#include <QSignalSpy>
+#include <q3dsqmlstream.h>
+#include <QQuickItem>
+
+class tst_Qt3DSQmlStream : public QObject
+{
+ Q_OBJECT
+public:
+ tst_Qt3DSQmlStream()
+ {
+ qRegisterMetaType<QQuickItem*>();
+ }
+ ~tst_Qt3DSQmlStream() {}
+private slots:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Q3DSQmlStream qmlstream;
+
+ // THEN
+ QVERIFY(qmlstream.presentationId().isNull());
+ QVERIFY(qmlstream.item() == nullptr);
+ }
+
+ void testSetPresentationId()
+ {
+ // GIVEN
+ Q3DSQmlStream qmlstream;
+ QString pid = "presentation0";
+ QSignalSpy spy(&qmlstream, SIGNAL(presentationIdChanged(const QString&)));
+
+ // WHEN
+ qmlstream.setPresentationId(pid);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(qmlstream.presentationId(), pid);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ qmlstream.setPresentationId(pid);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(spy.count(), 0);
+ }
+
+ void testSetItem()
+ {
+ // GIVEN
+ Q3DSQmlStream qmlstream;
+ QScopedPointer<QQuickItem> item(new QQuickItem());
+ QSignalSpy spy(&qmlstream, SIGNAL(itemChanged(QQuickItem *)));
+
+ // WHEN
+ qmlstream.setItem(item.data());
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(qmlstream.item(), item.data());
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ qmlstream.setItem(item.data());
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(spy.count(), 0);
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Qt3DSQmlStream)
+
+#include "tst_qt3dsqmlstream.moc"
diff --git a/tests/auto/qtextras/qtextras.pro b/tests/auto/qtextras/qtextras.pro
new file mode 100644
index 0000000..16a1ed8
--- /dev/null
+++ b/tests/auto/qtextras/qtextras.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+
+SUBDIRS += \
+ qt3dsqmlstream
diff --git a/tests/auto/runtime/Qt3DSRenderTestBase.cpp b/tests/auto/runtime/Qt3DSRenderTestBase.cpp
new file mode 100644
index 0000000..f4ab079
--- /dev/null
+++ b/tests/auto/runtime/Qt3DSRenderTestBase.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestBase.h"
+
+#include "Qt3DSDMPrefix.h"
+#include "EASTL/allocator.h"
+
+namespace eastl
+{
+void AssertionFailure(const char* pExpression)
+{
+ Q_UNUSED(pExpression);
+}
+EmptyString gEmptyString;
+void* gpEmptyBucketArray[2] = { nullptr, (void*)uintptr_t(~0) };
+}
+
+namespace qt3ds {
+
+void Qt3DSAssert(const char *exp, const char *file, int line, bool *ignore)
+{
+ Q_UNUSED(ignore)
+ qFatal("Assertion thrown %s(%d): %s", file, line, exp);
+}
+
+namespace render {
+SEndlType Endl;
+}
+}
+
+void *operator new[](size_t size, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
+
+void *operator new[](size_t size, size_t, size_t, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
+
+using namespace qt3ds::render;
+
+namespace qt3ds {
+namespace render {
+
+NVRenderTestBase::~NVRenderTestBase()
+{
+ delete m_renderImpl;
+}
+
+bool NVRenderTestBase::initializeQt3DSRenderer(QSurfaceFormat format)
+{
+ m_coreFactory = qt3ds::render::IQt3DSRenderFactoryCore::CreateRenderFactoryCore("", m_windowSystem,
+ m_timeProvider);
+ m_factory = m_coreFactory->CreateRenderFactory(format, false);
+ m_rc = m_factory->GetQt3DSRenderContext();
+ m_renderImpl = new qt3ds::render::Qt3DSRendererImpl(*m_rc);
+
+ return true;
+}
+
+Qt3DSRendererImpl *NVRenderTestBase::qt3dsRenderer()
+{
+ return m_renderImpl;
+}
+
+Q3DStudio::IRuntimeMetaData *NVRenderTestBase::metadata()
+{
+ if (m_metaData.mPtr == NULL)
+ m_metaData = &Q3DStudio::IRuntimeMetaData::Create(m_coreFactory->GetInputStreamFactory());
+ return m_metaData.mPtr;
+}
+
+}
+}
diff --git a/tests/auto/runtime/Qt3DSRenderTestBase.h b/tests/auto/runtime/Qt3DSRenderTestBase.h
new file mode 100644
index 0000000..bde0948
--- /dev/null
+++ b/tests/auto/runtime/Qt3DSRenderTestBase.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_BASE_H
+#define QT3DS_RENDER_TEST_BASE_H
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "render/Qt3DSRenderBaseTypes.h"
+#include "render/Qt3DSRenderContext.h"
+#include "Qt3DSWindowSystem.h"
+#include "Qt3DSTypes.h"
+#include "Qt3DSTimer.h"
+#include "Qt3DSRenderRuntimeBinding.h"
+#include "Qt3DSRenderRuntimeBindingImpl.h"
+#include "Qt3DSRenderContextCore.h"
+#include "rendererimpl/Qt3DSRendererImpl.h"
+#include "Qt3DSMetadata.h"
+
+namespace qt3ds {
+namespace render {
+class IQt3DSRenderer;
+class Qt3DSRendererImpl;
+class IQt3DSRenderFactoryCore;
+class IQt3DSRenderFactory;
+}
+}
+
+namespace qt3ds {
+namespace render {
+
+ class IQt3DSRenderFactoryCore;
+ class IQt3DSRenderFactory;
+ class Qt3DSRenderer;
+
+ typedef struct SUSER_CONTEXT_DATA
+ {
+ unsigned int winWidth;
+ unsigned int winHeight;
+ } userContextData;
+
+ struct SNullTimeProvider : public Q3DStudio::ITimeProvider
+ {
+ virtual Q3DStudio::INT64 GetCurrentTimeMicroSeconds() { return 0; }
+ };
+
+ struct SNullWindowSystem : public Q3DStudio::IWindowSystem
+ {
+ virtual QSize GetWindowDimensions() { return QSize(); }
+
+ virtual void SetWindowDimensions(const QSize &) {}
+ // For platforms that support it, we get the egl info for render plugins
+ // Feel free to return NULL.
+ virtual Q3DStudio::SEGLInfo *GetEGLInfo() { return NULL; }
+
+ // on some systems we allow our default render target to be a offscreen buffer
+ // otherwise return 0;
+ virtual int GetDefaultRenderTargetID() { return 0; }
+ // returns the depth buffer bit count for the render window
+ // does not really matter here
+ virtual int GetDepthBitCount() { return 16; }
+ };
+
+ /// this is the base class for all tests
+ class NVRenderTestBase
+ {
+ public:
+ /// constructor
+ NVRenderTestBase(){}
+ /// destructor
+ virtual ~NVRenderTestBase();
+
+ /// Checks if this test is supported
+ ///
+ /// @return true if supported
+ virtual bool isSupported(NVRenderContext *context) = 0;
+
+ /// This runs the test
+ ///
+ /// @param context (in) Pointer to a NVRenderContext context
+ /// @param pUserData (in) Pointer to pUserData
+ ///
+ /// @return false if failed
+ virtual bool run(NVRenderContext *context, userContextData *pUserData) = 0;
+
+ /// This cleans up state after the test if needed
+ ///
+ /// @param context (in) Pointer to a NVRenderContext context
+ /// @param pUserData (in) Pointer to pUserData
+ ///
+ /// @return false if failed
+ virtual void cleanup(NVRenderContext *context, userContextData *pUserData) = 0;
+
+ /// This runs the performance test
+ ///
+ /// @param context (in) Pointer to a NVRenderContext context
+ /// @param pUserData (in) Pointer to pUserData
+ ///
+ /// @return false if failed
+ virtual bool runPerformance(NVRenderContext *context, userContextData *pContextData) = 0;
+
+ /// This is a query to determine if we run on a ES context
+ ///
+ /// @param context (in) Pointer to a NVRenderContext context
+ ///
+ /// @return false if failed
+ virtual const bool isGLESContext(NVRenderContext *context)
+ {
+ NVRenderContextType ctxType = context->GetRenderContextType();
+
+ // Need minimum of GL3 or GLES3
+ if (ctxType == NVRenderContextValues::GLES2 || ctxType == NVRenderContextValues::GLES3
+ || ctxType == NVRenderContextValues::GLES3PLUS) {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool initializeQt3DSRenderer(QSurfaceFormat format);
+ qt3ds::render::Qt3DSRendererImpl *qt3dsRenderer();
+ Q3DStudio::IRuntimeMetaData *metadata();
+
+ private:
+
+ NVScopedRefCounted<qt3ds::render::IQt3DSRenderFactoryCore> m_coreFactory;
+ NVScopedRefCounted<qt3ds::render::IQt3DSRenderFactory> m_factory;
+ NVScopedRefCounted<qt3ds::render::IQt3DSRenderContext> m_rc;
+ qt3ds::foundation::NVScopedReleasable<Q3DStudio::IRuntimeMetaData> m_metaData;
+ qt3ds::render::Qt3DSRendererImpl *m_renderImpl;
+
+ SNullTimeProvider m_timeProvider;
+ SNullWindowSystem m_windowSystem;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_BASE_H
diff --git a/tests/auto/runtime/Qt3DSRenderTestMathUtil.cpp b/tests/auto/runtime/Qt3DSRenderTestMathUtil.cpp
new file mode 100644
index 0000000..f216faa
--- /dev/null
+++ b/tests/auto/runtime/Qt3DSRenderTestMathUtil.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestMathUtil.h"
+#include <math.h>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+#define QT3DS_RENDER_TEST_PI 3.14159265358979323846f
+
+inline float degreeToRad(float degree)
+{
+ return (degree * QT3DS_RENDER_TEST_PI) / 180.0f;
+}
+
+void qt3ds::render::NvRenderTestMatrixFrustum(QT3DSMat44 *m, float l, float r, float b, float t, float n,
+ float f)
+{
+ float rightMinusLeftInv, topMinusBottomInv, farMinusNearInv, twoNear;
+
+ rightMinusLeftInv = 1.0f / (r - l);
+ topMinusBottomInv = 1.0f / (t - b);
+ farMinusNearInv = 1.0f / (f - n);
+ twoNear = 2.0f * n;
+
+ m->column0 = QT3DSVec4(twoNear * rightMinusLeftInv, 0, 0, 0);
+ m->column1 = QT3DSVec4(0, twoNear * topMinusBottomInv, 0, 0);
+ m->column2 = QT3DSVec4((r + l) * rightMinusLeftInv, (t + b) * topMinusBottomInv,
+ -(f + n) * farMinusNearInv, -1.0f);
+ m->column3 = QT3DSVec4(0, 0, -(twoNear * f) * farMinusNearInv, 0.0f);
+}
+
+void qt3ds::render::NvGl2DemoMatrixOrtho(QT3DSMat44 *m, float l, float r, float b, float t, float n,
+ float f)
+{
+ float rightMinusLeftInv, topMinusBottomInv, farMinusNearInv;
+
+ rightMinusLeftInv = 1.0f / (r - l);
+ topMinusBottomInv = 1.0f / (t - b);
+ farMinusNearInv = 1.0f / (f - n);
+
+ m->column0 = QT3DSVec4(2.0f * rightMinusLeftInv, 0, 0, 0);
+ m->column1 = QT3DSVec4(0, 2.0f * topMinusBottomInv, 0, 0);
+ m->column2 = QT3DSVec4(0, 0, -2.0f * farMinusNearInv, 0);
+ m->column3 = QT3DSVec4(-(r + l) * rightMinusLeftInv, -(t + b) * topMinusBottomInv,
+ -(f + n) * farMinusNearInv, 1.0f);
+}
+
+void qt3ds::render::NvRenderTestMatrixRotX(QT3DSMat44 *m, float angle)
+{
+ float rad = degreeToRad(angle);
+ float cosPhi = cos(rad);
+ float sinPhi = sin(rad);
+
+ m->column0 = QT3DSVec4(1.0, 0.0, 0.0, 0.0);
+ m->column1 = QT3DSVec4(0.0, cosPhi, -sinPhi, 0.0);
+ m->column2 = QT3DSVec4(0.0, sinPhi, cosPhi, 0.0);
+ m->column3 = QT3DSVec4(0.0, 0.0, 0.0, 1.0);
+}
+
+void qt3ds::render::NvRenderTestMatrixRotY(QT3DSMat44 *m, float angle)
+{
+ float rad = degreeToRad(angle);
+ float cosPhi = cos(rad);
+ float sinPhi = sin(rad);
+
+ m->column0 = QT3DSVec4(cosPhi, 0.0, sinPhi, 0.0);
+ m->column1 = QT3DSVec4(0.0, 1.0, 0.0, 0.0);
+ m->column2 = QT3DSVec4(-sinPhi, 0.0, cosPhi, 0.0);
+ m->column3 = QT3DSVec4(0.0, 0.0, 0.0, 1.0);
+}
+
+void qt3ds::render::NvRenderTestMatrixRotZ(QT3DSMat44 *m, float angle)
+{
+ float rad = degreeToRad(angle);
+ float cosPhi = cos(rad);
+ float sinPhi = sin(rad);
+
+ m->column0 = QT3DSVec4(cosPhi, -sinPhi, 0.0, 0.0);
+ m->column1 = QT3DSVec4(sinPhi, cosPhi, 0.0, 0.0);
+ m->column2 = QT3DSVec4(0.0, 0.0, 1.0, 0.0);
+ m->column3 = QT3DSVec4(0.0, 0.0, 0.0, 1.0);
+}
+
+void qt3ds::render::NvRenderTestMatrixTranslation(QT3DSMat44 *m, float x, float y, float z)
+{
+ m->column0 = QT3DSVec4(1.0, 0.0, 0.0, 0.0);
+ m->column1 = QT3DSVec4(0.0, 1.0, 0.0, 0.0);
+ m->column2 = QT3DSVec4(0.0, 0.0, 1.0, 0.0);
+ m->column3 = QT3DSVec4(x, y, z, 1.0);
+}
diff --git a/tests/auto/runtime/Qt3DSRenderTestMathUtil.h b/tests/auto/runtime/Qt3DSRenderTestMathUtil.h
new file mode 100644
index 0000000..739209e
--- /dev/null
+++ b/tests/auto/runtime/Qt3DSRenderTestMathUtil.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_MATH_UTIL_H
+#define QT3DS_RENDER_TEST_MATH_UTIL_H
+
+#include "foundation/Qt3DSMat44.h"
+
+namespace qt3ds {
+namespace render {
+
+ void NvRenderTestMatrixFrustum(QT3DSMat44 *m, float l, float r, float b, float t, float n,
+ float f);
+
+ void NvGl2DemoMatrixOrtho(QT3DSMat44 *m, float l, float r, float b, float t, float n, float f);
+
+ void NvRenderTestMatrixRotX(QT3DSMat44 *m, float angle);
+ void NvRenderTestMatrixRotY(QT3DSMat44 *m, float angle);
+ void NvRenderTestMatrixRotZ(QT3DSMat44 *m, float angle);
+
+ void NvRenderTestMatrixTranslation(QT3DSMat44 *m, float x, float y, float z);
+}
+}
+
+#endif
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.cpp b/tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.cpp
new file mode 100644
index 0000000..9f81214
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.cpp
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestAtomicCounterBuffer.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderAtomicCounterBuffer.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "layout(binding = 2, offset = 0) uniform atomic_uint ac_raster;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " uint counter = atomicCounterIncrement(ac_raster);\n"
+ " float g = (float(counter)/255.0) / 255.0;\n"
+ " fragColor = vec4(0.0, g, 0.0, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+NVRenderTestAtomicCounterBuffer::NVRenderTestAtomicCounterBuffer()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestAtomicCounterBuffer::~NVRenderTestAtomicCounterBuffer()
+{
+}
+
+bool NVRenderTestAtomicCounterBuffer::isSupported(NVRenderContext *context)
+{
+ // This is currently only supported on GL 4 and GLES 3.1
+ if (!context->IsAtomicCounterBufferSupported())
+ return false;
+
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestAtomicCounterBuffer::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= rasterizerTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestAtomicCounterBuffer::rasterizerTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) },
+ { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderAtomicCounterBuffer> mAtomicCounterBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create atomic counter buffer
+ QT3DSU32 acCounter = 0;
+ NVDataRef<QT3DSU8> acData((QT3DSU8 *)&acCounter, sizeof(QT3DSU32));
+ mAtomicCounterBuffer = context->CreateAtomicCounterBuffer(
+ "ac_buffer", NVRenderBufferUsageType::Static, sizeof(QT3DSU32), acData);
+ if (!mAtomicCounterBuffer) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create atomic counter buffer";
+ return false;
+ }
+ // add a parameter
+ CRegisteredString theACName(context->GetStringTable().RegisterStr("ac_raster"));
+ mAtomicCounterBuffer->AddParam(theACName, 0);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestAtomicCounterBuffer shader",
+ toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderAtomicCounterBuffer *> atomicBuffer(
+ "ac_buffer", *compResult.mShader);
+ atomicBuffer.Set();
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestAtomicCounterBuffer::runPerformance(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestAtomicCounterBuffer::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.h b/tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.h
new file mode 100644
index 0000000..87b0910
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestAtomicCounterBuffer.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_ATOMIC_COUNTER_BUFFER_H
+#define QT3DS_RENDER_TEST_ATOMIC_COUNTER_BUFFER_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestAtomicCounterBuffer : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestAtomicCounterBuffer();
+ ~NVRenderTestAtomicCounterBuffer();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool rasterizerTest(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_ATOMIC_COUNTER_BUFFER_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.cpp b/tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.cpp
new file mode 100644
index 0000000..805782f
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestAttribBuffers.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "in vec3 attr_col; // Vertex col\n"
+ "out vec3 color; // output color\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ " color = attr_col;\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "in vec3 color; // input color\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4( color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+NVRenderTestAttribBuffers::NVRenderTestAttribBuffers()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestAttribBuffers::~NVRenderTestAttribBuffers()
+{
+}
+
+bool NVRenderTestAttribBuffers::isSupported(NVRenderContext *context)
+{
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestAttribBuffers::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= multiAttribBufferTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestAttribBuffers::multiAttribBufferTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) },
+ { QT3DSVec3(0.0, 0.9, 0) } };
+
+ static const Vertex vertexColors[] = { { QT3DSVec3(0.0, 1.0, 0.0) },
+ { QT3DSVec3(0.0, 0.6, 0.0) },
+ { QT3DSVec3(0.0, 0.2, 0.0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderVertexBuffer> mColorBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVRenderVertexBuffer *attribBuffers[2];
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestAttribBuffers shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0, 0),
+ NVRenderVertexBufferEntry("attr_col", NVRenderComponentTypes::QT3DSF32, 3, 0, 1),
+ };
+
+ // position buffer
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create vertex buffer";
+ return false;
+ }
+ // color buffer
+ NVDataRef<QT3DSU8> colorData((QT3DSU8 *)vertexColors, bufSize);
+ mColorBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), colorData);
+ if (!mColorBuffer) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create color buffer";
+ return false;
+ }
+
+ attribBuffers[0] = mVertexBuffer;
+ attribBuffers[1] = mColorBuffer;
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 2));
+ // create input Assembler
+ QT3DSU32 strides[2];
+ QT3DSU32 offsets[2];
+ strides[0] = mVertexBuffer->GetStride();
+ offsets[0] = 0;
+ strides[1] = mColorBuffer->GetStride();
+ offsets[1] = 0;
+
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, NVConstDataRef<NVRenderVertexBuffer *>(attribBuffers, 2), NULL,
+ toConstDataRef(strides, 2), toConstDataRef(offsets, 2), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestAttribBuffers::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestAttribBuffers::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.h b/tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.h
new file mode 100644
index 0000000..47e898f
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestAttribBuffers.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_ATTRIB_BUFFERS_H
+#define QT3DS_RENDER_TEST_ATTRIB_BUFFERS_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestAttribBuffers : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestAttribBuffers();
+ ~NVRenderTestAttribBuffers();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool multiAttribBufferTest(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_ATTRIB_BUFFERS_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.cpp b/tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.cpp
new file mode 100644
index 0000000..30f2637
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestBackendQuery.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *PassthroughVertShader()
+{
+ return "uniform mat4 mat_mvp;\n"
+ "attribute vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+}
+
+static const char *SimpleFragShader()
+{
+ return "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "uniform vec3 color;\n"
+ "void main()\n"
+ "{\n"
+ "gl_FragColor = vec4( color, 1);\n"
+ "}\n";
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+NVRenderTestBackendQuery::NVRenderTestBackendQuery()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestBackendQuery::~NVRenderTestBackendQuery()
+{
+}
+
+bool NVRenderTestBackendQuery::isSupported(NVRenderContext *context)
+{
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestBackendQuery::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= depthBitsTest(context, pUserData);
+ _curTest++;
+ success &= depthBitsFBOTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestBackendQuery::renderQuad(NVRenderContext *context, userContextData *pUserData,
+ QT3DSVec3 color)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestBackendQuery shader", toRef(PassthroughVertShader()),
+ toRef(SimpleFragShader()));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestBackendQuery::depthBitsTest: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestBackendQuery::depthBitsTest: Failed to create input assembler";
+ return false;
+ }
+
+ // check if default buffer bit size is in an acceptable size range
+ // we accept a range from 16 to 32
+ const QT3DSU32 bits = context->GetDepthBits();
+ bool passed = (bits >= 16 && bits <= 32);
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return passed;
+}
+
+bool NVRenderTestBackendQuery::depthBitsTest(NVRenderContext *context, userContextData *pUserData)
+{
+ QT3DSVec3 color(0.0, 0.0, 0.0);
+ // check if default buffer bit size is in an acceptable size range
+ // we accept a range from 16 to 32
+ const QT3DSU32 bits = context->GetDepthBits();
+ bool passed = (bits >= 16 && bits <= 32);
+ if (passed)
+ color.y = 1.0;
+ else
+ color.x = 1.0;
+
+ passed &= renderQuad(context, pUserData, color);
+
+ return passed;
+}
+
+bool NVRenderTestBackendQuery::depthBitsFBOTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ // depneding on the context we get different values
+ NVRenderContextType theContextFlags(NVRenderContextValues::GLES2 | NVRenderContextValues::GL2);
+ NVRenderContextType type = context->GetRenderContextType();
+ bool depth16_Only = (type & theContextFlags);
+ // create a FBO
+ NVScopedRefCounted<NVRenderFrameBuffer> m_FBO;
+ NVScopedRefCounted<NVRenderTexture2D> m_ColorTexture;
+ NVScopedRefCounted<NVRenderTexture2D> m_Depth16Texture;
+ NVScopedRefCounted<NVRenderTexture2D> m_Depth24Texture;
+ NVScopedRefCounted<NVRenderTexture2D> m_Depth32Texture;
+ NVScopedRefCounted<NVRenderTexture2D> m_Depth24Stencil8Texture;
+
+ m_ColorTexture = context->CreateTexture2D();
+ m_ColorTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0, 256, 256, NVRenderTextureFormats::RGBA8);
+ m_Depth16Texture = context->CreateTexture2D();
+ m_Depth16Texture->SetTextureData(NVDataRef<QT3DSU8>(), 0, 256, 256,
+ NVRenderTextureFormats::Depth16);
+
+ m_FBO = context->CreateFrameBuffer();
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*m_ColorTexture));
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Depth,
+ NVRenderTextureOrRenderBuffer(*m_Depth16Texture));
+
+ if (!m_FBO->IsComplete()) {
+ qWarning() << "NVRenderTestBackendQuery::depthBitsFBOTest: Failed to create FBO";
+ return false;
+ }
+
+ context->SetRenderTarget(m_FBO);
+
+ QT3DSVec3 color(0.0, 0.0, 0.0);
+ // check depth bit count
+ QT3DSU32 bits = context->GetDepthBits();
+ QT3DSU32 bitsExpected = 16;
+ bool passed = (bits == bitsExpected);
+
+ // detach depth
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Depth, NVRenderTextureOrRenderBuffer());
+
+ m_Depth24Texture = context->CreateTexture2D();
+ m_Depth24Texture->SetTextureData(NVDataRef<QT3DSU8>(), 0, 256, 256,
+ NVRenderTextureFormats::Depth24);
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Depth,
+ NVRenderTextureOrRenderBuffer(*m_Depth24Texture));
+ if (!m_FBO->IsComplete()) {
+ qWarning() << "NVRenderTestBackendQuery::depthBitsFBOTest: Failed to create FBO";
+ return false;
+ }
+ // check depth bit count
+ bits = context->GetDepthBits();
+ bitsExpected = (depth16_Only) ? 16 : 24;
+ passed &= (bits == bitsExpected);
+
+ // detach depth
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Depth, NVRenderTextureOrRenderBuffer());
+
+ m_Depth32Texture = context->CreateTexture2D();
+ m_Depth32Texture->SetTextureData(NVDataRef<QT3DSU8>(), 0, 256, 256,
+ NVRenderTextureFormats::Depth32);
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Depth,
+ NVRenderTextureOrRenderBuffer(*m_Depth32Texture));
+ if (!m_FBO->IsComplete()) {
+ qWarning() << "NVRenderTestBackendQuery::depthBitsFBOTest: Failed to create FBO";
+ return false;
+ }
+ // check depth bit count
+ bits = context->GetDepthBits();
+ bitsExpected = (depth16_Only) ? 16 : 32;
+ passed &= (bits == bitsExpected);
+
+ // detach depth
+ m_FBO->Attach(NVRenderFrameBufferAttachments::Depth, NVRenderTextureOrRenderBuffer());
+
+ // only test depth stencil if supported
+ if (context->IsDepthStencilSupported()) {
+ m_Depth24Stencil8Texture = context->CreateTexture2D();
+ m_Depth24Stencil8Texture->SetTextureData(NVDataRef<QT3DSU8>(), 0, 256, 256,
+ NVRenderTextureFormats::Depth24Stencil8);
+ m_FBO->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ NVRenderTextureOrRenderBuffer(*m_Depth24Stencil8Texture));
+ if (!m_FBO->IsComplete()) {
+ qWarning() << "NVRenderTestBackendQuery::depthBitsFBOTest: Failed to create FBO";
+ return false;
+ }
+ // check depth bit count
+ bits = context->GetDepthBits();
+ bitsExpected = (depth16_Only) ? 16 : 24;
+ passed &= (bits == bitsExpected);
+ }
+
+ context->SetRenderTarget(NULL);
+
+ if (passed)
+ color.y = 1.0;
+ else
+ color.x = 1.0;
+
+ passed &= renderQuad(context, pUserData, color);
+
+ return passed;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestBackendQuery::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestBackendQuery::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.h b/tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.h
new file mode 100644
index 0000000..e5fde64
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestBackendQuery.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_BACKEND_QUERY_H
+#define QT3DS_RENDER_TEST_BACKEND_QUERY_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestBackendQuery : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestBackendQuery();
+ ~NVRenderTestBackendQuery();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool depthBitsTest(NVRenderContext *context, userContextData *pUserData);
+ bool depthBitsFBOTest(NVRenderContext *context, userContextData *pUserData);
+
+ bool renderQuad(NVRenderContext *context, userContextData *pUserData, QT3DSVec3 color);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_CONSTANT_BUFFER_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestClear.cpp b/tests/auto/runtime/base/Qt3DSRenderTestClear.cpp
new file mode 100644
index 0000000..3e80d40
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestClear.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestClear.h"
+#include "foundation/Qt3DSVec4.h"
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+NVRenderTestClear::NVRenderTestClear()
+{
+}
+
+NVRenderTestClear::~NVRenderTestClear()
+{
+}
+
+bool NVRenderTestClear::isSupported(NVRenderContext *context)
+{
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+static bool checkColor(int width, int height, unsigned char *pixels, const QT3DSVec3 &color)
+{
+ unsigned char *pSrc = pixels;
+
+ for (int h = 0; h < height; h++) {
+ for (int w = 0; w < width; w++) {
+ if (pSrc[0] != (unsigned char)color.x || pSrc[1] != (unsigned char)color.y
+ || pSrc[2] != (unsigned char)color.z) {
+ return false;
+ }
+
+ pSrc += 3;
+ }
+ }
+
+ return true;
+}
+
+bool NVRenderTestClear::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+
+ success &= testColorClear(context, pUserData);
+
+ // if successful draw green otherwise a red
+ if (success) {
+ // set clear color to green
+ context->SetClearColor(QT3DSVec4(0.0f, 1.0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color));
+ } else {
+ // set clear color to green
+ context->SetClearColor(QT3DSVec4(1.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color));
+ }
+
+ return success;
+}
+
+bool NVRenderTestClear::testColorClear(NVRenderContext *context, userContextData *pUserData)
+{
+ // allocate buffer for readback
+ NVAllocatorCallback &alloc(context->GetFoundation().getAllocator());
+ QT3DSU32 size = pUserData->winHeight * pUserData->winHeight * 3 * sizeof(QT3DSU8);
+ QT3DSU8 *pixels = (QT3DSU8 *)alloc.allocate(size, "testColorClear color clear", __FILE__, __LINE__);
+
+ if (!pixels)
+ return false;
+
+ // set clear color to yellow
+ context->SetClearColor(QT3DSVec4(1.0f, 1.0f, .0f, 0.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color));
+
+ // read back pixels
+ context->ReadPixels(NVRenderRect(0, 0, pUserData->winHeight, pUserData->winHeight),
+ NVRenderReadPixelFormats::RGB8, NVDataRef<QT3DSU8>(pixels, size));
+ // check color
+ bool passed =
+ checkColor(pUserData->winHeight, pUserData->winHeight, pixels, QT3DSVec3(255.0f, 255.0f, .0f));
+
+ alloc.deallocate(pixels);
+
+ return passed;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestClear::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestClear::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestClear.h b/tests/auto/runtime/base/Qt3DSRenderTestClear.h
new file mode 100644
index 0000000..6113b7b
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestClear.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_CLEAR_H
+#define QT3DS_RENDER_TEST_CLEAR_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the render target clearing
+ class NVRenderTestClear : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestClear();
+ ~NVRenderTestClear();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextDat);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ /// subtests
+ bool testColorClear(NVRenderContext *context, userContextData *pUserData);
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_CLEAR_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.cpp b/tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.cpp
new file mode 100644
index 0000000..8b6cb34
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.cpp
@@ -0,0 +1,847 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestConstantBuffer.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const char *scalarVertShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "layout (std140) uniform cbBuffer { \n"
+ "float red;\n"
+ "float green;\n"
+ "mat4 mat_mvp;\n"
+ "float blue;\n };\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *scalarFragShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "layout (std140) uniform cbBuffer { \n"
+ "float red;\n"
+ "float green;\n"
+ "mat4 mat_mvp;\n"
+ "float blue;\n };\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(red, green, blue, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *vectorVertShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "layout (std140) uniform cbBuffer { \n"
+ "vec2 rg;\n"
+ "mat4 mat_mvp;\n"
+ "vec2 ba;\n };\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *vectorFragShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "layout (std140) uniform cbBuffer { \n"
+ "vec2 rg;\n"
+ "mat4 mat_mvp;\n"
+ "vec2 ba;\n };\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(rg[0], rg[1], ba[0], ba[1]);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *structVertShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "struct sampleStruct {\n"
+ "vec2 rg;\n"
+ "mat4 mat_mvp;\n"
+ "float blue;\n"
+ "float alpha; };\n"
+ "layout (std140) uniform cbBuffer { \n"
+ "sampleStruct s[2]; };\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = s[0].mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *structFragShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "struct sampleStruct {\n"
+ "vec2 rg;\n"
+ "mat4 mat_mvp;\n"
+ "float blue;\n"
+ "float alpha; };\n"
+ "layout (std140) uniform cbBuffer { \n"
+ "sampleStruct s[2]; };\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(s[0].rg[0], s[0].rg[1], s[0].blue, s[0].alpha);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *multiCBVertShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "layout (std140) uniform cbBufferTrans { \n"
+ "mat4 mat_mvp;\n };\n"
+ "layout (std140) uniform cbBufferCol { \n"
+ "float red;\n"
+ "float green;\n"
+ "float blue;\n };\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *multiCBFragShader(bool bESContext, std::string &prog)
+{
+ if (bESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330 compatibility\n";
+ }
+
+ prog += "layout (std140) uniform cbBufferTrans { \n"
+ "mat4 mat_mvp;\n };\n"
+ "layout (std140) uniform cbBufferCol { \n"
+ "float red;\n"
+ "float green;\n"
+ "float blue;\n };\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(red, green, blue, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+NVRenderTestConstantBuffer::NVRenderTestConstantBuffer()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestConstantBuffer::~NVRenderTestConstantBuffer()
+{
+}
+
+bool NVRenderTestConstantBuffer::isSupported(NVRenderContext *context)
+{
+ NVRenderContextType ctxType = context->GetRenderContextType();
+ NVRenderContextType nonSupportedFlags(NVRenderContextValues::GL2
+ | NVRenderContextValues::GLES2);
+
+ // This is currently only supported on GL(Es) >= 3
+ if ((ctxType & nonSupportedFlags))
+ return false;
+
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestConstantBuffer::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= scalarTest(context, pUserData);
+ _curTest++;
+ success &= vectorTest(context, pUserData);
+ _curTest++;
+ success &= structTest(context, pUserData);
+ _curTest++;
+ success &= rawTest(context, pUserData);
+ _curTest++;
+ success &= multiCBTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestConstantBuffer::scalarTest(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderConstantBuffer> mConstantBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create constant buffer referred in the program
+ mConstantBuffer = context->CreateConstantBuffer("cbBuffer", NVRenderBufferUsageType::Static, 0,
+ NVDataRef<QT3DSU8>());
+ // buffer parameter. They must be in the order of appearance
+ CRegisteredString theRedName(context->GetStringTable().RegisterStr("red"));
+ mConstantBuffer->AddParam(theRedName, NVRenderShaderDataTypes::QT3DSF32, 1);
+ CRegisteredString theGreenName(context->GetStringTable().RegisterStr("green"));
+ mConstantBuffer->AddParam(theGreenName, NVRenderShaderDataTypes::QT3DSF32, 1);
+ CRegisteredString theMatName(context->GetStringTable().RegisterStr("mat_mvp"));
+ mConstantBuffer->AddParam(theMatName, NVRenderShaderDataTypes::QT3DSMat44, 1);
+ CRegisteredString theBlueName(context->GetStringTable().RegisterStr("blue"));
+ mConstantBuffer->AddParam(theBlueName, NVRenderShaderDataTypes::QT3DSF32, 1);
+
+ // set values
+ QT3DSF32 red = 0.0;
+ mConstantBuffer->UpdateParam("red", NVDataRef<QT3DSU8>((QT3DSU8 *)&red, 1));
+ QT3DSF32 green = 1.0;
+ mConstantBuffer->UpdateParam("green", NVDataRef<QT3DSU8>((QT3DSU8 *)&green, 1));
+ QT3DSF32 blue = 0.0;
+ mConstantBuffer->UpdateParam("blue", NVDataRef<QT3DSU8>((QT3DSU8 *)&blue, 1));
+ mConstantBuffer->UpdateParam("mat_mvp", NVDataRef<QT3DSU8>((QT3DSU8 *)mvp.front(), 1));
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestConstantBuffer::scalarTest",
+ toRef(scalarVertShader(isGLESContext(context), vtxProg)),
+ toRef(scalarFragShader(isGLESContext(context), frgProg)));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestConstantBuffer::scalarTest: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestConstantBuffer::scalarTest: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderConstantBuffer *> cb("cbBuffer",
+ *compResult.mShader);
+ mConstantBuffer->Update();
+ cb.Set();
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestConstantBuffer::vectorTest(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderConstantBuffer> mConstantBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create constant buffer referred in the program
+ mConstantBuffer = context->CreateConstantBuffer("cbBuffer", NVRenderBufferUsageType::Static, 0,
+ NVDataRef<QT3DSU8>());
+ // buffer parameter. They must be in the order of appearance
+ CRegisteredString theRGName(context->GetStringTable().RegisterStr("rg"));
+ mConstantBuffer->AddParam(theRGName, NVRenderShaderDataTypes::QT3DSVec2, 1);
+ CRegisteredString theMatName(context->GetStringTable().RegisterStr("mat_mvp"));
+ mConstantBuffer->AddParam(theMatName, NVRenderShaderDataTypes::QT3DSMat44, 1);
+ CRegisteredString theBAName(context->GetStringTable().RegisterStr("ba"));
+ mConstantBuffer->AddParam(theBAName, NVRenderShaderDataTypes::QT3DSVec2, 1);
+
+ // set values
+ QT3DSVec2 rg;
+ rg[0] = 0.0;
+ rg[1] = 1.0;
+ mConstantBuffer->UpdateParam("rg", NVDataRef<QT3DSU8>((QT3DSU8 *)&rg, 1));
+ QT3DSVec2 ba;
+ ba[0] = 0.0;
+ ba[1] = 1.0;
+ mConstantBuffer->UpdateParam("ba", NVDataRef<QT3DSU8>((QT3DSU8 *)&ba, 1));
+ mConstantBuffer->UpdateParam("mat_mvp", NVDataRef<QT3DSU8>((QT3DSU8 *)mvp.front(), 1));
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestConstantBuffer::vectorTest",
+ toRef(vectorVertShader(isGLESContext(context), vtxProg)),
+ toRef(vectorFragShader(isGLESContext(context), frgProg)));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestConstantBuffer::vectorTest: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestConstantBuffer::vectorTest: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderConstantBuffer *> cb("cbBuffer",
+ *compResult.mShader);
+ cb.Set();
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestConstantBuffer::structTest(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderConstantBuffer> mConstantBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create constant buffer referred in the program
+ mConstantBuffer = context->CreateConstantBuffer("cbBuffer", NVRenderBufferUsageType::Static, 0,
+ NVDataRef<QT3DSU8>());
+ // buffer parameter. They must be in the order of appearance
+ CRegisteredString theRGName(context->GetStringTable().RegisterStr("s[0].rg"));
+ mConstantBuffer->AddParam(theRGName, NVRenderShaderDataTypes::QT3DSVec2, 1);
+ CRegisteredString theMatName(context->GetStringTable().RegisterStr("s[0].mat_mvp"));
+ mConstantBuffer->AddParam(theMatName, NVRenderShaderDataTypes::QT3DSMat44, 1);
+ CRegisteredString theBlueName(context->GetStringTable().RegisterStr("s[0].blue"));
+ mConstantBuffer->AddParam(theBlueName, NVRenderShaderDataTypes::QT3DSF32, 1);
+ CRegisteredString theAlphaName(context->GetStringTable().RegisterStr("s[0].alpha"));
+ mConstantBuffer->AddParam(theAlphaName, NVRenderShaderDataTypes::QT3DSF32, 1);
+
+ // set values
+ QT3DSVec2 rg;
+ rg[0] = 0.0;
+ rg[1] = 1.0;
+ mConstantBuffer->UpdateParam("s[0].rg", NVDataRef<QT3DSU8>((QT3DSU8 *)&rg, 1));
+ QT3DSF32 blue, alpha;
+ blue = 0.0;
+ alpha = 1.0;
+ mConstantBuffer->UpdateParam("s[0].blue", NVDataRef<QT3DSU8>((QT3DSU8 *)&blue, 1));
+ mConstantBuffer->UpdateParam("s[0].alpha", NVDataRef<QT3DSU8>((QT3DSU8 *)&alpha, 1));
+ mConstantBuffer->UpdateParam("s[0].mat_mvp", NVDataRef<QT3DSU8>((QT3DSU8 *)mvp.front(), 1));
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestConstantBuffer::structTest",
+ toRef(structVertShader(isGLESContext(context), vtxProg)),
+ toRef(structFragShader(isGLESContext(context), frgProg)));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestConstantBuffer::structTest: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestConstantBuffer::structTest: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderConstantBuffer *> cb("cbBuffer",
+ *compResult.mShader);
+ cb.Set();
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestConstantBuffer::rawTest(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ struct sampleStruct
+ {
+ float rg[2];
+ float padding[2];
+ QT3DSMat44 mat_mvp; // matrices start on 16 byte boundaries
+ float blue;
+ float alpha;
+ } s;
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderConstantBuffer> mConstantBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ NVDataRef<QT3DSU8> cBuffer((QT3DSU8 *)&s, sizeof(sampleStruct));
+ // create constant buffer referred in the program
+ mConstantBuffer = context->CreateConstantBuffer("cbBuffer", NVRenderBufferUsageType::Static,
+ sizeof(sampleStruct), cBuffer);
+ // set values
+ s.rg[0] = 0.0;
+ s.rg[1] = 1.0;
+ s.mat_mvp = mvp;
+ s.blue = 0.0;
+ s.alpha = 0.0;
+ mConstantBuffer->UpdateRaw(0, cBuffer);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestConstantBuffer::rawTest",
+ toRef(structVertShader(isGLESContext(context), vtxProg)),
+ toRef(structFragShader(isGLESContext(context), frgProg)));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestConstantBuffer::rawTest: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestConstantBuffer::rawTest: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderConstantBuffer *> cb("cbBuffer",
+ *compResult.mShader);
+ cb.Set();
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+///< test of multiple constant buffers
+bool NVRenderTestConstantBuffer::multiCBTest(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderConstantBuffer> mConstantBufferTrans;
+ NVScopedRefCounted<NVRenderConstantBuffer> mConstantBufferCol;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create constant buffer referred in the program
+ mConstantBufferTrans = context->CreateConstantBuffer(
+ "cbBufferTrans", NVRenderBufferUsageType::Static, 0, NVDataRef<QT3DSU8>());
+ // buffer parameter. They must be in the order of appearance
+ CRegisteredString theMatName(context->GetStringTable().RegisterStr("mat_mvp"));
+ mConstantBufferTrans->AddParam(theMatName, NVRenderShaderDataTypes::QT3DSMat44, 1);
+
+ // create constant buffer referred in the program
+ mConstantBufferCol = context->CreateConstantBuffer(
+ "cbBufferCol", NVRenderBufferUsageType::Static, 0, NVDataRef<QT3DSU8>());
+ CRegisteredString theRedName(context->GetStringTable().RegisterStr("red"));
+ mConstantBufferCol->AddParam(theRedName, NVRenderShaderDataTypes::QT3DSF32, 1);
+ CRegisteredString theGreenName(context->GetStringTable().RegisterStr("green"));
+ mConstantBufferCol->AddParam(theGreenName, NVRenderShaderDataTypes::QT3DSF32, 1);
+ CRegisteredString theBlueName(context->GetStringTable().RegisterStr("blue"));
+ mConstantBufferCol->AddParam(theBlueName, NVRenderShaderDataTypes::QT3DSF32, 1);
+
+ // set values
+ mConstantBufferTrans->UpdateParam("mat_mvp", NVDataRef<QT3DSU8>((QT3DSU8 *)mvp.front(), 1));
+
+ QT3DSF32 red = 0.0;
+ mConstantBufferCol->UpdateParam("red", NVDataRef<QT3DSU8>((QT3DSU8 *)&red, 1));
+ QT3DSF32 green = 1.0;
+ mConstantBufferCol->UpdateParam("green", NVDataRef<QT3DSU8>((QT3DSU8 *)&green, 1));
+ QT3DSF32 blue = 0.0;
+ mConstantBufferCol->UpdateParam("blue", NVDataRef<QT3DSU8>((QT3DSU8 *)&blue, 1));
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestConstantBuffer::multiCBTest",
+ toRef(multiCBVertShader(isGLESContext(context), vtxProg)),
+ toRef(multiCBFragShader(isGLESContext(context), frgProg)));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestConstantBuffer::scalarTest: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestConstantBuffer::scalarTest: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderConstantBuffer *> cbTrans(
+ "cbBufferTrans", *compResult.mShader);
+ mConstantBufferTrans->Update();
+ cbTrans.Set();
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderConstantBuffer *> cbCol(
+ "cbBufferCol", *compResult.mShader);
+ mConstantBufferCol->Update();
+ cbCol.Set();
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestConstantBuffer::runPerformance(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestConstantBuffer::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.h b/tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.h
new file mode 100644
index 0000000..417e4bb
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestConstantBuffer.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_CONSTANT_BUFFER_H
+#define QT3DS_RENDER_TEST_CONSTANT_BUFFER_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestConstantBuffer : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestConstantBuffer();
+ ~NVRenderTestConstantBuffer();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool scalarTest(NVRenderContext *context, userContextData *pUserData);
+ bool vectorTest(NVRenderContext *context, userContextData *pUserData);
+ bool structTest(NVRenderContext *context, userContextData *pUserData);
+ bool rawTest(NVRenderContext *context, userContextData *pUserData);
+ bool multiCBTest(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_CONSTANT_BUFFER_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.cpp b/tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.cpp
new file mode 100644
index 0000000..4b8044d
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestDrawIndirectBuffer.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderDrawIndirectBuffer.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+NVRenderTestDrawIndirectBuffer::NVRenderTestDrawIndirectBuffer()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestDrawIndirectBuffer::~NVRenderTestDrawIndirectBuffer()
+{
+}
+
+bool NVRenderTestDrawIndirectBuffer::isSupported(NVRenderContext *context)
+{
+ // This is currently only supported on GL 4 and GLES 3.1
+ // we have no direct check for this but this is the same version
+ if (!context->IsAtomicCounterBufferSupported())
+ return false;
+
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestDrawIndirectBuffer::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= drawArrayIndirect(context, pUserData);
+ _curTest++;
+ success &= drawElementsIndirect(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestDrawIndirectBuffer::drawArrayIndirect(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) },
+ { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderDrawIndirectBuffer> mDrawIndirectBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestDrawIndirectBuffer shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), NULL, toConstDataRef(&strides, 1),
+ toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create input assembler";
+ return false;
+ }
+
+ // create draw indirect buffer
+ DrawArraysIndirectCommand command;
+ command.baseInstance = 0;
+ command.count = 6;
+ command.first = 0;
+ command.primCount = 1;
+ QT3DSU32 commandBufSize = sizeof(DrawArraysIndirectCommand);
+ NVDataRef<QT3DSU8> commandData((QT3DSU8 *)&command, commandBufSize);
+ mDrawIndirectBuffer = context->CreateDrawIndirectBuffer(NVRenderBufferUsageType::Dynamic,
+ commandBufSize, commandData);
+
+ if (!mDrawIndirectBuffer) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create vertex buffer";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ mDrawIndirectBuffer->Bind();
+ context->DrawIndirect(mInputAssembler->GetPrimitiveType(), 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestDrawIndirectBuffer::drawElementsIndirect(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) },
+ { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ const unsigned short indices[] = { 0, 1, 2, 3, 4, 5 };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderDrawIndirectBuffer> mDrawIndirectBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestDrawIndirectBuffer shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create vertex buffer";
+ return false;
+ }
+
+ // index buffer
+ bufSize = 6 * sizeof(unsigned short);
+ NVDataRef<QT3DSU8> idxData((QT3DSU8 *)indices, bufSize);
+ mIndexBuffer = context->CreateIndexBuffer(
+ NVRenderBufferUsageType::Static, NVRenderComponentTypes::QT3DSU16, bufSize,
+ NVConstDataRef<QT3DSU8>(reinterpret_cast<const QT3DSU8 *>(indices), bufSize));
+ if (!mIndexBuffer) {
+ qWarning() << "NVRenderTestPrimitives::Triangles: Failed to create index buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create input assembler";
+ return false;
+ }
+
+ // create draw indirect buffer
+ DrawElementsIndirectCommand command;
+ command.baseInstance = 0;
+ command.count = 6;
+ command.firstIndex = 0;
+ command.baseVertex = 0;
+ command.primCount = 1;
+ QT3DSU32 commandBufSize = sizeof(DrawElementsIndirectCommand);
+ NVDataRef<QT3DSU8> commandData((QT3DSU8 *)&command, commandBufSize);
+ mDrawIndirectBuffer = context->CreateDrawIndirectBuffer(NVRenderBufferUsageType::Dynamic,
+ commandBufSize, commandData);
+
+ if (!mDrawIndirectBuffer) {
+ qWarning() << "NVRenderTestAtomicCounterBuffer: Failed to create vertex buffer";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ mDrawIndirectBuffer->Bind();
+ context->DrawIndirect(mInputAssembler->GetPrimitiveType(), 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestDrawIndirectBuffer::runPerformance(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestDrawIndirectBuffer::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.h b/tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.h
new file mode 100644
index 0000000..ee37a13
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestDrawIndirectBuffer.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_DRAW_INDIRECT_BUFFER_H
+#define QT3DS_RENDER_TEST_DRAW_INDIRECT_BUFFER_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestDrawIndirectBuffer : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestDrawIndirectBuffer();
+ ~NVRenderTestDrawIndirectBuffer();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool drawArrayIndirect(NVRenderContext *context, userContextData *pUserData);
+ bool drawElementsIndirect(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_ATOMIC_COUNTER_BUFFER_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestPrimitives.cpp b/tests/auto/runtime/base/Qt3DSRenderTestPrimitives.cpp
new file mode 100644
index 0000000..d3c2423
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestPrimitives.cpp
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestPrimitives.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *PassthroughVertShader()
+{
+ return "uniform mat4 mat_mvp;\n"
+ "attribute vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+}
+
+static const char *SimpleFragShader()
+{
+ return "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "void main()\n"
+ "{\n"
+ "gl_FragColor = vec4(0, 1, 0, 1);\n"
+ "}\n";
+}
+
+NVRenderTestPrimitives::NVRenderTestPrimitives()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestPrimitives::~NVRenderTestPrimitives()
+{
+}
+
+bool NVRenderTestPrimitives::isSupported(NVRenderContext *context)
+{
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestPrimitives::renderPrimitive(NVRenderContext *context,
+ userContextData *pContextData,
+ const Vertex *pVertexData, unsigned int vertexCount,
+ const unsigned short *pIndexData,
+ unsigned int indexCount,
+ NVRenderDrawMode::Enum primType)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestPrimitives shader", toRef(PassthroughVertShader()), toRef(SimpleFragShader()));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = vertexCount * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)pVertexData, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestPrimitives::Triangles: Failed to create vertex buffer";
+ return false;
+ }
+
+ // index buffer
+ if (pIndexData && indexCount) {
+ bufSize = indexCount * sizeof(unsigned short);
+ NVDataRef<QT3DSU8> idxData((QT3DSU8 *)pIndexData, bufSize);
+ mIndexBuffer = context->CreateIndexBuffer(
+ NVRenderBufferUsageType::Static, NVRenderComponentTypes::QT3DSU16, bufSize,
+ NVConstDataRef<QT3DSU8>(reinterpret_cast<const QT3DSU8 *>(pIndexData), bufSize));
+ if (!mIndexBuffer) {
+ qWarning() << "NVRenderTestPrimitives::Triangles: Failed to create index buffer";
+ return false;
+ }
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestPrimitives::Triangles: Failed to create inout assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ QT3DSU32 count = (mIndexBuffer.mPtr) ? indexCount : vertexCount;
+ context->Draw(primType, count, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestPrimitives::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= triangles(context, pUserData);
+ _curTest++;
+ success &= triangleStrip(context, pUserData);
+ _curTest++;
+ success &= lines(context, pUserData);
+ _curTest++;
+ success &= lineStrip(context, pUserData);
+ _curTest++;
+ success &= trianglesIndexed(context, pUserData);
+ _curTest++;
+ success &= triangleStripIndexed(context, pUserData);
+ _curTest++;
+ success &= linesIndexed(context, pUserData);
+ _curTest++;
+ success &= lineStripIndexed(context, pUserData);
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestPrimitives::triangles(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.85, -0.9, 0) }, { QT3DSVec3(-0.85, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 6, NULL, 0,
+ NVRenderDrawMode::Triangles);
+}
+
+bool NVRenderTestPrimitives::triangleStrip(NVRenderContext *context, userContextData *pUserData)
+{
+ const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0.0) },
+ { QT3DSVec3(-0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, 0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, -0.9f, 0.0f) } };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 4, NULL, 0,
+ NVRenderDrawMode::TriangleStrip);
+}
+
+bool NVRenderTestPrimitives::lines(NVRenderContext *context, userContextData *pUserData)
+{
+ const Vertex vertexPositions[] = {
+ { QT3DSVec3(0.9f, 0.9f, 0.0f) }, { QT3DSVec3(0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, -0.9f, 0.0f) }, { QT3DSVec3(-0.85f, -0.9f, 0.0f) },
+ { QT3DSVec3(-0.85f, -0.9f, 0.0f) }, { QT3DSVec3(0.9f, 0.9f, 0.0f) },
+ { QT3DSVec3(-0.9f, -0.9f, 0.0f) }, { QT3DSVec3(0.85f, 0.9f, 0.0f) },
+ { QT3DSVec3(0.85f, 0.9f, 0.0f) }, { QT3DSVec3(-0.9f, 0.9f, 0.0f) },
+ { QT3DSVec3(-0.9f, 0.9f, 0.0f) }, { QT3DSVec3(-0.9f, -0.9f, 0.0f) }
+ };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 12, NULL, 0,
+ NVRenderDrawMode::Lines);
+}
+
+bool NVRenderTestPrimitives::lineStrip(NVRenderContext *context, userContextData *pUserData)
+{
+ const Vertex vertexPositions[] = {
+ { QT3DSVec3(-0.9f, 0.9f, 0.0f) }, { QT3DSVec3(-0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, -0.9f, 0.0f) }, { QT3DSVec3(0.9f, 0.9f, 0.0f) },
+ { QT3DSVec3(-0.9f, 0.9f, 0.0f) },
+ };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 5, NULL, 0,
+ NVRenderDrawMode::LineStrip);
+}
+
+bool NVRenderTestPrimitives::trianglesIndexed(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.85, -0.9, 0) }, { QT3DSVec3(-0.85, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+ const unsigned short indices[] = { 0, 1, 2, 3, 4, 5 };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 6, indices, 6,
+ NVRenderDrawMode::Triangles);
+}
+
+bool NVRenderTestPrimitives::triangleStripIndexed(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0.0) },
+ { QT3DSVec3(-0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, 0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, -0.9f, 0.0f) } };
+
+ const unsigned short indices[] = { 0, 1, 2, 3 };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 4, indices, 4,
+ NVRenderDrawMode::TriangleStrip);
+}
+
+bool NVRenderTestPrimitives::linesIndexed(NVRenderContext *context, userContextData *pUserData)
+{
+ const Vertex vertexPositions[] = {
+ { QT3DSVec3(0.9f, 0.9f, 0.0f) }, { QT3DSVec3(0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(-0.85f, -0.9f, 0.0f) }, { QT3DSVec3(-0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.85f, 0.9f, 0.0f) }, { QT3DSVec3(-0.9f, 0.9f, 0.0f) },
+ };
+
+ const unsigned short indices[] = { 0, 1, 1, 2, 2, 0, 3, 4, 4, 5, 5, 3 };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 6, indices, 12,
+ NVRenderDrawMode::Lines);
+}
+
+bool NVRenderTestPrimitives::lineStripIndexed(NVRenderContext *context, userContextData *pUserData)
+{
+ const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0.0) },
+ { QT3DSVec3(-0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, -0.9f, 0.0f) },
+ { QT3DSVec3(0.9f, 0.9f, 0.0f) } };
+
+ const unsigned short indices[] = { 0, 1, 2, 3, 0 };
+
+ return renderPrimitive(context, pUserData, vertexPositions, 4, indices, 5,
+ NVRenderDrawMode::LineStrip);
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestPrimitives::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestPrimitives::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestPrimitives.h b/tests/auto/runtime/base/Qt3DSRenderTestPrimitives.h
new file mode 100644
index 0000000..4b6128e
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestPrimitives.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_PRIMITIVES_H
+#define QT3DS_RENDER_TEST_PRIMITIVES_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ struct Vertex
+ {
+ QT3DSVec3 positions;
+ };
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestPrimitives : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestPrimitives();
+ ~NVRenderTestPrimitives();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool triangles(NVRenderContext *context, userContextData *pUserData);
+ bool triangleStrip(NVRenderContext *context, userContextData *pUserData);
+ bool lines(NVRenderContext *context, userContextData *pUserData);
+ bool lineStrip(NVRenderContext *context, userContextData *pContextData);
+
+ bool trianglesIndexed(NVRenderContext *context, userContextData *pUserData);
+ bool triangleStripIndexed(NVRenderContext *context, userContextData *pUserData);
+ bool linesIndexed(NVRenderContext *context, userContextData *pUserData);
+ bool lineStripIndexed(NVRenderContext *context, userContextData *pContextData);
+
+ bool renderPrimitive(NVRenderContext *context, userContextData *pContextData,
+ const Vertex *pVertexData, unsigned int vertexCount,
+ const unsigned short *pIndexData, unsigned int indexCount,
+ NVRenderDrawMode::Enum primType);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_PRIMITIVES_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.cpp b/tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.cpp
new file mode 100644
index 0000000..a76bfa0
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.cpp
@@ -0,0 +1,401 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestProgramPipeline.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderProgramPipeline.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+
+ prog += "out gl_PerVertex\n"
+ "{\n"
+ "\tvec4 gl_Position;\n"
+ "\tfloat gl_PointSize;\n"
+ "\tfloat gl_ClipDistance[];\n"
+ "};\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "in vec3 attr_col; // Vertex col\n"
+ "out vec3 color; // output color\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ " color = attr_col;\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ prog += "in vec3 color; // input color\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4( color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+NVRenderTestProgramPipeline::NVRenderTestProgramPipeline()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestProgramPipeline::~NVRenderTestProgramPipeline()
+{
+}
+
+bool NVRenderTestProgramPipeline::isSupported(NVRenderContext *context)
+{
+ return context->IsProgramPipelineSupported();
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestProgramPipeline::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= vertFragSeparateTest(context, pUserData);
+ _curTest++;
+ success &= vertFragCombinedTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestProgramPipeline::vertFragSeparateTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) },
+ { QT3DSVec3(0.0, 0.9, 0) } };
+
+ static const Vertex vertexColors[] = { { QT3DSVec3(0.0, 1.0, 0.0) },
+ { QT3DSVec3(0.0, 1.0, 0.0) },
+ { QT3DSVec3(0.0, 1.0, 0.0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderVertexBuffer> mColorBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderProgramPipeline> mProgramPipeline;
+ NVRenderVertexBuffer *attribBuffers[2];
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult vtxResult = context->CompileSource(
+ "NVRenderTestProgramPipeline vertex shader",
+ toRef(vertShader(vtxProg, isGLESContext(context))), NVConstDataRef<QT3DSI8>(),
+ NVConstDataRef<QT3DSI8>(), NVConstDataRef<QT3DSI8>(), NVConstDataRef<QT3DSI8>(), true);
+ if (!vtxResult.mShader) {
+ return false;
+ }
+
+ NVRenderVertFragCompilationResult fragResult = context->CompileSource(
+ "NVRenderTestProgramPipeline fragment shader", NVConstDataRef<QT3DSI8>(),
+ toRef(fragShader(frgProg, isGLESContext(context))), NVConstDataRef<QT3DSI8>(),
+ NVConstDataRef<QT3DSI8>(), NVConstDataRef<QT3DSI8>(), true);
+
+ if (!fragResult.mShader) {
+ return false;
+ }
+
+ // setup program pipeline
+ mProgramPipeline = context->CreateProgramPipeline();
+ if (!mProgramPipeline) {
+ qWarning() << "NVRenderTestProgramPipeline: Failed to create program pipeline";
+ return false;
+ }
+
+ mProgramPipeline->SetProgramStages(vtxResult.mShader,
+ NVRenderShaderTypeFlags(NVRenderShaderTypeValue::Vertex));
+ mProgramPipeline->SetProgramStages(fragResult.mShader,
+ NVRenderShaderTypeFlags(NVRenderShaderTypeValue::Fragment));
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0, 0),
+ NVRenderVertexBufferEntry("attr_col", NVRenderComponentTypes::QT3DSF32, 3, 0, 1),
+ };
+
+ // position buffer
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create vertex buffer";
+ return false;
+ }
+ // color buffer
+ NVDataRef<QT3DSU8> colorData((QT3DSU8 *)vertexColors, bufSize);
+ mColorBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), colorData);
+ if (!mColorBuffer) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create color buffer";
+ return false;
+ }
+
+ attribBuffers[0] = mVertexBuffer;
+ attribBuffers[1] = mColorBuffer;
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 2));
+ // create input Assembler
+ QT3DSU32 strides[2];
+ QT3DSU32 offsets[2];
+ strides[0] = mVertexBuffer->GetStride();
+ offsets[0] = 0;
+ strides[1] = mColorBuffer->GetStride();
+ offsets[1] = 0;
+
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, NVConstDataRef<NVRenderVertexBuffer *>(attribBuffers, 2), NULL,
+ toConstDataRef(strides, 2), toConstDataRef(offsets, 2), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveProgramPipeline(mProgramPipeline);
+ vtxResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ vtxResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveProgramPipeline(0);
+ return true;
+}
+
+bool NVRenderTestProgramPipeline::vertFragCombinedTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) },
+ { QT3DSVec3(0.0, 0.9, 0) } };
+
+ static const Vertex vertexColors[] = { { QT3DSVec3(0.0, 1.0, 0.0) },
+ { QT3DSVec3(0.0, 1.0, 0.0) },
+ { QT3DSVec3(0.0, 1.0, 0.0) } };
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderVertexBuffer> mColorBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderProgramPipeline> mProgramPipeline;
+ NVRenderVertexBuffer *attribBuffers[2];
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestProgramPipeline vertex shader",
+ toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))), NVConstDataRef<QT3DSI8>(),
+ NVConstDataRef<QT3DSI8>(), NVConstDataRef<QT3DSI8>(), true);
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ // setup program pipeline
+ mProgramPipeline = context->CreateProgramPipeline();
+ if (!mProgramPipeline) {
+ qWarning() << "NVRenderTestProgramPipeline: Failed to create program pipeline";
+ return false;
+ }
+
+ mProgramPipeline->SetProgramStages(
+ compResult.mShader, NVRenderShaderTypeFlags(NVRenderShaderTypeValue::Vertex
+ | NVRenderShaderTypeValue::Fragment));
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0, 0),
+ NVRenderVertexBufferEntry("attr_col", NVRenderComponentTypes::QT3DSF32, 3, 0, 1),
+ };
+
+ // position buffer
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create vertex buffer";
+ return false;
+ }
+ // color buffer
+ NVDataRef<QT3DSU8> colorData((QT3DSU8 *)vertexColors, bufSize);
+ mColorBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), colorData);
+ if (!mColorBuffer) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create color buffer";
+ return false;
+ }
+
+ attribBuffers[0] = mVertexBuffer;
+ attribBuffers[1] = mColorBuffer;
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 2));
+ // create input Assembler
+ QT3DSU32 strides[2];
+ QT3DSU32 offsets[2];
+ strides[0] = mVertexBuffer->GetStride();
+ offsets[0] = 0;
+ strides[1] = mColorBuffer->GetStride();
+ offsets[1] = 0;
+
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, NVConstDataRef<NVRenderVertexBuffer *>(attribBuffers, 2), NULL,
+ toConstDataRef(strides, 2), toConstDataRef(offsets, 2), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestAttribBuffers: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveProgramPipeline(mProgramPipeline);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveProgramPipeline(0);
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestProgramPipeline::runPerformance(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestProgramPipeline::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.h b/tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.h
new file mode 100644
index 0000000..eeec086
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestProgramPipeline.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_PROGRAM_PIPELINE_H
+#define QT3DS_RENDER_TEST_PROGRAM_PIPELINE_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestProgramPipeline : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestProgramPipeline();
+ ~NVRenderTestProgramPipeline();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool vertFragSeparateTest(NVRenderContext *context, userContextData *pUserData);
+ bool vertFragCombinedTest(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_PROGRAM_PIPELINE_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestTexture2D.cpp b/tests/auto/runtime/base/Qt3DSRenderTestTexture2D.cpp
new file mode 100644
index 0000000..6904955
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestTexture2D.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestTexture2D.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderTexture2D.h"
+#include "render/Qt3DSRenderTexture2DArray.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "in vec3 attr_uv; // texture coord\n"
+ "out vec3 varTexCoord;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ " varTexCoord = attr_uv;\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330\n";
+ }
+
+ prog += "uniform sampler2DArray inTex;\n"
+ "in vec3 varTexCoord;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = texture(inTex, varTexCoord);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+ QT3DSVec3 texCoord;
+};
+
+static const Vertex vertexPositionsL0[] = {
+ { QT3DSVec3(-0.9, 0.0, 0), QT3DSVec3(0, 0, 0) }, { QT3DSVec3(0.0, 0.9, 0), QT3DSVec3(1, 1, 0) },
+ { QT3DSVec3(-0.9, 0.9, 0), QT3DSVec3(0, 1, 0) }, { QT3DSVec3(-0.9, 0.0, 0), QT3DSVec3(0, 0, 0) },
+ { QT3DSVec3(0.0, 0.0, 0), QT3DSVec3(1, 0, 0) }, { QT3DSVec3(0.0, 0.9, 0), QT3DSVec3(1, 1, 0) }
+};
+
+static const Vertex vertexPositionsL1[] = {
+ { QT3DSVec3(0.0, -0.9, 0), QT3DSVec3(0, 0, 1) }, { QT3DSVec3(0.9, 0.0, 0), QT3DSVec3(1, 1, 1) },
+ { QT3DSVec3(0.0, 0.0, 0), QT3DSVec3(0, 1, 1) }, { QT3DSVec3(0.0, -0.9, 0), QT3DSVec3(0, 0, 1) },
+ { QT3DSVec3(0.9, -0.9, 0), QT3DSVec3(1, 0, 1) }, { QT3DSVec3(0.9, 0.0, 0), QT3DSVec3(1, 1, 1) }
+};
+
+#define TEXTURE_LAYER_SIZE 2
+#define TEXTURE_SIZE 64
+#define PATTERN_SIZE 0x8
+
+NVRenderTestTexture2D::NVRenderTestTexture2D()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+ _pTextureData = NULL;
+}
+
+NVRenderTestTexture2D::~NVRenderTestTexture2D()
+{
+}
+
+bool NVRenderTestTexture2D::isSupported(NVRenderContext *context)
+{
+ return context->IsTextureArraySupported();
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestTexture2D::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ // alloc data
+ _pTextureData = new unsigned char[TEXTURE_SIZE * TEXTURE_SIZE * 4 * TEXTURE_LAYER_SIZE];
+ CreateTexData(_pTextureData);
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= texArray2DTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ if (_pTextureData)
+ delete _pTextureData;
+
+ return success;
+}
+
+void NVRenderTestTexture2D::CreateTexData(unsigned char *_pOutData)
+{
+ if (!_pOutData)
+ return;
+
+ unsigned char *_pData = _pOutData;
+
+ // Create a checkerboard pattern
+ for (int i = 0; i < TEXTURE_LAYER_SIZE; i++) {
+ for (int j = 0; j < TEXTURE_SIZE; j++) {
+ for (int k = 0; k < TEXTURE_SIZE; k++) {
+ unsigned char c = (((j & PATTERN_SIZE) == 0) ^ ((k & PATTERN_SIZE) == 0)) * 255;
+ *_pData++ = 0x0;
+ *_pData++ = c >> i;
+ *_pData++ = 0x0;
+ *_pData++ = 0xFF;
+ }
+ }
+ }
+}
+
+bool NVRenderTestTexture2D::renderTexArrayQuad(NVRenderContext *context, userContextData *pUserData,
+ NVRenderTexture2DArray *pTex, QT3DSU8 *vertexPositions)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestTexture2D shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ NVRenderVertexBufferEntry("attr_uv", NVRenderComponentTypes::QT3DSF32, 3, 12),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData(vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 6 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestTexture2D: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 2));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler =
+ context->CreateInputAssembler(mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestTexture2D: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ NVRenderCachedShaderProperty<NVRenderTexture2DArray *> mArrayTexture("inTex",
+ *compResult.mShader);
+ mArrayTexture.Set(pTex);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestTexture2D::texArray2DTest(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // create texture
+ NVScopedRefCounted<NVRenderTexture2DArray> mArrayTexture;
+ mArrayTexture = context->CreateTexture2DArray();
+ mArrayTexture->SetTextureData(
+ NVDataRef<QT3DSU8>(_pTextureData, TEXTURE_SIZE * TEXTURE_SIZE * 4 * TEXTURE_LAYER_SIZE), 0,
+ TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_LAYER_SIZE, NVRenderTextureFormats::RGBA8);
+
+ success &= renderTexArrayQuad(context, pUserData, mArrayTexture, (QT3DSU8 *)vertexPositionsL0);
+ success &= renderTexArrayQuad(context, pUserData, mArrayTexture, (QT3DSU8 *)vertexPositionsL1);
+
+ return success;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestTexture2D::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestTexture2D::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestTexture2D.h b/tests/auto/runtime/base/Qt3DSRenderTestTexture2D.h
new file mode 100644
index 0000000..5c5de11
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestTexture2D.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_TEXTURE_2D_H
+#define QT3DS_RENDER_TEST_TEXTURE_2D_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ class NVRenderTexture2D;
+ class NVRenderTexture2DArray;
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestTexture2D : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestTexture2D();
+ ~NVRenderTestTexture2D();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool texArray2DTest(NVRenderContext *context, userContextData *pUserData);
+
+ bool renderTexArrayQuad(NVRenderContext *context, userContextData *pUserData,
+ NVRenderTexture2DArray *pTex, QT3DSU8 *vertexPositions);
+ void CreateTexData(unsigned char *_pOutData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ unsigned char *_pTextureData;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_TEXTURE_2D_H
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.cpp b/tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.cpp
new file mode 100644
index 0000000..bf8ff0e
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.cpp
@@ -0,0 +1,436 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestTimerQuery.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderTimerQuery.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330\n";
+ }
+
+ prog += "uniform vec3 color;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+NVRenderTestTimerQuery::NVRenderTestTimerQuery()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestTimerQuery::~NVRenderTestTimerQuery()
+{
+}
+
+bool NVRenderTestTimerQuery::isSupported(NVRenderContext *context)
+{
+ return context->IsTimerQuerySupported();
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestTimerQuery::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= timerTest(context, pUserData);
+ _curTest++;
+ success &= absoluteTimerTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestTimerQuery::renderQuad(NVRenderContext *context, userContextData *pUserData,
+ QT3DSVec3 color)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestTimerQuery shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestTimerQuery: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler =
+ context->CreateInputAssembler(mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestTimerQuery: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestTimerQuery::timerTest(NVRenderContext *context, userContextData *pUserData)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ QT3DSMat44 proj = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&proj, -1, 1, -1, 1, -10, 10);
+ QT3DSVec3 color(1.0, 1.0, 0.0);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestTimerQuery shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestTimerQuery: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler =
+ context->CreateInputAssembler(mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestTimerQuery: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+
+ // setup translation
+ QT3DSMat44 transZ;
+ NvRenderTestMatrixTranslation(&transZ, 0.0, 0.0, 0.2);
+ mvp = transZ * proj;
+
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ NVScopedRefCounted<NVRenderTimerQuery> pQuery = context->CreateTimerQuery();
+
+ // render 1000 quads this should take at least some amount of time
+ pQuery->Begin();
+ for (QT3DSI32 i = 0; i < 1000; i++) {
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+ }
+ pQuery->End();
+
+ // get elapsed time in nano seconds
+ QT3DSU64 result = 0;
+ pQuery->GetResult(&result);
+ // convert to milli second
+ QT3DSF64 elapsed = double(result) / 1e06;
+
+ /// it should take at least a fraction of a milli second
+ if (elapsed > 0.0)
+ color.x = 0.0; // right
+ else
+ color.y = 0.0; // wrong
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ renderQuad(context, pUserData, color);
+
+ return (elapsed > 0.0);
+}
+
+bool NVRenderTestTimerQuery::absoluteTimerTest(NVRenderContext *context, userContextData *pUserData)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ QT3DSMat44 proj = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&proj, -1, 1, -1, 1, -10, 10);
+ QT3DSVec3 color(1.0, 1.0, 0.0);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestTimerQuery shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestTimerQuery: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler =
+ context->CreateInputAssembler(mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestTimerQuery: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+
+ // setup translation
+ QT3DSMat44 transZ;
+ NvRenderTestMatrixTranslation(&transZ, 0.0, 0.0, 0.2);
+ mvp = transZ * proj;
+
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ NVScopedRefCounted<NVRenderTimerQuery> pQueryStart = context->CreateTimerQuery();
+ NVScopedRefCounted<NVRenderTimerQuery> pQueryEnd = context->CreateTimerQuery();
+
+ // render 1000 quads this should take at least some amount of time
+ pQueryStart->SetTimerQuery();
+ for (QT3DSI32 i = 0; i < 1000; i++) {
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+ }
+ pQueryEnd->SetTimerQuery();
+
+ // get absolute time in nano seconds
+ QT3DSU64 start = 0;
+ pQueryStart->GetResult(&start);
+ QT3DSU64 end = 0;
+ pQueryEnd->GetResult(&end);
+
+ // convert to milli second
+ QT3DSF64 elapsed = double(end - start) / 1e06;
+
+ // it should take at least a fraction of a milli second
+ if (elapsed > 0.0)
+ color.x = 0.0; // right
+ else
+ color.y = 0.0; // wrong
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ renderQuad(context, pUserData, color);
+
+ return (elapsed > 0.0);
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestTimerQuery::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestTimerQuery::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.h b/tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.h
new file mode 100644
index 0000000..127c25f
--- /dev/null
+++ b/tests/auto/runtime/base/Qt3DSRenderTestTimerQuery.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_TIMER_QUERY_H
+#define QT3DS_RENDER_TEST_TIMER_QUERY_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ class NVRenderTimerQuery;
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestTimerQuery : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestTimerQuery();
+ ~NVRenderTestTimerQuery();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool timerTest(NVRenderContext *context, userContextData *pUserData);
+ bool absoluteTimerTest(NVRenderContext *context, userContextData *pUserData);
+
+ bool renderQuad(NVRenderContext *context, userContextData *pUserData, QT3DSVec3 color);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_TIMER_QUERY_H
diff --git a/tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.cpp b/tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.cpp
new file mode 100644
index 0000000..15035b4
--- /dev/null
+++ b/tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.cpp
@@ -0,0 +1,636 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestComputeShader.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderImageTexture.h"
+#include "render/Qt3DSRenderStorageBuffer.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *vertTexShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "in vec2 attr_uv; // texture coord\n"
+ "out vec2 varTexCoord;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ " varTexCoord = attr_uv;\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform vec3 color;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragTexShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform sampler2D inTex;\n"
+ "in vec2 varTexCoord;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = texture(inTex, varTexCoord);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *computeShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_ARB_compute_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n"
+ "#extension GL_ARB_compute_shader : enable\n";
+ }
+
+ prog += "// Set workgroup layout;\n"
+ "layout (local_size_x =16, local_size_y = 16) in;\n\n"
+ "void main()\n"
+ "{\n"
+ " // do nothing\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *computeWorkShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_ARB_compute_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n"
+ "precision mediump image2D;\n";
+ } else {
+ prog += "#version 430\n"
+ "#extension GL_ARB_compute_shader : enable\n";
+ }
+
+ prog += "// Set workgroup layout;\n"
+ "layout (local_size_x = 32, local_size_y = 32) in;\n\n"
+ "layout (rgba8, binding = 2) uniform image2D outputImage;\n\n"
+ "void main()\n"
+ "{\n"
+ " imageStore( outputImage, ivec2(gl_GlobalInvocationID.xy), vec4( "
+ "vec2(gl_LocalInvocationID.xy) / vec2(gl_WorkGroupSize.xy), 0.0, 1.0 ) );\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *computeStorageShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_ARB_compute_shader : enable\n"
+ "#extension GL_ARB_shader_storage_buffer_object : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n"
+ "#extension GL_ARB_compute_shader : enable\n"
+ "#extension GL_ARB_shader_storage_buffer_object : enable\n";
+ }
+
+ prog += "layout( std140, binding=4 ) buffer Pos\n"
+ "{\n"
+ " vec4 Positions[ ]; // array of positions\n"
+ "};\n"
+ "// Set workgroup layout;\n"
+ "layout (local_size_x = 32, local_size_y = 1) in;\n\n"
+ "void main()\n"
+ "{\n"
+ " uint gid = gl_GlobalInvocationID.x;\n"
+ " if ( gid < uint(1000) ) {\n"
+ " Positions[gid].x = float(gl_GlobalInvocationID.x);\n"
+ " }\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+ QT3DSVec2 texCoord;
+};
+
+NVRenderTestComputeShader::NVRenderTestComputeShader()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestComputeShader::~NVRenderTestComputeShader()
+{
+}
+
+bool NVRenderTestComputeShader::isSupported(NVRenderContext *context)
+{
+ return context->IsComputeSupported();
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestComputeShader::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+
+ context->SetRenderTarget(NULL);
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= computeCompile(context, pUserData);
+ _curTest++;
+ success &= computeWorkgroup(context, pUserData);
+ _curTest++;
+ success &= computeStorage(context, pUserData);
+ _curTest++;
+
+ return success;
+}
+
+bool NVRenderTestComputeShader::computeCompile(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.0, 0.9, 0), QT3DSVec2(0, 0) } };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestComputeShader shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 5 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create input assembler";
+ return false;
+ }
+
+ // create a compute shader which does nothing just as a compile check
+ std::string computeProg;
+ NVRenderVertFragCompilationResult computeResult = context->CompileComputeSource(
+ "Compute nothing shader", toRef(computeShader(computeProg, isGLESContext(context))));
+
+ if (!computeResult.mShader) {
+ color.x = 1.0;
+ color.y = 0.0;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+ if (computeResult.mShader)
+ computeResult.mShader->release();
+
+ return true;
+}
+
+#define WORKGROUP_SIZE 32
+
+bool NVRenderTestComputeShader::computeWorkgroup(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = {
+ { QT3DSVec3(-0.9, -0.9, 0), QT3DSVec2(0, 0) }, { QT3DSVec3(0.9, 0.9, 0), QT3DSVec2(1, 1) },
+ { QT3DSVec3(-0.9, 0.9, 0), QT3DSVec2(0, 1) }, { QT3DSVec3(-0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.9, -0.9, 0), QT3DSVec2(1, 0) }, { QT3DSVec3(0.9, 0.9, 0), QT3DSVec2(1, 1) }
+ };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ // create texture
+ NVScopedRefCounted<NVRenderTexture2D> mColorTexture;
+ mColorTexture = context->CreateTexture2D();
+ mColorTexture->SetTextureStorage(1, pUserData->winWidth, pUserData->winHeight,
+ NVRenderTextureFormats::RGBA8);
+ // create a image buffer wrapper
+ NVScopedRefCounted<NVRenderImage2D> mColorImage;
+ mColorImage = context->CreateImage2D(mColorTexture, NVRenderImageAccessType::Write);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestComputeShader shader", toRef(vertTexShader(vtxProg, isGLESContext(context))),
+ toRef(fragTexShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ NVRenderVertexBufferEntry("attr_uv", NVRenderComponentTypes::QT3DSF32, 2, 12),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 5 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 2));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create input assembler";
+ return false;
+ }
+
+ // create a compute shader which outputs the workgroups as color codes
+ std::string computeProg;
+ NVRenderVertFragCompilationResult computeResult = context->CompileComputeSource(
+ "Compute workgroup shader", toRef(computeWorkShader(computeProg, isGLESContext(context))));
+
+ if (!computeResult.mShader) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create compute shader";
+ return false;
+ }
+
+ // set program
+ context->SetActiveShader(computeResult.mShader);
+ NVRenderCachedShaderProperty<NVRenderImage2D *> mOutputImage("outputImage",
+ *computeResult.mShader);
+ mOutputImage.Set(mColorImage);
+ // run compute shader
+ context->DispatchCompute(computeResult.mShader, pUserData->winWidth / WORKGROUP_SIZE,
+ pUserData->winHeight / WORKGROUP_SIZE, 1);
+ NVRenderBufferBarrierFlags flags(NVRenderBufferBarrierValues::ShaderImageAccess);
+ // sync
+ context->SetMemoryBarrier(flags);
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+ // set texture
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> mInputImage("inTex", *compResult.mShader);
+ mInputImage.Set(mColorTexture);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 6, 0);
+
+ context->SetActiveShader(0);
+
+ compResult.mShader->release();
+ if (computeResult.mShader)
+ computeResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestComputeShader::computeStorage(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.0, 0.9, 0), QT3DSVec2(0, 0) } };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create vertex buffer for compute shader usage
+ NVScopedRefCounted<NVRenderVertexBuffer> mComputeVertexBuffer;
+ QT3DSF32 *storageData = new QT3DSF32[1000 * 4]; // vec 4 in shader program
+ NVDataRef<QT3DSU8> storData((QT3DSU8 *)storageData, 1000 * sizeof(QT3DSF32) * 4);
+ mComputeVertexBuffer = context->CreateVertexBuffer(
+ NVRenderBufferUsageType::Static, 1000 * sizeof(QT3DSF32) * 4, sizeof(QT3DSF32), storData);
+ if (!mComputeVertexBuffer) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create compute vertex buffer";
+ return false;
+ }
+ // create storage wrapper for vertex buffer
+ NVScopedRefCounted<NVRenderStorageBuffer> mComputeStorageBuffer;
+ mComputeStorageBuffer =
+ context->CreateStorageBuffer("Pos", NVRenderBufferUsageType::Static,
+ 1000 * sizeof(QT3DSF32) * 4, storData, mComputeVertexBuffer.mPtr);
+ if (!mComputeStorageBuffer) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create compute storage buffer";
+ return false;
+ }
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestComputeShader shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 5 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create input assembler";
+ return false;
+ }
+
+ // create a compute shader which places id's into the buffer
+ std::string computeProg;
+ NVRenderVertFragCompilationResult computeResult = context->CompileComputeSource(
+ "Compute storage shader", toRef(computeStorageShader(computeProg, isGLESContext(context))));
+
+ if (!computeResult.mShader) {
+ qWarning() << "NVRenderTestComputeShader: Failed to create compute shader";
+ return false;
+ }
+
+ // set and run compute program
+ context->SetActiveShader(computeResult.mShader);
+ qt3ds::render::NVRenderCachedShaderBuffer<NVRenderShaderStorageBuffer *> storageBuffer(
+ "Pos", *computeResult.mShader);
+ storageBuffer.Set();
+ // run compute shader
+ context->DispatchCompute(computeResult.mShader, 1024 / WORKGROUP_SIZE, 1, 1);
+ NVRenderBufferBarrierFlags flags(NVRenderBufferBarrierValues::ShaderStorage
+ | NVRenderBufferBarrierValues::VertexAttribArray);
+ // sync
+ context->SetMemoryBarrier(flags);
+
+ // check content
+ bool contentOK = true;
+ mComputeVertexBuffer->Bind();
+ NVDataRef<QT3DSU8> pData = mComputeVertexBuffer->MapBuffer();
+ QT3DSF32 *fData = (QT3DSF32 *)pData.begin();
+ QT3DSU32 size = pData.size() / 4;
+ for (QT3DSU32 i = 0, k = 0; i < size; i += 4, k++) {
+ if (fData[i] != (float)k)
+ contentOK = false;
+ }
+
+ mComputeVertexBuffer->UnmapBuffer();
+
+ if (!contentOK) {
+ color.x = 1.0;
+ color.y = 0.0;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+ if (computeResult.mShader)
+ computeResult.mShader->release();
+
+ delete storageData;
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestComputeShader::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestComputeShader::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.h b/tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.h
new file mode 100644
index 0000000..826fb9c
--- /dev/null
+++ b/tests/auto/runtime/compute/Qt3DSRenderTestComputeShader.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_COMPUTE_SHADER_H
+#define QT3DS_RENDER_TEST_COMPUTE_SHADER_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestComputeShader : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestComputeShader();
+ ~NVRenderTestComputeShader();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool computeCompile(NVRenderContext *context, userContextData *pUserData);
+ bool computeWorkgroup(NVRenderContext *context, userContextData *pUserData);
+ bool computeStorage(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif
diff --git a/tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.cpp b/tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.cpp
new file mode 100644
index 0000000..400cfc5
--- /dev/null
+++ b/tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.cpp
@@ -0,0 +1,299 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestFboMsaa.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *PassthroughVertShader()
+{
+ return "uniform mat4 mat_mvp;\n"
+ "attribute vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+}
+
+static const char *SimpleFragShader()
+{
+ return "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "uniform vec3 color;\n"
+ "void main()\n"
+ "{\n"
+ "gl_FragColor = vec4( color, 1.0);\n"
+ "}\n";
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) },
+ { QT3DSVec3(0.0, 0.9, 0) } };
+
+NVRenderTestFboMsaa::NVRenderTestFboMsaa()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestFboMsaa::~NVRenderTestFboMsaa()
+{
+}
+
+bool NVRenderTestFboMsaa::isSupported(NVRenderContext *context)
+{
+ NVRenderContextType ctxType = context->GetRenderContextType();
+ NVRenderContextType nonSupportedFlags(NVRenderContextValues::GL2 | NVRenderContextValues::GLES2
+ | NVRenderContextValues::GLES3);
+
+ // This is currently only supported on >= GL3 && >= GLES 3.1
+ if ((ctxType & nonSupportedFlags))
+ return false;
+
+ return true;
+}
+
+bool NVRenderTestFboMsaa::run(NVRenderContext *context, userContextData *pUserData)
+{
+ if (!setupResolveFbo(context, pUserData))
+ return false;
+
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetRenderTarget(NULL);
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= simpleMsaaTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestFboMsaa::renderTriangle(NVRenderContext *context, QT3DSVec3 color)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ NVRenderVertFragCompilationResult compResult =
+ context->CompileSource("NVRenderTestBackendQuery shader", toRef(PassthroughVertShader()),
+ toRef(SimpleFragShader()));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestFboMsaa: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestFboMsaa: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestFboMsaa::setupResolveFbo(NVRenderContext *context, userContextData *pUserData)
+{
+ // color texture
+ m_ResolveColorTexture = context->CreateTexture2D();
+ m_ResolveColorTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0, pUserData->winWidth,
+ pUserData->winHeight, NVRenderTextureFormats::RGBA8);
+ // depth texture
+ m_ResolveDepthTexture = context->CreateTexture2D();
+ m_ResolveDepthTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0, pUserData->winWidth,
+ pUserData->winHeight, NVRenderTextureFormats::Depth24);
+ // create resolve FBO
+ m_ResolveFbo = context->CreateFrameBuffer();
+ m_ResolveFbo->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*m_ResolveColorTexture));
+ m_ResolveFbo->Attach(NVRenderFrameBufferAttachments::Depth,
+ NVRenderTextureOrRenderBuffer(*m_ResolveDepthTexture));
+
+ return m_ResolveFbo->IsComplete();
+}
+
+bool NVRenderTestFboMsaa::simpleMsaaTest(NVRenderContext *context, userContextData *pUserData)
+{
+ // create a multisampled FBO
+ NVScopedRefCounted<NVRenderFrameBuffer> msFBO;
+ NVScopedRefCounted<NVRenderTexture2D> msColorTexture;
+ NVScopedRefCounted<NVRenderTexture2D> msDepth24Texture;
+
+ msColorTexture = context->CreateTexture2D();
+ msColorTexture->SetTextureDataMultisample(4, pUserData->winWidth, pUserData->winHeight,
+ NVRenderTextureFormats::RGBA8);
+ msDepth24Texture = context->CreateTexture2D();
+ msDepth24Texture->SetTextureDataMultisample(4, pUserData->winWidth, pUserData->winHeight,
+ NVRenderTextureFormats::Depth24);
+
+ msFBO = context->CreateFrameBuffer();
+ msFBO->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*msColorTexture),
+ NVRenderTextureTargetType::Texture2D_MS);
+ msFBO->Attach(NVRenderFrameBufferAttachments::Depth,
+ NVRenderTextureOrRenderBuffer(*msDepth24Texture),
+ NVRenderTextureTargetType::Texture2D_MS);
+
+ if (!msFBO->IsComplete())
+ return false;
+
+ // clear and draw to multisampled buffer
+ context->SetRenderTarget(msFBO);
+ context->SetMultisampleEnabled(true);
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+ renderTriangle(context, qt3ds::QT3DSVec3(0.0, 1.0, 0.0));
+ context->SetMultisampleEnabled(false);
+
+ // do resolve blit
+ // first we must setup the render target
+ context->SetRenderTarget(m_ResolveFbo);
+ // second setup read target
+ context->SetReadTarget(msFBO);
+ context->SetReadBuffer(NVReadFaces::Color0);
+
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ context->BlitFramebuffer(0, 0, pUserData->winWidth, pUserData->winHeight, 0, 0,
+ pUserData->winWidth, pUserData->winHeight, NVRenderClearValues::Color,
+ NVRenderTextureMagnifyingOp::Nearest);
+
+ // copy to default buffer
+ // first we must setup the render target
+ context->SetRenderTarget(NULL);
+ // second setup read target
+ context->SetReadTarget(m_ResolveFbo);
+ context->SetReadBuffer(NVReadFaces::Color0);
+
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ context->BlitFramebuffer(0, 0, pUserData->winWidth, pUserData->winHeight, 0, 0,
+ pUserData->winWidth, pUserData->winHeight, NVRenderClearValues::Color,
+ NVRenderTextureMagnifyingOp::Nearest);
+
+ context->SetReadTarget(NULL);
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestFboMsaa::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestFboMsaa::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ m_ResolveColorTexture->release();
+ m_ResolveDepthTexture->release();
+ m_ResolveFbo->release();
+
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ context->SetRenderTarget(NULL);
+}
diff --git a/tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.h b/tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.h
new file mode 100644
index 0000000..bf9ed84
--- /dev/null
+++ b/tests/auto/runtime/fbo/Qt3DSRenderTestFboMsaa.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_FBO_MSAA_H
+#define QT3DS_RENDER_TEST_FBO_MSAA_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestFboMsaa : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestFboMsaa();
+ ~NVRenderTestFboMsaa();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool setupResolveFbo(NVRenderContext *context, userContextData *pUserData);
+ bool renderTriangle(NVRenderContext *context, QT3DSVec3 color);
+
+ // tests
+ bool simpleMsaaTest(NVRenderContext *context, userContextData *pUserData);
+
+ NVScopedRefCounted<NVRenderFrameBuffer> m_ResolveFbo;
+ NVScopedRefCounted<NVRenderTexture2D> m_ResolveColorTexture;
+ NVScopedRefCounted<NVRenderTexture2D> m_ResolveDepthTexture;
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_FBO_MSAA_H
diff --git a/tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.cpp b/tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.cpp
new file mode 100644
index 0000000..1a1c34c
--- /dev/null
+++ b/tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.cpp
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestGeometryShader.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderImageTexture.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform vec3 color;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *geometryShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_EXT_geometry_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ // pass through shader
+ prog += "layout (triangles) in;\n"
+ "layout (triangle_strip, max_vertices = 3) out;\n"
+ "void main()\n"
+ "{\n"
+ " int i;\n"
+ " for(i=0; i<gl_in.length(); i++)\n"
+ " {\n"
+ " gl_Position = gl_in[i].gl_Position;\n"
+ " EmitVertex();\n"
+ " }\n"
+ " EndPrimitive();\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *wireframeShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_EXT_geometry_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 430\n";
+ }
+
+ // convert to wireframe
+ prog += "layout (triangles) in;\n"
+ "layout (line_strip, max_vertices = 4) out;\n"
+ "void main()\n"
+ "{\n"
+ " int i;\n"
+ " for(i=0; i<gl_in.length(); i++)\n"
+ " {\n"
+ " gl_Position = gl_in[i].gl_Position;\n"
+ " EmitVertex();\n"
+ " }\n"
+ " gl_Position = gl_in[0].gl_Position;\n"
+ " EmitVertex();\n"
+ " EndPrimitive();\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+ QT3DSVec2 texCoord;
+};
+
+NVRenderTestGeometryShader::NVRenderTestGeometryShader()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestGeometryShader::~NVRenderTestGeometryShader()
+{
+}
+
+bool NVRenderTestGeometryShader::isSupported(NVRenderContext *context)
+{
+ return context->IsGeometryStageSupported();
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestGeometryShader::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+
+ context->SetRenderTarget(NULL);
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= geometryCompile(context, pUserData);
+ _curTest++;
+ success &= wireframe(context, pUserData);
+ _curTest++;
+
+ return success;
+}
+
+bool NVRenderTestGeometryShader::geometryCompile(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.0, 0.9, 0), QT3DSVec2(0, 0) } };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestGeometryShader shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 5 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestGeometryShader: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestGeometryShader: Failed to create input assembler";
+ return false;
+ }
+
+ // create a geometry shader which does nothing just as a compile check
+ std::string geomProg;
+ std::string vtxProgDummy;
+ std::string frgProgDummy;
+ NVRenderVertFragCompilationResult geomResult = context->CompileSource(
+ "NVRenderTestGeometryShader shader",
+ toRef(vertShader(vtxProgDummy, isGLESContext(context))),
+ toRef(fragShader(frgProgDummy, isGLESContext(context))), NVConstDataRef<QT3DSI8>(),
+ NVConstDataRef<QT3DSI8>(), toRef(geometryShader(geomProg, isGLESContext(context))));
+
+ if (!geomResult.mShader) {
+ color.x = 1.0;
+ color.y = 0.0;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+ if (geomResult.mShader)
+ geomResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestGeometryShader::wireframe(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.9, -0.9, 0), QT3DSVec2(0, 0) },
+ { QT3DSVec3(0.0, 0.9, 0), QT3DSVec2(0, 0) } };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ // geometry shader converts primitives from triangles to lines
+ std::string vtxProg;
+ std::string frgProg;
+ std::string geomProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestGeometryShader shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))), NVConstDataRef<QT3DSI8>(),
+ NVConstDataRef<QT3DSI8>(), toRef(wireframeShader(geomProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 5 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestGeometryShader: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Triangles);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestGeometryShader: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestGeometryShader::runPerformance(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestGeometryShader::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.h b/tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.h
new file mode 100644
index 0000000..139a7e2
--- /dev/null
+++ b/tests/auto/runtime/geometry/Qt3DSRenderTestGeometryShader.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_GEOMETRY_SHADER_H
+#define QT3DS_RENDER_TEST_GEOMETRY_SHADER_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestGeometryShader : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestGeometryShader();
+ ~NVRenderTestGeometryShader();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool geometryCompile(NVRenderContext *context, userContextData *pUserData);
+ bool wireframe(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif
diff --git a/tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.cpp b/tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.cpp
new file mode 100644
index 0000000..1bb0b16
--- /dev/null
+++ b/tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.cpp
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestOcclusionQuery.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderOcclusionQuery.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = mat_mvp * vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 300 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 330\n";
+ }
+
+ prog += "uniform vec3 color;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+};
+
+static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, 0.9, 0) }, { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(-0.9, 0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) }, { QT3DSVec3(0.9, 0.9, 0) } };
+
+static const Vertex largeQuadPositions[] = { { QT3DSVec3(-0.7, 0.7, 0) }, { QT3DSVec3(-0.7, -0.7, 0) },
+ { QT3DSVec3(0.7, -0.7, 0) }, { QT3DSVec3(-0.7, 0.7, 0) },
+ { QT3DSVec3(0.7, -0.7, 0) }, { QT3DSVec3(0.7, 0.7, 0) } };
+
+static const Vertex smallQuadPositions[] = { { QT3DSVec3(-0.5, 0.5, 0) }, { QT3DSVec3(-0.5, -0.5, 0) },
+ { QT3DSVec3(0.5, -0.5, 0) }, { QT3DSVec3(-0.5, 0.5, 0) },
+ { QT3DSVec3(0.5, -0.5, 0) }, { QT3DSVec3(0.5, 0.5, 0) } };
+
+NVRenderTestOcclusionQuery::NVRenderTestOcclusionQuery()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestOcclusionQuery::~NVRenderTestOcclusionQuery()
+{
+}
+
+bool NVRenderTestOcclusionQuery::isSupported(NVRenderContext *context)
+{
+ return context->IsSampleQuerySupported();
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestOcclusionQuery::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= occlusionPassTest(context, pUserData);
+ _curTest++;
+ success &= occlusionFailTest(context, pUserData);
+ _curTest++;
+
+ // cleanup
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+
+ return success;
+}
+
+bool NVRenderTestOcclusionQuery::renderQuad(NVRenderContext *context, userContextData *pUserData,
+ QT3DSVec3 color)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestOcclusionQuery shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 3 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestOcclusionQuery: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler =
+ context->CreateInputAssembler(mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestOcclusionQuery: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+void NVRenderTestOcclusionQuery::renderPrim(NVRenderContext *context, userContextData *pUserData,
+ void *pData, float zOffset, QT3DSVec3 color,
+ NVRenderOcclusionQuery *pQuery)
+{
+ NVScopedRefCounted<NVRenderVertexBuffer> mVB;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mIA;
+ Vertex *pVtxData = (Vertex *)pData;
+ QT3DSMat44 proj = QT3DSMat44::createIdentity();
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&proj, -1, 1, -1, 1, -10, 10);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestOcclusionQuery shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 6 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertDataSmall((QT3DSU8 *)pVtxData, bufSize);
+ mVB = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize, 3 * sizeof(QT3DSF32),
+ vertDataSmall);
+ if (!mVB)
+ qWarning() << "NVRenderTestOcclusionQuery: Failed to create vertex buffer";
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVB->GetStride();
+ QT3DSU32 offsets = 0;
+ mIA = context->CreateInputAssembler(mAttribLayout, toConstDataRef(&mVB.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ if (!mVB) {
+ qWarning() << "NVRenderTestOcclusionQuery: Failed to create input assembler";
+ return;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mIA);
+ // setup translation
+ QT3DSMat44 transZ;
+ NvRenderTestMatrixTranslation(&transZ, 0.0, 0.0, zOffset);
+ mvp = transZ * proj;
+
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+
+ // start query
+ if (pQuery)
+ pQuery->Begin();
+
+ context->Draw(NVRenderDrawMode::Triangles, 6, 0);
+
+ // end query
+ if (pQuery)
+ pQuery->End();
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+}
+
+bool NVRenderTestOcclusionQuery::occlusionPassTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ NVScopedRefCounted<NVRenderOcclusionQuery> pQuery = context->CreateOcclusionQuery();
+
+ renderPrim(context, pUserData, (void *)largeQuadPositions, 0.1, QT3DSVec3(0.0, 0.0, 1.0), NULL);
+ // this quad should be covered by the previous one
+ renderPrim(context, pUserData, (void *)smallQuadPositions, 0.2, QT3DSVec3(1.0, 1.0, 0.0), pQuery);
+ // check visibility
+ QT3DSU32 result = 0;
+ pQuery->GetResult(&result);
+
+ QT3DSVec3 color(0.0, 0.0, 0.0);
+ if (result)
+ color.x = 1.0; // wrong
+ else
+ color.y = 1.0; // right
+
+ renderQuad(context, pUserData, color);
+
+ return (result == 0);
+}
+
+bool NVRenderTestOcclusionQuery::occlusionFailTest(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ NVScopedRefCounted<NVRenderOcclusionQuery> pQuery = context->CreateOcclusionQuery();
+
+ renderPrim(context, pUserData, (void *)largeQuadPositions, 0.2, QT3DSVec3(0.0, 0.0, 1.0), NULL);
+ // this quad should be visible by the previous one
+ renderPrim(context, pUserData, (void *)smallQuadPositions, 0.1, QT3DSVec3(1.0, 1.0, 0.0), pQuery);
+ // check visibility
+ QT3DSU32 result = 0;
+ pQuery->GetResult(&result);
+
+ QT3DSVec3 color(0.0, 0.0, 0.0);
+ if (result == 0)
+ color.x = 1.0; // wrong
+ else
+ color.y = 1.0; // right
+
+ renderQuad(context, pUserData, color);
+
+ return (result == 1);
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestOcclusionQuery::runPerformance(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestOcclusionQuery::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(0.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.h b/tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.h
new file mode 100644
index 0000000..d540dad
--- /dev/null
+++ b/tests/auto/runtime/geometry/Qt3DSRenderTestOcclusionQuery.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2014 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_OCCLUSION_QUERY_H
+#define QT3DS_RENDER_TEST_OCCLUSION_QUERY_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ class NVRenderOcclusionQuery;
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestOcclusionQuery : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestOcclusionQuery();
+ ~NVRenderTestOcclusionQuery();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool occlusionPassTest(NVRenderContext *context, userContextData *pUserData);
+ bool occlusionFailTest(NVRenderContext *context, userContextData *pUserData);
+
+ bool renderQuad(NVRenderContext *context, userContextData *pUserData, QT3DSVec3 color);
+ void renderPrim(NVRenderContext *context, userContextData *pUserData, void *pData, float z,
+ QT3DSVec3 color, NVRenderOcclusionQuery *pQuery);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_OCCLUSION_QUERY_H
diff --git a/tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.cpp b/tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.cpp
new file mode 100644
index 0000000..f2724a4
--- /dev/null
+++ b/tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.cpp
@@ -0,0 +1,560 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestTessellation.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/backends/gl/Qt3DSOpenGLUtil.h"
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+static const char *vertShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *vertPhongShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform mat4 mat_mvp;\n"
+ "in vec3 attr_pos; // Vertex pos\n"
+ "in vec3 attr_norm; // normal pos\n"
+ "out vec3 ctNorm; // output normal control patch\n"
+ "void main()\n"
+ "{\n"
+ " ctNorm = attr_norm;\n"
+ " gl_Position = vec4(attr_pos, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform vec3 color;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *fragPhongShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "uniform vec3 color;\n"
+ "in vec3 normWorld;\n"
+ "out vec4 fragColor;\n"
+ "void main()\n"
+ "{\n"
+ " fragColor = vec4(color, 1.0);\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *tessControlShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_EXT_tessellation_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "// number of CPs in patch\n"
+ "layout (vertices = 3) out;\n"
+ "uniform float tessLevelInner; // controlled by keyboard buttons\n"
+ "uniform float tessLevelOuter; // controlled by keyboard buttons\n"
+ "void main () {\n"
+ "gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+ "// Calculate the tessellation levels\n"
+ "gl_TessLevelInner[0] = tessLevelInner; // number of nested primitives to generate\n"
+ "gl_TessLevelOuter[0] = tessLevelOuter; // times to subdivide first side\n"
+ "gl_TessLevelOuter[1] = tessLevelOuter; // times to subdivide second side\n"
+ "gl_TessLevelOuter[2] = tessLevelOuter; // times to subdivide third side\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *tessPhongControlShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_EXT_tessellation_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog +=
+ "// number of CPs in patch\n"
+ "layout (vertices = 3) out;\n"
+ "// phong tessellation per patch data\n"
+ "struct PhongTessPatch {\n"
+ " float projIJ;\n"
+ " float projJK;\n"
+ " float projIK;\n"
+ "};\n"
+ "in vec3 ctNorm[]; // control point normal\n"
+ "out vec3 normObj[]; // output normal pos\n"
+ "uniform float tessLevels;\n"
+ "uniform float tessBlend;\n"
+ "out PhongTessPatch tcTessPatch[3];\n"
+ "float PIi(int i, vec3 q)\n"
+ "{\n"
+ " vec3 q_minus_p = q - gl_in[i].gl_Position.xyz;\n"
+ " return q[gl_InvocationID] - dot(q_minus_p, ctNorm[i]) * ctNorm[i][gl_InvocationID];\n"
+ "}\n"
+ "void main () {\n"
+ " // path through data\n"
+ " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
+ " normObj[gl_InvocationID] = ctNorm[gl_InvocationID];\n"
+ " // compute projections separate for each xyz component\n"
+ " tcTessPatch[gl_InvocationID].projIJ = PIi(0, gl_in[1].gl_Position.xyz) + PIi(1, "
+ "gl_in[0].gl_Position.xyz);\n"
+ " tcTessPatch[gl_InvocationID].projJK = PIi(1, gl_in[2].gl_Position.xyz) + PIi(2, "
+ "gl_in[1].gl_Position.xyz);\n"
+ " tcTessPatch[gl_InvocationID].projIK = PIi(2, gl_in[0].gl_Position.xyz) + PIi(0, "
+ "gl_in[2].gl_Position.xyz);\n"
+ " // set the tessellation levels\n"
+ " gl_TessLevelInner[0] = tessLevels; // number of nested primitives to generate\n"
+ " gl_TessLevelOuter[gl_InvocationID] = tessLevels; // times to subdivide first side\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *tessEvaluationShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_EXT_tessellation_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "// triangles, quads, or isolines\n"
+ "layout (triangles, equal_spacing, ccw) in;\n"
+ "uniform mat4 mat_mvp;\n"
+ "// gl_TessCoord is location within the patch\n"
+ "// (barycentric for triangles, UV for quads)\n"
+ "void main () {\n"
+ "vec4 p0 = gl_TessCoord.x * gl_in[0].gl_Position; // x is one corner\n"
+ "vec4 p1 = gl_TessCoord.y * gl_in[1].gl_Position; // y is the 2nd corner\n"
+ "vec4 p2 = gl_TessCoord.z * gl_in[2].gl_Position; // z is the 3rd corner (ignore when "
+ "using quads)\n"
+ "vec4 pos = p0 + p1 + p2;\n"
+ "gl_Position = mat_mvp * pos;\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+static const char *tessPhongEvaluationShader(std::string &prog, bool binESContext)
+{
+ if (binESContext) {
+ prog += "#version 310 es\n"
+ "#extension GL_EXT_tessellation_shader : enable\n"
+ "precision highp float;\n"
+ "precision highp int;\n";
+ } else {
+ prog += "#version 400\n";
+ }
+
+ prog += "// triangles, quads, or isolines\n"
+ "layout (triangles, fractional_odd_spacing, ccw) in;\n"
+ "struct PhongTessPatch {\n"
+ " float projIJ;\n"
+ " float projJK;\n"
+ " float projIK;\n"
+ "};\n"
+ "in vec3 normObj[]; // control point normal\n"
+ "out vec3 normWorld; // output normal pos\n"
+ "in PhongTessPatch tcTessPatch[];\n"
+ "uniform mat4 mat_mvp;\n"
+ "uniform float tessBlend;\n"
+ "// gl_TessCoord is location within the patch\n"
+ "// (barycentric for triangles, UV for quads)\n"
+ "void main () {\n"
+ " // output normal\n"
+ " // pre compute square tesselation coord\n"
+ " vec3 tessSquared = gl_TessCoord * gl_TessCoord;\n"
+ " vec3 norm = gl_TessCoord.x * normObj[0]\n"
+ " + gl_TessCoord.y * normObj[1]\n"
+ " + gl_TessCoord.z * normObj[2]; // z is the 3rd corner (ignore when "
+ "using quads)\n"
+ " // barycentric linear position\n"
+ " vec3 linearPos = gl_TessCoord.x * gl_in[0].gl_Position.xyz\n"
+ " + gl_TessCoord.y * gl_in[1].gl_Position.xyz\n"
+ " + gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
+ " // projective terms\n"
+ " vec3 projJI = vec3(tcTessPatch[0].projIJ, tcTessPatch[1].projIJ, "
+ "tcTessPatch[2].projIJ);\n"
+ " vec3 projKJ = vec3(tcTessPatch[0].projJK, tcTessPatch[1].projJK, "
+ "tcTessPatch[2].projJK);\n"
+ " vec3 projIK = vec3(tcTessPatch[0].projIK, tcTessPatch[1].projIK, "
+ "tcTessPatch[2].projIK);\n"
+ " // phong interpolated position\n"
+ " vec3 phongPos = tessSquared.x * gl_in[0].gl_Position.xyz\n"
+ " + tessSquared.y * gl_in[1].gl_Position.xyz\n"
+ " + tessSquared.z * gl_in[2].gl_Position.xyz\n"
+ " + gl_TessCoord.x * gl_TessCoord.y * projJI\n"
+ " + gl_TessCoord.y * gl_TessCoord.z * projKJ\n"
+ " + gl_TessCoord.z * gl_TessCoord.x * projIK;\n"
+ " // final position\n"
+ " vec3 finalPos = (1.0-tessBlend)*linearPos + tessBlend*phongPos;\n"
+ " gl_Position = mat_mvp * vec4(finalPos, 1.0);\n"
+ " normWorld = norm;\n"
+ "}\n";
+
+ return prog.c_str();
+}
+
+struct Vertex
+{
+ QT3DSVec3 positions;
+ QT3DSVec3 normals;
+};
+
+NVRenderTestTessellation::NVRenderTestTessellation()
+{
+ _curTest = 0;
+ _maxColumn = 4;
+}
+
+NVRenderTestTessellation::~NVRenderTestTessellation()
+{
+}
+
+bool NVRenderTestTessellation::isSupported(NVRenderContext *context)
+{
+ NVRenderContextType ctxType = context->GetRenderContextType();
+ NVRenderContextType nonSupportedFlags(
+ NVRenderContextValues::GL2 | NVRenderContextValues::GLES2 | NVRenderContextValues::GL3
+ | NVRenderContextValues::GLES3 | NVRenderContextValues::GLES3PLUS);
+
+ // This is currently only supported on >= GL4 && >= GLES 3.1
+ if ((ctxType & nonSupportedFlags))
+ return false;
+
+ return true;
+}
+
+////////////////////////////////
+// test for functionality
+////////////////////////////////
+
+inline NVConstDataRef<QT3DSI8> toRef(const char *data)
+{
+ size_t len = strlen(data) + 1;
+ return NVConstDataRef<QT3DSI8>((const QT3DSI8 *)data, (QT3DSU32)len);
+}
+
+bool NVRenderTestTessellation::run(NVRenderContext *context, userContextData *pUserData)
+{
+ bool success = true;
+
+ context->SetRenderTarget(NULL);
+ // conpute cell width
+ _cellSize = pUserData->winWidth / _maxColumn;
+
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 1.f));
+ context->Clear(NVRenderClearFlags(NVRenderClearValues::Color | NVRenderClearValues::Depth));
+
+ success &= trianglePatches(context, pUserData);
+ _curTest++;
+ success &= phongPatches(context, pUserData);
+ _curTest++;
+
+ return success;
+}
+
+bool NVRenderTestTessellation::trianglePatches(NVRenderContext *context, userContextData *pUserData)
+{
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0) },
+ { QT3DSVec3(0.9, -0.9, 0) },
+ { QT3DSVec3(0.0, 0.9, 0) } };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&mvp, -1, 1, -1, 1, -10, 10);
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ std::string tcProg;
+ std::string teProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestTessellation shader", toRef(vertShader(vtxProg, isGLESContext(context))),
+ toRef(fragShader(frgProg, isGLESContext(context))),
+ toRef(tessControlShader(tcProg, isGLESContext(context))),
+ toRef(tessEvaluationShader(teProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 6 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestFboMsaa: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 1));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Patches, 3);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestFboMsaa: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+ // set tessellation values
+ float tessLevelInner = 4.0;
+ compResult.mShader->SetPropertyValue("tessLevelInner", tessLevelInner);
+ float tessLevelOuter = 4.0;
+ compResult.mShader->SetPropertyValue("tessLevelOuter", tessLevelOuter);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+bool NVRenderTestTessellation::phongPatches(NVRenderContext *context, userContextData *pUserData)
+{
+ QT3DSVec3 n1(-1.0, 0.5, 1.0);
+ n1.normalize();
+ QT3DSVec3 n2(1.0, 0.5, 1.0);
+ n2.normalize();
+ QT3DSVec3 n3(0.0, 1.0, 1.0);
+ n3.normalize();
+ static const Vertex vertexPositions[] = { { QT3DSVec3(-0.9, -0.9, 0.0), n1 },
+ { QT3DSVec3(0.9, -0.9, 0.0), n2 },
+ { QT3DSVec3(0.0, 0.9, -0.0), n3 } };
+
+ qt3ds::QT3DSVec3 color(0.0, 1.0, 0.0);
+
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderIndexBuffer> mIndexBuffer;
+ QT3DSMat44 p = QT3DSMat44::createIdentity();
+ QT3DSMat44 rotX = QT3DSMat44::createIdentity();
+ QT3DSMat44 rotY = QT3DSMat44::createIdentity();
+ QT3DSMat44 mv = QT3DSMat44::createIdentity();
+ QT3DSMat44 mvp = QT3DSMat44::createIdentity();
+ NvGl2DemoMatrixOrtho(&p, -1, 1, -1, 1, -10, 10);
+ // NvRenderTestMatrixRotY( &rotY, 45.0 );
+ // NvRenderTestMatrixRotX( &rotX, 90.0 );
+ mv = rotY * rotX;
+ mvp = mv * p;
+
+ // create shaders
+ std::string vtxProg;
+ std::string frgProg;
+ std::string tcProg;
+ std::string teProg;
+ NVRenderVertFragCompilationResult compResult = context->CompileSource(
+ "NVRenderTestTessellation shader", toRef(vertPhongShader(vtxProg, isGLESContext(context))),
+ toRef(fragPhongShader(frgProg, isGLESContext(context))),
+ toRef(tessPhongControlShader(tcProg, isGLESContext(context))),
+ toRef(tessPhongEvaluationShader(teProg, isGLESContext(context))));
+ if (!compResult.mShader) {
+ return false;
+ }
+
+ unsigned int curY = 0;
+ unsigned int curX = _curTest;
+ if (_curTest >= _maxColumn) {
+ curY = (_curTest / _maxColumn);
+ curX = (_curTest % _maxColumn);
+ }
+
+ // set viewport
+ context->SetViewport(NVRenderRect(curX * _cellSize, curY * _cellSize, _cellSize, _cellSize));
+
+ // this is the layout
+ NVRenderVertexBufferEntry entries[] = {
+ NVRenderVertexBufferEntry("attr_pos", NVRenderComponentTypes::QT3DSF32, 3, 0),
+ NVRenderVertexBufferEntry("attr_norm", NVRenderComponentTypes::QT3DSF32, 3, 12),
+ };
+
+ QT3DSU32 bufSize = 3 * sizeof(Vertex);
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)vertexPositions, bufSize);
+ mVertexBuffer = context->CreateVertexBuffer(NVRenderBufferUsageType::Static, bufSize,
+ 6 * sizeof(QT3DSF32), vertData);
+ if (!mVertexBuffer) {
+ qWarning() << "NVRenderTestFboMsaa: Failed to create vertex buffer";
+ return false;
+ }
+
+ // create our attribute layout
+ mAttribLayout = context->CreateAttributeLayout(toConstDataRef(entries, 2));
+ // create input Assembler
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = context->CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), mIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1), NVRenderDrawMode::Patches, 3);
+ if (!mInputAssembler) {
+ qWarning() << "NVRenderTestFboMsaa: Failed to create input assembler";
+ return false;
+ }
+
+ // make input assembler active
+ context->SetInputAssembler(mInputAssembler);
+ // set program
+ context->SetActiveShader(compResult.mShader);
+ compResult.mShader->SetPropertyValue("mat_mvp", mvp);
+ // set color
+ compResult.mShader->SetPropertyValue("color", color);
+ // set tessellation values
+ float tessLevels = 8.0;
+ compResult.mShader->SetPropertyValue("tessLevels", tessLevels);
+ float tessBlend = 1.0;
+ compResult.mShader->SetPropertyValue("tessBlend", tessBlend);
+
+ context->SetDepthTestEnabled(true);
+ context->SetDepthWriteEnabled(true);
+
+ // draw
+ context->Draw(mInputAssembler->GetPrimitiveType(), 3, 0);
+
+ context->SetActiveShader(0);
+ compResult.mShader->release();
+
+ return true;
+}
+
+////////////////////////////////
+// performance test
+////////////////////////////////
+bool NVRenderTestTessellation::runPerformance(NVRenderContext *context, userContextData *pUserData)
+{
+ return true;
+}
+
+////////////////////////////////
+// test cleanup
+////////////////////////////////
+void NVRenderTestTessellation::cleanup(NVRenderContext *context, userContextData *pUserData)
+{
+ context->SetClearColor(QT3DSVec4(.0f, .0f, .0f, 0.f));
+ // dummy
+ context->SetViewport(NVRenderRect(0, 0, pUserData->winWidth, pUserData->winHeight));
+}
diff --git a/tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.h b/tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.h
new file mode 100644
index 0000000..7403696
--- /dev/null
+++ b/tests/auto/runtime/geometry/Qt3DSRenderTestTessellation.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_TEST_TESSELLATION_H
+#define QT3DS_RENDER_TEST_TESSELLATION_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+ /// This class tests the creation of all kinds of primitives
+ class NVRenderTestTessellation : public NVRenderTestBase
+ {
+ public:
+ NVRenderTestTessellation();
+ ~NVRenderTestTessellation();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+ private:
+ bool trianglePatches(NVRenderContext *context, userContextData *pUserData);
+ bool phongPatches(NVRenderContext *context, userContextData *pUserData);
+
+ unsigned int _curTest;
+ unsigned int _cellSize;
+ unsigned int _maxColumn;
+ };
+}
+}
+
+#endif // QT3DS_RENDER_TEST_TESSELLATION_H
diff --git a/tests/auto/runtime/images/NVRenderTestAttribBuffers.png b/tests/auto/runtime/images/NVRenderTestAttribBuffers.png
new file mode 100644
index 0000000..e0fe946
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestAttribBuffers.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestBackendQuery.png b/tests/auto/runtime/images/NVRenderTestBackendQuery.png
new file mode 100644
index 0000000..7659236
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestBackendQuery.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestClear.png b/tests/auto/runtime/images/NVRenderTestClear.png
new file mode 100644
index 0000000..6e4c319
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestClear.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestComputeShader.png b/tests/auto/runtime/images/NVRenderTestComputeShader.png
new file mode 100644
index 0000000..6f08814
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestComputeShader.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestDrawIndirectBuffer.png b/tests/auto/runtime/images/NVRenderTestDrawIndirectBuffer.png
new file mode 100644
index 0000000..7659236
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestDrawIndirectBuffer.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestFboMsaa.png b/tests/auto/runtime/images/NVRenderTestFboMsaa.png
new file mode 100644
index 0000000..8eab95c
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestFboMsaa.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestGeometryShader.png b/tests/auto/runtime/images/NVRenderTestGeometryShader.png
new file mode 100644
index 0000000..820534e
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestGeometryShader.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestOcclusionQuery.png b/tests/auto/runtime/images/NVRenderTestOcclusionQuery.png
new file mode 100644
index 0000000..7659236
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestOcclusionQuery.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestProgramPipeline.png b/tests/auto/runtime/images/NVRenderTestProgramPipeline.png
new file mode 100644
index 0000000..f868b2d
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestProgramPipeline.png
Binary files differ
diff --git a/tests/auto/runtime/images/NVRenderTestTexture2D.png b/tests/auto/runtime/images/NVRenderTestTexture2D.png
new file mode 100644
index 0000000..afde59f
--- /dev/null
+++ b/tests/auto/runtime/images/NVRenderTestTexture2D.png
Binary files differ
diff --git a/tests/auto/runtime/runtime.pro b/tests/auto/runtime/runtime.pro
new file mode 100644
index 0000000..995c901
--- /dev/null
+++ b/tests/auto/runtime/runtime.pro
@@ -0,0 +1,82 @@
+TEMPLATE = app
+CONFIG += testcase
+include($$PWD/../../../commoninclude.pri)
+
+TARGET = tst_qt3dsruntime
+QT += testlib gui
+QT += quick-private
+
+RESOURCES += \
+ runtime.qrc
+
+INCLUDEPATH += \
+ $$PWD/../../../src/Qt3DSRuntimeRender/RendererImpl
+
+HEADERS += \
+ base/Qt3DSRenderTestAtomicCounterBuffer.h \
+ base/Qt3DSRenderTestAttribBuffers.h \
+ base/Qt3DSRenderTestBackendQuery.h \
+ base/Qt3DSRenderTestClear.h \
+ base/Qt3DSRenderTestConstantBuffer.h \
+ base/Qt3DSRenderTestDrawIndirectBuffer.h \
+ base/Qt3DSRenderTestPrimitives.h \
+ base/Qt3DSRenderTestProgramPipeline.h \
+ base/Qt3DSRenderTestTexture2D.h \
+ base/Qt3DSRenderTestTimerQuery.h \
+ compute/Qt3DSRenderTestComputeShader.h \
+ fbo/Qt3DSRenderTestFboMsaa.h \
+ geometry/Qt3DSRenderTestGeometryShader.h \
+ geometry/Qt3DSRenderTestOcclusionQuery.h \
+ geometry/Qt3DSRenderTestTessellation.h \
+ Qt3DSRenderTestBase.h \
+ Qt3DSRenderTestMathUtil.h \
+ tst_qt3dsruntime.h \
+ shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.h \
+ shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.h \
+ shadergenerator/Qt3DSRenderTestEffectGenerator.h
+
+SOURCES += \
+ base/Qt3DSRenderTestAtomicCounterBuffer.cpp \
+ base/Qt3DSRenderTestAttribBuffers.cpp \
+ base/Qt3DSRenderTestBackendQuery.cpp \
+ base/Qt3DSRenderTestClear.cpp \
+ base/Qt3DSRenderTestConstantBuffer.cpp \
+ base/Qt3DSRenderTestDrawIndirectBuffer.cpp \
+ base/Qt3DSRenderTestPrimitives.cpp \
+ base/Qt3DSRenderTestProgramPipeline.cpp \
+ base/Qt3DSRenderTestTexture2D.cpp \
+ base/Qt3DSRenderTestTimerQuery.cpp \
+ compute/Qt3DSRenderTestComputeShader.cpp \
+ fbo/Qt3DSRenderTestFboMsaa.cpp \
+ geometry/Qt3DSRenderTestGeometryShader.cpp \
+ geometry/Qt3DSRenderTestOcclusionQuery.cpp \
+ geometry/Qt3DSRenderTestTessellation.cpp \
+ Qt3DSRenderTestMathUtil.cpp \
+ tst_qt3dsruntime.cpp \
+ Qt3DSRenderTestBase.cpp \
+ shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.cpp \
+ shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.cpp \
+ shadergenerator/Qt3DSRenderTestEffectGenerator.cpp
+
+linux {
+ BEGIN_ARCHIVE = -Wl,--whole-archive
+ END_ARCHIVE = -Wl,--no-whole-archive
+}
+
+LIBS += \
+ -lqt3dsopengl$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+ANDROID_EXTRA_LIBS = \
+ libqt3dsqmlstreamer.so
+
+win32 {
+ LIBS += \
+ -lws2_32
+}
+
+linux {
+ LIBS += \
+ -ldl \
+ -lEGL
+}
diff --git a/tests/auto/runtime/runtime.qrc b/tests/auto/runtime/runtime.qrc
new file mode 100644
index 0000000..f4318f5
--- /dev/null
+++ b/tests/auto/runtime/runtime.qrc
@@ -0,0 +1,14 @@
+<RCC>
+ <qresource prefix="/">
+ <file>images/NVRenderTestTexture2D.png</file>
+ <file>images/NVRenderTestProgramPipeline.png</file>
+ <file>images/NVRenderTestAttribBuffers.png</file>
+ <file>images/NVRenderTestBackendQuery.png</file>
+ <file>images/NVRenderTestClear.png</file>
+ <file>images/NVRenderTestComputeShader.png</file>
+ <file>images/NVRenderTestDrawIndirectBuffer.png</file>
+ <file>images/NVRenderTestFboMsaa.png</file>
+ <file>images/NVRenderTestGeometryShader.png</file>
+ <file>images/NVRenderTestOcclusionQuery.png</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.cpp b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.cpp
new file mode 100644
index 0000000..244065a
--- /dev/null
+++ b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestCustomMaterialGenerator.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderContext.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderCustomMaterialRenderContext.h"
+#include "Qt3DSRenderCustomMaterialShaderGenerator.h"
+#include "Qt3DSRenderDynamicObjectSystem.h"
+#include "Qt3DSRenderDynamicObjectSystemCommands.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSTypes.h"
+#include "Qt3DSRenderRuntimeBinding.h"
+#include "Qt3DSApplication.h"
+#include "Qt3DSInputEngine.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSWindowSystem.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "rendererimpl/Qt3DSRendererImpl.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderUIPLoader.h"
+#include "Qt3DSDMMetaDataTypes.h"
+
+#include <QTime>
+#include <QString>
+#include <QTextStream>
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+
+
+namespace qt3ds {
+namespace render {
+
+Qt3DSRenderTestCustomMaterialGenerator::Qt3DSRenderTestCustomMaterialGenerator()
+{
+
+}
+
+Qt3DSRenderTestCustomMaterialGenerator::~Qt3DSRenderTestCustomMaterialGenerator()
+{
+
+}
+
+
+bool Qt3DSRenderTestCustomMaterialGenerator::isSupported(NVRenderContext *context)
+{
+ Q_UNUSED(context);
+ return true;
+}
+
+bool Qt3DSRenderTestCustomMaterialGenerator::runPerformance(NVRenderContext *context,
+ userContextData *pContextData)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(pContextData);
+ return false;
+}
+
+void Qt3DSRenderTestCustomMaterialGenerator::cleanup(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(pUserData);
+}
+
+struct CustomTestParams
+{
+ SRenderableObjectFlags flags;
+ dynamic::SDynamicShaderProgramFlags dynamicFlags;
+ QT3DSF32 opacity;
+ SLayer layer;
+ SLayerRenderData layerData;
+ SRenderableImage *images;
+ SLight light[QT3DS_MAX_NUM_LIGHTS];
+ SModel model;
+ SRenderSubset subset;
+ SShaderDefaultMaterialKey shaderkey;
+ SCustomMaterial *material;
+ eastl::vector<SShaderPreprocessorFeature> features;
+ Option<qt3dsdm::SMetaDataCustomMaterial> metaMaterial;
+ SImage dummyImages[SShaderDefaultMaterialKeyProperties::ImageMapCount];
+ eastl::vector<SRenderableImage*> renderableImages;
+ qt3ds::render::Qt3DSRendererImpl *render;
+ SImage iblLightProbe;
+ NVRenderTexture2D *texture;
+
+ CustomTestParams(Qt3DSRendererImpl &impl)
+ : layerData(layer, impl)
+ , images(NULL)
+ , subset(impl.GetContext().GetAllocator())
+ , material(NULL)
+ , render(&impl)
+ , texture(NULL)
+ {
+ }
+ ~CustomTestParams()
+ {
+ if (texture)
+ texture->release();
+ }
+
+ void addRenderableImage(ImageMapTypes::Enum type,
+ SShaderDefaultMaterialKeyProperties::ImageMapNames name)
+ {
+ renderableImages.push_back(new SRenderableImage(type, dummyImages[name]));
+ render->DefaultMaterialShaderKeyProperties().m_ImageMaps[name].SetEnabled(shaderkey, true);
+ }
+ void prepare()
+ {
+ for (unsigned int i = 0; i < renderableImages.size(); i++) {
+ if (i == 0)
+ images = renderableImages[0];
+ else
+ renderableImages[i-1]->m_NextImage = renderableImages[i];
+ }
+ }
+};
+
+struct CustomTestKey
+{
+ unsigned int tessellation : 2;
+ unsigned int wireframe : 1;
+ unsigned int lighting: 1;
+ unsigned int indirectLightmap: 1;
+ unsigned int radiosityLightmap: 1;
+ unsigned int shadowLightmap: 1;
+ unsigned int transparency : 1;
+ unsigned int refraction : 1;
+ unsigned int iblprobe : 1;
+ unsigned int emissiveMap : 1;
+ unsigned int displacementMap : 1;
+ unsigned int diffuse = 1;
+ unsigned int specular = 1;
+ unsigned int glossy = 1;
+ unsigned int cutout = 1;
+ unsigned int transmissive : 1;
+ unsigned int ssao : 1;
+ unsigned int ssdo : 1;
+ unsigned int ssm : 1;
+
+ CustomTestKey(TessModeValues::Enum tess = TessModeValues::NoTess, bool wire = false,
+ bool lights = false, bool indirect = false, bool radiosity = false,
+ bool shadow = false, bool trans = false, bool refract = false, bool ibl = false,
+ bool emissive = false, bool disp = false, bool diff = false,
+ bool spec = false, bool glo = false, bool cut = false, bool transm = false,
+ bool ao = false, bool direct = false, bool shadowssm = false)
+ : tessellation(tess), wireframe(wire), lighting(lights), indirectLightmap(indirect)
+ , radiosityLightmap(radiosity), shadowLightmap(shadow), transparency(trans)
+ , refraction(refract), iblprobe(ibl), emissiveMap(emissive), displacementMap(disp)
+ , diffuse(diff), specular(spec), glossy(glo), cutout(cut), transmissive(transm)
+ , ssao(ao), ssdo(direct), ssm(shadowssm)
+ {
+
+ }
+
+ bool operator == (const CustomTestKey &other) const
+ {
+ uint64_t a = *(uint64_t *)this;
+ uint64_t b = *(uint64_t *)&other;
+ return a == b;
+ }
+
+ QString toString()
+ {
+ QString str;
+ QTextStream stream(&str);
+ stream << "Custom Key tessellation: " << int(tessellation);
+ stream << " wireframe: " << (wireframe ? "true" : "false");
+ stream << " lighting: " << (lighting ? "true" : "false");
+ stream << " indirectLightmap: " << (indirectLightmap ? "true" : "false");
+ stream << " radiosityLightmap: " << (radiosityLightmap ? "true" : "false");
+ stream << " shadowLightmap: " << (shadowLightmap ? "true" : "false");
+ stream << " transparency: " << (transparency ? "true" : "false");
+ stream << " refraction: " << (refraction ? "true" : "false");
+ stream << " iblprobe: " << (iblprobe ? "true" : "false");
+ stream << " emissiveMap: " << (emissiveMap ? "true" : "false");
+ stream << " displacementMap: " << (displacementMap ? "true" : "false");
+ stream << " diffuse: " << (diffuse ? "true" : "false");
+ stream << " specular: " << (specular ? "true" : "false");
+ stream << " glossy: " << (glossy ? "true" : "false");
+ stream << " cutout: " << (cutout ? "true" : "false");
+ stream << " transmissive: " << (transmissive ? "true" : "false");
+ stream << " ssao: " << (ssao ? "true" : "false");
+ stream << " ssdo: " << (ssdo ? "true" : "false");
+ stream << " ssm: " << (ssm ? "true" : "false");
+ return str;
+ }
+};
+
+#define MAX_TEST_KEY ((1llu<<20)-1)
+
+static CustomTestKey randomizeTestKey()
+{
+ uint64_t v = (uint64_t(qrand()))%MAX_TEST_KEY;
+ return *reinterpret_cast<CustomTestKey*>(&v);
+}
+
+CustomTestParams *generateTest(qt3ds::render::Qt3DSRendererImpl *renderImpl,
+ NVRenderContext *context, CustomTestKey key, SCustomMaterial *material)
+{
+ CustomTestParams *params = new CustomTestParams(*renderImpl);
+ params->material = material;
+ params->material->m_ShaderKeyValues = (SCustomMaterialShaderKeyFlags)0;
+ params->material->m_Lightmaps = SLightmaps();
+ params->material->m_DisplacementMap = NULL;
+ params->material->m_EmissiveMap2 = NULL;
+ params->material->m_hasTransparency = false;
+ params->material->m_IblProbe = NULL;
+ params->material->m_hasRefraction = false;
+ switch (key.tessellation) {
+ case 1:
+ params->model.m_TessellationMode = TessModeValues::TessLinear;
+ break;
+ case 2:
+ params->model.m_TessellationMode = TessModeValues::TessPhong;
+ break;
+ case 3:
+ params->model.m_TessellationMode = TessModeValues::TessNPatch;
+ break;
+ default:
+ params->model.m_TessellationMode = TessModeValues::NoTess;
+ break;
+ }
+
+ renderImpl->DefaultMaterialShaderKeyProperties()
+ .m_TessellationMode.SetValue(params->shaderkey, params->model.m_TessellationMode);
+
+ if (key.wireframe && key.tessellation > 0) {
+ params->subset.m_WireframeMode = true;
+ renderImpl->DefaultMaterialShaderKeyProperties().m_WireframeMode.SetValue(
+ params->shaderkey, true);
+ }
+
+ CRegisteredString lighting =
+ renderImpl->GetContext().GetStringTable().RegisterStr("QT3DS_ENABLE_CG_LIGHTING");
+ params->features.push_back(SShaderPreprocessorFeature(lighting, key.lighting));
+
+ if (key.indirectLightmap) {
+ params->material->m_Lightmaps.m_LightmapIndirect
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::LightmapIndirect];
+ params->addRenderableImage(ImageMapTypes::LightmapIndirect,
+ SShaderDefaultMaterialKeyProperties::LightmapIndirect);
+ }
+ if (key.radiosityLightmap) {
+ params->material->m_Lightmaps.m_LightmapRadiosity
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::LightmapRadiosity];
+ params->addRenderableImage(ImageMapTypes::LightmapRadiosity,
+ SShaderDefaultMaterialKeyProperties::LightmapRadiosity);
+ }
+ if (key.shadowLightmap) {
+ params->material->m_Lightmaps.m_LightmapShadow
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::LightmapShadow];
+ params->addRenderableImage(ImageMapTypes::LightmapRadiosity,
+ SShaderDefaultMaterialKeyProperties::LightmapShadow);
+ }
+
+ if (key.diffuse)
+ params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::diffuse;
+
+ // TODO: emissive mask doesn't work
+// if (key.emissiveMap >= 1) {
+// params->material->m_EmissiveMap2
+// = &params->dummyImages[SShaderDefaultMaterialKeyProperties::EmissiveMap];
+// params->addRenderableImage(ImageMapTypes::Emissive,
+// SShaderDefaultMaterialKeyProperties::EmissiveMap);
+// }
+
+ if (key.specular)
+ params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::specular;
+
+ if (key.displacementMap) {
+ params->material->m_DisplacementMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::DisplacementMap];
+ params->material->m_DisplacementMap->m_ImageShaderName
+ = renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("DisplacementMap");
+ params->material->m_DisplaceAmount = 1.0f;
+ params->addRenderableImage(ImageMapTypes::Displacement,
+ SShaderDefaultMaterialKeyProperties::DisplacementMap);
+
+ params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::displace;
+ }
+
+ if (key.iblprobe) {
+ renderImpl->DefaultMaterialShaderKeyProperties().m_HasIbl.SetValue(
+ params->shaderkey, true);
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_LIGHT_PROBE"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+
+ params->material->m_IblProbe = &params->iblLightProbe;
+ params->texture = context->CreateTexture2D();
+ NVRenderTextureFormats::Enum format = NVRenderTextureFormats::RGBA8;
+ unsigned int data = 0;
+ NVDataRef<QT3DSU8> buffer = toU8DataRef<unsigned int>(data);
+ params->texture->SetTextureData(buffer, 0, 1, 1, format);
+ params->iblLightProbe.m_TextureData.m_Texture = params->texture;
+ } else {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_LIGHT_PROBE"));
+ params->features.push_back(SShaderPreprocessorFeature(str, false));
+ }
+
+ // these requires calculateGlass function in material
+// if (key.transparency) {
+// params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::transparent;
+// params->material->m_hasTransparency = true;
+// }
+// if (key.refraction) {
+// params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::refraction;
+// params->material->m_hasRefraction = true;
+// }
+ if (key.glossy)
+ params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::glossy;
+
+ if (key.cutout)
+ params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::cutout;
+
+ if (key.transmissive)
+ params->material->m_ShaderKeyValues &= SCustomMaterialShaderKeyValues::transmissive;
+
+ if (key.ssm) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_SSM"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+ if (key.ssao) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_SSAO"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+ if (key.ssdo) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_SSDO"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+
+ params->prepare();
+ return params;
+}
+
+bool GenShader(IQt3DSRenderContext &qt3dsContext, CustomTestParams &params)
+{
+ bool success = true;
+ ICustomMaterialShaderGenerator &theMaterialGenerator(qt3dsContext.GetCustomMaterialShaderGenerator());
+
+ SCustomMaterialVertexPipeline thePipeline(&qt3dsContext,
+ params.model.m_TessellationMode);
+
+ for (int i = 0; i < params.metaMaterial->m_CustomMaterialCommands.size(); i++) {
+ dynamic::SCommand &command = *params.metaMaterial->m_CustomMaterialCommands[i];
+ if (command.m_Type == dynamic::CommandTypes::Enum::BindShader) {
+ dynamic::SBindShader *bindShader = static_cast<dynamic::SBindShader *>(&command);
+ NVRenderShaderProgram *theProgram = theMaterialGenerator.GenerateShader(
+ *params.material, params.shaderkey, thePipeline,
+ toConstDataRef(params.features.data(), (QT3DSU32)params.features.size()),
+ params.layerData.m_Lights, params.images,
+ (params.material->m_hasTransparency || params.material->m_hasRefraction),
+ "custom material pipeline-- ", bindShader->m_ShaderPath);
+ if (!theProgram) {
+ success = false;
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+bool Qt3DSRenderTestCustomMaterialGenerator::run(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ Q_UNUSED(pUserData);
+ bool success = true;
+
+ QVector<CustomTestKey> testKeys;
+ testKeys.push_back(CustomTestKey());
+ testKeys.push_back(CustomTestKey(TessModeValues::TessLinear));
+ testKeys.push_back(CustomTestKey(TessModeValues::TessNPatch));
+ testKeys.push_back(CustomTestKey(TessModeValues::TessPhong));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true));
+ testKeys.push_back(CustomTestKey(TessModeValues::NoTess, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true));
+
+ while (testKeys.size() < 100) {
+ CustomTestKey key = randomizeTestKey();
+ if (!testKeys.contains(key))
+ testKeys.push_back(key);
+ }
+
+ if (success) {
+ CRegisteredString name = context->GetStringTable().RegisterStr("qrc:/copper.shader");
+
+ metadata()->LoadMaterialXMLFile("CustomMaterial", "", "copper", "qrc:/copper.shader");
+ Option<qt3dsdm::SMetaDataCustomMaterial> metaMaterial =
+ metadata()->GetMaterialMetaDataBySourcePath("qrc:/copper.shader");
+
+ if (metaMaterial.hasValue()) {
+ qt3ds::render::IUIPLoader::CreateMaterialClassFromMetaMaterial(
+ name, context->GetFoundation(),
+ qt3dsRenderer()->GetQt3DSContext().GetCustomMaterialSystem(), *metaMaterial,
+ context->GetStringTable());
+ SCustomMaterial *material = qt3dsRenderer()->GetQt3DSContext().GetCustomMaterialSystem()
+ .CreateCustomMaterial(name, qt3dsRenderer()->GetContext().GetAllocator());
+
+ for (CustomTestKey key : testKeys) {
+ CustomTestParams *params = generateTest(qt3dsRenderer(), context, key, material);
+ params->metaMaterial = metaMaterial;
+ success &= GenShader(qt3dsRenderer()->GetQt3DSContext(), *params);
+ if (!success)
+ qDebug () << "failing key: " << key.toString();
+ delete params;
+ }
+ delete material;
+ }
+ }
+
+ return success;
+}
+
+} // render
+} // qt3ds
diff --git a/tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.h b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.h
new file mode 100644
index 0000000..621d20f
--- /dev/null
+++ b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_RENDER_TEST_CUSTOM_MATERIAL_GENERATOR_H
+#define QT3DS_RENDER_TEST_CUSTOM_MATERIAL_GENERATOR_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+class Qt3DSRenderTestCustomMaterialGenerator : public NVRenderTestBase
+{
+public:
+ Qt3DSRenderTestCustomMaterialGenerator();
+ ~Qt3DSRenderTestCustomMaterialGenerator();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+private:
+
+};
+
+} // render
+} // qt3ds
+
+#endif
diff --git a/tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.cpp b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.cpp
new file mode 100644
index 0000000..1e2c07e
--- /dev/null
+++ b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestDefaultMaterialGenerator.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderContext.h"
+#include "Qt3DSTypes.h"
+#include "Qt3DSRenderRuntimeBinding.h"
+#include "Qt3DSApplication.h"
+#include "Qt3DSInputEngine.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSWindowSystem.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "rendererimpl/Qt3DSRendererImpl.h"
+#include "Qt3DSRenderLight.h"
+
+#include <QTime>
+
+#include <string>
+
+using namespace qt3ds;
+using namespace qt3ds::render;
+
+
+
+namespace qt3ds {
+namespace render {
+
+Qt3DSRenderTestDefaultMaterialGenerator::Qt3DSRenderTestDefaultMaterialGenerator()
+{
+
+}
+
+Qt3DSRenderTestDefaultMaterialGenerator::~Qt3DSRenderTestDefaultMaterialGenerator()
+{
+
+}
+
+
+bool Qt3DSRenderTestDefaultMaterialGenerator::isSupported(NVRenderContext *context)
+{
+ Q_UNUSED(context);
+ return true;
+}
+
+bool Qt3DSRenderTestDefaultMaterialGenerator::runPerformance(NVRenderContext *context,
+ userContextData *pContextData)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(pContextData);
+ return false;
+}
+
+void Qt3DSRenderTestDefaultMaterialGenerator::cleanup(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(pUserData);
+}
+
+
+#define MAX_TEST_KEY ((1llu<<32)-1)
+
+struct TestKey
+{
+ unsigned int tessellation: 2;
+ unsigned int wireframe: 1;
+ unsigned int lighting: 2;
+ unsigned int lights: 4;
+ unsigned int indirectLightmap: 1;
+ unsigned int radiosityLightmap: 1;
+ unsigned int lightProbe: 2;
+ unsigned int iblLightProbe: 1;
+ unsigned int iblfow: 1;
+ unsigned int diffuseMap: 2;
+ unsigned int emissiveMap: 2;
+ unsigned int specularModel: 2;
+ unsigned int specularMap: 1;
+ unsigned int specularReflection: 1;
+ unsigned int fresnel: 1;
+ unsigned int bumpmapping: 2;
+ unsigned int displacementMap: 1;
+ unsigned int opacityMap: 1;
+ unsigned int translucencyMap: 1;
+ unsigned int ssm: 1;
+ unsigned int ssdo: 1;
+ unsigned int ssao: 1;
+
+ TestKey(TessModeValues::Enum tess = TessModeValues::NoTess, bool wire = false,
+ DefaultMaterialLighting::Enum lmode = DefaultMaterialLighting::NoLighting,
+ int lightCount = 0, bool indirect = false, bool radio = false, int lprobe = 0,
+ bool iblProbe = false, bool iblf = false, int diffuse = 0, int emissive = 0,
+ DefaultMaterialSpecularModel::Enum sModel = DefaultMaterialSpecularModel::Default,
+ bool sMap = false, bool sRef = false, bool fre = false, int bump = 0,
+ bool disp = false, bool opac = false, bool trans = false, bool shadow = false,
+ bool ao = false, bool directOcc = false)
+ : tessellation(tess), wireframe(wire), lighting(lmode), lights(lightCount)
+ , indirectLightmap(indirect), radiosityLightmap(radio), lightProbe(lprobe)
+ , iblLightProbe(iblProbe), iblfow(iblf), diffuseMap(diffuse), emissiveMap(emissive)
+ , specularModel(sModel), specularMap(sMap), specularReflection(sRef)
+ , fresnel(fre), bumpmapping(bump), displacementMap(disp), opacityMap(opac)
+ , translucencyMap(trans), ssm(shadow), ssao(ao), ssdo(directOcc)
+ {
+
+ }
+
+ bool operator == (const TestKey &other) const
+ {
+ return toInt() == other.toInt();
+ }
+
+ QString toString()
+ {
+ QString str;
+ QTextStream stream(&str);
+
+ stream << " tessellation: " << tessellation;
+ stream << " wireframe: " << (wireframe ? "true" : "false");
+ stream << " lighting: " << lighting;
+ stream << " lights: " << lights;
+ stream << " indirectLightmap: " << (indirectLightmap ? "true" : "false");
+ stream << " radiosityLightmap: " << (radiosityLightmap ? "true" : "false");
+ stream << " lightProbe: " << lightProbe;
+ stream << " iblLightProbe: " << (iblLightProbe ? "true" : "false");
+ stream << " iblfow: " << (iblfow ? "true" : "false");
+ stream << " diffuseMap: " << diffuseMap;
+ stream << " emissiveMap: " << emissiveMap;
+ stream << " specularModel: " << specularModel;
+ stream << " specularMap: " << (specularMap ? "true" : "false");
+ stream << " specularReflection: " << (specularReflection ? "true" : "false");
+ stream << " fresnel: " << (fresnel ? "true" : "false");
+ stream << " bumpmapping: " << bumpmapping;
+ stream << " displacementMap: " << (displacementMap ? "true" : "false");
+ stream << " opacityMap: " << (opacityMap ? "true" : "false");
+ stream << " translucencyMap: " << (translucencyMap ? "true" : "false");
+ stream << " ssm: " << (ssm ? "true" : "false");
+ stream << " ssdo: " << (ssdo ? "true" : "false");
+ stream << " ssao: " << (ssao ? "true" : "false");
+
+ return str;
+ }
+
+ void clampValues()
+ {
+ lighting = qMin(lighting, 2u);
+ if (lighting == 1)
+ lighting = 2;
+ emissiveMap = qMin(emissiveMap, 2u);
+ specularModel = qMin(specularModel, 2u);
+ bumpmapping = qMin(bumpmapping, 2u);
+ lightProbe = 0;
+ if (!iblLightProbe)
+ iblfow = 0;
+ if (!tessellation)
+ wireframe = 0;
+ }
+
+ uint64_t toInt() const
+ {
+ return (*(uint64_t *)this)&MAX_TEST_KEY;
+ }
+};
+
+struct TestParams
+{
+ SRenderableObjectFlags flags;
+ NVConstDataRef<QT3DSMat44> boneGlobals;
+ SRenderSubset subset;
+ SDefaultMaterial material;
+ SModel model;
+ QT3DSMat44 viewProjection;
+ SModelContext modelContext;
+ SRenderableImage *images;
+ SShaderDefaultMaterialKey shaderkey;
+ SSubsetRenderable renderable;
+ eastl::vector<SShaderPreprocessorFeature> features;
+ SLight light[QT3DS_MAX_NUM_LIGHTS];
+ SLayer layer;
+ SLayerRenderData layerData;
+ SImage dummyImages[SShaderDefaultMaterialKeyProperties::ImageMapCount];
+ NVRenderTexture2D *textures[4];
+ eastl::vector<SRenderableImage*> renderableImages;
+ qt3ds::render::Qt3DSRendererImpl *render;
+
+ TestParams(NVRenderContext *context, qt3ds::render::Qt3DSRendererImpl *renderImpl)
+ : subset(context->GetAllocator())
+ , modelContext(model, viewProjection)
+ , images(NULL)
+ , renderable(flags, QT3DSVec3(), *renderImpl, subset, material, modelContext, 1.0f, images,
+ shaderkey, boneGlobals)
+ , layerData(layer, *renderImpl)
+ , render(renderImpl)
+ {
+ for (int i = 0; i < 4; ++i) {
+ textures[i] = context->CreateTexture2D();
+ NVRenderTextureFormats::Enum format = NVRenderTextureFormats::RGBA8;
+ unsigned int data = 0;
+ NVDataRef<QT3DSU8> buffer = toU8DataRef<unsigned int>(data);
+ textures[i]->SetTextureData(buffer, 0, 1, 1, format);
+ }
+ for (int i = 0; i < SShaderDefaultMaterialKeyProperties::ImageMapCount; ++i)
+ dummyImages[i].m_TextureData.m_Texture = textures[i%4];
+ dummyImages[SShaderDefaultMaterialKeyProperties::DiffuseMap1].m_TextureData.
+ m_TextureFlags.SetPreMultiplied(true);
+ dummyImages[SShaderDefaultMaterialKeyProperties::EmissiveMap2].m_TextureData.
+ m_TextureFlags.SetInvertUVCoords(true);
+ }
+ ~TestParams()
+ {
+ for (NVRenderTexture2D *tex : textures)
+ tex->release();
+ for (SRenderableImage *img : renderableImages)
+ delete img;
+ }
+ void addRenderableImage(ImageMapTypes::Enum type,
+ SShaderDefaultMaterialKeyProperties::ImageMapNames name)
+ {
+ renderableImages.push_back(new SRenderableImage(type, dummyImages[name]));
+ render->DefaultMaterialShaderKeyProperties().m_ImageMaps[name].SetEnabled(shaderkey, true);
+ }
+ void prepare()
+ {
+ for (unsigned int i = 0; i < renderableImages.size(); i++) {
+ if (i == 0)
+ images = renderableImages[0];
+ else {
+ renderableImages[i-1]->m_NextImage = renderableImages[i];
+ }
+
+ }
+ renderable.m_ShaderDescription = shaderkey;
+ renderable.m_FirstImage = images;
+ }
+};
+
+TestKey randomizeTestKey()
+{
+ uint64_t v = (uint64_t(qrand()) << 32 | uint64_t(qrand()))&MAX_TEST_KEY;
+ TestKey key = *reinterpret_cast<TestKey*>(&v);
+ key.clampValues();
+ return key;
+}
+
+
+TestParams *generateTest(qt3ds::render::Qt3DSRendererImpl *renderImpl,
+ NVRenderContext *context, TestKey key)
+{
+ // TODO: light probes
+ TestParams *params = new TestParams(context, renderImpl);
+
+ switch (key.tessellation) {
+ case 1:
+ params->model.m_TessellationMode = TessModeValues::TessLinear;
+ break;
+ case 2:
+ params->model.m_TessellationMode = TessModeValues::TessPhong;
+ break;
+ case 3:
+ params->model.m_TessellationMode = TessModeValues::TessNPatch;
+ break;
+ default:
+ params->model.m_TessellationMode = TessModeValues::NoTess;
+ break;
+ }
+
+ renderImpl->DefaultMaterialShaderKeyProperties()
+ .m_TessellationMode.SetValue(params->shaderkey, params->model.m_TessellationMode);
+
+ switch (key.lighting) {
+ case 1:
+ params->material.m_Lighting = DefaultMaterialLighting::VertexLighting;
+ break;
+ case 2:
+ params->material.m_Lighting = DefaultMaterialLighting::FragmentLighting;
+ break;
+ default:
+ params->material.m_Lighting = DefaultMaterialLighting::NoLighting;
+ break;
+ }
+ if (key.lighting != 0) {
+ renderImpl->DefaultMaterialShaderKeyProperties()
+ .m_HasLighting.SetValue(params->shaderkey, true);
+ }
+
+ if (key.wireframe && key.tessellation > 0) {
+ params->subset.m_WireframeMode = true;
+ renderImpl->DefaultMaterialShaderKeyProperties().m_WireframeMode.SetValue(
+ params->shaderkey, true);
+ }
+ bool castShadow = false;
+ key.lights = qMin(int(key.lights), int(QT3DS_MAX_NUM_LIGHTS));
+ for (unsigned int i = 0; i < key.lights; ++i) {
+ params->light[i].m_LightType = static_cast<RenderLightTypes::Enum>((i%3)+1);
+ if (params->light[i].m_LightType != RenderLightTypes::Directional) {
+ renderImpl->DefaultMaterialShaderKeyProperties().m_LightFlags[i].SetValue(
+ params->shaderkey, true);
+ }
+ if (params->light[i].m_LightType == RenderLightTypes::Area) {
+ renderImpl->DefaultMaterialShaderKeyProperties()
+ .m_LightAreaFlags[i]
+ .SetValue(params->shaderkey, true);
+ }
+ if (params->light[i].m_LightType != RenderLightTypes::Point) {
+ renderImpl->DefaultMaterialShaderKeyProperties()
+ .m_LightShadowFlags[i]
+ .SetValue(params->shaderkey, castShadow);
+ castShadow = !castShadow;
+ }
+ params->layerData.m_Lights.push_back(&params->light[i]);
+ }
+
+ renderImpl->DefaultMaterialShaderKeyProperties().m_LightCount.SetValue(params->shaderkey,
+ key.lights);
+
+ // shadow lightmap is not used
+ if (key.indirectLightmap) {
+ params->material.m_Lightmaps.m_LightmapIndirect
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::LightmapIndirect];
+ params->addRenderableImage(ImageMapTypes::LightmapIndirect,
+ SShaderDefaultMaterialKeyProperties::LightmapIndirect);
+ }
+ if (key.radiosityLightmap) {
+ params->material.m_Lightmaps.m_LightmapRadiosity
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::LightmapRadiosity];
+ params->addRenderableImage(ImageMapTypes::LightmapRadiosity,
+ SShaderDefaultMaterialKeyProperties::LightmapRadiosity);
+ }
+
+ for (unsigned int i = 0; i < key.diffuseMap; ++i) {
+ params->material.m_DiffuseMaps[i]
+ = &params->dummyImages[static_cast<SShaderDefaultMaterialKeyProperties::ImageMapNames>
+ (SShaderDefaultMaterialKeyProperties::DiffuseMap0 + i)];
+ params->addRenderableImage(ImageMapTypes::Diffuse,
+ static_cast<SShaderDefaultMaterialKeyProperties::ImageMapNames>
+ (SShaderDefaultMaterialKeyProperties::DiffuseMap0 + i));
+ }
+
+ if (key.emissiveMap >= 1) {
+ params->material.m_EmissiveMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::EmissiveMap];
+ params->addRenderableImage(ImageMapTypes::Emissive,
+ SShaderDefaultMaterialKeyProperties::EmissiveMap);
+ }
+ if (key.emissiveMap == 2) {
+ params->material.m_EmissiveMap2
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::EmissiveMap2];
+ params->addRenderableImage(ImageMapTypes::Emissive,
+ SShaderDefaultMaterialKeyProperties::EmissiveMap2);
+ }
+
+ switch (key.specularModel) {
+ case 1:
+ params->material.m_SpecularModel = DefaultMaterialSpecularModel::KGGX;
+ break;
+ case 2:
+ params->material.m_SpecularModel = DefaultMaterialSpecularModel::KWard;
+ break;
+ default:
+ params->material.m_SpecularModel = DefaultMaterialSpecularModel::Default;
+ break;
+ }
+
+ if (key.specularMap) {
+ params->material.m_SpecularMap =
+ &params->dummyImages[SShaderDefaultMaterialKeyProperties::SpecularAmountMap];
+ params->material.m_SpecularAmount = 1.0f;
+ params->addRenderableImage(ImageMapTypes::SpecularAmountMap,
+ SShaderDefaultMaterialKeyProperties::SpecularAmountMap);
+ }
+ if (key.specularReflection) {
+ params->dummyImages[SShaderDefaultMaterialKeyProperties::SpecularMap].m_MappingMode
+ = ImageMappingModes::Environment;
+ params->material.m_SpecularAmount = 1.0f;
+ params->material.m_SpecularReflection
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::SpecularMap];
+ params->addRenderableImage(ImageMapTypes::Specular,
+ SShaderDefaultMaterialKeyProperties::SpecularMap);
+ }
+ if (key.fresnel)
+ params->material.m_FresnelPower = 1.0f;
+
+ if (key.bumpmapping == 1) {
+ params->material.m_BumpMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::BumpMap];
+ params->material.m_BumpAmount = 1.0f;
+ params->addRenderableImage(ImageMapTypes::Bump, SShaderDefaultMaterialKeyProperties::BumpMap);
+ }
+ if (key.bumpmapping == 2) {
+ params->material.m_NormalMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::NormalMap];
+ params->addRenderableImage(ImageMapTypes::Normal, SShaderDefaultMaterialKeyProperties::NormalMap);
+ }
+
+ if (key.displacementMap) {
+ params->material.m_DisplacementMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::DisplacementMap];
+ params->material.m_DisplaceAmount = 1.0f;
+ params->addRenderableImage(ImageMapTypes::Displacement,
+ SShaderDefaultMaterialKeyProperties::DisplacementMap);
+ }
+
+ if (key.opacityMap) {
+ params->material.m_OpacityMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::OpacityMap];
+ params->material.m_Opacity = 0.5f;
+ params->addRenderableImage(ImageMapTypes::Opacity,
+ SShaderDefaultMaterialKeyProperties::OpacityMap);
+ }
+
+ if (key.translucencyMap) {
+ params->material.m_TranslucencyMap
+ = &params->dummyImages[SShaderDefaultMaterialKeyProperties::TranslucencyMap];
+ params->material.m_TranslucentFalloff = 0.1f;
+ params->addRenderableImage(ImageMapTypes::Translucency,
+ SShaderDefaultMaterialKeyProperties::TranslucencyMap);
+ }
+
+ if (key.ssm) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_SSM"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+ if (key.ssao) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_SSAO"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+ if (key.ssdo) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_SSDO"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+
+ if (key.iblLightProbe) {
+ renderImpl->DefaultMaterialShaderKeyProperties().m_HasIbl.SetValue(
+ params->shaderkey, true);
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_LIGHT_PROBE"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ if (key.iblfow) {
+ CRegisteredString str(renderImpl->GetQt3DSContext().GetStringTable()
+ .RegisterStr("QT3DS_ENABLE_IBL_FOV"));
+ params->features.push_back(SShaderPreprocessorFeature(str, true));
+ }
+ }
+
+ if (params->material.IsSpecularEnabled()) {
+ renderImpl->DefaultMaterialShaderKeyProperties().m_SpecularEnabled.SetValue(
+ params->shaderkey, true);
+ renderImpl->DefaultMaterialShaderKeyProperties().m_SpecularModel.SetSpecularModel(
+ params->shaderkey, params->material.m_SpecularModel);
+ }
+ if (params->material.IsFresnelEnabled()) {
+ renderImpl->DefaultMaterialShaderKeyProperties().m_FresnelEnabled.SetValue(
+ params->shaderkey, true);
+ }
+
+ params->prepare();
+ return params;
+}
+
+
+
+bool Qt3DSRenderTestDefaultMaterialGenerator::run(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ Q_UNUSED(pUserData);
+ bool success = true;
+
+ qsrand(QTime::currentTime().msec());
+
+ QVector<TestKey> testKeys;
+
+ testKeys.push_back(TestKey());
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 1));
+ testKeys.push_back(TestKey(TessModeValues::TessLinear, false, DefaultMaterialLighting::FragmentLighting, 1));
+ testKeys.push_back(TestKey(TessModeValues::TessNPatch, false, DefaultMaterialLighting::FragmentLighting, 1));
+ testKeys.push_back(TestKey(TessModeValues::TessPhong, false, DefaultMaterialLighting::FragmentLighting, 1));
+ testKeys.push_back(TestKey(TessModeValues::TessLinear, true, DefaultMaterialLighting::FragmentLighting, 1));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 6));
+ // vertex lighting is not supported?
+ //testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::VertexLighting, 6));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 1, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 1, true, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 2));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 3, true, true, 0, false, false, 3));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 3, true, true, 0, false, false, 1, 1));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 4, true, true, 0, false, false, 1, 2));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 4, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::KGGX, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 5, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::KWard, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 5, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 6, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 6, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 1));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 2));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 0, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 0, true, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 0, true, true, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 0, true, true, true, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 0, true, true, true, false, true));
+ testKeys.push_back(TestKey(TessModeValues::NoTess, false, DefaultMaterialLighting::FragmentLighting, 2, true, true, 0, false, false, 1, 1, DefaultMaterialSpecularModel::Default, true, true, true, 0, true, true, true, true, false, true));
+
+ while (testKeys.size() < 100) {
+ TestKey key = randomizeTestKey();
+ if (!testKeys.contains(key))
+ testKeys.push_back(key);
+ }
+ // generated programs must be unique
+ QVector<NVRenderShaderProgram *> programs;
+ success = initializeQt3DSRenderer(context->format());
+ if (success) {
+ for (TestKey key : testKeys) {
+ qDebug () << "testing key: " << key.toInt();
+ TestParams *params = generateTest(qt3dsRenderer(), context, key);
+
+ qt3dsRenderer()->BeginLayerRender(params->layerData);
+ NVRenderShaderProgram *program
+ = qt3dsRenderer()->GenerateShader(params->renderable,
+ toConstDataRef(params->features.data(),
+ (QT3DSU32)params->features.size()));
+ if (!program) {
+ success = false;
+ } else {
+ if (programs.contains(program)) {
+ qDebug () << "Generated program is not unique vs " << testKeys[programs.indexOf(program)].toString();
+ success = false;
+ }
+ else {
+ programs.push_back(program);
+ }
+ }
+
+ if (!success)
+ qDebug () << "failing test key: " << key.toString();
+
+ qt3dsRenderer()->EndLayerRender();
+ delete params;
+ }
+ }
+
+ return success;
+}
+
+} // render
+} // qt3ds
diff --git a/tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.h b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.h
new file mode 100644
index 0000000..c1464a3
--- /dev/null
+++ b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_RENDER_TEST_DEFAULT_MATERIAL_GENERATOR_H
+#define QT3DS_RENDER_TEST_DEFAULT_MATERIAL_GENERATOR_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+
+namespace qt3ds {
+namespace render {
+
+class Qt3DSRenderTestDefaultMaterialGenerator : public NVRenderTestBase
+{
+public:
+ Qt3DSRenderTestDefaultMaterialGenerator();
+ ~Qt3DSRenderTestDefaultMaterialGenerator();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+private:
+
+};
+
+} // render
+} // qt3ds
+
+#endif
diff --git a/tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.cpp b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.cpp
new file mode 100644
index 0000000..48346e6
--- /dev/null
+++ b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "Qt3DSRenderTestEffectGenerator.h"
+#include "../Qt3DSRenderTestMathUtil.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderContext.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderCustomMaterialRenderContext.h"
+#include "Qt3DSRenderCustomMaterialShaderGenerator.h"
+#include "Qt3DSRenderDynamicObjectSystem.h"
+#include "Qt3DSRenderDynamicObjectSystemCommands.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSTypes.h"
+#include "Qt3DSRenderRuntimeBinding.h"
+#include "Qt3DSApplication.h"
+#include "Qt3DSInputEngine.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSWindowSystem.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "rendererimpl/Qt3DSRendererImpl.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderUIPLoader.h"
+#include "Qt3DSDMMetaDataTypes.h"
+
+#include <QTime>
+#include <QString>
+#include <QStringList>
+
+#include <string>
+
+using namespace qt3ds::render;
+
+namespace qt3ds {
+namespace render {
+
+Qt3DSRenderTestEffectGenerator::Qt3DSRenderTestEffectGenerator()
+{
+
+}
+
+Qt3DSRenderTestEffectGenerator::~Qt3DSRenderTestEffectGenerator()
+{
+
+}
+
+bool Qt3DSRenderTestEffectGenerator::isSupported(NVRenderContext *context)
+{
+ Q_UNUSED(context);
+ return true;
+}
+
+bool Qt3DSRenderTestEffectGenerator::runPerformance(NVRenderContext *context,
+ userContextData *pContextData)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(pContextData);
+ return false;
+}
+
+void Qt3DSRenderTestEffectGenerator::cleanup(NVRenderContext *context,
+ userContextData *pUserData)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(pUserData);
+}
+
+bool GenShader(IQt3DSRenderContext &qt3dsContext, SEffect &effect, qt3dsdm::SMetaDataEffect *metaEffect)
+{
+ bool success = true;
+ for (int i = 0; i < metaEffect->m_EffectCommands.size(); i++) {
+ dynamic::SCommand &command = *metaEffect->m_EffectCommands[i];
+ if (command.m_Type == dynamic::CommandTypes::Enum::BindShader) {
+ dynamic::SBindShader *bindShader = static_cast<dynamic::SBindShader *>(&command);
+ NVRenderShaderProgram *theProgram =
+ qt3dsContext.GetDynamicObjectSystem()
+ .GetShaderProgram(bindShader->m_ShaderPath, bindShader->m_ShaderDefine,
+ TShaderFeatureSet(), dynamic::SDynamicShaderProgramFlags())
+ .first;
+ if (!theProgram)
+ success = false;
+ }
+ }
+ return success;
+}
+
+bool Qt3DSRenderTestEffectGenerator::run(NVRenderContext *context, userContextData *pUserData)
+{
+ Q_UNUSED(pUserData);
+ bool success = true;
+
+ QStringList effectFiles;
+ effectFiles.append("Desaturate.effect");
+ effectFiles.append("Gaussian Blur.effect");
+ effectFiles.append("Sepia.effect");
+ effectFiles.append("Bloom.effect");
+
+ for (QString effectName : effectFiles) {
+ QString qfile = "qrc:/";
+ qfile.append(effectName);
+ QByteArray data = qfile.toLatin1();
+ const char *cname = data.data();
+ CRegisteredString name = context->GetStringTable().RegisterStr(cname);
+
+ metadata()->LoadEffectXMLFile("Effect", "", effectName.toLatin1().data(), cname);
+ Option<qt3dsdm::SMetaDataEffect> metaEffect =
+ metadata()->GetEffectMetaDataBySourcePath(cname);
+
+ if (metaEffect.hasValue()) {
+ qt3ds::render::IUIPLoader::CreateEffectClassFromMetaEffect(
+ name, context->GetFoundation(),
+ qt3dsRenderer()->GetQt3DSContext().GetEffectSystem(), *metaEffect,
+ context->GetStringTable());
+
+ SEffect *effect = qt3dsRenderer()->GetQt3DSContext().GetEffectSystem()
+ .CreateEffectInstance(name, qt3dsRenderer()->GetContext().GetAllocator());
+
+ success &= GenShader(qt3dsRenderer()->GetQt3DSContext(), *effect, &metaEffect.getValue());
+ if (!success)
+ qDebug () << "failed effect: " << effectName;
+ delete effect;
+ }
+ }
+
+ return success;
+}
+
+} // render
+} // qt3ds
diff --git a/tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.h b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.h
new file mode 100644
index 0000000..4e26cf3
--- /dev/null
+++ b/tests/auto/runtime/shadergenerator/Qt3DSRenderTestEffectGenerator.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_RENDER_TEST_EFFECT_GENERATOR_H
+#define QT3DS_RENDER_TEST_EFFECT_GENERATOR_H
+
+#include "../Qt3DSRenderTestBase.h"
+
+namespace qt3ds {
+namespace render {
+
+class Qt3DSRenderTestEffectGenerator : public NVRenderTestBase
+{
+public:
+ Qt3DSRenderTestEffectGenerator();
+ ~Qt3DSRenderTestEffectGenerator();
+
+ bool isSupported(NVRenderContext *context);
+ bool run(NVRenderContext *context, userContextData *pUserData);
+ bool runPerformance(NVRenderContext *context, userContextData *pContextData);
+ void cleanup(NVRenderContext *context, userContextData *pUserData);
+
+private:
+
+};
+
+} // render
+} // qt3ds
+
+#endif
diff --git a/tests/auto/runtime/tst_qt3dsruntime.cpp b/tests/auto/runtime/tst_qt3dsruntime.cpp
new file mode 100644
index 0000000..763529c
--- /dev/null
+++ b/tests/auto/runtime/tst_qt3dsruntime.cpp
@@ -0,0 +1,727 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "tst_qt3dsruntime.h"
+
+#include "render/Qt3DSRenderContext.h"
+#include "foundation/TrackingAllocator.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/StringTable.h"
+#include "foundation/Qt3DSMat44.h"
+
+#include "base/Qt3DSRenderTestClear.h"
+#include "base/Qt3DSRenderTestPrimitives.h"
+#include "base/Qt3DSRenderTestConstantBuffer.h"
+#include "base/Qt3DSRenderTestBackendQuery.h"
+#include "base/Qt3DSRenderTestTimerQuery.h"
+#include "base/Qt3DSRenderTestTexture2D.h"
+#include "base/Qt3DSRenderTestAtomicCounterBuffer.h"
+#include "base/Qt3DSRenderTestDrawIndirectBuffer.h"
+#include "base/Qt3DSRenderTestAttribBuffers.h"
+#include "base/Qt3DSRenderTestProgramPipeline.h"
+#include "fbo/Qt3DSRenderTestFboMsaa.h"
+#include "geometry/Qt3DSRenderTestTessellation.h"
+#include "geometry/Qt3DSRenderTestGeometryShader.h"
+#include "geometry/Qt3DSRenderTestOcclusionQuery.h"
+#include "compute/Qt3DSRenderTestComputeShader.h"
+#include "shadergenerator/Qt3DSRenderTestDefaultMaterialGenerator.h"
+#include "shadergenerator/Qt3DSRenderTestCustomMaterialGenerator.h"
+#include "shadergenerator/Qt3DSRenderTestEffectGenerator.h"
+
+#include <QImage>
+#include <QOpenGLContext>
+#include <QOffscreenSurface>
+#include <QOpenGLFramebufferObject>
+#include <QOpenGLFramebufferObjectFormat>
+
+using namespace std;
+using namespace qt3ds;
+using namespace qt3ds::render;
+using namespace qt3ds::foundation;
+
+extern "C" {
+bool InitializeGL();
+}
+
+// Enable this to dump the test output into a log.txt file
+//#define DUMP_LOGFILE
+
+#ifndef EA_PLATFORM_WINDOWS
+
+#ifndef EASTL_DEBUG_BREAK
+void EASTL_DEBUG_BREAK()
+{
+ return;
+}
+#endif
+
+namespace qt3ds {
+void NVAssert(const char *exp, const char *file, int line, bool *ignore)
+{
+ *ignore = true;
+ QString message = QString("failed: %1, file %2, line %3\n")
+ .arg(exp).arg(file).arg(line);
+ QFAIL(message.toLatin1().constData());
+}
+}
+#endif
+
+void messageOutput(QtMsgType type, const QMessageLogContext &context,
+ const QString &msg)
+{
+ Q_UNUSED(context);
+ switch (type) {
+ case QtDebugMsg:
+ case QtInfoMsg:
+ case QtWarningMsg:
+ case QtCriticalMsg: {
+#ifdef DUMP_LOGFILE
+ QFile file("log.txt");
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
+ QTextStream stream(&file);
+ stream << msg;
+ }
+ file.close();
+#endif
+ } break; // swallow
+ case QtFatalMsg:
+ QFAIL(msg.toLocal8Bit().constData());
+ }
+}
+
+void tst_qt3dsruntime::initTestCase()
+{
+ qInstallMessageHandler(messageOutput);
+#ifdef DUMP_LOGFILE
+ QFile file("log.txt");
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ QTextStream stream(&file);
+ stream << "Log file: " << QTime::currentTime().toString() << "\n";
+ }
+ file.close();
+#endif
+}
+
+QSurfaceFormat makeFormat(int major, int minor, bool gles = false, bool coreProfile = true)
+{
+ QSurfaceFormat format;
+ format.setDepthBufferSize(32);
+ format.setVersion(major, minor);
+ if (coreProfile)
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ else
+ format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ if (gles)
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+ return format;
+}
+
+bool tst_qt3dsruntime::init(QSurfaceFormat format)
+{
+ m_glContext = new QT_PREPEND_NAMESPACE(QOpenGLContext)(this);
+ m_glContext->setFormat(format);
+ bool success = m_glContext->create();
+ if (!success)
+ return false;
+
+ m_glSurface = new QOffscreenSurface;
+ m_glSurface->setFormat(format);
+ m_glSurface->create();
+ m_glContext->makeCurrent(m_glSurface);
+
+ m_allocator = new CAllocator;
+ m_foundation = NVCreateFoundation(QT3DS_FOUNDATION_VERSION, *m_allocator);
+ m_stringTable = &IStringTable::CreateStringTable(*m_allocator);
+ m_renderContext = &NVRenderContext::CreateGL(*m_foundation, *m_stringTable, format);
+ return true;
+}
+
+bool tst_qt3dsruntime::init()
+{
+#if defined(QT_OPENGL_ES_2)
+ return init(makeFormat(2, 0, true, false));
+#elif defined(Q_OS_ANDROID) || defined(QT_OPENGL_ES_3)
+ return init(makeFormat(3, 2, true, false));
+#else
+ return init(makeFormat(4, 3));
+#endif
+}
+
+bool tst_qt3dsruntime::executeTest(NVRenderTestBase *curTest,
+ const QString &testName,
+ bool performPixelTest)
+{
+ bool success = true;
+ int width = 640;
+ int height = 480;
+ userContextData userData = { (unsigned int)width, (unsigned int)height };
+
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(QSize(width, height), fboFormat);
+
+ m_renderContext->SetDefaultRenderTarget(fbo->handle());
+ m_renderContext->SetDefaultDepthBufferBitCount(m_glContext->format().depthBufferSize());
+ m_renderContext->SetViewport(NVRenderRect(0, 0, userData.winWidth, userData.winHeight));
+
+ success = curTest->run(m_renderContext, &userData);
+
+ if (performPixelTest) {
+ QImage image = fbo->toImage();
+ QImage refImage(QString(":/images/%1.png").arg(testName));
+ refImage = refImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ if (!refImage.isNull()) {
+ bool pixelTest = image == refImage;
+ success &= pixelTest;
+ if (!pixelTest)
+ image.save(QString("%1_failed.png").arg(testName));
+ }
+ }
+
+ curTest->cleanup(m_renderContext, &userData);
+
+ return success;
+}
+
+void tst_qt3dsruntime::testNVRenderTestClear()
+{
+ init();
+ NVRenderTestClear *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestClear);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestClear");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestPrimitives()
+{
+ init();
+ NVRenderTestPrimitives *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestPrimitives);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestPrimitives");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestConstantBuffer()
+{
+ init();
+ NVRenderTestConstantBuffer *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestConstantBuffer);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestConstantBuffer");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestBackendQuery()
+{
+ init();
+ NVRenderTestBackendQuery *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestBackendQuery);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestBackendQuery", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestTimerQuery()
+{
+ init();
+ NVRenderTestTimerQuery *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestTimerQuery);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestTimerQuery");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestFboMsaa()
+{
+ init();
+ NVRenderTestFboMsaa *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestFboMsaa);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestFboMsaa", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestTessellation()
+{
+ init();
+ NVRenderTestTessellation *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestTessellation);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestTessellation");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestGeometryShader()
+{
+ init();
+ NVRenderTestGeometryShader *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestGeometryShader);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestGeometryShader");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestComputeShader()
+{
+ init();
+ NVRenderTestComputeShader *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestComputeShader);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestComputeShader", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestOcclusionQuery()
+{
+ init();
+ NVRenderTestOcclusionQuery *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestOcclusionQuery);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestOcclusionQuery", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestTexture2D()
+{
+ init();
+ NVRenderTestTexture2D *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestTexture2D);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestTexture2D", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestAtomicCounterBuffer()
+{
+ init();
+ NVRenderTestAtomicCounterBuffer *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestAtomicCounterBuffer);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ bool success = executeTest(test, "NVRenderTestAtomicCounterBuffer");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestDrawIndirectBuffer()
+{
+ init();
+ NVRenderTestDrawIndirectBuffer *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestDrawIndirectBuffer);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestDrawIndirectBuffer", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestAttribBuffers()
+{
+ init();
+ NVRenderTestAttribBuffers *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestAttribBuffers);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestAttribBuffers", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testNVRenderTestProgramPipeline()
+{
+ init();
+ NVRenderTestProgramPipeline *test =
+ QT3DS_NEW(m_foundation->getAllocator(), NVRenderTestProgramPipeline);
+ if (!test->isSupported(m_renderContext)) {
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ QSKIP("not supported");
+ }
+ // TODO: Fix BOUL-332 to re-enable this pixel test
+ bool success = executeTest(test, "NVRenderTestProgramPipeline", false);
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+#if defined(QT_OPENGL_ES_2)
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_200es()
+{
+ if (init(makeFormat(2, 0, true, false))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_200es()
+{
+ runCustomShaderGeneratorTest(makeFormat(2, 0, true, false));
+ cleanup();
+}
+#endif
+
+#if defined(QT_OPENGL_ES_3)
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_300es()
+{
+ if (init(makeFormat(3, 0, true, false))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_300es()
+{
+ runCustomShaderGeneratorTest(makeFormat(3, 0, true, false));
+ cleanup();
+}
+
+#if defined(QT_FEATURE_opengles31)
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_310es()
+{
+ if (init(makeFormat(3, 1, true, false))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_310es()
+{
+ runCustomShaderGeneratorTest(makeFormat(3, 1, true, false));
+ cleanup();
+}
+#endif
+#if defined(QT_FEATURE_opengles32)
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_320es()
+{
+ if (init(makeFormat(3, 1, true, false))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_320es()
+{
+ runCustomShaderGeneratorTest(makeFormat(3, 1, true, false));
+ cleanup();
+}
+
+#endif
+#endif
+
+#if defined(QT_OPENGL_DYNAMIC)
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_300()
+{
+ QSKIP("OpenGL 3.0 is not supported");
+ if (init(makeFormat(3, 0))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_310()
+{
+ if (init(makeFormat(3, 1))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_320()
+{
+ if (init(makeFormat(3, 2))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_330()
+{
+ if (init(makeFormat(3, 3))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_400()
+{
+ if (init(makeFormat(4, 0))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_410()
+{
+ if (init(makeFormat(4, 1))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_420()
+{
+ if (init(makeFormat(4, 2))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderDefaultShaderGenerator_430()
+{
+ if (init(makeFormat(4, 3))) {
+ runDefaultShaderGeneratorTest();
+ cleanup();
+ }
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_300()
+{
+ QSKIP("OpenGL 3.0 is not supported");
+ runCustomShaderGeneratorTest(makeFormat(3, 0));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_310()
+{
+ runCustomShaderGeneratorTest(makeFormat(3, 1));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_320()
+{
+ runCustomShaderGeneratorTest(makeFormat(3, 2));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_330()
+{
+ runCustomShaderGeneratorTest(makeFormat(3, 3));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_400()
+{
+ runCustomShaderGeneratorTest(makeFormat(4, 0));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_410()
+{
+ runCustomShaderGeneratorTest(makeFormat(4, 1));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_420()
+{
+ runCustomShaderGeneratorTest(makeFormat(4, 2));
+}
+
+void tst_qt3dsruntime::testRenderCustomShaderGenerator_430()
+{
+ runCustomShaderGeneratorTest(makeFormat(4, 3));
+}
+
+#endif
+
+void tst_qt3dsruntime::runDefaultShaderGeneratorTest()
+{
+ Qt3DSRenderTestDefaultMaterialGenerator *test =
+ QT3DS_NEW(m_foundation->getAllocator(), Qt3DSRenderTestDefaultMaterialGenerator);
+ if (!test->isSupported(m_renderContext))
+ QSKIP("not supported");
+ bool success = executeTest(test, "Qt3DSRenderTestDefaultMaterialGenerator");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+}
+
+void tst_qt3dsruntime::runCustomShaderGeneratorTest(QSurfaceFormat format)
+{
+ m_glContext = new QT_PREPEND_NAMESPACE(QOpenGLContext)(this);
+ m_glContext->setFormat(format);
+ bool success = m_glContext->create();
+ if (!success)
+ return;
+
+ m_glSurface = new QOffscreenSurface;
+ m_glSurface->setFormat(format);
+ m_glSurface->create();
+ m_glContext->makeCurrent(m_glSurface);
+
+ m_allocator = new CAllocator;
+ m_foundation = NVCreateFoundation(QT3DS_FOUNDATION_VERSION, *m_allocator);
+
+ Qt3DSRenderTestCustomMaterialGenerator *test =
+ QT3DS_NEW(m_foundation->getAllocator(), Qt3DSRenderTestCustomMaterialGenerator);
+
+ test->initializeQt3DSRenderer(format);
+ m_renderContext = &NVRenderContext::CreateGL(*m_foundation, test->qt3dsRenderer()->GetContext()
+ .GetStringTable(), format);
+
+ if (!test->isSupported(m_renderContext))
+ QSKIP("not supported");
+ success = executeTest(test, "Qt3DSRenderTestCusromMaterialGenerator");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::testRenderEffectGenerator()
+{
+ QSurfaceFormat format = makeFormat(4, 3);
+ m_glContext = new QT_PREPEND_NAMESPACE(QOpenGLContext)(this);
+ m_glContext->setFormat(format);
+ bool success = m_glContext->create();
+ if (!success)
+ return;
+
+ m_glSurface = new QOffscreenSurface;
+ m_glSurface->setFormat(format);
+ m_glSurface->create();
+ m_glContext->makeCurrent(m_glSurface);
+
+ m_allocator = new CAllocator;
+ m_foundation = NVCreateFoundation(QT3DS_FOUNDATION_VERSION, *m_allocator);
+
+ Qt3DSRenderTestEffectGenerator *test =
+ QT3DS_NEW(m_foundation->getAllocator(), Qt3DSRenderTestEffectGenerator);
+
+ test->initializeQt3DSRenderer(format);
+ m_renderContext = &NVRenderContext::CreateGL(*m_foundation, test->qt3dsRenderer()->GetContext()
+ .GetStringTable(), format);
+
+ if (!test->isSupported(m_renderContext))
+ QSKIP("not supported");
+ success = executeTest(test, "Qt3DSRenderTestEffectGenerator");
+ QT3DS_FREE(m_foundation->getAllocator(), test);
+ test = 0;
+ QVERIFY(success);
+ cleanup();
+}
+
+void tst_qt3dsruntime::cleanup()
+{
+ if (m_renderContext)
+ m_renderContext->release();
+ if (m_foundation)
+ m_foundation->release();
+
+ m_renderContext = 0;
+ m_stringTable = 0;
+ m_foundation = 0;
+
+ delete m_allocator;
+ m_allocator = 0;
+
+ m_glSurface->destroy();
+ delete m_glSurface;
+ m_glSurface = 0;
+
+ delete m_glContext;
+ m_glContext = 0;
+}
+
+QTEST_MAIN(tst_qt3dsruntime)
diff --git a/tests/auto/runtime/tst_qt3dsruntime.h b/tests/auto/runtime/tst_qt3dsruntime.h
new file mode 100644
index 0000000..1f5b943
--- /dev/null
+++ b/tests/auto/runtime/tst_qt3dsruntime.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef TST_QT3DSRUNTIME
+#define TST_QT3DSRUNTIME
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+
+namespace qt3ds {
+class NVFoundation;
+namespace foundation {
+class CAllocator;
+class IStringTable;
+}
+namespace render {
+class NVRenderContext;
+class NVRenderTestBase;
+}
+}
+
+QT_BEGIN_NAMESPACE
+class QOpenGLContext;
+class QOffscreenSurface;
+QT_END_NAMESPACE
+
+class tst_qt3dsruntime : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qt3dsruntime()
+ : m_allocator(0)
+ , m_foundation(0)
+ , m_stringTable(0)
+ , m_renderContext(0)
+ , m_glContext(0)
+ , m_glSurface(0)
+ {
+ }
+
+private Q_SLOTS:
+ void initTestCase();
+
+ void testNVRenderTestClear();
+ void testNVRenderTestPrimitives();
+ void testNVRenderTestConstantBuffer();
+ void testNVRenderTestBackendQuery();
+ void testNVRenderTestTimerQuery();
+ void testNVRenderTestFboMsaa();
+ void testNVRenderTestTessellation();
+ void testNVRenderTestGeometryShader();
+ void testNVRenderTestComputeShader();
+ void testNVRenderTestOcclusionQuery();
+ void testNVRenderTestTexture2D();
+ void testNVRenderTestAtomicCounterBuffer();
+ void testNVRenderTestDrawIndirectBuffer();
+ void testNVRenderTestAttribBuffers();
+ void testNVRenderTestProgramPipeline();
+
+ void testRenderEffectGenerator();
+
+#if defined(QT_OPENGL_ES_2)
+ void testRenderDefaultShaderGenerator_200es();
+ void testRenderCustomShaderGenerator_200es();
+#endif
+#if defined(QT_OPENGL_ES_3)
+ void testRenderDefaultShaderGenerator_300es();
+ void testRenderCustomShaderGenerator_300es();
+#if defined(QT_FEATURE_opengles31)
+ void testRenderDefaultShaderGenerator_310es();
+ void testRenderCustomShaderGenerator_310es();
+#endif
+#if defined(QT_FEATURE_opengles32)
+ void testRenderDefaultShaderGenerator_320es();
+ void testRenderCustomShaderGenerator_320es();
+#endif
+#endif
+
+#if defined(QT_OPENGL_DYNAMIC)
+ void testRenderDefaultShaderGenerator_300();
+ void testRenderDefaultShaderGenerator_310();
+ void testRenderDefaultShaderGenerator_320();
+ void testRenderDefaultShaderGenerator_330();
+ void testRenderDefaultShaderGenerator_400();
+ void testRenderDefaultShaderGenerator_410();
+ void testRenderDefaultShaderGenerator_420();
+ void testRenderDefaultShaderGenerator_430();
+
+ void testRenderCustomShaderGenerator_300();
+ void testRenderCustomShaderGenerator_310();
+ void testRenderCustomShaderGenerator_320();
+ void testRenderCustomShaderGenerator_330();
+ void testRenderCustomShaderGenerator_400();
+ void testRenderCustomShaderGenerator_410();
+ void testRenderCustomShaderGenerator_420();
+ void testRenderCustomShaderGenerator_430();
+#endif
+
+
+
+private:
+ bool executeTest(qt3ds::render::NVRenderTestBase *curTest,
+ const QString &testName, bool peformPixelTest = true);
+ bool init(QSurfaceFormat format);
+ bool init();
+ void runDefaultShaderGeneratorTest();
+ void runCustomShaderGeneratorTest(QSurfaceFormat format);
+ void cleanup();
+
+ qt3ds::foundation::CAllocator *m_allocator;
+ qt3ds::NVFoundation *m_foundation;
+ qt3ds::foundation::IStringTable *m_stringTable;
+ qt3ds::render::NVRenderContext *m_renderContext;
+ QOpenGLContext *m_glContext;
+ QOffscreenSurface *m_glSurface;
+};
+
+#endif // TST_QT3DSRUNTIME
diff --git a/tests/auto/studio3d/q3dssurfaceviewer/q3dssurfaceviewer.pro b/tests/auto/studio3d/q3dssurfaceviewer/q3dssurfaceviewer.pro
new file mode 100644
index 0000000..7da6bf7
--- /dev/null
+++ b/tests/auto/studio3d/q3dssurfaceviewer/q3dssurfaceviewer.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+CONFIG += testcase
+
+TARGET = tst_q3dssurfaceviewer
+
+QT += testlib studio3d
+
+SOURCES += tst_q3dssurfaceviewer.cpp
+
+RESOURCES += ../shared/shared_presentations.qrc
diff --git a/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp b/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp
new file mode 100644
index 0000000..786ef3a
--- /dev/null
+++ b/tests/auto/studio3d/q3dssurfaceviewer/tst_q3dssurfaceviewer.cpp
@@ -0,0 +1,1516 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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/QtTest>
+#include <QtStudio3D/q3dssurfaceviewer.h>
+#include <QtStudio3D/q3dsviewersettings.h>
+#include <QtStudio3D/q3dspresentation.h>
+#include <QtStudio3D/q3dssceneelement.h>
+#include <QtStudio3D/q3dselement.h>
+#include <QtStudio3D/q3dsdatainput.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qopenglframebufferobject.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qfile.h>
+#include "../shared/shared_presentations.h"
+
+class tst_Q3DSSurfaceViewer : public QObject
+{
+ Q_OBJECT
+public:
+ tst_Q3DSSurfaceViewer();
+ ~tst_Q3DSSurfaceViewer() {}
+
+private slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+ void testBasics_data();
+ void testBasics();
+ void testSourceChange_data();
+ void testSourceChange();
+ void testSizeChange_data();
+ void testSizeChange();
+ void testUpdateInterval_data();
+ void testUpdateInterval();
+ void testMultiple_data();
+ void testMultiple();
+ void testGrab_data();
+ void testGrab();
+ void testReset_data();
+ void testReset();
+ void testSettings_data();
+ void testSettings();
+ void testPresentation_data();
+ void testPresentation();
+ void testPresentationActivation_data();
+ void testPresentationActivation();
+ void testSceneElement_data();
+ void testSceneElement();
+ void testElement_data();
+ void testElement();
+ void testMouseInput_data();
+ void testMouseInput();
+ void testDataInput_data();
+ void testDataInput();
+
+private:
+ QWindow *createWindow(const QSize &size);
+ QOffscreenSurface *createOffscreen();
+ QOpenGLFramebufferObject *createFbo(const QSize &size);
+
+ // Created viewers are returned via *&viewer parameter rather than return value, so that we can
+ // use QCOMPARE and QVERIFY inside these functions (they require void return value).
+ void createViewer(Q3DSSurfaceViewer *&viewer, QSurface *surface, const QUrl &url,
+ bool autoSize, const QSize &size, int updateInterval, int fboId);
+ void createWindowAndViewer(Q3DSSurfaceViewer *&viewer, const QUrl &url = RED,
+ bool autoSize = true, const QSize &size = QSize(),
+ int updateInterval = 0);
+ void createOffscreenAndViewer(Q3DSSurfaceViewer *&viewer, const QUrl &url = RED,
+ const QSize &size = QSize(), int updateInterval = 0);
+ void checkPixel(Q3DSSurfaceViewer *viewer, const QColor &color,
+ const QPoint &pixel = QPoint(50, 50));
+
+ QWindow *m_window;
+ QOffscreenSurface *m_surface;
+ Q3DSSurfaceViewer *m_viewer;
+ QSurfaceFormat m_format;
+ QOpenGLContext *m_context;
+ QOpenGLFramebufferObject *m_fbo;
+};
+
+tst_Q3DSSurfaceViewer::tst_Q3DSSurfaceViewer()
+ : m_window(nullptr)
+ , m_surface(nullptr)
+ , m_viewer(nullptr)
+ , m_context(nullptr)
+ , m_fbo(nullptr)
+{
+}
+
+//#define DUMP_LOGFILE // Uncomment log Qt 3D Studio internal messages to log.txt file
+void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ Q_UNUSED(context);
+ switch (type) {
+ // case QtDebugMsg:
+ case QtInfoMsg:
+ case QtWarningMsg:
+ case QtCriticalMsg: {
+#ifdef DUMP_LOGFILE
+ QFile file("log.txt");
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
+ QTextStream stream(&file);
+ stream << msg << "\n";
+ }
+ file.close();
+#endif
+ } break; // swallow
+ case QtFatalMsg:
+ QFAIL(msg.toLocal8Bit().constData());
+ }
+}
+
+void tst_Q3DSSurfaceViewer::initTestCase()
+{
+ qInstallMessageHandler(messageOutput);
+#ifdef DUMP_LOGFILE
+ QFile file("log.txt");
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ QTextStream stream(&file);
+ stream << "Log file: " << QTime::currentTime().toString() << "\n";
+ }
+ file.close();
+#endif
+
+ QWindow *dummy = createWindow(QSize(100, 100));
+ m_format = dummy->format();
+ qDebug() << m_format;
+ delete dummy;
+}
+
+void tst_Q3DSSurfaceViewer::init()
+{
+ m_context = new QOpenGLContext();
+ m_context->setFormat(m_format);
+ m_context->create();
+}
+
+void tst_Q3DSSurfaceViewer::cleanup()
+{
+ if (m_window)
+ m_window->close();
+
+ delete m_viewer;
+ m_viewer = nullptr;
+
+ delete m_window;
+ m_window = nullptr;
+
+ delete m_surface;
+ m_surface = nullptr;
+
+ delete m_fbo;
+ m_fbo = nullptr;
+
+ delete m_context;
+ m_context = nullptr;
+}
+
+QWindow *tst_Q3DSSurfaceViewer::createWindow(const QSize &size)
+{
+ QWindow *window = new QWindow();
+
+ window->resize(size);
+ window->setSurfaceType(QSurface::OpenGLSurface);
+ window->setFormat(m_format);
+ window->setTitle(QStringLiteral("Q3DSSurfaceViewer test window"));
+ window->create();
+
+ return window;
+}
+
+QOffscreenSurface *tst_Q3DSSurfaceViewer::createOffscreen()
+{
+ QOffscreenSurface *surface = new QOffscreenSurface();
+ surface->setFormat(m_format);
+ surface->create();
+
+ return surface;
+}
+
+QOpenGLFramebufferObject *tst_Q3DSSurfaceViewer::createFbo(const QSize &size)
+{
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ return new QOpenGLFramebufferObject(size, fboFormat);
+}
+
+void tst_Q3DSSurfaceViewer::createViewer(Q3DSSurfaceViewer *&viewer, QSurface *surface,
+ const QUrl &url, bool autoSize, const QSize &size,
+ int updateInterval, int fboId)
+{
+ viewer = new Q3DSSurfaceViewer();
+ QSignalSpy spy(viewer, &Q3DSSurfaceViewer::runningChanged);
+
+ viewer->presentation()->setSource(url);
+ QCOMPARE(viewer->presentation()->source(), url);
+
+ QVERIFY(spy.isValid());
+ QCOMPARE(spy.count(), 0);
+
+ viewer->setAutoSize(autoSize);
+ if (!autoSize)
+ viewer->setSize(size);
+ viewer->setUpdateInterval(updateInterval);
+
+ QVERIFY(viewer->create(surface, m_context, fboId));
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(viewer->isRunning());
+
+ QVERIFY(viewer->fboId() == fboId);
+ QVERIFY(viewer->surface() == surface);
+ QVERIFY(viewer->context() == m_context);
+}
+
+void tst_Q3DSSurfaceViewer::createWindowAndViewer(Q3DSSurfaceViewer *&viewer,
+ const QUrl &url, bool autoSize,
+ const QSize &size, int updateInterval)
+{
+ QSize actualSize = size;
+ if (actualSize.isEmpty())
+ actualSize = QSize(300, 200);
+
+ m_window = createWindow(actualSize);
+
+ createViewer(viewer, m_window, url, autoSize, actualSize, updateInterval, 0);
+
+ m_window->show();
+ QGuiApplication::processEvents();
+}
+
+void tst_Q3DSSurfaceViewer::createOffscreenAndViewer(Q3DSSurfaceViewer *&viewer,
+ const QUrl &url, const QSize &size,
+ int updateInterval)
+{
+ QSize actualSize = size;
+ if (actualSize.isEmpty())
+ actualSize = QSize(300, 200);
+
+ m_surface = createOffscreen();
+ m_context->makeCurrent(m_surface);
+ m_fbo = createFbo(actualSize);
+
+ createViewer(viewer, m_surface, url, false, actualSize, updateInterval, m_fbo->handle());
+}
+
+void tst_Q3DSSurfaceViewer::checkPixel(Q3DSSurfaceViewer *viewer, const QColor &color,
+ const QPoint &pixel)
+{
+ // Grab operation is potentially costly, so retry only every second instead of using
+ // QTRY_COMPARE which would try it every 50ms. We also want to wait first as it takes some time
+ // for the presentation to be displayed.
+ QColor grabColor;
+ for (int i = 0; i < 20; i++) {
+ // Note: If checkpixel is ever changed to not have this wait, some
+ // QGuiApplication::processEvents() calls may be necessary in various test cases to
+ // ensure expected signaling order.
+ QTest::qWait(1000);
+ QImage image = viewer->grab(QRect(pixel, QSize(1, 1)));
+ grabColor = QColor(image.pixel(0, 0));
+ if (grabColor == color)
+ break;
+ }
+ QCOMPARE(grabColor, color);
+}
+
+void tst_Q3DSSurfaceViewer::testBasics_data()
+{
+ QTest::addColumn<bool>("isWindow");
+ QTest::newRow("window") << true;
+ QTest::newRow("offscreen") << false;
+}
+
+void tst_Q3DSSurfaceViewer::testBasics()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, RED);
+ else
+ createOffscreenAndViewer(m_viewer, RED);
+
+ QSignalSpy spy(m_viewer, &Q3DSSurfaceViewer::runningChanged);
+ QVERIFY(spy.isValid());
+
+ checkPixel(m_viewer, Qt::red);
+
+ m_viewer->destroy();
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(!m_viewer->isRunning());
+}
+
+void tst_Q3DSSurfaceViewer::testSourceChange_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSourceChange()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, RED);
+ else
+ createOffscreenAndViewer(m_viewer, RED);
+
+ QSignalSpy spy(m_viewer->presentation(), &Q3DSPresentation::sourceChanged);
+ QVERIFY(spy.isValid());
+ QVERIFY(m_viewer->presentation()->source() == RED);
+
+ checkPixel(m_viewer, Qt::red);
+
+ // Different source
+ m_viewer->presentation()->setSource(BLUE);
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(m_viewer->presentation()->source() == BLUE);
+
+ checkPixel(m_viewer, Qt::blue);
+
+ // Reset same source
+ m_viewer->presentation()->setSource(BLUE);
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(m_viewer->presentation()->source() == BLUE);
+
+ checkPixel(m_viewer, Qt::blue);
+
+ // Different source again
+ m_viewer->presentation()->setSource(RED);
+ QCOMPARE(spy.count(), 2);
+ QVERIFY(m_viewer->presentation()->source() == RED);
+
+ checkPixel(m_viewer, Qt::red);
+}
+
+void tst_Q3DSSurfaceViewer::testSizeChange_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSizeChange()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow) {
+ createWindowAndViewer(m_viewer, MIXED, true, QSize(600, 600));
+ } else {
+ // Changing size for offscreen surface means recreating the fbo. There's no guarantee
+ // we can get the same fbo id if we do that, so we would have to reinitialize anyway
+ QSKIP("Skipping size change testing for offscreen surfaces");
+ }
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spy1(m_viewer, &Q3DSSurfaceViewer::sizeChanged);
+ QVERIFY(spy1.isValid());
+ QSignalSpy spy2(m_viewer, &Q3DSSurfaceViewer::autoSizeChanged);
+ QVERIFY(spy2.isValid());
+
+ QPoint leftPoint(m_viewer->size().width() * 11 / 24, m_viewer->size().height() / 2);
+ QPoint rightPoint(m_viewer->size().width() * 13 / 24, m_viewer->size().height() / 2);
+
+ // MIXED presentation has left side blue, right side red
+ checkPixel(m_viewer, Qt::blue, leftPoint);
+ checkPixel(m_viewer, Qt::red, rightPoint);
+
+ m_window->resize(QSize(800, 800));
+ QGuiApplication::processEvents();
+ QCOMPARE(spy1.count(), 1);
+
+ checkPixel(m_viewer, Qt::blue, leftPoint);
+ checkPixel(m_viewer, Qt::blue, rightPoint);
+
+ m_window->resize(QSize(400, 400));
+ QGuiApplication::processEvents();
+ QCOMPARE(spy1.count(), 2);
+
+ checkPixel(m_viewer, Qt::red, leftPoint);
+ checkPixel(m_viewer, Qt::red, rightPoint);
+
+ m_viewer->setAutoSize(false);
+ QCOMPARE(spy2.count(), 1);
+
+ // Size should not change since autosize is no longer on
+ m_window->resize(QSize(600, 600));
+ QGuiApplication::processEvents();
+ QCOMPARE(spy1.count(), 2);
+
+ checkPixel(m_viewer, Qt::red, leftPoint);
+ checkPixel(m_viewer, Qt::red, rightPoint);
+
+ m_viewer->setSize(QSize(700, 700));
+ QCOMPARE(spy1.count(), 3);
+
+ checkPixel(m_viewer, Qt::blue, leftPoint);
+ checkPixel(m_viewer, Qt::blue, rightPoint);
+}
+
+void tst_Q3DSSurfaceViewer::testUpdateInterval_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testUpdateInterval()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, ANIMATION);
+ else
+ createOffscreenAndViewer(m_viewer, ANIMATION);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spy(m_viewer, &Q3DSSurfaceViewer::updateIntervalChanged);
+ QVERIFY(spy.isValid());
+ QVERIFY(m_viewer->updateInterval() == 0);
+
+ checkPixel(m_viewer, Qt::black);
+ {
+ // Grab two images two seconds apart to verify animation is happening
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+
+ }
+ {
+ m_viewer->setUpdateInterval(100000);
+ QVERIFY(m_viewer->updateInterval() == 100000);
+ QCOMPARE(spy.count(), 1);
+ // Can't test if animation actually stopped, as grabbing the viewer forces update on it
+ }
+ {
+ m_viewer->setUpdateInterval(20);
+ QCOMPARE(spy.count(), 2);
+ QVERIFY(m_viewer->updateInterval() == 20);
+
+ // Non-zero interval short enough to see animation
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ }
+ {
+ m_viewer->setUpdateInterval(-1);
+ QCOMPARE(spy.count(), 3);
+ QVERIFY(m_viewer->updateInterval() == -1);
+ // Can't test if animation actually stopped, as grabbing the viewer forces update on it
+ }
+}
+
+void tst_Q3DSSurfaceViewer::testMultiple_data()
+{
+ QTest::addColumn<int>("windowCount");
+ QTest::addColumn<int>("offscreenCount");
+ QTest::newRow("windows") << 2 << 0;
+ QTest::newRow("offscreens") << 0 << 2;
+ QTest::newRow("mixed") << 1 << 1;
+}
+
+void tst_Q3DSSurfaceViewer::testMultiple()
+{
+ QFETCH(int, windowCount);
+ QFETCH(int, offscreenCount);
+
+ QVector<QWindow *> windows;
+ QVector<QOffscreenSurface *> surfaces;
+ QVector<Q3DSSurfaceViewer *> viewers;
+ QVector<QOpenGLFramebufferObject *> fbos;
+
+ int viewerCount = windowCount + offscreenCount;
+ windows.resize(windowCount);
+ surfaces.resize(offscreenCount);
+ fbos.resize(offscreenCount);
+ viewers.resize(viewerCount);
+
+ QSize size(200, 150);
+ QUrl url;
+ for (int i = 0; i < windowCount; i++) {
+ windows[i] = createWindow(size);
+ if (i % 2)
+ url = RED;
+ else
+ url = BLUE;
+ createViewer(viewers[i], windows[i], url, true, size, 0, 0);
+ windows[i]->setPosition(10 + i * 50, 10 + i * 50);
+ windows[i]->show();
+ QGuiApplication::processEvents();
+ }
+ for (int i = 0; i < offscreenCount; i++) {
+ surfaces[i] = createOffscreen();
+ m_context->makeCurrent(surfaces[i]);
+ fbos[i] = createFbo(size);
+ if ((i + windowCount) % 2)
+ url = RED;
+ else
+ url = BLUE;
+ createViewer(viewers[i + windowCount], surfaces[i], url, false, size, 0,
+ fbos[i]->handle());
+ }
+
+ for (int i = 0; i < viewerCount; i++) {
+ if (i % 2)
+ checkPixel(viewers[i], Qt::red);
+ else
+ checkPixel(viewers[i], Qt::blue);
+ }
+
+ for (QWindow *w : windows) {
+ w->close();
+ delete w;
+ }
+ windows.clear();
+
+ for (QOffscreenSurface *s : surfaces)
+ delete s;
+ surfaces.clear();
+
+ for (Q3DSSurfaceViewer *v : viewers)
+ delete v;
+ viewers.clear();
+
+ for (QOpenGLFramebufferObject *f : fbos)
+ delete f;
+ fbos.clear();
+}
+
+void tst_Q3DSSurfaceViewer::testGrab_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testGrab()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MIXED_VERTICAL);
+ else
+ createOffscreenAndViewer(m_viewer, MIXED_VERTICAL);
+
+ // Single pixels
+ int w = m_viewer->size().width();
+ int h = m_viewer->size().height();
+
+ checkPixel(m_viewer, Qt::blue, QPoint(w / 2, h / 4));
+ checkPixel(m_viewer, Qt::red, QPoint(w / 2, 3 * h / 4));
+
+ checkPixel(m_viewer, Qt::blue, QPoint(0, 0));
+ checkPixel(m_viewer, Qt::blue, QPoint(w - 1, 0));
+ checkPixel(m_viewer, Qt::red, QPoint(0, h - 1));
+ checkPixel(m_viewer, Qt::red, QPoint(w - 1, h - 1));
+
+ // Full buffer
+ QImage img = m_viewer->grab();
+ QColor grabColor1 = img.pixel(w / 2, h / 4);
+ QColor grabColor2 = img.pixel(w / 2, 3 * h / 4);
+ QCOMPARE(grabColor1, QColor(Qt::blue));
+ QCOMPARE(grabColor2, QColor(Qt::red));
+
+ // Partial buffer
+ img = m_viewer->grab(QRect(w / 3, h / 3, w / 2, h / 2));
+ grabColor1 = img.pixel(0, 0);
+ grabColor2 = img.pixel(w / 2 - 1, h / 2 - 1);
+ QCOMPARE(grabColor1, QColor(Qt::blue));
+ QCOMPARE(grabColor2, QColor(Qt::red));
+}
+
+void tst_Q3DSSurfaceViewer::testReset_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testReset()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, RED);
+ else
+ createOffscreenAndViewer(m_viewer, RED);
+
+ checkPixel(m_viewer, Qt::red);
+
+ m_viewer->presentation()->setAttribute(QStringLiteral("Scene.Layer.Rectangle.Material"),
+ QStringLiteral("diffuse.r"), QVariant(0.0));
+ m_viewer->presentation()->setAttribute(QStringLiteral("Scene.Layer.Rectangle.Material"),
+ QStringLiteral("diffuse.b"), QVariant(1.0));
+ checkPixel(m_viewer, Qt::blue);
+
+ // Note: reset() is private method now, instead can reload presentation by switching sources
+ // m_viewer->reset();
+ m_viewer->presentation()->setSource(ANIMATION);
+ m_viewer->presentation()->setSource(RED);
+
+ checkPixel(m_viewer, Qt::red);
+}
+
+void tst_Q3DSSurfaceViewer::testSettings_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSettings()
+{
+ QFETCH(bool, isWindow);
+
+ int width = 500;
+ int height = 500;
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, SETTINGS, false, QSize(width, height));
+ else
+ createOffscreenAndViewer(m_viewer, SETTINGS, QSize(width, height));
+
+ Q3DSViewerSettings *s = m_viewer->settings();
+
+ QSignalSpy spy1(s, &Q3DSViewerSettings::matteColorChanged);
+ QSignalSpy spy2(s, &Q3DSViewerSettings::showRenderStatsChanged);
+ QSignalSpy spy4(s, &Q3DSViewerSettings::scaleModeChanged);
+ QVERIFY(spy1.isValid());
+ QVERIFY(spy2.isValid());
+ QVERIFY(spy4.isValid());
+
+ // Check defaults
+ QCOMPARE(s->matteColor(), QColor(Qt::black));
+ QCOMPARE(s->isShowRenderStats(), false);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeCenter);
+
+ // Matte
+ checkPixel(m_viewer, Qt::black);
+
+ s->setMatteColor(Qt::cyan);
+ QCOMPARE(s->matteColor(), QColor(Qt::cyan));
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 0);
+ QCOMPARE(spy4.count(), 0);
+
+ checkPixel(m_viewer, Qt::cyan);
+
+ // Render stats
+ QImage image1 = m_viewer->grab();
+
+ s->setShowRenderStats(true);
+ QCOMPARE(s->isShowRenderStats(), true);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy4.count(), 0);
+
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+
+ s->setShowRenderStats(false);
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy4.count(), 0);
+
+ // ScaleMode
+ checkPixel(m_viewer, Qt::cyan);
+ checkPixel(m_viewer, Qt::cyan, QPoint(50, height / 2));
+ s->setScaleMode(Q3DSViewerSettings::ScaleModeFit);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFit);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy4.count(), 1);
+
+ checkPixel(m_viewer, Qt::cyan);
+ checkPixel(m_viewer, Qt::red, QPoint(50, height / 2));
+
+ s->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFill);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+
+ checkPixel(m_viewer, Qt::blue);
+ checkPixel(m_viewer, Qt::red, QPoint(50, height / 2));
+
+ // Saving & loading settings
+ s->save(QStringLiteral("testViewer"), QStringLiteral("The Qt Company"),
+ QStringLiteral("tst_q3dsurfaceviewer"));
+
+ image1 = m_viewer->grab();
+
+ s->setMatteColor(Qt::yellow);
+ s->setShowRenderStats(true);
+ s->setScaleMode(Q3DSViewerSettings::ScaleModeFit);
+
+ QCOMPARE(s->matteColor(), QColor(Qt::yellow));
+ QCOMPARE(s->isShowRenderStats(), true);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFit);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 3);
+ QCOMPARE(spy4.count(), 3);
+
+ image2 = m_viewer->grab();
+
+ s->load(QStringLiteral("testViewer"), QStringLiteral("The Qt Company"),
+ QStringLiteral("tst_q3dsurfaceviewer"));
+
+ QCOMPARE(s->matteColor(), QColor(Qt::cyan));
+ QCOMPARE(s->isShowRenderStats(), false);
+ QCOMPARE(s->scaleMode(), Q3DSViewerSettings::ScaleModeFill);
+
+ QCOMPARE(spy1.count(), 3);
+ QCOMPARE(spy2.count(), 4);
+ QCOMPARE(spy4.count(), 4);
+
+ QImage image3 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ QVERIFY(image3 != image2);
+ QVERIFY(image1 == image3);
+
+ // Clean up the settings so they don't pollute the system (and we have clean slate next time)
+ QSettings(QStringLiteral("The Qt Company"), QStringLiteral("tst_q3dsurfaceviewer")).clear();
+}
+
+void tst_Q3DSSurfaceViewer::testPresentation_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testPresentation()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MULTISLIDE);
+ else
+ createOffscreenAndViewer(m_viewer, MULTISLIDE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QList<QVariant> args;
+ Q3DSPresentation *p = m_viewer->presentation();
+ QSignalSpy spy1(p, &Q3DSPresentation::slideEntered);
+ QSignalSpy spy2(p, &Q3DSPresentation::slideExited);
+ QVERIFY(spy1.isValid());
+ QVERIFY(spy2.isValid());
+
+ // There are three different "scenes":
+ // The main Scene, three slides: S1, S2, S3
+ // Two components on Scene.Layer:
+ // Scene.Layer.Component1, two slides: C1S1, C1S2
+ // Scene.Layer.Component2, two slides: C2S1, C2S2
+ // The component slides also get enter when parent slide is entered, but they do not get
+ // the corresponding exit if parent slide is exited.
+ QString path = QStringLiteral("Scene");
+ QString pathC1 = QStringLiteral("Scene.Layer.Component1");
+ QString pathC2 = QStringLiteral("Scene.Layer.Component2");
+ QPoint mainPoint(m_viewer->size().width() * 2 / 8, m_viewer->size().height() / 2);
+ QPoint bgPoint(m_viewer->size().width() * 2 / 8, m_viewer->size().height() / 32);
+ QPoint c1Point(m_viewer->size().width() * 5 / 8, m_viewer->size().height() / 2);
+ QPoint c2Point(m_viewer->size().width() * 7 / 8, m_viewer->size().height() / 2);
+
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ QCOMPARE(spy1.count(), 3);
+ QCOMPARE(spy2.count(), 0);
+
+ // String Attribute
+ QImage image1 = m_viewer->grab();
+ p->setAttribute(QStringLiteral("Scene.Layer.Text"),
+ QStringLiteral("textstring"), QStringLiteral("Test!"));
+ QImage image2 = m_viewer->grab();
+ QTRY_VERIFY(image1 != image2);
+
+ // Float Attribute
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.r"), 0.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.g"), 1.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.b"), 1.0);
+
+ checkPixel(m_viewer, Qt::cyan, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.r"), 1.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.g"), 0.0);
+ p->setAttribute(QStringLiteral("Scene.Layer.Rect.Material"),
+ QStringLiteral("diffuse.b"), 0.0);
+
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ // Bool Attribute
+ checkPixel(m_viewer, Qt::yellow, bgPoint);
+ p->setAttribute(QStringLiteral("Scene"), QStringLiteral("bgcolorenable"), false);
+ checkPixel(m_viewer, Qt::black, bgPoint);
+
+ // Slide changes
+ p->goToSlide(path, 2);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::blue, c1Point);
+ checkPixel(m_viewer, Qt::blue, c2Point);
+
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 1);
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S2"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S1"));
+
+ // Time change
+ p->goToTime(path, 7.0f);
+ checkPixel(m_viewer, Qt::black, mainPoint);
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 1);
+
+ // More complex slide changes
+ // Changing slide that is not visible should not trigger enter signals
+ // The slides should still change, though, and become visible later when we switch back to S1
+ p->goToSlide(pathC1, QStringLiteral("C1S2"));
+ p->goToSlide(pathC2, QStringLiteral("C2S2"));
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 1);
+
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::cyan, c1Point);
+ checkPixel(m_viewer, Qt::magenta, c2Point);
+ QCOMPARE(spy1.count(), 7);
+ QCOMPARE(spy2.count(), 2);
+
+ p->goToSlide(pathC1, QStringLiteral("C1S1"));
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::magenta, c2Point);
+ QCOMPARE(spy1.count(), 8);
+ QCOMPARE(spy2.count(), 3);
+
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), pathC1);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C1S1"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), pathC1);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C1S2"));
+
+ p->goToSlide(pathC2, QStringLiteral("C2S1"));
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 9);
+ QCOMPARE(spy2.count(), 4);
+
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), pathC2);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C2S1"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), pathC2);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("C2S2"));
+
+ p->goToSlide(path, true, true);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::blue, c1Point);
+ checkPixel(m_viewer, Qt::blue, c2Point);
+ QCOMPARE(spy1.count(), 10);
+ QCOMPARE(spy2.count(), 5);
+
+ args = spy1.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 2);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S2"));
+ args = spy2.last();
+ QCOMPARE(args.at(0).toString(), path);
+ QCOMPARE(args.at(1).toInt(), 1);
+ QCOMPARE(args.at(2).toString(), QStringLiteral("S1"));
+
+ p->goToSlide(path, false, true);
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 13);
+ QCOMPARE(spy2.count(), 6);
+
+ // No wrap, should not change
+ p->goToSlide(path, false, false);
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 13);
+ QCOMPARE(spy2.count(), 6);
+
+ // Should wrap
+ p->goToSlide(path, false, true);
+ checkPixel(m_viewer, Qt::green, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::green, c2Point);
+ QCOMPARE(spy1.count(), 14);
+ QCOMPARE(spy2.count(), 7);
+
+ // No wrap, should not change
+ p->goToSlide(path, true, false);
+ checkPixel(m_viewer, Qt::green, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::green, c2Point);
+ QCOMPARE(spy1.count(), 14);
+ QCOMPARE(spy2.count(), 7);
+
+ // Should wrap
+ p->goToSlide(path, true, true);
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy1.count(), 17);
+ QCOMPARE(spy2.count(), 8);
+}
+
+void tst_Q3DSSurfaceViewer::testPresentationActivation_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testPresentationActivation()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, ANIMATION);
+ else
+ createOffscreenAndViewer(m_viewer, ANIMATION);
+
+ // Note: Presentation filename isn't default ID anymore, need to set manually.
+ m_viewer->setPresentationId(QStringLiteral("animation"));
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ {
+ // Grab two images two seconds apart to verify animation is happening
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ }
+
+ m_viewer->presentation()->setPresentationActive(QStringLiteral("animation"), false);
+
+ {
+ // Grab two images two seconds apart to verify animation has stopped
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 == image2);
+ }
+
+ m_viewer->presentation()->setPresentationActive(QStringLiteral("animation"), true);
+
+ {
+ // Grab two images two seconds apart to verify animation is happening
+ QImage image1 = m_viewer->grab();
+ QTest::qWait(2000);
+ QImage image2 = m_viewer->grab();
+ QVERIFY(image1 != image2);
+ }
+}
+
+void tst_Q3DSSurfaceViewer::testSceneElement_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testSceneElement()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MULTISLIDE);
+ else
+ createOffscreenAndViewer(m_viewer, MULTISLIDE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QString path = QStringLiteral("Scene");
+ QString pathC1 = QStringLiteral("Scene.Layer.Component1");
+ QString pathC2 = QStringLiteral("Scene.Layer.Component2");
+
+ Q3DSPresentation *p = m_viewer->presentation();
+ Q3DSSceneElement *scene = new Q3DSSceneElement(path);
+ Q3DSSceneElement *sceneC1 = new Q3DSSceneElement(pathC1);
+ Q3DSSceneElement *sceneC2 = new Q3DSSceneElement(pathC2);
+ QSignalSpy spy1(scene, &Q3DSSceneElement::currentSlideIndexChanged);
+ QSignalSpy spy2(scene, &Q3DSSceneElement::previousSlideIndexChanged);
+ QSignalSpy spy3(scene, &Q3DSSceneElement::currentSlideNameChanged);
+ QSignalSpy spy4(scene, &Q3DSSceneElement::previousSlideNameChanged);
+ QSignalSpy spy5(scene, &Q3DSSceneElement::elementPathChanged);
+ QSignalSpy spy6(sceneC1, &Q3DSSceneElement::currentSlideIndexChanged);
+ QSignalSpy spy7(sceneC1, &Q3DSSceneElement::previousSlideIndexChanged);
+ QSignalSpy spy8(sceneC1, &Q3DSSceneElement::currentSlideNameChanged);
+ QSignalSpy spy9(sceneC1, &Q3DSSceneElement::previousSlideNameChanged);
+ QSignalSpy spy10(sceneC1, &Q3DSSceneElement::elementPathChanged);
+ QSignalSpy spy11(sceneC2, &Q3DSSceneElement::currentSlideIndexChanged);
+ QSignalSpy spy12(sceneC2, &Q3DSSceneElement::previousSlideIndexChanged);
+ QSignalSpy spy13(sceneC2, &Q3DSSceneElement::currentSlideNameChanged);
+ QSignalSpy spy14(sceneC2, &Q3DSSceneElement::previousSlideNameChanged);
+ QSignalSpy spy15(sceneC2, &Q3DSSceneElement::elementPathChanged);
+ QVERIFY(spy1.isValid());
+ QVERIFY(spy2.isValid());
+ QVERIFY(spy3.isValid());
+ QVERIFY(spy4.isValid());
+ QVERIFY(spy5.isValid());
+ QVERIFY(spy6.isValid());
+ QVERIFY(spy7.isValid());
+ QVERIFY(spy8.isValid());
+ QVERIFY(spy9.isValid());
+ QVERIFY(spy10.isValid());
+ QVERIFY(spy11.isValid());
+ QVERIFY(spy12.isValid());
+ QVERIFY(spy13.isValid());
+ QVERIFY(spy14.isValid());
+ QVERIFY(spy15.isValid());
+
+ // Defaults
+ QCOMPARE(scene->currentSlideIndex(), 0);
+ QCOMPARE(scene->previousSlideIndex(), 0);
+ QCOMPARE(scene->currentSlideName(), QStringLiteral(""));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral(""));
+ QCOMPARE(scene->elementPath(), path);
+
+ checkPixel(m_viewer, Qt::red);
+
+ // Ensure we have no pending events to confuse spy counts
+ QGuiApplication::processEvents();
+
+ p->registerElement(scene);
+ p->registerElement(sceneC1);
+ p->registerElement(sceneC2);
+
+ QCOMPARE(scene->currentSlideIndex(), 1);
+ QCOMPARE(scene->previousSlideIndex(), 0);
+ QCOMPARE(scene->currentSlideName(), QStringLiteral("S1"));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral(""));
+ QCOMPARE(scene->elementPath(), path);
+
+ p->goToSlide(path, QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 1);
+ QCOMPARE(spy2.count(), 1);
+ QCOMPARE(spy3.count(), 1);
+ QCOMPARE(spy4.count(), 1);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 0);
+ QCOMPARE(spy7.count(), 0);
+ QCOMPARE(spy8.count(), 0);
+ QCOMPARE(spy9.count(), 0);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 0);
+ QCOMPARE(spy12.count(), 0);
+ QCOMPARE(spy13.count(), 0);
+ QCOMPARE(spy14.count(), 0);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 0);
+ // Getting previous slide change without getting current slide change seems illogical here,
+ // but that's how the internal viewer logic for previous slide works. It makes sense when
+ // you consider the fact that we always get enter events for child slides when parent slide
+ // is entered.
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 0);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 0);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 0);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(pathC1, QStringLiteral("C1S2"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 1);
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 1);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 0);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 0);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(pathC2, QStringLiteral("C2S2"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 2);
+ QCOMPARE(spy2.count(), 2);
+ QCOMPARE(spy3.count(), 2);
+ QCOMPARE(spy4.count(), 2);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 1);
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 1);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 1);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 1);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ // Subscenes revert to original slides when parent is re-entered
+ p->goToSlide(path, QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 3);
+ QCOMPARE(spy2.count(), 3);
+ QCOMPARE(spy3.count(), 3);
+ QCOMPARE(spy4.count(), 3);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 1);
+ QCOMPARE(spy7.count(), 1);
+ QCOMPARE(spy8.count(), 1);
+ QCOMPARE(spy9.count(), 1);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 1);
+ QCOMPARE(spy12.count(), 1);
+ QCOMPARE(spy13.count(), 1);
+ QCOMPARE(spy14.count(), 1);
+ QCOMPARE(spy15.count(), 0);
+
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 4);
+ QCOMPARE(spy3.count(), 4);
+ QCOMPARE(spy4.count(), 4);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 2);
+ QCOMPARE(spy7.count(), 2);
+ QCOMPARE(spy8.count(), 2);
+ QCOMPARE(spy9.count(), 2);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 2);
+ QCOMPARE(spy12.count(), 2);
+ QCOMPARE(spy13.count(), 2);
+ QCOMPARE(spy14.count(), 2);
+ QCOMPARE(spy15.count(), 0);
+
+ p->unregisterElement(scene);
+ p->unregisterElement(sceneC1);
+ p->unregisterElement(sceneC2);
+
+ // No more signals after unregistering
+ p->goToSlide(path, QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 4);
+ QCOMPARE(spy2.count(), 4);
+ QCOMPARE(spy3.count(), 4);
+ QCOMPARE(spy4.count(), 4);
+ QCOMPARE(spy5.count(), 0);
+ QCOMPARE(spy6.count(), 2);
+ QCOMPARE(spy7.count(), 2);
+ QCOMPARE(spy8.count(), 2);
+ QCOMPARE(spy9.count(), 2);
+ QCOMPARE(spy10.count(), 0);
+ QCOMPARE(spy11.count(), 2);
+ QCOMPARE(spy12.count(), 2);
+ QCOMPARE(spy13.count(), 2);
+ QCOMPARE(spy14.count(), 2);
+ QCOMPARE(spy15.count(), 0);
+
+ // Reregister
+ p->registerElement(scene);
+ p->goToSlide(path, QStringLiteral("S1"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 5);
+ QCOMPARE(spy2.count(), 5);
+ QCOMPARE(spy3.count(), 5);
+ QCOMPARE(spy4.count(), 5);
+ QCOMPARE(spy5.count(), 0);
+
+ QCOMPARE(scene->currentSlideIndex(), 1);
+ QCOMPARE(scene->previousSlideIndex(), 2);
+ QCOMPARE(scene->currentSlideName(), QStringLiteral("S1"));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral("S2"));
+ QCOMPARE(scene->elementPath(), path);
+
+ scene->setCurrentSlideName(QStringLiteral("S2"));
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 6);
+ QCOMPARE(spy2.count(), 6);
+
+ scene->setCurrentSlideIndex(0);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 7);
+ QCOMPARE(spy2.count(), 7);
+
+ // Go to next slide, wrap parameter doesn't matter
+ scene->goToSlide(true, true);
+ checkPixel(m_viewer, Qt::blue);
+
+ QCOMPARE(spy1.count(), 8);
+ QCOMPARE(spy2.count(), 8);
+
+ // Go to next slide, wrap parameter doesn't matter
+ scene->goToSlide(true, false);
+ checkPixel(m_viewer, Qt::green);
+
+ QCOMPARE(spy1.count(), 9);
+ QCOMPARE(spy2.count(), 9);
+
+ // No wrap, should not change
+ scene->goToSlide(true, false);
+ checkPixel(m_viewer, Qt::green);
+
+ QCOMPARE(spy1.count(), 9);
+ QCOMPARE(spy2.count(), 9);
+
+ // Should wrap
+ scene->goToSlide(true, true);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 10);
+ QCOMPARE(spy2.count(), 10);
+
+ // No wrap, should not change
+ scene->goToSlide(false, false);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 10);
+ QCOMPARE(spy2.count(), 10);
+
+ // Should wrap
+ scene->goToSlide(false, true);
+ checkPixel(m_viewer, Qt::green);
+
+ QCOMPARE(spy1.count(), 11);
+ QCOMPARE(spy2.count(), 11);
+
+ // Time change
+ scene->goToTime(7.0f);
+ checkPixel(m_viewer, Qt::yellow);
+
+ QCOMPARE(spy1.count(), 11);
+ QCOMPARE(spy2.count(), 11);
+
+ // Back to first slide for further tests
+ scene->setCurrentSlideIndex(0);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 12);
+ QCOMPARE(spy2.count(), 12);
+
+ // Change element path
+ scene->setElementPath(pathC1);
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 12);
+ QCOMPARE(spy2.count(), 12);
+ QCOMPARE(spy3.count(), 12);
+ QCOMPARE(spy4.count(), 12);
+ QCOMPARE(spy5.count(), 1);
+
+ QCOMPARE(scene->currentSlideIndex(), 1);
+ QCOMPARE(scene->previousSlideIndex(), 1);
+ // Having current and previous slides the same seems weird, but that's how the slide
+ // logic works internally.
+ QCOMPARE(scene->currentSlideName(), QStringLiteral("C1S1"));
+ QCOMPARE(scene->previousSlideName(), QStringLiteral("C1S1"));
+ QCOMPARE(scene->elementPath(), pathC1);
+
+ p->goToSlide(pathC1, QStringLiteral("C1S2"));
+ checkPixel(m_viewer, Qt::red);
+
+ QCOMPARE(spy1.count(), 13);
+ QCOMPARE(spy2.count(), 12);
+ QCOMPARE(spy3.count(), 13);
+ QCOMPARE(spy4.count(), 12);
+ QCOMPARE(spy5.count(), 1);
+}
+
+void tst_Q3DSSurfaceViewer::testElement_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testElement()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MULTISLIDE);
+ else
+ createOffscreenAndViewer(m_viewer, MULTISLIDE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QString path1 = QStringLiteral("Scene.Layer.Rect.Material"); // Red
+ QString path2 = QStringLiteral("Scene.Layer.Component1.Rectangle4.Material"); // Green
+ QString path3 = QStringLiteral("Scene.Layer.Component2.Rectangle6.Material"); // Yellow
+
+ QPoint mainPoint(m_viewer->size().width() * 2 / 8, m_viewer->size().height() / 2);
+ QPoint c1Point(m_viewer->size().width() * 5 / 8, m_viewer->size().height() / 2);
+ QPoint c2Point(m_viewer->size().width() * 7 / 8, m_viewer->size().height() / 2);
+
+ Q3DSPresentation *p = m_viewer->presentation();
+ Q3DSElement *element1 = new Q3DSElement(p, path1);
+ Q3DSElement *element2 = new Q3DSElement(p, path2);
+ QSignalSpy spy2(element2, &Q3DSSceneElement::elementPathChanged);
+ QVERIFY(spy2.isValid());
+
+ checkPixel(m_viewer, Qt::red, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ element1->setAttribute(QStringLiteral("diffuse.r"), 0.0);
+ element1->setAttribute(QStringLiteral("diffuse.g"), 0.0);
+ element1->setAttribute(QStringLiteral("diffuse.b"), 1.0);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::green, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ element2->setAttribute(QStringLiteral("diffuse.r"), 1.0);
+ element2->setAttribute(QStringLiteral("diffuse.g"), 0.0);
+ element2->setAttribute(QStringLiteral("diffuse.b"), 1.0);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::magenta, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+
+ // Change elementpath, nothing changes visually
+ element2->setElementPath(path3);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::magenta, c1Point);
+ checkPixel(m_viewer, Qt::yellow, c2Point);
+ QCOMPARE(spy2.count(), 1);
+
+ element2->setAttribute(QStringLiteral("diffuse.r"), 0.0);
+ element2->setAttribute(QStringLiteral("diffuse.g"), 1.0);
+ element2->setAttribute(QStringLiteral("diffuse.b"), 1.0);
+ checkPixel(m_viewer, Qt::blue, mainPoint);
+ checkPixel(m_viewer, Qt::magenta, c1Point);
+ checkPixel(m_viewer, Qt::cyan, c2Point);
+}
+
+void tst_Q3DSSurfaceViewer::testMouseInput_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testMouseInput()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, MOUSE);
+ else
+ createOffscreenAndViewer(m_viewer, MOUSE);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QPoint point1(m_viewer->size().width() * 1 / 4, m_viewer->size().height() / 2);
+ QPoint point2(m_viewer->size().width() * 3 / 4, m_viewer->size().height() / 2);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ QMouseEvent e1(QEvent::MouseButtonPress, point1, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mousePressEvent(&e1);
+
+ checkPixel(m_viewer, Qt::green, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ QMouseEvent e2(QEvent::MouseButtonRelease, point1, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mouseReleaseEvent(&e2);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ QMouseEvent e3(QEvent::MouseButtonPress, point2, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mousePressEvent(&e3);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::blue, point2);
+
+ QMouseEvent e4(QEvent::MouseButtonRelease, point2, Qt::LeftButton, Qt::LeftButton,
+ Qt::NoModifier);
+ m_viewer->presentation()->mouseReleaseEvent(&e4);
+
+ checkPixel(m_viewer, Qt::blue, point1);
+ checkPixel(m_viewer, Qt::red, point2);
+
+ // Note: No way yet to hook mouse move into anything in the presentation
+}
+
+void tst_Q3DSSurfaceViewer::testDataInput_data()
+{
+ testBasics_data();
+}
+
+void tst_Q3DSSurfaceViewer::testDataInput()
+{
+ QFETCH(bool, isWindow);
+
+ if (isWindow)
+ createWindowAndViewer(m_viewer, DATAINPUT);
+ else
+ createOffscreenAndViewer(m_viewer, DATAINPUT);
+
+ m_viewer->settings()->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QPoint point1(m_viewer->size().width() / 4, m_viewer->size().height() / 4);
+
+ const QString animationName = QStringLiteral("animationInput");
+ const QString slideName = QStringLiteral("slideInput");
+
+ checkPixel(m_viewer, Qt::red, point1);
+ m_viewer->presentation()->setDataInputValue(animationName, 90);
+ checkPixel(m_viewer, Qt::blue, point1);
+ m_viewer->presentation()->setDataInputValue(animationName, 10);
+ checkPixel(m_viewer, Qt::red, point1);
+
+ Q3DSDataInput *animationInput = new Q3DSDataInput();
+ animationInput->setName(animationName);
+
+ m_viewer->presentation()->registerDataInput(animationInput);
+ QVERIFY(m_viewer->presentation()->registeredDataInput(animationInput->name()));
+
+ Q3DSDataInput *slideInput = new Q3DSDataInput(m_viewer->presentation(), slideName);
+ QVERIFY(m_viewer->presentation()->registeredDataInput(slideInput->name()));
+
+ animationInput->setValue(90);
+ checkPixel(m_viewer, Qt::blue, point1);
+ animationInput->setValue(10);
+ checkPixel(m_viewer, Qt::red, point1);
+
+ slideInput->setValue(QStringLiteral("Slide2"));
+ checkPixel(m_viewer, Qt::green, point1);
+ slideInput->setValue(QStringLiteral("Slide1"));
+ checkPixel(m_viewer, Qt::red, point1);
+
+ m_viewer->presentation()->unregisterDataInput(animationInput);
+ m_viewer->presentation()->unregisterDataInput(slideInput);
+ QVERIFY(!m_viewer->presentation()->registeredDataInput(animationInput->name()));
+ QVERIFY(!m_viewer->presentation()->registeredDataInput(slideInput->name()));
+ delete animationInput;
+ delete slideInput;
+}
+
+
+QTEST_MAIN(tst_Q3DSSurfaceViewer)
+
+#include "tst_q3dssurfaceviewer.moc"
diff --git a/tests/auto/studio3d/shared/presentation/animation.uip b/tests/auto/studio3d/shared/presentation/animation.uip
new file mode 100644
index 0000000..bd78b51
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/animation.uip
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Cube" >
+ <Material id="Material" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="29690" />
+ <Set ref="#Camera" endtime="29690" />
+ <Set ref="#Light" endtime="29690" />
+ <Add ref="#Cube" name="Cube" endtime="29690" position="5.7735 -14.4338 0" sourcepath="#Cube" >
+ <AnimationTrack property="position.x" type="EaseInOut" >0 -457.55 100 100 4.832 -8.66028 100 100 11.174 440.23 100 100 20.037 -64.9519 100 100 29.69 -401.258 100 100</AnimationTrack>
+ <AnimationTrack property="position.y" type="EaseInOut" >0 -1.52588e-05 100 100 4.832 -220.837 100 100 11.174 -18.7639 100 100 20.037 225.167 100 100 29.69 -14.4337 100 100</AnimationTrack>
+ <AnimationTrack property="position.z" type="EaseInOut" >0 0 100 100 4.832 0 100 100 11.174 0 100 100 20.037 0 100 100 29.69 0 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Material" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/blue.uip b/tests/auto/studio3d/shared/presentation/blue.uip
new file mode 100644
index 0000000..a6eefa7
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/blue.uip
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle" >
+ <Material id="Material" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle" name="Rectangle" endtime="8000" position="0 -15.8771 0" scale="13.3333 9.5252 1" sourcepath="#Rectangle" />
+ <Add ref="#Material" diffuse="0 0 1" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/datainput.uia b/tests/auto/studio3d/shared/presentation/datainput.uia
new file mode 100644
index 0000000..fbfa55b
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/datainput.uia
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<application>
+ <assets initial="datainput">
+ <dataInput name="animationInput" type="Ranged Number" min="0" max="100"/>
+ <dataInput name="slideInput" type="String" />
+ <presentation id="datainput" src="datainput.uip"/>
+ <presentation id="subpres" src="datainput_sub.uip"/>
+ </assets>
+ <statemachine ref="#logic">
+ <visual-states>
+ <state ref="Initial">
+ <enter>
+ <goto-slide element="main:Scene" rel="next"/>
+ </enter>
+ </state>
+ </visual-states>
+ </statemachine>
+</application>
diff --git a/tests/auto/studio3d/shared/presentation/datainput.uip b/tests/auto/studio3d/shared/presentation/datainput.uip
new file mode 100644
index 0000000..3807cec
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/datainput.uip
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="600" maintainAspect="False" >
+ <CustomColors count="16" >#ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
+ </ProjectSettings>
+ <Graph >
+ <Scene id="Scene" backgroundcolor="0 1 0" controlledproperty="$animationInput @timeline $slideInput @slide" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Component id="Component" >
+ <Text id="Text" />
+ </Component>
+ <Model id="Rectangle" >
+ <Material id="Default" name="Default" >
+ <Image id="Default_diffusemap" />
+ </Material>
+ </Model>
+ <Text id="Text_001" />
+ <Model id="Rectangle2" >
+ <Material id="Default_001" name="Default" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" background="Transparent" sourcepath="" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" />
+ <Add ref="#Rectangle" name="Rectangle" sourcepath="#Rectangle" >
+ <AnimationTrack property="position.x" type="EaseInOut" >0 -327.165 100 100 10 351.542 100 100</AnimationTrack>
+ <AnimationTrack property="position.y" type="EaseInOut" >0 -6.41502 100 100 10 -17.962 100 100</AnimationTrack>
+ <AnimationTrack property="position.z" type="EaseInOut" >0 0 100 100 10 0 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Default" diffusemap="#Default_diffusemap" />
+ <Add ref="#Default_diffusemap" sourcepath="maps/QT-symbol.png" subpresentation="subpres" />
+ <State id="Scene-Slide1" name="Slide1" initialplaystate="Pause" >
+ <Add ref="#Component" name="Component" controlledproperty="$animationInput @timeline" />
+ <Add ref="#Rectangle2" name="Rectangle2" position="0 0 100" scale="9999 9999 99999" sourcepath="#Rectangle" />
+ <Add ref="#Default_001" >
+ <AnimationTrack property="diffuse.x" type="EaseInOut" >0 1 100 100 4.487 1 100 100 5.5 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="diffuse.y" type="EaseInOut" >0 0 100 100 4.487 0 100 100 5.5 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="diffuse.z" type="EaseInOut" >0 0 100 100 4.487 0 100 100 5.5 1 100 100 10 1 100 100</AnimationTrack>
+ </Add>
+ </State>
+ <State id="Scene-Slide2" name="Slide2" initialplaystate="Play" playmode="Stop at end" playthroughto="Previous" >
+ <Add ref="#Text_001" name="Text" font="TitilliumWeb-Regular" position="-442.635 -193.733 0" textstring="Second slide" />
+ </State>
+ </State>
+ <State name="Master Slide" component="#Component" >
+ <State id="Component-Slide1" name="Slide1" initialplaystate="Pause" >
+ <Add ref="#Text" name="Text" controlledproperty="$animationInput textstring" font="TitilliumWeb-Regular" position="-5.132 137.281 0" >
+ <AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.z" type="EaseInOut" >0 0 100 100 10 -360 100 100</AnimationTrack>
+ </Add>
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/datainput_sub.uip b/tests/auto/studio3d/shared/presentation/datainput_sub.uip
new file mode 100644
index 0000000..c007eab
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/datainput_sub.uip
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="400" presentationHeight="200" maintainAspect="False" >
+ <CustomColors count="16" >#ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
+ </ProjectSettings>
+ <Graph >
+ <Scene id="Scene" controlledproperty="$animationInput @timeline" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Text id="Text" controlledproperty="$slideInput textstring" />
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" />
+ <State id="Scene-Slide1" name="Slide1" initialplaystate="Pause" >
+ <Add ref="#Text" name="Text" font="TitilliumWeb-Regular" opacity="99" size="96" >
+ <AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.z" type="EaseInOut" >0 0 100 100 10 -360 100 100</AnimationTrack>
+ </Add>
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/fonts/TitilliumWeb-Regular.ttf b/tests/auto/studio3d/shared/presentation/fonts/TitilliumWeb-Regular.ttf
new file mode 100644
index 0000000..6da8219
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/fonts/TitilliumWeb-Regular.ttf
Binary files differ
diff --git a/tests/auto/studio3d/shared/presentation/mixed.uip b/tests/auto/studio3d/shared/presentation/mixed.uip
new file mode 100644
index 0000000..16fea00
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/mixed.uip
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle" >
+ <Material id="Material" />
+ </Model>
+ <Model id="Rectangle2" >
+ <Material id="Material_001" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle" name="Rectangle" endtime="8000" position="401.651 25 0" scale="8 16 1" sourcepath="#Rectangle" />
+ <Add ref="#Material" diffuse="1 0 0" emissivecolor="1 1 1" emissivepower="1" />
+ <Add ref="#Rectangle2" name="Rectangle2" endtime="8000" position="-378.164 25 0" scale="8 16 1" sourcepath="#Rectangle" />
+ <Add ref="#Material_001" diffuse="0 0 1" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/mixed_vertical.uip b/tests/auto/studio3d/shared/presentation/mixed_vertical.uip
new file mode 100644
index 0000000..7914b11
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/mixed_vertical.uip
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle" >
+ <Material id="Material" />
+ </Model>
+ <Model id="Rectangle2" >
+ <Material id="Material_001" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle" name="Rectangle" endtime="8000" position="0 -400 0" scale="16 8 1" sourcepath="#Rectangle" />
+ <Add ref="#Material" diffuse="1 0 0" emissivecolor="1 1 1" emissivepower="1" />
+ <Add ref="#Rectangle2" name="Rectangle2" endtime="8000" position="0 400 0" scale="16 8 1" sourcepath="#Rectangle" />
+ <Add ref="#Material_001" diffuse="0 0 1" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/mouse.uip b/tests/auto/studio3d/shared/presentation/mouse.uip
new file mode 100644
index 0000000..edd9f95
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/mouse.uip
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle" >
+ <Material id="Material" />
+ </Model>
+ <Model id="Rectangle2" >
+ <Material id="Material_001" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle" name="Rectangle" endtime="8000" position="668.283 7.21691 0" scale="13.3333 9.5252 1" sourcepath="#Rectangle" >
+ <Action id="Rectangle-Action" eyeball="True" triggerObject="#Rectangle" event="onPressureDown" targetObject="#Material" handler="Set Property" >
+ <HandlerArgument name="Property Name" type="String" argtype="Property" value="diffuse" />
+ <HandlerArgument name="Property Value" type="Float3" argtype="Dependent" value="0 0 1" />
+ </Action>
+ <Action id="Rectangle-Action_001" eyeball="True" triggerObject="#Rectangle" event="onPressureUp" targetObject="#Material" handler="Set Property" >
+ <HandlerArgument name="Property Name" type="String" argtype="Property" value="diffuse" />
+ <HandlerArgument name="Property Value" type="Float3" argtype="Dependent" value="1 0 0" />
+ </Action>
+ </Add>
+ <Add ref="#Material" diffuse="1 0 0" emissivecolor="1 1 1" emissivepower="1" />
+ <Add ref="#Rectangle2" name="Rectangle2" endtime="8000" position="-528.276 -19.6247 0" scale="10.6053 8.67004 1" sourcepath="#Rectangle" >
+ <Action id="Rectangle2-Action" eyeball="True" triggerObject="#Rectangle2" event="onPressureDown" targetObject="#Material_001" handler="Set Property" >
+ <HandlerArgument name="Property Name" type="String" argtype="Property" value="diffuse" />
+ <HandlerArgument name="Property Value" type="Float3" argtype="Dependent" value="0 1 0" />
+ </Action>
+ <Action id="Rectangle2-Action_001" eyeball="True" triggerObject="#Rectangle2" event="onPressureUp" targetObject="#Material_001" handler="Set Property" >
+ <HandlerArgument name="Property Name" type="String" argtype="Property" value="diffuse" />
+ <HandlerArgument name="Property Value" type="Float3" argtype="Dependent" value="0 0 1" />
+ </Action>
+ </Add>
+ <Add ref="#Material_001" diffuse="0 0 1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/multislide.uip b/tests/auto/studio3d/shared/presentation/multislide.uip
new file mode 100644
index 0000000..e17db1d
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/multislide.uip
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" backgroundcolor="1 1 0" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle1" >
+ <Material id="Material" />
+ </Model>
+ <Model id="Rectangle2" >
+ <Material id="Material_001" />
+ </Model>
+ <Model id="Rectangle2_003" >
+ <Material id="Material_006" />
+ </Model>
+ <Component id="Component" >
+ <Model id="Rectangle" >
+ <Material id="Material_002" />
+ </Model>
+ <Model id="Rectangle2_001" >
+ <Material id="Material_003" />
+ </Model>
+ </Component>
+ <Component id="Component2" >
+ <Model id="Rectangle_001" >
+ <Material id="Material_004" />
+ </Model>
+ <Model id="Rectangle2_002" >
+ <Material id="Material_005" />
+ </Model>
+ </Component>
+ <Text id="Text" />
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-S1" name="S1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle1" name="Rect" position="0 0 0" scale="13.3333 5 1" sourcepath="#Rectangle" />
+ <Add ref="#Material" diffuse="1 0 0" emissivecolor="1 1 1" emissivepower="1" opacity="100" />
+ <Add ref="#Component" name="Component1" endtime="8000" position="400 0 -1" scale="4 3 1" />
+ <Add ref="#Component2" name="Component2" endtime="8000" position="461.548 -5.72538 -5" />
+ <Add ref="#Text" name="Text" endtime="8000" font="TitilliumWeb-Regular" position="-304.552 -193.631 0" size="36" />
+ </State>
+ <State id="Scene-S2" name="S2" initialplaystate="Pause" playmode="Looping" playthroughto="Previous" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle2" name="Rectangle2" position="0 -15.8771 0" scale="13.3333 9.5252 1" sourcepath="#Rectangle" >
+ <AnimationTrack property="scale.x" type="EaseInOut" >0 11.6 100 100 8 1 100 100</AnimationTrack>
+ <AnimationTrack property="scale.y" type="EaseInOut" >0 9.5252 100 100 8 1 100 100</AnimationTrack>
+ <AnimationTrack property="scale.z" type="EaseInOut" >0 1 100 100 8 1 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Material_001" diffuse="0 0 1" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ <State id="Scene-S3" name="S3" initialplaystate="Pause" playmode="Looping" playthroughto="Previous" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle2_003" name="Rectangle3" position="0 -15.8771 0" scale="13.3333 9.5252 1" sourcepath="#Rectangle" >
+ <AnimationTrack property="scale.x" type="EaseInOut" >0 11.6 100 100 8 1 100 100</AnimationTrack>
+ <AnimationTrack property="scale.y" type="EaseInOut" >0 9.5252 100 100 8 1 100 100</AnimationTrack>
+ <AnimationTrack property="scale.z" type="EaseInOut" >0 1 100 100 8 1 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Material_006" diffuse="0 1 0" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ </State>
+ <State name="Master Slide" component="#Component" >
+ <State id="Component1-C1S1" name="C1S1" >
+ <Add ref="#Rectangle" name="Rectangle4" position="0 0 -1" scale="2 3 1" sourcepath="#Rectangle" />
+ <Add ref="#Material_002" diffuse="0 1 0" />
+ </State>
+ <State id="Component1-C1S2" name="C1S2" playthroughto="Previous" >
+ <Add ref="#Rectangle2_001" name="Rectangle5" position="0 0 -1" scale="2 3 1" sourcepath="#Rectangle" />
+ <Add ref="#Material_003" diffuse="0 1 1" />
+ </State>
+ </State>
+ <State name="Master Slide" component="#Component2" >
+ <State id="Component2-C2S1" name="C2S1" >
+ <Add ref="#Rectangle_001" name="Rectangle6" scale="3.5 7 3.03591" sourcepath="#Rectangle" />
+ <Add ref="#Material_004" diffuse="1 1 0" />
+ </State>
+ <State id="Component2-C2S2" name="C2S2" playthroughto="Previous" >
+ <Add ref="#Rectangle2_002" name="Rectangle7" scale="3.5 7 3.03591" sourcepath="#Rectangle" />
+ <Add ref="#Material_005" diffuse="1 0 1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/red.uip b/tests/auto/studio3d/shared/presentation/red.uip
new file mode 100644
index 0000000..a04d2f8
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/red.uip
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="480" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle" >
+ <Material id="Material" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle" name="Rectangle" endtime="8000" position="0 -15.8771 0" scale="13.3333 9.5252 1" sourcepath="#Rectangle" />
+ <Add ref="#Material" diffuse="1 0 0" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/presentation/settings.uip b/tests/auto/studio3d/shared/presentation/settings.uip
new file mode 100644
index 0000000..acd580a
--- /dev/null
+++ b/tests/auto/studio3d/shared/presentation/settings.uip
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="3" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="300" presentationHeight="200" maintainAspect="False" />
+ <Graph >
+ <Scene id="Scene" backgroundcolor="0 0 1" >
+ <Layer id="Layer" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Rectangle" >
+ <Material id="Material" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" lighttype="Directional" position="0 0 -500" rotation="0 0 0" />
+ <State id="Scene-Slide1" name="Slide1" playmode="Looping" >
+ <Set ref="#Layer" endtime="8000" />
+ <Set ref="#Camera" endtime="8000" />
+ <Set ref="#Light" endtime="8000" />
+ <Add ref="#Rectangle" name="Rectangle" edgetess="1" endtime="8000" innertess="1" position="0 -15.8771 0" scale="11 2.375 1" sourcepath="#Rectangle" tessellation="Linear" />
+ <Add ref="#Material" diffuse="1 0 0" emissivecolor="1 1 1" emissivepower="1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/auto/studio3d/shared/shared_presentations.h b/tests/auto/studio3d/shared/shared_presentations.h
new file mode 100644
index 0000000..6d38273
--- /dev/null
+++ b/tests/auto/studio3d/shared/shared_presentations.h
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 <QtCore/qurl.h>
+
+const QUrl RED = QUrl(QStringLiteral("qrc:/red.uip"));
+const QUrl BLUE = QUrl(QStringLiteral("qrc:/blue.uip"));
+const QUrl MIXED = QUrl(QStringLiteral("qrc:/mixed.uip"));
+const QUrl MIXED_VERTICAL = QUrl(QStringLiteral("qrc:/mixed_vertical.uip"));
+const QUrl ANIMATION = QUrl(QStringLiteral("qrc:/animation.uip"));
+const QUrl SETTINGS = QUrl(QStringLiteral("qrc:/settings.uip"));
+const QUrl MULTISLIDE = QUrl(QStringLiteral("qrc:/multislide.uip"));
+const QUrl MOUSE = QUrl(QStringLiteral("qrc:/mouse.uip"));
+const QUrl DATAINPUT = QUrl(QStringLiteral("qrc:/datainput.uia"));
diff --git a/tests/auto/studio3d/shared/shared_presentations.qrc b/tests/auto/studio3d/shared/shared_presentations.qrc
new file mode 100644
index 0000000..d4bb668
--- /dev/null
+++ b/tests/auto/studio3d/shared/shared_presentations.qrc
@@ -0,0 +1,15 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="blue.uip">presentation/blue.uip</file>
+ <file alias="red.uip">presentation/red.uip</file>
+ <file alias="mixed.uip">presentation/mixed.uip</file>
+ <file alias="animation.uip">presentation/animation.uip</file>
+ <file alias="mixed_vertical.uip">presentation/mixed_vertical.uip</file>
+ <file alias="settings.uip">presentation/settings.uip</file>
+ <file alias="multislide.uip">presentation/multislide.uip</file>
+ <file alias="mouse.uip">presentation/mouse.uip</file>
+ <file alias="datainput.uip">presentation/datainput.uip</file>
+ <file alias="datainput.uia">presentation/datainput.uia</file>
+ <file alias="datainput_sub.uip">presentation/datainput_sub.uip</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/studio3d/studio3d.pro b/tests/auto/studio3d/studio3d.pro
new file mode 100644
index 0000000..e92019f
--- /dev/null
+++ b/tests/auto/studio3d/studio3d.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+
+SUBDIRS += \
+ q3dssurfaceviewer
diff --git a/tests/auto/viewer/tst_qt3dsviewer.cpp b/tests/auto/viewer/tst_qt3dsviewer.cpp
new file mode 100644
index 0000000..2273f89
--- /dev/null
+++ b/tests/auto/viewer/tst_qt3dsviewer.cpp
@@ -0,0 +1,764 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "tst_qt3dsviewer.h"
+
+#include <QtQuick/QQuickItem>
+#include <QtGui/QSurfaceFormat>
+#include <QtStudio3D/Q3DSPresentation>
+#include <QtStudio3D/Q3DSElement>
+#include <QtStudio3D/Q3DSViewerSettings>
+#include <QtStudio3D/Q3DSGeometry>
+#include <QtCore/QRandomGenerator>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtCore/QRegularExpression>
+
+void messageOutput(QtMsgType type, const QMessageLogContext &context,
+ const QString &msg)
+{
+ Q_UNUSED(context);
+ switch (type) {
+ case QtDebugMsg:
+ case QtInfoMsg:
+ case QtWarningMsg:
+ case QtCriticalMsg:
+ break; // swallow
+ case QtFatalMsg:
+ QFAIL(msg.toLocal8Bit().constData());
+ }
+}
+
+void tst_qt3dsviewer::initTestCase()
+{
+ qInstallMessageHandler(messageOutput);
+}
+
+void tst_qt3dsviewer::cleanupTestCase()
+{
+}
+
+void tst_qt3dsviewer::init()
+{
+#if defined(Q_OS_ANDROID)
+ QSurfaceFormat format;
+ format.setDepthBufferSize(32);
+ format.setVersion(3, 2);
+ format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+#else
+ QSurfaceFormat format;
+ format.setDepthBufferSize(32);
+ format.setVersion(4, 3);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ QSurfaceFormat::setDefaultFormat(format);
+#endif
+
+ m_viewer = new QQuickView;
+ m_viewer->setTitle(QStringLiteral("tst_qt3dsviewer"));
+ m_viewer->setSource(QUrl("qrc:/tst_qt3dsviewer.qml"));
+ m_studio3DItem = m_viewer->rootObject();
+ m_presentation = nullptr;
+ m_settings = nullptr;
+ m_ignoreError = false;
+
+ QVERIFY(m_studio3DItem);
+
+ const auto children = m_studio3DItem->children();
+ for (auto &child : children) {
+ if (!m_presentation)
+ m_presentation = qobject_cast<Q3DSPresentation *>(child);
+ if (!m_settings)
+ m_settings = qobject_cast<Q3DSViewerSettings *>(child);
+ }
+
+ QVERIFY(m_presentation);
+ QVERIFY(m_settings);
+}
+
+void tst_qt3dsviewer::cleanup()
+{
+ deleteCreated();
+ if (!m_ignoreError)
+ QCOMPARE(m_studio3DItem->property("error").toString(), {});
+ m_studio3DItem = nullptr;
+ m_viewer->hide();
+ m_viewer->deleteLater();
+ m_viewer = nullptr;
+}
+
+void tst_qt3dsviewer::testEmpty()
+{
+ m_presentation->setProperty("source", QUrl());
+ m_viewer->show();
+ QTest::qWait(1000);
+ QCOMPARE(m_studio3DItem->property("running").toBool(), false);
+ QVERIFY(!m_studio3DItem->property("error").toString().isEmpty());
+ m_ignoreError = true; // To avoid triggering cleanup() fail as we are expecting an error
+}
+
+void tst_qt3dsviewer::testLoading()
+{
+ QCOMPARE(m_studio3DItem->property("running").toBool(), false);
+ m_viewer->show();
+ QTest::qWait(1000);
+ QCOMPARE(m_studio3DItem->property("running").toBool(), true);
+}
+
+
+void tst_qt3dsviewer::testSlides()
+{
+ QSignalSpy spyEntered(m_presentation,
+ SIGNAL(slideEntered(const QString &, unsigned int, const QString &)));
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+ QCOMPARE(spyEntered.count(), 0);
+ QCOMPARE(spyExited.count(), 0);
+
+ m_viewer->show();
+ QTest::qWait(1000);
+
+ QCOMPARE(spyEntered.count(), 1);
+ QCOMPARE(spyExited.count(), 0);
+
+ QVERIFY(spyExited.wait(12000));
+ QCOMPARE(spyEntered.count(), 2);
+ QCOMPARE(spyExited.count(), 1);
+}
+
+void tst_qt3dsviewer::testFrameUpdates()
+{
+ QSignalSpy spyFrames(m_studio3DItem, SIGNAL(frameUpdate()));
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+ m_viewer->show();
+ QVERIFY(spyExited.wait(12000));
+ // Just ensure we get some frames, exact count will vary a lot due to external factors
+ QVERIFY(spyFrames.count() > 10);
+}
+
+void tst_qt3dsviewer::testSettings()
+{
+ m_viewer->show();
+ m_settings->setMatteColor(QColor("#0000ff"));
+ QVERIFY(m_settings->matteColor() == QColor("#0000ff"));
+
+ // Save and change matte color
+ m_settings->save("", "tst_qt3dsviewer", "tst_qt3dsviewer");
+ m_settings->setMatteColor(QColor("#00ff00"));
+ QVERIFY(m_settings->matteColor() == QColor("#00ff00"));
+ // Load and previous matte color should be back
+ m_settings->load("", "tst_qt3dsviewer", "tst_qt3dsviewer");
+ QVERIFY(m_settings->matteColor() == QColor("#0000ff"));
+}
+
+void tst_qt3dsviewer::testCreateElement()
+{
+ m_viewer->show();
+
+ m_settings->setShowRenderStats(true);
+ m_settings->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+ QSignalSpy spyElemCreated(m_presentation, SIGNAL(elementsCreated(const QStringList &,
+ const QString &)));
+
+ QObject::connect(m_presentation, &Q3DSPresentation::elementsCreated,
+ [this](const QStringList &elementNames, const QString &error) {
+ QCOMPARE(error, QString());
+ for (const auto &elementName : elementNames)
+ QVERIFY(m_createdElements.contains(elementName));
+ });
+
+ auto loadMatDefFile = [&](const QString &fileName) -> QString {
+ QFile matDefFile(fileName);
+ if (!matDefFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return {};
+
+ QTextStream in(&matDefFile);
+ return in.readAll();
+ };
+
+ int animValue = 0;
+
+ QString md = loadMatDefFile(QStringLiteral(
+ ":/scenes/simple_cube_animation/materials/Basic Red.materialdef"));
+ m_presentation->createMaterial(md);
+ m_createdMaterials << QStringLiteral("materials/Basic Red");
+ md = loadMatDefFile(QStringLiteral(
+ ":/scenes/simple_cube_animation/materials/Basic Green.materialdef"));
+ m_presentation->createMaterial(md);
+ m_createdMaterials << QStringLiteral("materials/Basic Green");
+
+
+ QHash<QString, QVariant> data;
+ data.insert(QStringLiteral("name"), QStringLiteral("New Cylinder"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), QString());
+ data.insert(QStringLiteral("starttime"), 0);
+ data.insert(QStringLiteral("endtime"), 4500);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(200, 300, 200)));
+ data.insert(QStringLiteral("opacity"), 20.0);
+ data.insert(QStringLiteral("controlledproperty"), QStringLiteral("$newDataInput opacity"));
+
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+
+ // Elements can be registered before they are created
+ Q3DSElement newCylinder(m_presentation, QStringLiteral("Scene.Layer.New Cylinder"));
+ Q3DSElement newCylinder2(m_presentation,
+ QStringLiteral("Scene.Layer.New Cylinder.New Cylinder 2"));
+ Q3DSElement newGroup(m_presentation, QStringLiteral("Scene.Layer.New Group"));
+ Q3DSElement newSphere(m_presentation, QStringLiteral("Scene.Layer.Cube2.New Sphere"));
+
+ QTimer animationTimer;
+ animationTimer.setInterval(10);
+ int animDir = 1;
+ QObject::connect(&animationTimer, &QTimer::timeout, [&]() {
+ if (qAbs(animValue) > 100)
+ animDir = -animDir;
+ animValue += animDir;
+ newCylinder.setAttribute(QStringLiteral("rotation.x"), animValue * 4);
+ newCylinder2.setAttribute(QStringLiteral("position.y"), animValue * 3);
+ newSphere.setAttribute(QStringLiteral("position.x"), 50 + animValue * 2);
+ newGroup.setAttribute(QStringLiteral("opacity"), qAbs(animValue));
+ m_presentation->setDataInputValue(QStringLiteral("newDataInput"), qAbs(animValue / 2));
+ });
+
+ // Create objects to slides 1 & 2 while slide 1 is executing
+ QTimer::singleShot(1000, [&]() {
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("New Cylinder 2"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Red"));
+ data.insert(QStringLiteral("starttime"), 500);
+ data.insert(QStringLiteral("endtime"), 5000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(50, animValue, 50)));
+
+ createElement(QStringLiteral("Scene.Layer.New Cylinder"),
+ QStringLiteral("Slide1"), data);
+
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("New Sphere"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Sphere"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Green"));
+ data.insert(QStringLiteral("starttime"), 1000);
+ data.insert(QStringLiteral("endtime"), 4000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(animValue, 75, 0)));
+
+ createElement(QStringLiteral("Scene.Layer.Cube2"), QStringLiteral("Slide2"), data);
+
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("Sphere To Delete"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Sphere"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Red"));
+ data.insert(QStringLiteral("starttime"), 0);
+ data.insert(QStringLiteral("endtime"), 10000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-100, -100, 0)));
+ // Test that this datainput control entry is removed at element delete
+ data.insert(QStringLiteral("controlledproperty"), QStringLiteral("$newDataInput opacity"));
+
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"), data);
+
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("New Group"));
+ data.insert(QStringLiteral("type"), QStringLiteral("group"));
+ data.insert(QStringLiteral("starttime"), 0);
+ data.insert(QStringLiteral("endtime"), 10000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(50, -100, 0)));
+
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+
+ QVector<QHash<QString, QVariant>> groupElemProps;
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("Child 1 of Group"));
+ data.insert(QStringLiteral("type"), QStringLiteral("model"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Green"));
+ data.insert(QStringLiteral("starttime"), 1000);
+ data.insert(QStringLiteral("endtime"), 4000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(0, 0, 0)));
+ groupElemProps << data;
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("Child 2 of Group"));
+ data.insert(QStringLiteral("type"), QStringLiteral("model"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Green"));
+ data.insert(QStringLiteral("starttime"), 2000);
+ data.insert(QStringLiteral("endtime"), 4000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(100, 0, 0)));
+ groupElemProps << data;
+
+ m_createdElements << QStringLiteral("Scene.Layer.New Group.Child 1 of Group")
+ << QStringLiteral("Scene.Layer.New Group.Child 2 of Group");
+
+ m_presentation->createElements(QStringLiteral("Scene.Layer.New Group"),
+ QStringLiteral("Slide1"), groupElemProps);
+
+ animationTimer.start();
+ });
+
+ // Switch to slide 2
+ QVERIFY(spyExited.wait(20000));
+
+ // Remove dynamically added object
+ QTimer::singleShot(3000, [&]() {
+ m_presentation->deleteElement(QStringLiteral("Scene.Layer.Sphere To Delete"));
+ m_createdElements.removeOne(QStringLiteral("Scene.Layer.Sphere To Delete"));
+ });
+
+ // Create objects to slides 1 and 2 while slide 2 is executing
+ QTimer::singleShot(2000, [&]() {
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("New Cylinder 3"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Green"));
+ data.insert(QStringLiteral("starttime"), 0);
+ data.insert(QStringLiteral("endtime"), 3000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-100, -100, 0)));
+
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+
+ data.clear();
+ data.insert(QStringLiteral("name"), QStringLiteral("New Sphere 2"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Sphere"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Green"));
+ data.insert(QStringLiteral("starttime"), 0);
+ data.insert(QStringLiteral("endtime"), 5000);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-100, 100, 0)));
+
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"), data);
+ });
+
+ // Switch to slide 1
+ QVERIFY(spyExited.wait(20000));
+
+ QRandomGenerator rnd;
+ QVector<QHash<QString, QVariant>> massProps;
+ for (int i = 0; i < 1000; ++i) {
+ data.clear();
+ QString elementName = QStringLiteral("MassElement_%1").arg(i);
+ data.insert(QStringLiteral("name"), elementName);
+ data.insert(QStringLiteral("sourcepath"),
+ i % 2 ? QStringLiteral("#Cube") : QStringLiteral("#Cone"));
+ data.insert(QStringLiteral("material"),
+ i % 2 ? QStringLiteral("Basic Green") : QStringLiteral("Basic Red"));
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(rnd.bounded(-600, 600),
+ rnd.bounded(-600, 600),
+ rnd.bounded(800, 1200))));
+ massProps << data;
+ m_createdElements << QStringLiteral("Scene.Layer.") + elementName;
+ }
+ m_presentation->createElements(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"),
+ massProps);
+
+ // Switch to slide 2
+ QVERIFY(spyExited.wait(20000));
+
+ QTest::qWait(500);
+ QCOMPARE(spyElemCreated.count(), 9);
+ const QStringList createdElements = m_presentation->createdElements();
+ QCOMPARE(createdElements.size(), m_createdElements.size());
+ for (const auto &elementName : createdElements)
+ QVERIFY(m_createdElements.contains(elementName));
+ deleteCreated();
+
+ // Switch to slide 1
+ QVERIFY(spyExited.wait(20000));
+ QTest::qWait(1000);
+}
+
+void tst_qt3dsviewer::testCreateMaterial()
+{
+ m_viewer->show();
+
+ m_settings->setShowRenderStats(true);
+ m_settings->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+ QSignalSpy spyMatCreated(m_presentation, SIGNAL(materialsCreated(const QStringList &,
+ const QString &)));
+ QSignalSpy spyElemCreated(m_presentation, SIGNAL(elementsCreated(const QStringList &,
+ const QString &)));
+
+ QStringList materialDefinitions;
+ // Create material via .materialdef file in resources
+ materialDefinitions
+ << QStringLiteral(":/scenes/simple_cube_animation/materials/Basic Blue.materialdef")
+ << QStringLiteral(":/scenes/simple_cube_animation/materials/Basic Texture.materialdef");
+
+ // Create material directly from materialdef content
+ auto loadMatDefFile = [&](const QString &fileName) -> QString {
+ QFile matDefFile(fileName);
+ if (!matDefFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return {};
+
+ QTextStream in(&matDefFile);
+ return in.readAll();
+ };
+ QString matDef = loadMatDefFile(
+ QStringLiteral(":/scenes/simple_cube_animation/materials/Copper.materialdef"));
+ QVERIFY(!matDef.isEmpty());
+ materialDefinitions << matDef;
+
+ m_presentation->createMaterials(materialDefinitions);
+ m_createdMaterials << QStringLiteral("materials/Basic Blue")
+ << QStringLiteral("materials/Basic Texture")
+ << QStringLiteral("materials/Copper");
+
+ QObject::connect(m_presentation, &Q3DSPresentation::materialsCreated,
+ [this](const QStringList &materialNames, const QString &error) {
+ QCOMPARE(error, QString());
+ for (auto &name : materialNames) {
+ QVERIFY(m_createdMaterials.contains(name));
+ QHash<QString, QVariant> data;
+ if (name == QLatin1String("materials/Basic Blue")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Blue Cylinder"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(200, 300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ } else if (name == QLatin1String("materials/Basic Texture")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Textured Cone"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cone"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-200, -300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ } else if (name == QLatin1String("materials/Copper")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Copper Sphere"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Sphere"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-200, 300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ } else if (name == QLatin1String("materials/Just Yellow")) {
+ QHash<QString, QVariant> data;
+ data.insert(QStringLiteral("name"), QStringLiteral("Yellow Cube"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cube"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(200, -300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ } else {
+ QVERIFY(false);
+ }
+ }
+ });
+
+ // Create material after start
+ QTimer::singleShot(1000, [&]() {
+ QString md = loadMatDefFile(QStringLiteral(
+ ":/scenes/simple_cube_animation/materials/Basic Blue.materialdef"));
+ // Modify the diffuse color and material name so that we can be sure it is a new one
+ md.replace(QStringLiteral("Basic Blue"), QStringLiteral("Just Yellow"));
+ md.replace(QRegularExpression(QStringLiteral("\"diffuse\">.*<")),
+ QStringLiteral("\"diffuse\">1 1 0 1<"));
+ m_presentation->createMaterial(md);
+ m_createdMaterials << QStringLiteral("materials/Just Yellow");
+ });
+
+ // Delete material
+ QTimer::singleShot(2500, [&]() {
+ m_presentation->deleteElement(QStringLiteral("Scene.Layer.Textured Cone"));
+ m_presentation->deleteMaterial("materials/Basic Texture");
+ m_createdMaterials.removeOne(QStringLiteral("materials/Basic Texture"));
+
+ // Try to use the deleted material - should find a fallback material
+ QHash<QString, QVariant> data;
+ data.insert(QStringLiteral("name"), QStringLiteral("Textured Cone 2"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cone"));
+ data.insert(QStringLiteral("material"), QStringLiteral("materials/Basic Texture"));
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-100, -300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ });
+
+ QVERIFY(spyExited.wait(20000));
+ QCOMPARE(spyMatCreated.count(), 2);
+ QCOMPARE(spyElemCreated.count(), 5);
+ const QStringList createdMaterials = m_presentation->createdMaterials();
+ QCOMPARE(createdMaterials.size(), m_createdMaterials.size());
+ for (const auto &name : createdMaterials)
+ QVERIFY(m_createdMaterials.contains(name));
+ deleteCreated();
+ QTest::qWait(200); // Extra wait to verify slide change visually
+}
+
+void tst_qt3dsviewer::testCreateMesh()
+{
+ m_viewer->show();
+
+ m_settings->setShowRenderStats(true);
+ m_settings->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+ QSignalSpy spyMeshCreated(m_presentation, SIGNAL(meshesCreated(const QStringList &,
+ const QString &)));
+ QSignalSpy spyElemCreated(m_presentation, SIGNAL(elementsCreated(const QStringList &,
+ const QString &)));
+ Q3DSGeometry pyramid;
+ Q3DSGeometry star;
+ createGeometries(pyramid, star);
+
+ Q3DSElement pyramidElem(m_presentation, QStringLiteral("Scene.Layer.Pyramid"));
+ Q3DSElement starElem(m_presentation, QStringLiteral("Scene.Layer.Star"));
+
+ int animValue = 0;
+ QTimer animationTimer;
+ animationTimer.setInterval(10);
+ QObject::connect(&animationTimer, &QTimer::timeout, [&]() {
+ animValue++;
+ pyramidElem.setAttribute(QStringLiteral("rotation.x"), animValue * 2);
+ pyramidElem.setAttribute(QStringLiteral("rotation.y"), animValue);
+ starElem.setAttribute(QStringLiteral("rotation.x"), -animValue * 2);
+ starElem.setAttribute(QStringLiteral("rotation.y"), -animValue);
+ });
+
+ m_presentation->createMaterial(
+ QStringLiteral(":/scenes/simple_cube_animation/materials/Basic Texture.materialdef"));
+ m_createdMaterials << QStringLiteral("materials/Basic Texture");
+ m_presentation->createMesh(QStringLiteral("Pyramid"), pyramid);
+ m_createdMeshes << QStringLiteral("Pyramid");
+
+ QObject::connect(m_presentation, &Q3DSPresentation::meshesCreated,
+ [&](const QStringList &meshNames, const QString &error) {
+ QCOMPARE(error, QString());
+ for (auto &name : meshNames) {
+ QVERIFY(m_createdMeshes.contains(name));
+ QHash<QString, QVariant> data;
+ if (name == QLatin1String("Pyramid")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Pyramid"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("Pyramid"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Texture"));
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(100, 150, 500)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ animationTimer.start();
+ } else if (name == QLatin1String("Star")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Star"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("Star"));
+ data.insert(QStringLiteral("material"), QStringLiteral("Basic Texture"));
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(100, -150, 500)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ } else {
+ QVERIFY(false);
+ }
+ }
+ });
+
+ // Create mesh after start
+ QTimer::singleShot(1000, [&]() {
+ m_presentation->createMesh(QStringLiteral("Star"), star);
+ m_createdMeshes << QStringLiteral("Star");
+ });
+
+ QTimer::singleShot(3000, [&]() {
+ m_presentation->deleteElement(QStringLiteral("Scene.Layer.Star"));
+ m_presentation->deleteMesh(QStringLiteral("Star"));
+ m_createdMeshes.removeOne(QStringLiteral("Star"));
+ });
+
+ QVERIFY(spyExited.wait(20000));
+ QCOMPARE(spyMeshCreated.count(), 2);
+ QCOMPARE(spyElemCreated.count(), 2);
+ const QStringList createdMeshes = m_presentation->createdMeshes();
+ QCOMPARE(createdMeshes.size(), m_createdMeshes.size());
+ for (const auto &name : createdMeshes)
+ QVERIFY(m_createdMeshes.contains(name));
+ deleteCreated();
+ QTest::qWait(200); // Extra wait to verify slide change visually
+}
+
+void tst_qt3dsviewer::testMouseEvents()
+{
+ m_viewer->show();
+ QTest::qWait(1000);
+
+ QSignalSpy spyEvents(m_studio3DItem,
+ SIGNAL(ignoredEventsChanged()));
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+
+ QCOMPARE(spyEvents.count(), 0);
+ QCOMPARE(spyExited.count(), 0);
+
+ // Ignore mouse, so slide doesn't change
+ m_studio3DItem->setProperty("ignoredEvents", 1);
+ QTest::mousePress(m_viewer, Qt::LeftButton);
+ QTest::qWait(1000);
+ QTest::mouseRelease(m_viewer, Qt::LeftButton);
+ QCOMPARE(spyEvents.count(), 1);
+ QCOMPARE(spyExited.count(), 0);
+
+ // Enable mouse, clicking switches slide
+ m_studio3DItem->setProperty("ignoredEvents", 0);
+ QTest::mousePress(m_viewer, Qt::LeftButton);
+ QTest::qWait(1000);
+ QTest::mouseRelease(m_viewer, Qt::LeftButton);
+ QCOMPARE(spyEvents.count(), 2);
+ QCOMPARE(spyExited.count(), 1);
+}
+
+void tst_qt3dsviewer::deleteCreated()
+{
+ m_presentation->deleteElements(m_createdElements);
+ m_presentation->deleteMaterials(m_createdMaterials);
+ m_presentation->deleteMeshes(m_createdMeshes);
+ m_createdElements.clear();
+ m_createdMaterials.clear();
+ m_createdMeshes.clear();
+ QVERIFY(m_presentation->createdElements().size() == 0);
+ QVERIFY(m_presentation->createdMaterials().size() == 0);
+ QVERIFY(m_presentation->createdMeshes().size() == 0);
+}
+
+void tst_qt3dsviewer::createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties)
+{
+ m_createdElements << parentElementPath + QLatin1Char('.')
+ + properties[QStringLiteral("name")].toString();
+ m_presentation->createElement(parentElementPath, slideName, properties);
+}
+
+void tst_qt3dsviewer::createGeometries(Q3DSGeometry &pyramid, Q3DSGeometry &star)
+{
+ struct Vertex {
+ QVector3D position;
+ QVector3D normal;
+ QVector2D uv;
+ };
+
+ QVector<Vertex> vertices;
+
+ auto createVertex = [&](const QVector3D &xyz, const QVector3D &n, const QVector2D &uv) {
+ Vertex newVertex;
+ newVertex.position = xyz;
+ if (n.isNull())
+ newVertex.normal = xyz; // This is almost never the correct normal
+ else
+ newVertex.normal = n.normalized();
+ newVertex.uv = uv;
+ vertices.append(newVertex);
+ };
+
+ auto createTriangle = [&](const QVector3D &xyz1, const QVector2D &uv1,
+ const QVector3D &xyz2, const QVector2D &uv2,
+ const QVector3D &xyz3, const QVector2D &uv3) {
+ QVector3D n;
+ n = QVector3D::crossProduct(xyz2 - xyz1, xyz3 - xyz1).normalized();
+
+ createVertex(xyz1, n, uv1);
+ createVertex(xyz2, n, uv2);
+ createVertex(xyz3, n, uv3);
+ };
+
+ // Pyramid (no index buffer)
+ {
+ QVector3D xyz[5] = {{0, 0, 50}, {50, 50, -50}, {50, -50, -50}, {-50, -50, -50},
+ {-50, 50, -50}};
+ QVector2D uv[4] = {{1, 1}, {1, 0}, {0, 0}, {0, 1}};
+ createTriangle(xyz[0], uv[0], xyz[1], uv[1], xyz[2], uv[2]);
+ createTriangle(xyz[0], uv[0], xyz[2], uv[1], xyz[3], uv[2]);
+ createTriangle(xyz[0], uv[0], xyz[3], uv[1], xyz[4], uv[2]);
+ createTriangle(xyz[0], uv[0], xyz[4], uv[1], xyz[1], uv[2]);
+ createTriangle(xyz[1], uv[0], xyz[4], uv[2], xyz[3], uv[1]);
+ createTriangle(xyz[1], uv[0], xyz[3], uv[3], xyz[2], uv[2]);
+
+ QByteArray vertexBuffer(reinterpret_cast<const char *>(vertices.constData()),
+ vertices.size() * int(sizeof(Vertex)));
+
+ pyramid.clear();
+ pyramid.setVertexData(vertexBuffer);
+ pyramid.addAttribute(Q3DSGeometry::Attribute::PositionSemantic);
+ pyramid.addAttribute(Q3DSGeometry::Attribute::NormalSemantic);
+ pyramid.addAttribute(Q3DSGeometry::Attribute::TexCoordSemantic);
+ }
+
+ vertices.clear();
+
+ // Star (using index buffer)
+ {
+ // Note: Since faces share vertices, the normals on the vertices are not correct
+ // for any face, leading to weird lighting behavior
+ createVertex({0, 150, 0}, {}, {0.5f, 1});
+ createVertex({50, 50, -50}, {}, {0.66f, 0.66f});
+ createVertex({150, 0, 0}, {}, {1, 0.5f});
+ createVertex({50, -50, -50}, {}, {0.66f, 0.33f});
+ createVertex({0, -150, 0}, {}, {0.5f, 0});
+ createVertex({-50, -50, -50}, {}, {0.33f, 0.33f});
+ createVertex({-150, 0, 0}, {}, {0, 0.5f});
+ createVertex({-50, 50, -50}, {}, {0.33f, 0.66f});
+ createVertex({50, 50, 50}, {}, {0.66f, 0.66f});
+ createVertex({50, -50, 50}, {}, {0.66f, 0.33f});
+ createVertex({-50, -50, 50}, {}, {0.33f, 0.33f});
+ createVertex({-50, 50, 50}, {}, {0.33f, 0.66f});
+
+ QVector<quint16> indices = {
+ 0, 1, 8, 0, 7, 1, 0, 11, 7, 0, 8, 11, // Top pyramid
+ 2, 1, 3, 2, 3, 9, 2, 9, 8, 2, 8, 1, // Right pyramid
+ 4, 3, 5, 4, 5, 10, 4, 10, 9, 4, 9, 3, // Bottom pyramid
+ 6, 5, 7, 6, 7, 11, 6, 11, 10, 6, 10, 5, // Left pyramid
+ 1, 7, 5, 1, 5, 3, // Front center rect
+ 8, 10, 11, 8, 9, 10 // Back center rect
+ };
+
+ QByteArray vertexBuffer(reinterpret_cast<const char *>(vertices.constData()),
+ vertices.size() * int(sizeof(Vertex)));
+ QByteArray indexBuffer(reinterpret_cast<const char *>(indices.constData()),
+ indices.size() * int(sizeof(quint16)));
+
+ Q3DSGeometry::Attribute indexAtt;
+ indexAtt.semantic = Q3DSGeometry::Attribute::IndexSemantic;
+ indexAtt.componentType = Q3DSGeometry::Attribute::ComponentType::U16Type;
+
+ star.clear();
+ star.setVertexData(vertexBuffer);
+ star.setIndexData(indexBuffer);
+ star.addAttribute(Q3DSGeometry::Attribute::PositionSemantic);
+ star.addAttribute(Q3DSGeometry::Attribute::NormalSemantic);
+ star.addAttribute(Q3DSGeometry::Attribute::TexCoordSemantic);
+ star.addAttribute(indexAtt);
+ }
+}
+
+QTEST_MAIN(tst_qt3dsviewer)
diff --git a/tests/auto/viewer/tst_qt3dsviewer.h b/tests/auto/viewer/tst_qt3dsviewer.h
new file mode 100644
index 0000000..3d1f947
--- /dev/null
+++ b/tests/auto/viewer/tst_qt3dsviewer.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef TST_QT3DSVIEWER
+#define TST_QT3DSVIEWER
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+#include <QtQuick/QQuickView>
+#include <QtStudio3D/q3dspresentation.h>
+#include <QtStudio3D/q3dsviewersettings.h>
+
+class tst_qt3dsviewer : public QObject
+{
+ Q_OBJECT
+public:
+ tst_qt3dsviewer()
+ {
+ }
+
+private Q_SLOTS:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+ void testEmpty();
+ void testLoading();
+ void testSlides();
+ void testFrameUpdates();
+ void testSettings();
+ void testCreateElement();
+ void testCreateMaterial();
+ void testCreateMesh();
+ void testMouseEvents();
+
+private:
+ void deleteCreated();
+ void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties);
+ void createGeometries(Q3DSGeometry &pyramid, Q3DSGeometry &star);
+
+ QQuickView *m_viewer = nullptr;
+ QObject *m_studio3DItem = nullptr;
+ Q3DSPresentation *m_presentation = nullptr;
+ Q3DSViewerSettings *m_settings = nullptr;
+ QStringList m_createdElements;
+ QStringList m_createdMaterials;
+ QStringList m_createdMeshes;
+ bool m_ignoreError = false;
+
+};
+
+#endif // TST_QT3DSVIEWER
diff --git a/tests/auto/viewer/tst_qt3dsviewer.qml b/tests/auto/viewer/tst_qt3dsviewer.qml
new file mode 100644
index 0000000..e65a49d
--- /dev/null
+++ b/tests/auto/viewer/tst_qt3dsviewer.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtStudio3D.OpenGL 2.4
+
+Studio3D {
+ id: studio3D
+ width: 800
+ height: 800
+ Presentation {
+ source: "qrc:/scenes/simple_cube_animation/simple_cube_animation.uia"
+ }
+ ViewerSettings {
+ }
+}
diff --git a/tests/auto/viewer/viewer.pro b/tests/auto/viewer/viewer.pro
new file mode 100644
index 0000000..9a8da77
--- /dev/null
+++ b/tests/auto/viewer/viewer.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+CONFIG += testcase
+include($$PWD/../../../commoninclude.pri)
+
+TARGET = tst_qt3dsviewer
+QT += testlib gui quick studio3d
+RESOURCES += viewer.qrc
+
+HEADERS += \
+ tst_qt3dsviewer.h
+
+SOURCES += \
+ tst_qt3dsviewer.cpp
+
+LIBS += \
+ -lqt3dsopengl$$qtPlatformTargetSuffix() \
+ -lqt3dsqmlstreamer$$qtPlatformTargetSuffix()
+
+ANDROID_EXTRA_LIBS = \
+ libqt3dsopengl.so \
+ libqt3dsqmlstreamer.so
diff --git a/tests/auto/viewer/viewer.qrc b/tests/auto/viewer/viewer.qrc
new file mode 100644
index 0000000..dcdddbe
--- /dev/null
+++ b/tests/auto/viewer/viewer.qrc
@@ -0,0 +1,16 @@
+<RCC>
+ <qresource prefix="/">
+ <file>../../scenes/simple_cube_animation/simple_cube_animation.uia</file>
+ <file>../../scenes/simple_cube_animation/presentations/simple_cube_animation.uip</file>
+ <file>../../scenes/simple_cube_animation/materials/Basic Green.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Basic Red.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Basic Blue.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Basic Texture.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Copper.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/copper.shader</file>
+ <file>../../scenes/simple_cube_animation/maps/materials/shadow.png</file>
+ <file>../../scenes/simple_cube_animation/maps/materials/spherical_checker.png</file>
+ <file>../../scenes/simple_cube_animation/maps/QT-symbol.png</file>
+ <file>tst_qt3dsviewer.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/scenes/customvertex/customvertex.uia b/tests/scenes/customvertex/customvertex.uia
new file mode 100644
index 0000000..8448810
--- /dev/null
+++ b/tests/scenes/customvertex/customvertex.uia
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='utf-8'?>
+<application xmlns="http://qt.io/qt3dstudio/uia">
+ <assets initial="customvertex">
+ <presentation id="customvertex" src="presentations/customvertex.uip"/>
+ </assets>
+ <statemachine ref="#logic">
+ <visual-states>
+ <state ref="Initial">
+ <enter>
+ <goto-slide rel="next" element="main:Scene"/>
+ </enter>
+ </state>
+ </visual-states>
+ </statemachine>
+</application>
diff --git a/tests/scenes/customvertex/materials/simple.shader b/tests/scenes/customvertex/materials/simple.shader
new file mode 100644
index 0000000..bdbd21e
--- /dev/null
+++ b/tests/scenes/customvertex/materials/simple.shader
@@ -0,0 +1,29 @@
+<Material name="simple" version="1.0">
+ <MetaData>
+ <Property formalName="Scale" name="scale" type="Vector" default="1 1 1" stage="vertex" category="Material" />
+ <Property formalName="Color" name="color" type="Color" default="1 1 1" stage="fragment" category="Material" />
+ </MetaData>
+ <Shaders type="GLSL" version="330">
+ <Shader>
+ <VertexShader>
+ attribute vec3 attr_pos;
+ uniform mat4 modelViewProjection;
+
+ void main() {
+ gl_Position = modelViewProjection * vec4(attr_pos * scale, 1.0);
+ }
+ </VertexShader>
+ <FragmentShader>
+ out vec4 fragColor;
+ void main() {
+ fragColor = vec4(color.rgb, 1.0);
+ }
+ </FragmentShader>
+ </Shader>
+ </Shaders>
+<Passes>
+ <Pass>
+ </Pass>
+</Passes>
+</Material>
+
diff --git a/tests/scenes/customvertex/presentations/customvertex.uip b/tests/scenes/customvertex/presentations/customvertex.uip
new file mode 100644
index 0000000..eba06da
--- /dev/null
+++ b/tests/scenes/customvertex/presentations/customvertex.uip
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="5" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="1920" presentationHeight="1080" maintainAspect="False" preferKtx="False" >
+ <CustomColors count="16" >#7391ff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
+ </ProjectSettings>
+ <Classes >
+ <CustomMaterial id="simple" name="simple" sourcepath="../materials/simple.shader" />
+ </Classes>
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" variants="" >
+ <Camera id="Camera" />
+ <Light id="Light" />
+ <Model id="Sphere" >
+ <CustomMaterial id="simple_001" class="#simple" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" disabledepthprepass="True" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" />
+ <State id="Scene-Slide1" name="Slide1" >
+ <Add ref="#Sphere" name="Sphere" position="0 0 0" sourcepath="#Sphere" />
+ <Add ref="#simple_001" name="Material" color="0.333333 0.666667 0" scale="1 2 1" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/scenes/simple_cube_animation/maps/QT-symbol.png b/tests/scenes/simple_cube_animation/maps/QT-symbol.png
new file mode 100644
index 0000000..752a2e2
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/maps/QT-symbol.png
Binary files differ
diff --git a/tests/scenes/simple_cube_animation/maps/materials/shadow.png b/tests/scenes/simple_cube_animation/maps/materials/shadow.png
new file mode 100644
index 0000000..599b1cc
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/maps/materials/shadow.png
Binary files differ
diff --git a/tests/scenes/simple_cube_animation/maps/materials/spherical_checker.png b/tests/scenes/simple_cube_animation/maps/materials/spherical_checker.png
new file mode 100644
index 0000000..e42394d
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/maps/materials/spherical_checker.png
Binary files differ
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef
new file mode 100644
index 0000000..c35d47b
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef
@@ -0,0 +1,25 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">0 0.482353 1 1</Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Material</Property>
+ <Property name="name"><![CDATA[materials/Basic Blue]]></Property>
+ <Property name="path"><![CDATA[C:/dev/q3dstudio/qt3dstudio/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef
new file mode 100644
index 0000000..273a348
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef
@@ -0,0 +1,25 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">0.180392 1 0 1</Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Material</Property>
+ <Property name="name"><![CDATA[materials/Basic Green]]></Property>
+ <Property name="path"><![CDATA[C:/dev/q3dstudio/qt3dstudio/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef
new file mode 100644
index 0000000..38b8eb7
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef
@@ -0,0 +1,25 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">1 0 0.0156863 1</Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Material</Property>
+ <Property name="name"><![CDATA[materials/Basic Red]]></Property>
+ <Property name="path"><![CDATA[C:/dev/q3dstudio/qt3dstudio/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef
new file mode 100644
index 0000000..4defa98
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef
@@ -0,0 +1,63 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">0.752941 0.756863 1 1</Property>
+ <Property name="diffusemap"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="diffusemap2"><![CDATA[./maps/QT-symbol.png]]></Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Material</Property>
+ <Property name="name"><![CDATA[materials/Basic Texture]]></Property>
+ <Property name="path"><![CDATA[C:/dev/qt/NDD/qt3ds2/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef]]></Property>
+ <TextureData name="diffusemap">
+ <Property name="scaleu">1</Property>
+ <Property name="scalev">1</Property>
+ <Property name="mappingmode">UV Mapping</Property>
+ <Property name="tilingmodehorz">Tiled</Property>
+ <Property name="tilingmodevert">Tiled</Property>
+ <Property name="rotationuv">0</Property>
+ <Property name="positionu">0</Property>
+ <Property name="positionv">0</Property>
+ <Property name="pivotu">0</Property>
+ <Property name="pivotv">0</Property>
+ <Property name="subpresentation"></Property>
+ <Property name="sourcepath"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Image</Property>
+ <Property name="name"><![CDATA[Image]]></Property>
+ </TextureData>
+ <TextureData name="diffusemap2">
+ <Property name="scaleu">2</Property>
+ <Property name="scalev">3</Property>
+ <Property name="mappingmode">UV Mapping</Property>
+ <Property name="tilingmodehorz">Tiled</Property>
+ <Property name="tilingmodevert">Tiled</Property>
+ <Property name="rotationuv">0</Property>
+ <Property name="positionu">0</Property>
+ <Property name="positionv">0</Property>
+ <Property name="pivotu">0</Property>
+ <Property name="pivotv">0</Property>
+ <Property name="subpresentation"></Property>
+ <Property name="sourcepath"><![CDATA[./maps/QT-symbol.png]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Image</Property>
+ <Property name="name"><![CDATA[Image]]></Property>
+ </TextureData>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/Copper.materialdef b/tests/scenes/simple_cube_animation/materials/Copper.materialdef
new file mode 100644
index 0000000..7688098
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Copper.materialdef
@@ -0,0 +1,14 @@
+<MaterialData version="1.0">
+ <Property name="uEnvironmentTexture" type="Texture"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="uEnvironmentMappingEnabled">True</Property>
+ <Property name="uBakedShadowTexture" type="Texture"><![CDATA[./maps/materials/shadow.png]]></Property>
+ <Property name="uShadowMappingEnabled">False</Property>
+ <Property name="roughness">0</Property>
+ <Property name="metal_color">0.807843 0.45098 0.211765 1</Property>
+ <Property name="sourcepath"><![CDATA[./materials/copper.shader]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">CustomMaterial</Property>
+ <Property name="name"><![CDATA[materials/Copper]]></Property>
+ <Property name="path"><![CDATA[C:/dev/qt/NDD/qt3ds2/tests/scenes/simple_cube_animation/materials/Copper.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/copper.shader b/tests/scenes/simple_cube_animation/materials/copper.shader
new file mode 100644
index 0000000..cf9e1ad
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/copper.shader
@@ -0,0 +1,178 @@
+<Material name="copper" version="1.0">
+ <MetaData >
+ <Property formalName="Environment Map" name="uEnvironmentTexture" description="Environment texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="environment" default="./maps/materials/spherical_checker.png" category="Material"/>
+ <Property formalName="Enable Environment" name="uEnvironmentMappingEnabled" description="Enable environment mapping" type="Boolean" default="True" category="Material"/>
+ <Property formalName="Baked Shadow Map" name="uBakedShadowTexture" description="Baked shadow texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="shadow" default="./maps/materials/shadow.png" category="Material"/>
+ <Property formalName="Shadow Mapping" name="uShadowMappingEnabled" description="Enable shadow mapping" type="Boolean" default="False" category="Material"/>
+ <Property formalName="Roughness" name="roughness" type="Float" min="0.000000" max="1.000000" default="0.000000" description="Roughness of the material.\n0 = fully specular\n1 = fully diffuse" category="Material"/>
+ <Property formalName="Metal Color" name="metal_color" type="Color" default="0.805 0.395 0.305" description="Color of the material" category="Material"/>
+ </MetaData>
+ <Shaders type="GLSL" version="330">
+ <Shader>
+ <Shared> </Shared>
+<VertexShader>
+ </VertexShader>
+ <FragmentShader>
+
+// add enum defines
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QT3DS_ENABLE_UV0 1
+#define QT3DS_ENABLE_WORLD_POSITION 1
+#define QT3DS_ENABLE_TEXTAN 1
+#define QT3DS_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+ vec4 base;
+ vec4 layer;
+ mat3 tanFrame;
+};
+
+
+// temporary declarations
+ vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "luminance.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "fresnelLayer.glsllib"
+
+bool evalTwoSided()
+{
+ return( false );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+ return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, roughness, roughness, scatter_reflect );
+
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, roughness, roughness );
+
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QT3DS_ENABLE_LIGHT_PROBE
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, roughness, roughness, scatter_reflect );
+
+#else
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, roughness, roughness );
+
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+ return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QT3DS_ENABLE_LIGHT_PROBE
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+ return( false ? 1.0 : luminance( vec3( 1, 1, 1 ) ) );
+}
+
+float evalCutout()
+{
+ return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+ return( normal );
+}
+
+void computeTemporaries()
+{
+ tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+ vec4 color;
+ color = fresnelLayer( normal, vec3( 25.65, 25.65, 25.65 ), 1.000000, metal_color.rgb, layers[0].layer, layers[0].base, alpha );
+ return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+ // clear layers
+ layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+ layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+ layers[0].tanFrame = orthoNormalize( mat3( tangent, cross(normal, tangent), normal ) );
+}
+
+ </FragmentShader>
+ </Shader>
+ </Shaders>
+<Passes >
+ <ShaderKey value="4"/>
+ <LayerKey count="1"/>
+ <Pass >
+ </Pass>
+</Passes>
+</Material>
diff --git a/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip b/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip
new file mode 100644
index 0000000..f8fae90
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<UIP version="6" >
+ <Project >
+ <ProjectSettings author="" company="" presentationWidth="600" presentationHeight="600" maintainAspect="False" preferKtx="False" >
+ <CustomColors count="16" >#7391ff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors>
+ </ProjectSettings>
+ <Graph >
+ <Scene id="Scene" >
+ <Layer id="Layer" variants="" >
+ <Camera id="Camera" />
+ <Light id="Light" >
+ <Model id="Sphere" variants="" >
+ <Material id="Default_animatable" />
+ </Model>
+ </Light>
+ <Model id="Cube" variants="" >
+ <Material id="Basic Green_animatable" />
+ </Model>
+ <Model id="Cube2" variants="" >
+ <Material id="Basic Red_animatable" />
+ </Model>
+ </Layer>
+ </Scene>
+ </Graph>
+ <Logic >
+ <State name="Master Slide" component="#Scene" >
+ <Add ref="#Layer" background="SolidColor" backgroundcolor="0.584314 0.0941176 0.34902 1" />
+ <Add ref="#Camera" />
+ <Add ref="#Light" brightness="400" lighttype="Point" >
+ <AnimationTrack property="position.x" type="EaseInOut" >0 -341.785 100 100 5 269.972 100 100</AnimationTrack>
+ <AnimationTrack property="position.y" type="EaseInOut" >0 0 100 100 5 0 100 100</AnimationTrack>
+ <AnimationTrack property="position.z" type="EaseInOut" >0 0 100 100 5 0 100 100</AnimationTrack>
+ </Add>
+ <State id="Scene-Slide1" name="Slide1" playmode="Play Through To..." >
+ <Set ref="#Layer" endtime="5000" >
+ <Action id="Layer-Action" eyeball="True" triggerObject="#Scene" event="onPressureDown" targetObject="#Scene" handler="Next Slide" />
+ </Set>
+ <Set ref="#Camera" endtime="5000" />
+ <Set ref="#Light" endtime="5000" />
+ <Add ref="#Sphere" name="Sphere" endtime="5000" scale="0.1 0.1 0.1" sourcepath="#Sphere" />
+ <Add ref="#Default_animatable" name="Default_animatable" blendmode="Normal" bumpamount="0.5" diffuse="1 1 0 1" diffuselightwrap="0" displaceamount="20" emissivecolor="1 1 1 1" emissivepower="0" fresnelPower="0" importfile="" importid="" ior="1.5" opacity="100" shaderlighting="None" sourcepath="" specularamount="0" specularmodel="Default" specularroughness="0" speculartint="1 1 1 1" translucentfalloff="1" type="Material" vertexcolors="False" />
+ <Add ref="#Cube" name="Cube" endtime="5000" position="-458.877 -70.3589 600" sourcepath="#Cube" >
+ <AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 1 0 100 100 4 0 100 100 5 90 100 100 7 90 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 1 0 100 100 4 90 100 100 5 0 100 100 7 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="rotation.z" type="EaseInOut" >0 0 100 100 1 -90 100 100 4 -90 100 100 5 -90 100 100 7 0 100 100 10 0 100 100</AnimationTrack>
+ <AnimationTrack property="scale.x" type="EaseInOut" >0 1 100 100 2 1.5 100 100 3 1.5 100 100 6 2 100 100 7 1 100 100 8 1 100 100 9 1 100 100</AnimationTrack>
+ <AnimationTrack property="scale.y" type="EaseInOut" >0 1 100 100 2 1.5 100 100 3 1.5 100 100 6 2 100 100 7 2 100 100 8 1 100 100 9 1 100 100</AnimationTrack>
+ <AnimationTrack property="scale.z" type="EaseInOut" >0 1 100 100 2 1 100 100 3 1.5 100 100 6 2 100 100 7 2 100 100 8 2 100 100 9 1 100 100</AnimationTrack>
+ </Add>
+ <Add ref="#Basic Green_animatable" name="Basic Green_animatable" blendmode="Normal" bumpamount="0.5" diffuse="0.180392 1 0 1" diffuselightwrap="0" displaceamount="20" emissivecolor="1 1 1 1" emissivepower="0" fresnelPower="0" importfile="" importid="" ior="1.5" opacity="100" shaderlighting="Pixel" sourcepath="" specularamount="0" specularmodel="Default" specularroughness="0" speculartint="1 1 1 1" translucentfalloff="1" type="Material" vertexcolors="False" />
+ </State>
+ <State id="Scene-Slide2" name="Slide2" playmode="Play Through To..." playthroughto="Previous" >
+ <Set ref="#Layer" endtime="5000" />
+ <Set ref="#Camera" endtime="5000" />
+ <Set ref="#Light" endtime="5000" />
+ <Add ref="#Cube2" name="Cube2" endtime="5000" position="-401.836 -18.4752 600" scale="3 3 3" sourcepath="#Cube" />
+ <Add ref="#Basic Red_animatable" name="Basic Red_animatable" blendmode="Normal" bumpamount="0.5" diffuse="1 0 0.0156863 1" diffuselightwrap="0" displaceamount="20" emissivecolor="1 1 1 1" emissivepower="0" fresnelPower="0" importfile="" importid="" ior="1.5" opacity="100" shaderlighting="Pixel" sourcepath="" specularamount="0" specularmodel="Default" specularroughness="0" speculartint="1 1 1 1" translucentfalloff="1" type="Material" vertexcolors="False" />
+ </State>
+ </State>
+ </Logic>
+ </Project>
+</UIP>
diff --git a/tests/scenes/simple_cube_animation/simple_cube_animation.uia b/tests/scenes/simple_cube_animation/simple_cube_animation.uia
new file mode 100644
index 0000000..ca2d770
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/simple_cube_animation.uia
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8'?>
+<application xmlns="http://qt.io/qt3dstudio/uia">
+ <assets initial="simple_cube_animation">
+ <presentation id="simple_cube_animation" src="presentations/simple_cube_animation.uip"/>
+ <dataInput metadata="" name="newDataInput" type="Float"/>
+ </assets>
+ <statemachine ref="#logic">
+ <visual-states>
+ <state ref="Initial">
+ <enter>
+ <goto-slide rel="next" element="main:Scene"/>
+ </enter>
+ </state>
+ </visual-states>
+ </statemachine>
+</application>
diff --git a/tests/tests.pro b/tests/tests.pro
index 9671085..c458bbb 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -1 +1,4 @@
TEMPLATE = subdirs
+
+!package: SUBDIRS += \
+ auto
diff --git a/tools/viewer/main.cpp b/tools/viewer/main.cpp
index 12abd3b..ba06346 100644
--- a/tools/viewer/main.cpp
+++ b/tools/viewer/main.cpp
@@ -265,6 +265,9 @@ int main(int argc, char *argv[])
QString extraImportPath2(QStringLiteral("%1/../../../../qml"));
engine.addImportPath(extraImportPath2.arg(QGuiApplication::applicationDirPath()));
#endif
+ // Add import path for running viewer without having to install it during development
+ QString extraImportPath3(QStringLiteral("%1/../qml"));
+ engine.addImportPath(extraImportPath3.arg(QGuiApplication::applicationDirPath()));
QQmlContext *ctx = engine.rootContext();
ctx->setContextProperty(QStringLiteral("_menuBackgroundColor"), QColor("#404244"));
diff --git a/tools/viewer/qml/main.qml b/tools/viewer/qml/main.qml
index 1357f39..258a539 100644
--- a/tools/viewer/qml/main.qml
+++ b/tools/viewer/qml/main.qml
@@ -46,9 +46,8 @@ ApplicationWindow {
property string error
property int previousVisibility
- property color showMatteColor: Qt.rgba(0.2, 0.2, 0.2, 1)
- property color hideMatteColor: Qt.rgba(0, 0, 0, 1)
- property color matteColor: hideMatteColor
+ property bool matteEnabled: false
+ property color matteColor: Qt.rgba(0.2, 0.2, 0.2, 1)
property bool showRenderStats: false
property int scaleMode: ViewerSettings.ScaleModeCenter
@@ -212,6 +211,7 @@ ApplicationWindow {
focus: true
ViewerSettings {
+ matteEnabled: window.matteEnabled
matteColor: window.matteColor
showRenderStats: window.showRenderStats
scaleMode: window.scaleMode
@@ -489,14 +489,10 @@ ApplicationWindow {
text: qsTr("Show Matte")
shortcut: "Ctrl+D"
enabled: _viewerHelper.contentView === ViewerHelper.StudioView
- showCheckMark: window.matteColor !== window.hideMatteColor
+ showCheckMark: window.matteEnabled
onTriggered: {
- if (enabled) {
- if (window.matteColor === window.hideMatteColor)
- window.matteColor = window.showMatteColor;
- else
- window.matteColor = window.hideMatteColor;
- }
+ if (enabled)
+ window.matteEnabled = !window.matteEnabled
}
}
StyledMenuItem {