summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--config.tests/assimp/assimp.pro7
-rw-r--r--configure.json5
-rw-r--r--examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.pro33
-rw-r--r--examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.qrc12
-rw-r--r--examples/qt3d/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc53
-rw-r--r--examples/qt3d/deferred-renderer-cpp/final_gl2.frag36
-rw-r--r--examples/qt3d/deferred-renderer-cpp/final_gl2.vert9
-rw-r--r--examples/qt3d/deferred-renderer-cpp/final_gl3.frag37
-rw-r--r--examples/qt3d/deferred-renderer-cpp/final_gl3.vert9
-rw-r--r--examples/qt3d/deferred-renderer-cpp/finaleffect.cpp101
-rw-r--r--examples/qt3d/deferred-renderer-cpp/geometry_gl2.frag12
-rw-r--r--examples/qt3d/deferred-renderer-cpp/geometry_gl2.vert21
-rw-r--r--examples/qt3d/deferred-renderer-cpp/geometry_gl3.frag16
-rw-r--r--examples/qt3d/deferred-renderer-cpp/geometry_gl3.vert21
-rw-r--r--examples/qt3d/deferred-renderer-cpp/sceneeffect.cpp103
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negx.webpbin34492 -> 121754 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negy.webpbin1828 -> 1926 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negz.webpbin44834 -> 147696 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posx.webpbin40882 -> 136426 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posy.webpbin19430 -> 57622 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posz.webpbin49890 -> 164564 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/night/night_negx.webpbin14968 -> 38042 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/night/night_negy.webpbin17910 -> 42278 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/night/night_negz.webpbin14172 -> 36790 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/night/night_posx.webpbin14270 -> 37092 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/night/night_posy.webpbin6858 -> 26008 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/cubemaps/night/night_posz.webpbin14744 -> 37802 bytes
-rw-r--r--examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc4
-rw-r--r--qt3d.pro3
-rw-r--r--src/3rdparty/assimp/assimp_dependency.pri11
-rw-r--r--src/3rdparty/assimp/qt_attribution.json13
-rw-r--r--src/core/aspects/qabstractaspect.cpp1
-rw-r--r--src/core/aspects/qabstractaspect.h1
-rw-r--r--src/core/aspects/qaspectengine.cpp1
-rw-r--r--src/core/aspects/qaspectfactory.cpp9
-rw-r--r--src/core/changes/qcomponentaddedchange.cpp1
-rw-r--r--src/core/changes/qcomponentremovedchange.cpp1
-rw-r--r--src/core/changes/qdynamicpropertyupdatedchange.cpp1
-rw-r--r--src/core/changes/qnodecreatedchange.cpp2
-rw-r--r--src/core/changes/qnodedestroyedchange.cpp1
-rw-r--r--src/core/changes/qpropertynodeaddedchange.cpp1
-rw-r--r--src/core/changes/qpropertynoderemovedchange.cpp1
-rw-r--r--src/core/changes/qpropertyupdatedchange.cpp1
-rw-r--r--src/core/changes/qpropertyupdatedchangebase.cpp1
-rw-r--r--src/core/changes/qpropertyvalueaddedchange.cpp1
-rw-r--r--src/core/changes/qpropertyvalueaddedchangebase.cpp1
-rw-r--r--src/core/changes/qpropertyvalueremovedchange.cpp1
-rw-r--r--src/core/changes/qpropertyvalueremovedchangebase.cpp1
-rw-r--r--src/core/changes/qscenechange.cpp1
-rw-r--r--src/core/changes/qstaticpropertyupdatedchangebase.cpp1
-rw-r--r--src/core/changes/qstaticpropertyvalueaddedchangebase.cpp1
-rw-r--r--src/core/changes/qstaticpropertyvalueremovedchangebase.cpp1
-rw-r--r--src/core/configure.json35
-rw-r--r--src/core/core.pro1
-rw-r--r--src/core/jobs/qaspectjob.cpp1
-rw-r--r--src/core/nodes/qabstractnodefactory.cpp1
-rw-r--r--src/core/nodes/qbackendnode.cpp2
-rw-r--r--src/core/nodes/qnodeid.cpp1
-rw-r--r--src/core/nodes/qnodeid.h2
-rw-r--r--src/core/qlockableobserverinterface_p.h2
-rw-r--r--src/core/qobserverinterface_p.h2
-rw-r--r--src/core/qpostman_p.h2
-rw-r--r--src/core/qscene_p.h2
-rw-r--r--src/core/qsceneobserverinterface_p.h2
-rw-r--r--src/core/qt3dcore_global.h6
-rw-r--r--src/core/resources/qframeallocator.cpp39
-rw-r--r--src/core/resources/qframeallocator_p_p.h3
-rw-r--r--src/core/transforms/qtransform.cpp1
-rw-r--r--src/doc/src/qt3d-index.qdoc15
-rw-r--r--src/doc/src/qt3d-overview.qdoc1
-rw-r--r--src/extras/defaults/qfirstpersoncameracontroller.cpp12
-rw-r--r--src/extras/defaults/qorbitcameracontroller.cpp12
-rw-r--r--src/extras/defaults/qskyboxentity.cpp11
-rw-r--r--src/extras/geometries/qconegeometry.cpp39
-rw-r--r--src/extras/geometries/qconemesh.cpp1
-rw-r--r--src/extras/geometries/qcuboidgeometry.cpp1
-rw-r--r--src/extras/geometries/qcuboidmesh.cpp1
-rw-r--r--src/extras/geometries/qcylindergeometry.cpp25
-rw-r--r--src/extras/geometries/qcylindermesh.cpp1
-rw-r--r--src/extras/geometries/qplanegeometry.cpp1
-rw-r--r--src/extras/geometries/qplanemesh.cpp1
-rw-r--r--src/extras/geometries/qspheregeometry.cpp1
-rw-r--r--src/extras/geometries/qspheremesh.cpp1
-rw-r--r--src/extras/geometries/qtorusgeometry.cpp5
-rw-r--r--src/extras/geometries/qtorusmesh.cpp1
-rw-r--r--src/input/backend/abstractaxisinput.cpp2
-rw-r--r--src/input/backend/abstractaxisinput_p.h6
-rw-r--r--src/input/backend/action.cpp2
-rw-r--r--src/input/backend/actioninput.cpp19
-rw-r--r--src/input/backend/analogaxisinput.cpp19
-rw-r--r--src/input/backend/analogaxisinput_p.h2
-rw-r--r--src/input/backend/axis.cpp2
-rw-r--r--src/input/backend/backend.pri9
-rw-r--r--src/input/backend/buttonaxisinput.cpp39
-rw-r--r--src/input/backend/buttonaxisinput_p.h5
-rw-r--r--src/input/backend/handle_types_p.h2
-rw-r--r--src/input/backend/inputchord.cpp3
-rw-r--r--src/input/backend/inputhandler.cpp13
-rw-r--r--src/input/backend/inputhandler_p.h6
-rw-r--r--src/input/backend/inputmanagers_p.h17
-rw-r--r--src/input/backend/inputsequence.cpp3
-rw-r--r--src/input/backend/job_common_p.h3
-rw-r--r--src/input/backend/loadproxydevicejob.cpp97
-rw-r--r--src/input/backend/loadproxydevicejob_p.h89
-rw-r--r--src/input/backend/mousedevice.cpp25
-rw-r--r--src/input/backend/mousedevice_p.h45
-rw-r--r--src/input/backend/physicaldeviceproxy.cpp141
-rw-r--r--src/input/backend/physicaldeviceproxy_p.h109
-rw-r--r--src/input/backend/updateaxisactionjob.cpp71
-rw-r--r--src/input/backend/updateaxisactionjob_p.h4
-rw-r--r--src/input/backend/utils_p.h103
-rw-r--r--src/input/frontend/frontend.pri7
-rw-r--r--src/input/frontend/qabstractaxisinput.cpp1
-rw-r--r--src/input/frontend/qabstractphysicaldeviceproxy.cpp234
-rw-r--r--src/input/frontend/qabstractphysicaldeviceproxy_p.h105
-rw-r--r--src/input/frontend/qabstractphysicaldeviceproxy_p_p.h88
-rw-r--r--src/input/frontend/qaction.cpp2
-rw-r--r--src/input/frontend/qanalogaxisinput.cpp1
-rw-r--r--src/input/frontend/qaxis.cpp2
-rw-r--r--src/input/frontend/qaxisaccumulator.h2
-rw-r--r--src/input/frontend/qbuttonaxisinput.cpp1
-rw-r--r--src/input/frontend/qinputaspect.cpp25
-rw-r--r--src/input/frontend/qinputsettings.cpp8
-rw-r--r--src/input/frontend/qinputsettings.h2
-rw-r--r--src/input/frontend/qinputsettings_p.h1
-rw-r--r--src/input/frontend/qmousedevice.cpp24
-rw-r--r--src/input/frontend/qmousedevice.h5
-rw-r--r--src/input/frontend/qmouseevent.cpp2
-rw-r--r--src/input/frontend/qmouseevent.h12
-rw-r--r--src/input/frontend/qmousehandler.cpp1
-rw-r--r--src/logic/logic.pro1
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.cpp2
-rw-r--r--src/plugins/sceneparsers/gltf/gltfparser.cpp1560
-rw-r--r--src/quick3d/imports/render/plugins.qmltypes2
-rw-r--r--src/quick3d/imports/render/qt3dquick3drenderplugin.cpp2
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp18
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem_p.h2
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer.cpp55
-rw-r--r--src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp6
-rw-r--r--src/quick3d/quick3d/qqmlaspectengine.cpp1
-rw-r--r--src/quick3d/quick3d/qquaternionanimation_p.h2
-rw-r--r--src/quick3d/quick3d/quick3d.pro1
-rw-r--r--src/quick3d/quick3dextras/qt3dquickwindow.h2
-rw-r--r--src/quick3d/quick3dextras/quick3dextras.pro1
-rw-r--r--src/quick3d/quick3dinput/quick3dinput.pro1
-rw-r--r--src/quick3d/quick3drender/items/quick3dshaderdata_p.h2
-rw-r--r--src/quick3d/quick3drender/items/quick3dshaderdataarray_p.h2
-rw-r--r--src/quick3d/quick3drender/quick3drender.pro1
-rw-r--r--src/render/backend/managers_p.h73
-rw-r--r--src/render/backend/nodemanagers.cpp8
-rw-r--r--src/render/backend/nodemanagers_p.h8
-rw-r--r--src/render/backend/render-backend.pri6
-rw-r--r--src/render/backend/renderer.cpp155
-rw-r--r--src/render/backend/renderer_p.h17
-rw-r--r--src/render/backend/rendertarget_p.h2
-rw-r--r--src/render/backend/renderview.cpp7
-rw-r--r--src/render/backend/renderviewbuilder.cpp510
-rw-r--r--src/render/backend/renderviewbuilder_p.h133
-rw-r--r--src/render/backend/transform.cpp24
-rw-r--r--src/render/backend/transform_p.h7
-rw-r--r--src/render/backend/triangleboundingvolume_p.h2
-rw-r--r--src/render/backend/uniform.cpp71
-rw-r--r--src/render/backend/uniform_p.h2
-rw-r--r--src/render/framegraph/framegraphvisitor.cpp289
-rw-r--r--src/render/framegraph/qclearbuffers.h2
-rw-r--r--src/render/framegraph/qdispatchcompute.cpp42
-rw-r--r--src/render/framegraph/qframegraphnode.cpp12
-rw-r--r--src/render/framegraph/qfrustumculling.cpp33
-rw-r--r--src/render/framegraph/qnodraw.cpp83
-rw-r--r--src/render/framegraph/qrendercapture.cpp2
-rw-r--r--src/render/framegraph/qrendercapture_p.h2
-rw-r--r--src/render/framegraph/qrenderstateset.cpp1
-rw-r--r--src/render/framegraph/qrendersurfaceselector.cpp10
-rw-r--r--src/render/framegraph/qrendertargetselector.cpp73
-rw-r--r--src/render/framegraph/qrendertargetselector.h2
-rw-r--r--src/render/framegraph/qsortcriterion.h2
-rw-r--r--src/render/framegraph/qsortpolicy.h2
-rw-r--r--src/render/framegraph/rendercapture.cpp9
-rw-r--r--src/render/framegraph/rendercapture_p.h3
-rw-r--r--src/render/frontend/qcamera.cpp1
-rw-r--r--src/render/frontend/qcamera.h2
-rw-r--r--src/render/frontend/qcameralens.cpp1
-rw-r--r--src/render/frontend/qcameralens.h2
-rw-r--r--src/render/frontend/qcomputecommand.cpp82
-rw-r--r--src/render/frontend/qpickingsettings.cpp2
-rw-r--r--src/render/frontend/qpickingsettings.h8
-rw-r--r--src/render/frontend/qrenderaspect.cpp24
-rw-r--r--src/render/frontend/qrendersettings.cpp8
-rw-r--r--src/render/frontend/qrendersettings.h2
-rw-r--r--src/render/frontend/qrendertarget.cpp49
-rw-r--r--src/render/frontend/qrendertargetoutput.cpp174
-rw-r--r--src/render/frontend/qrendertargetoutput.h4
-rw-r--r--src/render/frontend/sphere_p.h2
-rw-r--r--src/render/geometry/geometryrenderer.cpp2
-rw-r--r--src/render/geometry/qattribute.cpp3
-rw-r--r--src/render/geometry/qattribute.h9
-rw-r--r--src/render/geometry/qbuffer.cpp90
-rw-r--r--src/render/geometry/qbuffer.h4
-rw-r--r--src/render/geometry/qbuffer_p.h2
-rw-r--r--src/render/geometry/qbufferdatagenerator.h2
-rw-r--r--src/render/geometry/qgeometry.cpp5
-rw-r--r--src/render/geometry/qgeometryfactory.h2
-rw-r--r--src/render/geometry/qgeometryrenderer.cpp1
-rw-r--r--src/render/geometry/qgeometryrenderer.h2
-rw-r--r--src/render/geometry/qmesh.cpp19
-rw-r--r--src/render/geometry/qmesh_p.h15
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp376
-rw-r--r--src/render/graphicshelpers/graphicscontext_p.h35
-rw-r--r--src/render/graphicshelpers/graphicshelperes2.cpp23
-rw-r--r--src/render/graphicshelpers/graphicshelperes2_p.h1
-rw-r--r--src/render/graphicshelpers/graphicshelperes3.cpp14
-rw-r--r--src/render/graphicshelpers/graphicshelperes3_p.h1
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2.cpp23
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2_p.h1
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2.cpp6
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2_p.h1
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3.cpp8
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3_p.h1
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4.cpp8
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4_p.h1
-rw-r--r--src/render/graphicshelpers/graphicshelperinterface_p.h4
-rw-r--r--src/render/io/objloader.cpp15
-rw-r--r--src/render/io/qsceneimporter_p.h2
-rw-r--r--src/render/io/qsceneloader.h2
-rw-r--r--src/render/jobs/filtercompatibletechniquejob.cpp96
-rw-r--r--src/render/jobs/filtercompatibletechniquejob_p.h92
-rw-r--r--src/render/jobs/filterlayerentityjob_p.h6
-rw-r--r--src/render/jobs/framecleanupjob.cpp4
-rw-r--r--src/render/jobs/frustumcullingjob_p.h2
-rw-r--r--src/render/jobs/job_common_p.h6
-rw-r--r--src/render/jobs/jobs.pri14
-rw-r--r--src/render/jobs/loadgeometryjob_p.h2
-rw-r--r--src/render/jobs/loadtexturedatajob.cpp163
-rw-r--r--src/render/jobs/loadtexturedatajob_p.h11
-rw-r--r--src/render/jobs/materialparametergathererjob_p.h3
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp762
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h24
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp268
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h166
-rw-r--r--src/render/jobs/renderviewinitializerjob_p.h2
-rw-r--r--src/render/jobs/renderviewjobutils.cpp8
-rw-r--r--src/render/jobs/renderviewjobutils_p.h3
-rw-r--r--src/render/jobs/sendrendercapturejob_p.h1
-rw-r--r--src/render/jobs/updatemeshtrianglelistjob.cpp126
-rw-r--r--src/render/jobs/updatemeshtrianglelistjob_p.h88
-rw-r--r--src/render/jobs/updateshaderdatatransformjob.cpp (renamed from src/render/jobs/framepreparationjob.cpp)67
-rw-r--r--src/render/jobs/updateshaderdatatransformjob_p.h (renamed from src/render/jobs/framepreparationjob_p.h)21
-rw-r--r--src/render/lights/light_p.h2
-rw-r--r--src/render/lights/qabstractlight.h2
-rw-r--r--src/render/materialsystem/effect.cpp2
-rw-r--r--src/render/materialsystem/effect_p.h2
-rw-r--r--src/render/materialsystem/filterkey.cpp11
-rw-r--r--src/render/materialsystem/filterkey_p.h6
-rw-r--r--src/render/materialsystem/materialsystem.pri6
-rw-r--r--src/render/materialsystem/parameter.cpp8
-rw-r--r--src/render/materialsystem/parameter_p.h5
-rw-r--r--src/render/materialsystem/qgraphicsapifilter.h4
-rw-r--r--src/render/materialsystem/qgraphicsapifilter_p.h6
-rw-r--r--src/render/materialsystem/qparameter.cpp1
-rw-r--r--src/render/materialsystem/qshaderdata.cpp1
-rw-r--r--src/render/materialsystem/qshaderdata.h4
-rw-r--r--src/render/materialsystem/qshaderprogram.h2
-rw-r--r--src/render/materialsystem/renderpass.cpp1
-rw-r--r--src/render/materialsystem/shaderdata_p.h2
-rw-r--r--src/render/materialsystem/technique.cpp85
-rw-r--r--src/render/materialsystem/technique_p.h24
-rw-r--r--src/render/materialsystem/techniquemanager.cpp68
-rw-r--r--src/render/materialsystem/techniquemanager_p.h87
-rw-r--r--src/render/picking/qpickevent.cpp3
-rw-r--r--src/render/picking/qpickevent.h6
-rw-r--r--src/render/picking/qpicktriangleevent.cpp12
-rw-r--r--src/render/raycasting/qabstractcollisionqueryservice_p.h2
-rw-r--r--src/render/raycasting/qboundingvolume_p.h2
-rw-r--r--src/render/raycasting/qray3d_p.h2
-rw-r--r--src/render/render.pro1
-rw-r--r--src/render/renderstates/qalphacoverage.cpp42
-rw-r--r--src/render/renderstates/qalphatest.cpp98
-rw-r--r--src/render/renderstates/qalphatest.h2
-rw-r--r--src/render/renderstates/qblendequation.cpp1
-rw-r--r--src/render/renderstates/qblendequation.h2
-rw-r--r--src/render/renderstates/qblendequationarguments.cpp3
-rw-r--r--src/render/renderstates/qblendequationarguments.h5
-rw-r--r--src/render/renderstates/qclipplane.cpp48
-rw-r--r--src/render/renderstates/qcolormask.cpp43
-rw-r--r--src/render/renderstates/qcullface.cpp72
-rw-r--r--src/render/renderstates/qcullface.h2
-rw-r--r--src/render/renderstates/qdepthtest.cpp89
-rw-r--r--src/render/renderstates/qdepthtest.h2
-rw-r--r--src/render/renderstates/qdithering.cpp32
-rw-r--r--src/render/renderstates/qfrontface.cpp62
-rw-r--r--src/render/renderstates/qfrontface.h2
-rw-r--r--src/render/renderstates/qmultisampleantialiasing.cpp30
-rw-r--r--src/render/renderstates/qnodepthmask.cpp32
-rw-r--r--src/render/renderstates/qpointsize.cpp24
-rw-r--r--src/render/renderstates/qpointsize.h2
-rw-r--r--src/render/renderstates/qpolygonoffset.cpp77
-rw-r--r--src/render/renderstates/qrenderstate.cpp24
-rw-r--r--src/render/renderstates/qrenderstatecreatedchange.cpp2
-rw-r--r--src/render/renderstates/qscissortest.cpp109
-rw-r--r--src/render/renderstates/qseamlesscubemap.cpp31
-rw-r--r--src/render/renderstates/qstencilmask.cpp80
-rw-r--r--src/render/renderstates/qstenciloperation.cpp68
-rw-r--r--src/render/renderstates/qstenciloperationarguments.cpp152
-rw-r--r--src/render/renderstates/qstenciloperationarguments.h4
-rw-r--r--src/render/renderstates/qstenciltest.cpp63
-rw-r--r--src/render/renderstates/qstenciltestarguments.cpp134
-rw-r--r--src/render/renderstates/qstenciltestarguments.h4
-rw-r--r--src/render/renderstates/statevariant_p.h8
-rw-r--r--src/render/texture/apitexturemanager_p.h376
-rw-r--r--src/render/texture/gltexture.cpp413
-rw-r--r--src/render/texture/gltexture_p.h196
-rw-r--r--src/render/texture/gltexturemanager_p.h79
-rw-r--r--src/render/texture/qabstracttexture.cpp11
-rw-r--r--src/render/texture/qabstracttexture.h16
-rw-r--r--src/render/texture/qabstracttexture_p.h5
-rw-r--r--src/render/texture/qabstracttextureimage.cpp2
-rw-r--r--src/render/texture/qtexture.cpp18
-rw-r--r--src/render/texture/qtexture_p.h6
-rw-r--r--src/render/texture/qtexturedata.cpp1
-rw-r--r--src/render/texture/qtexturegenerator.h2
-rw-r--r--src/render/texture/qtextureimage.cpp38
-rw-r--r--src/render/texture/qtextureimage.h2
-rw-r--r--src/render/texture/qtextureimage_p.h9
-rw-r--r--src/render/texture/qtextureimagedatagenerator.h2
-rw-r--r--src/render/texture/qtexturewrapmode.h2
-rw-r--r--src/render/texture/texture.cpp766
-rw-r--r--src/render/texture/texture.pri9
-rw-r--r--src/render/texture/texture_p.h162
-rw-r--r--src/render/texture/texturedatamanager.cpp172
-rw-r--r--src/render/texture/texturedatamanager_p.h175
-rw-r--r--src/render/texture/textureimage.cpp109
-rw-r--r--src/render/texture/textureimage_p.h54
-rw-r--r--sync.profile13
-rw-r--r--tests/auto/core/common/common.pri6
-rw-r--r--tests/auto/core/common/testpostmanarbiter.cpp (renamed from tests/auto/render/commons/testpostmanarbiter.cpp)0
-rw-r--r--tests/auto/core/common/testpostmanarbiter.h (renamed from tests/auto/render/commons/testpostmanarbiter.h)0
-rw-r--r--tests/auto/core/qtransform/qtransform.pro2
-rw-r--r--tests/auto/extras/extras.pro11
-rw-r--r--tests/auto/extras/qfirstpersoncameracontroller/qfirstpersoncameracontroller.pro9
-rw-r--r--tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp129
-rw-r--r--tests/auto/extras/qforwardrenderer/qforwardrenderer.pro9
-rw-r--r--tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp172
-rw-r--r--tests/auto/extras/qorbitcameracontroller/qorbitcameracontroller.pro10
-rw-r--r--tests/auto/extras/qorbitcameracontroller/tst_qorbitcameracontroller.cpp149
-rw-r--r--tests/auto/input/abstractaxisinput/tst_abstractaxisinput.cpp7
-rw-r--r--tests/auto/input/action/action.pro1
-rw-r--r--tests/auto/input/action/tst_action.cpp17
-rw-r--r--tests/auto/input/actioninput/tst_actioninput.cpp24
-rw-r--r--tests/auto/input/analogaxisinput/tst_analogaxisinput.cpp72
-rw-r--r--tests/auto/input/axis/axis.pro1
-rw-r--r--tests/auto/input/axis/tst_axis.cpp17
-rw-r--r--tests/auto/input/buttonaxisinput/tst_buttonaxisinput.cpp84
-rw-r--r--tests/auto/input/commons/commons.pri3
-rw-r--r--tests/auto/input/commons/testdevice.h5
-rw-r--r--tests/auto/input/commons/testdeviceproxy.h115
-rw-r--r--tests/auto/input/input.pro9
-rw-r--r--tests/auto/input/inputchord/tst_inputchord.cpp39
-rw-r--r--tests/auto/input/inputsequence/tst_inputsequence.cpp47
-rw-r--r--tests/auto/input/loadproxydevicejob/loadproxydevicejob.pro11
-rw-r--r--tests/auto/input/loadproxydevicejob/tst_loadproxydevicejob.cpp186
-rw-r--r--tests/auto/input/logicaldevice/logicaldevice.pro11
-rw-r--r--tests/auto/input/logicaldevice/tst_logicaldevice.cpp188
-rw-r--r--tests/auto/input/mousedevice/mousedevice.pro11
-rw-r--r--tests/auto/input/mousedevice/tst_mousedevice.cpp253
-rw-r--r--tests/auto/input/physicaldeviceproxy/physicaldeviceproxy.pro11
-rw-r--r--tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp155
-rw-r--r--tests/auto/input/qabstractaxisinput/qabstractaxisinput.pro1
-rw-r--r--tests/auto/input/qabstractphysicaldeviceproxy/qabstractphysicaldeviceproxy.pro11
-rw-r--r--tests/auto/input/qabstractphysicaldeviceproxy/tst_qabstractphysicaldeviceproxy.cpp160
-rw-r--r--tests/auto/input/qaction/qaction.pro2
-rw-r--r--tests/auto/input/qactioninput/qactioninput.pro1
-rw-r--r--tests/auto/input/qanalogaxisinput/qanalogaxisinput.pro1
-rw-r--r--tests/auto/input/qaxis/qaxis.pro2
-rw-r--r--tests/auto/input/qaxisaccumulator/qaxisaccumulator.pro2
-rw-r--r--tests/auto/input/qbuttonaxisinput/qbuttonaxisinput.pro1
-rw-r--r--tests/auto/input/qkeyboardhandler/qkeyboardhandler.pro1
-rw-r--r--tests/auto/input/qlogicaldevice/qlogicaldevice.pro2
-rw-r--r--tests/auto/input/qmousedevice/qmousedevice.pro11
-rw-r--r--tests/auto/input/qmousedevice/tst_qmousedevice.cpp191
-rw-r--r--tests/auto/input/utils/tst_utils.cpp228
-rw-r--r--tests/auto/input/utils/utils.pro11
-rw-r--r--tests/auto/quick3d/quick3dnodeinstantiator/data/createMultiple.qml12
-rw-r--r--tests/auto/quick3d/quick3dnodeinstantiator/data/createNone.qml16
-rw-r--r--tests/auto/quick3d/quick3dnodeinstantiator/data/createSingle.qml10
-rw-r--r--tests/auto/quick3d/quick3dnodeinstantiator/data/inactive.qml12
-rw-r--r--tests/auto/quick3d/quick3dnodeinstantiator/data/stringModel.qml12
-rw-r--r--tests/auto/quick3d/quick3dnodeinstantiator/tst_quick3dnodeinstantiator.cpp34
-rw-r--r--tests/auto/render/commons/commons.pri2
-rw-r--r--tests/auto/render/computecommand/computecommand.pro12
-rw-r--r--tests/auto/render/computecommand/tst_computecommand.cpp160
-rw-r--r--tests/auto/render/effect/effect.pro12
-rw-r--r--tests/auto/render/effect/tst_effect.cpp189
-rw-r--r--tests/auto/render/filterkey/filterkey.pro12
-rw-r--r--tests/auto/render/filterkey/tst_filterkey.cpp194
-rw-r--r--tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp8
-rw-r--r--tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp75
-rw-r--r--tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp251
-rw-r--r--tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp246
-rw-r--r--tests/auto/render/materialparametergathererjob/materialparametergathererjob.pro11
-rw-r--r--tests/auto/render/materialparametergathererjob/tst_materialparametergathererjob.cpp459
-rw-r--r--tests/auto/render/parameter/parameter.pro12
-rw-r--r--tests/auto/render/parameter/tst_parameter.cpp157
-rw-r--r--tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.pro17
-rw-r--r--tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc9
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_childentity.qml127
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_dragdisabled.qml131
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_dragenabled.qml131
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_dragenabledhoverenabled.qml (renamed from examples/qt3d/deferred-renderer-cpp/gbuffer.cpp)129
-rw-r--r--tests/auto/render/pickboundingvolumejob/testscene_improperframegraph.qml114
-rw-r--r--tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp985
-rw-r--r--tests/auto/render/qabstractlight/qabstractlight.pro2
-rw-r--r--tests/auto/render/qabstracttexture/qabstracttexture.pro12
-rw-r--r--tests/auto/render/qabstracttexture/tst_qabstracttexture.cpp889
-rw-r--r--tests/auto/render/qabstracttextureimage/qabstracttextureimage.pro12
-rw-r--r--tests/auto/render/qabstracttextureimage/tst_qabstracttextureimage.cpp296
-rw-r--r--tests/auto/render/qattribute/qattribute.pro1
-rw-r--r--tests/auto/render/qattribute/tst_qattribute.cpp23
-rw-r--r--tests/auto/render/qbuffer/qbuffer.pro1
-rw-r--r--tests/auto/render/qcameraselector/qcameraselector.pro2
-rw-r--r--tests/auto/render/qclearbuffers/qclearbuffers.pro2
-rw-r--r--tests/auto/render/qdispatchcompute/qdispatchcompute.pro12
-rw-r--r--tests/auto/render/qdispatchcompute/tst_qdispatchcompute.cpp282
-rw-r--r--tests/auto/render/qeffect/qeffect.pro12
-rw-r--r--tests/auto/render/qeffect/tst_qeffect.cpp290
-rw-r--r--tests/auto/render/qfilterkey/qfilterkey.pro12
-rw-r--r--tests/auto/render/qfilterkey/tst_qfilterkey.cpp226
-rw-r--r--tests/auto/render/qframegraphnode/qframegraphnode.pro2
-rw-r--r--tests/auto/render/qgeometry/qgeometry.pro1
-rw-r--r--tests/auto/render/qgeometryrenderer/qgeometryrenderer.pro2
-rw-r--r--tests/auto/render/qlayerfilter/qlayerfilter.pro2
-rw-r--r--tests/auto/render/qmaterial/qmaterial.pro1
-rw-r--r--tests/auto/render/qmesh/qmesh.pro12
-rw-r--r--tests/auto/render/qmesh/tst_qmesh.cpp230
-rw-r--r--tests/auto/render/qmlscenereader/qmlscenereader.cpp84
-rw-r--r--tests/auto/render/qmlscenereader/qmlscenereader.h63
-rw-r--r--tests/auto/render/qmlscenereader/qmlscenereader.pri7
-rw-r--r--tests/auto/render/qobjectpicker/qobjectpicker.pro2
-rw-r--r--tests/auto/render/qparameter/qparameter.pro11
-rw-r--r--tests/auto/render/qparameter/tst_qparameter.cpp256
-rw-r--r--tests/auto/render/qrendercapture/qrendercapture.pro1
-rw-r--r--tests/auto/render/qrenderpass/qrenderpass.pro12
-rw-r--r--tests/auto/render/qrenderpass/tst_qrenderpass.cpp452
-rw-r--r--tests/auto/render/qrenderpassfilter/qrenderpassfilter.pro2
-rw-r--r--tests/auto/render/qrendersettings/qrendersettings.pro12
-rw-r--r--tests/auto/render/qrendersettings/tst_qrendersettings.cpp417
-rw-r--r--tests/auto/render/qrenderstateset/qrenderstateset.pro2
-rw-r--r--tests/auto/render/qrendersurfaceselector/qrendersurfaceselector.pro1
-rw-r--r--tests/auto/render/qrendersurfaceselector/tst_qrendersurfaceselector.cpp249
-rw-r--r--tests/auto/render/qrendertarget/qrendertarget.pro12
-rw-r--r--tests/auto/render/qrendertarget/tst_qrendertarget.cpp198
-rw-r--r--tests/auto/render/qrendertargetselector/qrendertargetselector.pro2
-rw-r--r--tests/auto/render/qsceneloader/qsceneloader.pro2
-rw-r--r--tests/auto/render/qsortpolicy/qsortpolicy.pro2
-rw-r--r--tests/auto/render/qtechnique/qtechnique.pro12
-rw-r--r--tests/auto/render/qtechnique/tst_qtechnique.cpp507
-rw-r--r--tests/auto/render/qtechniquefilter/qtechniquefilter.pro2
-rw-r--r--tests/auto/render/qtextureimage/qtextureimage.pro12
-rw-r--r--tests/auto/render/qtextureimage/tst_qtextureimage.cpp240
-rw-r--r--tests/auto/render/qtextureimagedata/qtextureimagedata.pro2
-rw-r--r--tests/auto/render/qtextureloader/qtextureloader.pro12
-rw-r--r--tests/auto/render/qtextureloader/tst_qtextureloader.cpp228
-rw-r--r--tests/auto/render/qviewport/qviewport.pro2
-rw-r--r--tests/auto/render/render.pro29
-rw-r--r--tests/auto/render/renderpass/tst_renderpass.cpp57
-rw-r--r--tests/auto/render/rendertarget/rendertarget.pro12
-rw-r--r--tests/auto/render/rendertarget/tst_rendertarget.cpp211
-rw-r--r--tests/auto/render/sendrendercapturejob/sendrendercapturejob.pro12
-rw-r--r--tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp83
-rw-r--r--tests/auto/render/technique/technique.pro12
-rw-r--r--tests/auto/render/technique/tst_technique.cpp484
-rw-r--r--tests/auto/render/texture/tst_texture.cpp22
-rw-r--r--tests/auto/render/texturedatamanager/texturedatamanager.pro12
-rw-r--r--tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp246
-rw-r--r--tests/auto/render/textures/textures.pro11
-rw-r--r--tests/auto/render/textures/tst_textures.cpp315
-rw-r--r--tests/auto/render/transform/transform.pro12
-rw-r--r--tests/auto/render/transform/tst_transform.cpp170
-rw-r--r--tests/auto/render/uniform/tst_uniform.cpp37
-rw-r--r--tests/auto/render/updatemeshtrianglelistjob/test_scene.qml (renamed from examples/qt3d/deferred-renderer-cpp/finaleffect.h)68
-rw-r--r--tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp316
-rw-r--r--tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro18
-rw-r--r--tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc5
-rw-r--r--tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml110
-rw-r--r--tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml110
-rw-r--r--tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp228
-rw-r--r--tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.pro18
-rw-r--r--tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.qrc6
-rw-r--r--tests/benchmarks/render/jobs/tst_bench_jobs.cpp4
-rw-r--r--tests/benchmarks/render/layerfiltering/layerfiltering.pro14
-rw-r--r--tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp190
-rw-r--r--tests/benchmarks/render/render.pro3
-rw-r--r--tests/manual/additional-attributes-qml/additional-attributes-qml.pro14
-rw-r--r--tests/manual/additional-attributes-qml/additional-attributes-qml.qrc5
-rw-r--r--tests/manual/additional-attributes-qml/main.cpp (renamed from examples/qt3d/deferred-renderer-cpp/pointlightblock.cpp)27
-rw-r--r--tests/manual/additional-attributes-qml/main.qml191
-rw-r--r--tests/manual/clip-planes-qml/ClippingPlanes.qml2
-rw-r--r--tests/manual/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc21
-rw-r--r--tests/manual/manual.pro7
-rw-r--r--tests/manual/rendercapture-cpp/main.cpp192
-rw-r--r--tests/manual/rendercapture-cpp/mycapture.h112
-rw-r--r--tests/manual/rendercapture-cpp/orbittransformcontroller.cpp116
-rw-r--r--tests/manual/rendercapture-cpp/orbittransformcontroller.h (renamed from examples/qt3d/deferred-renderer-cpp/sceneeffect.h)56
-rw-r--r--tests/manual/rendercapture-cpp/rendercapture-cpp.pro13
-rw-r--r--tests/manual/rendercapture-qml/CaptureScene.qml149
-rw-r--r--tests/manual/rendercapture-qml/main.cpp (renamed from examples/qt3d/deferred-renderer-cpp/pointlightblock.h)38
-rw-r--r--tests/manual/rendercapture-qml/main.qml136
-rw-r--r--tests/manual/rendercapture-qml/qml.qrc6
-rw-r--r--tests/manual/rendercapture-qml/rendercapture-qml.pro18
-rw-r--r--tests/manual/rendercapture-qml/rendercaptureprovider.h (renamed from examples/qt3d/deferred-renderer-cpp/gbuffer.h)48
-rw-r--r--tools/qgltf/qgltf.pro1
-rw-r--r--tools/tools.pro2
512 files changed, 23766 insertions, 3962 deletions
diff --git a/.gitignore b/.gitignore
index cd1417b84..32a748504 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,3 +73,9 @@ examples/*/*/*[.]exe
# Assimp
AssimpLog.txt
+
+# Generated wrapper scripts
+*_wrapper.sh
+*_wrapper.bat
+wrapper.sh
+wrapper.bat
diff --git a/config.tests/assimp/assimp.pro b/config.tests/assimp/assimp.pro
index 712986c17..28dcadcbf 100644
--- a/config.tests/assimp/assimp.pro
+++ b/config.tests/assimp/assimp.pro
@@ -1,8 +1 @@
SOURCES += main.cpp
-
-unix:qtConfig(pkg-config) {
- CONFIG += link_pkgconfig
- PKGCONFIG += assimp
-} else {
- LIBS += -lassimp
-}
diff --git a/configure.json b/configure.json
new file mode 100644
index 000000000..40d6bfe56
--- /dev/null
+++ b/configure.json
@@ -0,0 +1,5 @@
+{
+ "subconfigs": [
+ "src/core"
+ ]
+}
diff --git a/examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.pro b/examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.pro
deleted file mode 100644
index f9f239f24..000000000
--- a/examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.pro
+++ /dev/null
@@ -1,33 +0,0 @@
-!include( ../examples.pri ) {
- error( "Couldn't find the examples.pri file!" )
-}
-
-QT += 3dcore 3drender 3dinput 3dextras
-
-HEADERS += \
- gbuffer.h \
- deferredrenderer.h \
- finaleffect.h \
- sceneeffect.h \
- pointlightblock.h
-
-SOURCES += \
- main.cpp \
- gbuffer.cpp \
- deferredrenderer.cpp \
- finaleffect.cpp \
- sceneeffect.cpp \
- pointlightblock.cpp
-
-RESOURCES += \
- deferred-renderer-cpp.qrc
-
-OTHER_FILES += \
- geometry_gl2.vert \
- geometry_gl2.frag \
- geometry_gl3.frag \
- geometry_gl3.vert \
- final_gl2.vert \
- final_gl2.frag \
- final_gl3.frag \
- final_gl3.vert
diff --git a/examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.qrc b/examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.qrc
deleted file mode 100644
index 0e38e39ca..000000000
--- a/examples/qt3d/deferred-renderer-cpp/deferred-renderer-cpp.qrc
+++ /dev/null
@@ -1,12 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>geometry_gl2.frag</file>
- <file>geometry_gl2.vert</file>
- <file>geometry_gl3.frag</file>
- <file>geometry_gl3.vert</file>
- <file>final_gl2.frag</file>
- <file>final_gl2.vert</file>
- <file>final_gl3.frag</file>
- <file>final_gl3.vert</file>
- </qresource>
-</RCC>
diff --git a/examples/qt3d/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc b/examples/qt3d/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc
deleted file mode 100644
index 610270316..000000000
--- a/examples/qt3d/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc
+++ /dev/null
@@ -1,53 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $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$
-**
-****************************************************************************/
-
-/*!
- \example deferred-renderer-cpp
- \title Qt 3D: Deferred Renderer C++ Example
- \ingroup qt3d-examples-cpp
- \brief A C++ application that demonstrates rendering to an intermediate
- G-buffer.
-
- \e {Deferred Renderer} demonstrates using a two pass rendering method.
- First, all the meshes in the scene are drawn using the same shader that will
- output the following values for each fragment: world normal vector, color,
- depth, and world position vector.
-
- Each of these values will be stored in a texture, which together form what
- is called the G-buffer. Nothing is drawn onscreen during the first pass, but
- rather drawn into the G-buffer ready for later use.
-
- Once all the meshes have been drawn, the G-buffer is filled with all the
- meshes that can currently be seen by the camera. The second render pass is
- then used to render the scene to the back buffer with the final color
- shading by reading the values from the G-buffer textures and outputting a
- color onto a full screen quad.
-
- For more information, see \l{Deferred Renderer}.
-
- \include examples-run.qdocinc
-*/
diff --git a/examples/qt3d/deferred-renderer-cpp/final_gl2.frag b/examples/qt3d/deferred-renderer-cpp/final_gl2.frag
deleted file mode 100644
index f384a2df4..000000000
--- a/examples/qt3d/deferred-renderer-cpp/final_gl2.frag
+++ /dev/null
@@ -1,36 +0,0 @@
-#version 110
-
-uniform sampler2D color;
-uniform sampler2D position;
-uniform sampler2D normal;
-uniform vec2 winSize;
-
-struct PointLight
-{
- vec3 position;
- vec3 direction;
- vec4 color;
- float intensity;
-};
-
-const int lightCount = 3;
-uniform struct
-{
- PointLight lights[lightCount];
-} pointLights;
-
-void main()
-{
- vec2 texCoord = gl_FragCoord.xy / winSize;
- vec4 col = texture2D(color, texCoord);
- vec3 pos = texture2D(position, texCoord).xyz;
- vec3 norm = texture2D(normal, texCoord).xyz;
-
- vec4 lightColor;
- for (int i = 0; i < 3; i++) {
- vec3 s = normalize(pointLights.lights[i].position - pos);
- lightColor += pointLights.lights[i].color * (pointLights.lights[i].intensity * max(dot(s, norm), 0.0));
- }
- lightColor /= float(lightCount);
- gl_FragColor = col * lightColor;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/final_gl2.vert b/examples/qt3d/deferred-renderer-cpp/final_gl2.vert
deleted file mode 100644
index a907e10ca..000000000
--- a/examples/qt3d/deferred-renderer-cpp/final_gl2.vert
+++ /dev/null
@@ -1,9 +0,0 @@
-#version 110
-
-attribute vec4 vertexPosition;
-uniform mat4 modelMatrix;
-
-void main()
-{
- gl_Position = modelMatrix * vertexPosition;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/final_gl3.frag b/examples/qt3d/deferred-renderer-cpp/final_gl3.frag
deleted file mode 100644
index 88abd5cb1..000000000
--- a/examples/qt3d/deferred-renderer-cpp/final_gl3.frag
+++ /dev/null
@@ -1,37 +0,0 @@
-#version 140
-
-uniform sampler2D color;
-uniform sampler2D position;
-uniform sampler2D normal;
-uniform vec2 winSize;
-
-out vec4 fragColor;
-
-struct PointLight
-{
- vec3 position;
- vec3 direction;
- vec4 color;
- float intensity;
-};
-
-const int lightCount = 3;
-uniform PointLightBlock {
- PointLight lights[lightCount];
-};
-
-void main()
-{
- vec2 texCoord = gl_FragCoord.xy / winSize;
- vec4 col = texture(color, texCoord);
- vec3 pos = texture(position, texCoord).xyz;
- vec3 norm = texture(normal, texCoord).xyz;
-
- vec4 lightColor;
- for (int i = 0; i < 3; i++) {
- vec3 s = normalize(lights[i].position - pos);
- lightColor += lights[i].color * (lights[i].intensity * max(dot(s, norm), 0.0));
- }
- lightColor /= float(lightCount);
- fragColor = col * lightColor;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/final_gl3.vert b/examples/qt3d/deferred-renderer-cpp/final_gl3.vert
deleted file mode 100644
index 60410d34d..000000000
--- a/examples/qt3d/deferred-renderer-cpp/final_gl3.vert
+++ /dev/null
@@ -1,9 +0,0 @@
-#version 140
-
-in vec4 vertexPosition;
-uniform mat4 modelMatrix;
-
-void main()
-{
- gl_Position = modelMatrix * vertexPosition;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/finaleffect.cpp b/examples/qt3d/deferred-renderer-cpp/finaleffect.cpp
deleted file mode 100644
index 63c821caa..000000000
--- a/examples/qt3d/deferred-renderer-cpp/finaleffect.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE: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 "finaleffect.h"
-
-#include <Qt3DRender/QGraphicsApiFilter>
-#include <Qt3DRender/QShaderProgram>
-#include <QUrl>
-
-FinalEffect::FinalEffect(Qt3DCore::QNode *parent)
- : Qt3DRender::QEffect(parent)
- , m_gl3Technique(new Qt3DRender::QTechnique())
- , m_gl2Technique(new Qt3DRender::QTechnique())
- , m_gl2Pass(new Qt3DRender::QRenderPass())
- , m_gl3Pass(new Qt3DRender::QRenderPass())
- , m_passCriterion(new Qt3DRender::QFilterKey(this))
-{
- m_gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
- m_gl3Technique->graphicsApiFilter()->setMajorVersion(3);
- m_gl3Technique->graphicsApiFilter()->setMinorVersion(1);
- m_gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);
-
- m_gl2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
- m_gl2Technique->graphicsApiFilter()->setMajorVersion(2);
- m_gl2Technique->graphicsApiFilter()->setMinorVersion(0);
- m_gl2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile);
-
- m_passCriterion->setName(QStringLiteral("pass"));
- m_passCriterion->setValue(QStringLiteral("final"));
-
- Qt3DRender::QShaderProgram *gl3Shader = new Qt3DRender::QShaderProgram();
- gl3Shader->setVertexShaderCode(gl3Shader->loadSource(QUrl(QStringLiteral("qrc:/final_gl3.vert"))));
- gl3Shader->setFragmentShaderCode(gl3Shader->loadSource(QUrl(QStringLiteral("qrc:/final_gl3.frag"))));
-
- m_gl3Pass->addFilterKey(m_passCriterion);
- m_gl3Pass->setShaderProgram(gl3Shader);
- m_gl3Technique->addRenderPass(m_gl3Pass);
-
- Qt3DRender::QShaderProgram *gl2Shader = new Qt3DRender::QShaderProgram();
- gl2Shader->setVertexShaderCode(gl2Shader->loadSource(QUrl(QStringLiteral("qrc:/final_gl2.vert"))));
- gl2Shader->setFragmentShaderCode(gl2Shader->loadSource(QUrl(QStringLiteral("qrc:/final_gl2.frag"))));
-
- m_gl2Pass->addFilterKey(m_passCriterion);
- m_gl2Pass->setShaderProgram(gl2Shader);
- m_gl2Technique->addRenderPass(m_gl2Pass);
-
- addTechnique(m_gl3Technique);
- addTechnique(m_gl2Technique);
-}
-
-QList<Qt3DRender::QFilterKey *> FinalEffect::passCriteria() const
-{
- return QList<Qt3DRender::QFilterKey *>() << m_passCriterion;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/geometry_gl2.frag b/examples/qt3d/deferred-renderer-cpp/geometry_gl2.frag
deleted file mode 100644
index 0e7776f15..000000000
--- a/examples/qt3d/deferred-renderer-cpp/geometry_gl2.frag
+++ /dev/null
@@ -1,12 +0,0 @@
-#version 110
-
-varying vec4 color0;
-varying vec3 position0;
-varying vec3 normal0;
-
-void main()
-{
- gl_FragData[0] = color0;
- gl_FragData[1] = vec4(position0, 0);
- gl_FragData[2] = vec4(normal0, 0);
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/geometry_gl2.vert b/examples/qt3d/deferred-renderer-cpp/geometry_gl2.vert
deleted file mode 100644
index 72d5345f1..000000000
--- a/examples/qt3d/deferred-renderer-cpp/geometry_gl2.vert
+++ /dev/null
@@ -1,21 +0,0 @@
-#version 110
-
-attribute vec4 vertexPosition;
-attribute vec3 vertexNormal;
-
-varying vec4 color0;
-varying vec3 position0;
-varying vec3 normal0;
-
-uniform mat4 mvp;
-uniform mat4 modelView;
-uniform mat3 modelViewNormal;
-uniform vec4 meshColor;
-
-void main()
-{
- color0 = meshColor;
- position0 = vec3(modelView * vertexPosition);
- normal0 = normalize(modelViewNormal * vertexNormal);
- gl_Position = mvp * vertexPosition;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/geometry_gl3.frag b/examples/qt3d/deferred-renderer-cpp/geometry_gl3.frag
deleted file mode 100644
index 7d9c7d64e..000000000
--- a/examples/qt3d/deferred-renderer-cpp/geometry_gl3.frag
+++ /dev/null
@@ -1,16 +0,0 @@
-#version 140
-
-in vec4 color0;
-in vec3 position0;
-in vec3 normal0;
-
-out vec4 color;
-out vec3 position;
-out vec3 normal;
-
-void main()
-{
- color = color0;
- position = position0;
- normal = normal0;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/geometry_gl3.vert b/examples/qt3d/deferred-renderer-cpp/geometry_gl3.vert
deleted file mode 100644
index d3e302d16..000000000
--- a/examples/qt3d/deferred-renderer-cpp/geometry_gl3.vert
+++ /dev/null
@@ -1,21 +0,0 @@
-#version 140
-
-in vec4 vertexPosition;
-in vec3 vertexNormal;
-
-out vec4 color0;
-out vec3 position0;
-out vec3 normal0;
-
-uniform mat4 mvp;
-uniform mat4 modelView;
-uniform mat3 modelViewNormal;
-uniform vec4 meshColor;
-
-void main()
-{
- color0 = meshColor;
- position0 = vec3(modelView * vertexPosition);
- normal0 = normalize(modelViewNormal * vertexNormal);
- gl_Position = mvp * vertexPosition;
-}
diff --git a/examples/qt3d/deferred-renderer-cpp/sceneeffect.cpp b/examples/qt3d/deferred-renderer-cpp/sceneeffect.cpp
deleted file mode 100644
index bdb6ea76e..000000000
--- a/examples/qt3d/deferred-renderer-cpp/sceneeffect.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE: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 "sceneeffect.h"
-
-#include <Qt3DRender/QGraphicsApiFilter>
-#include <Qt3DRender/QShaderProgram>
-#include <QUrl>
-
-SceneEffect::SceneEffect(Qt3DCore::QNode *parent)
- : Qt3DRender::QEffect(parent)
- , m_gl3Technique(new Qt3DRender::QTechnique())
- , m_gl2Technique(new Qt3DRender::QTechnique())
- , m_gl2Pass(new Qt3DRender::QRenderPass())
- , m_gl3Pass(new Qt3DRender::QRenderPass())
- , m_passCriterion(new Qt3DRender::QFilterKey(this))
-{
-
- m_gl3Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile);
- m_gl3Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
- m_gl3Technique->graphicsApiFilter()->setMajorVersion(3);
- m_gl3Technique->graphicsApiFilter()->setMinorVersion(3);
-
- m_gl2Technique->graphicsApiFilter()->setApi(Qt3DRender::QGraphicsApiFilter::OpenGL);
- m_gl2Technique->graphicsApiFilter()->setMajorVersion(2);
- m_gl2Technique->graphicsApiFilter()->setMinorVersion(0);
- m_gl2Technique->graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::NoProfile);
-
-
- m_passCriterion->setName(QStringLiteral("pass"));
- m_passCriterion->setValue(QStringLiteral("geometry"));
-
- Qt3DRender::QShaderProgram *gl3Shader = new Qt3DRender::QShaderProgram();
- gl3Shader->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/geometry_gl3.vert"))));
- gl3Shader->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/geometry_gl3.frag"))));
-
- m_gl3Pass->addFilterKey(m_passCriterion);
- m_gl3Pass->setShaderProgram(gl3Shader);
- m_gl3Technique->addRenderPass(m_gl3Pass);
-
- Qt3DRender::QShaderProgram *gl2Shader = new Qt3DRender::QShaderProgram();
- gl2Shader->setVertexShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/geometry_gl2.vert"))));
- gl2Shader->setFragmentShaderCode(Qt3DRender::QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/geometry_gl2.frag"))));
-
- m_gl2Pass->addFilterKey(m_passCriterion);
- m_gl2Pass->setShaderProgram(gl2Shader);
- m_gl2Technique->addRenderPass(m_gl2Pass);
-
- addTechnique(m_gl3Technique);
- addTechnique(m_gl2Technique);
-}
-
-QList<Qt3DRender::QFilterKey *> SceneEffect::passCriteria() const
-{
- return QList<Qt3DRender::QFilterKey *>() << m_passCriterion;
-}
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negx.webp b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negx.webp
index d6c230e1d..1ea719fb3 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negx.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negx.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negy.webp b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negy.webp
index 101c0db05..5329f6ac9 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negy.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negy.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negz.webp b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negz.webp
index 164298faa..2bae54690 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negz.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_negz.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posx.webp b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posx.webp
index 1cf2f4936..ec33d1eb7 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posx.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posx.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posy.webp b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posy.webp
index 16316a77c..6d36fcba5 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posy.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posy.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posz.webp b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posz.webp
index 3b178422e..327041c71 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posz.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/miramar/miramar_posz.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/night/night_negx.webp b/examples/qt3d/exampleresources/assets/cubemaps/night/night_negx.webp
index 05700db5a..1c595caf3 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/night/night_negx.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/night/night_negx.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/night/night_negy.webp b/examples/qt3d/exampleresources/assets/cubemaps/night/night_negy.webp
index c189703c2..9a597d998 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/night/night_negy.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/night/night_negy.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/night/night_negz.webp b/examples/qt3d/exampleresources/assets/cubemaps/night/night_negz.webp
index 07fae984f..a05772c23 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/night/night_negz.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/night/night_negz.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/night/night_posx.webp b/examples/qt3d/exampleresources/assets/cubemaps/night/night_posx.webp
index 599f07287..0b15aa6eb 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/night/night_posx.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/night/night_posx.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/night/night_posy.webp b/examples/qt3d/exampleresources/assets/cubemaps/night/night_posy.webp
index b3c7a2bfb..23cd803a9 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/night/night_posy.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/night/night_posy.webp
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/cubemaps/night/night_posz.webp b/examples/qt3d/exampleresources/assets/cubemaps/night/night_posz.webp
index 8ff3fc500..4899aa98e 100644
--- a/examples/qt3d/exampleresources/assets/cubemaps/night/night_posz.webp
+++ b/examples/qt3d/exampleresources/assets/cubemaps/night/night_posz.webp
Binary files differ
diff --git a/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc b/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc
index 7edfd70ce..ad6190e95 100644
--- a/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc
+++ b/examples/qt3d/shadow-map-qml/doc/src/shadow-map-qml.qdoc
@@ -121,7 +121,7 @@
\skipto import QtQuick
\printuntil Render 2.0
- The code defines a \l RendererSettings entity that has a tree of entities as the
+ The code defines a \l RenderSettings entity that has a tree of entities as the
active framegraph:
\printuntil clearColor
@@ -202,7 +202,7 @@
\printuntil ]
It is possible to put such parameters all the way down, from a \l Material,
- to its \l Effect, to one of the effect’s \l Techniques. This allows a
+ to its \l Effect, to one of the effect’s \l {Technique}{Techniques}. This allows a
\l Material instance to override defaults in an \l Effect or \l Technique.
The bindings array provides the same thing, except that it also allows us to
rename some parameters. In this example, it renames the \c ambient,
diff --git a/qt3d.pro b/qt3d.pro
index 83e0ffcaf..2cc347a1c 100644
--- a/qt3d.pro
+++ b/qt3d.pro
@@ -1,8 +1,5 @@
requires(qtConfig(opengl))
-load(configure)
-qtCompileTest(assimp)
-
CONFIG += examples_need_tools
load(qt_parts)
diff --git a/src/3rdparty/assimp/assimp_dependency.pri b/src/3rdparty/assimp/assimp_dependency.pri
index f1a109f10..8ba2d9a41 100644
--- a/src/3rdparty/assimp/assimp_dependency.pri
+++ b/src/3rdparty/assimp/assimp_dependency.pri
@@ -1,11 +1,6 @@
-config_assimp:!if(cross_compile:host_build) {
- unix:qtConfig(pkg-config) {
- CONFIG += link_pkgconfig
- PKGCONFIG_PRIVATE += assimp
- } else {
- LIBS += -lassimp
- }
- return()
+QT_FOR_CONFIG += 3dcore-private
+qtConfig(system-assimp):!if(cross_compile:host_build) {
+ QMAKE_USE_PRIVATE += assimp
} else {
include(assimp.pri)
}
diff --git a/src/3rdparty/assimp/qt_attribution.json b/src/3rdparty/assimp/qt_attribution.json
new file mode 100644
index 000000000..703836456
--- /dev/null
+++ b/src/3rdparty/assimp/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "assimp",
+ "Name": "Open Asset Import Library",
+ "QDocModule": "qt3d",
+ "Description": "assimp (Open Asset Import Library) is a portable open source library to import various well-known 3D model formats in a uniform manner.",
+ "QtUsage": "Used in Qt 3D.",
+
+ "Homepage": "http://www.assimp.org/",
+ "License": "BSD 3-clause \"New\" or \"Revised\" Licensee",
+ "LicenseId": "BSD-3-Clause",
+ "LicenseFile": "LICENSE",
+ "Copyright": "Copyright (c) 2006-2012, assimp team"
+}
diff --git a/src/core/aspects/qabstractaspect.cpp b/src/core/aspects/qabstractaspect.cpp
index 13195a798..c049d3503 100644
--- a/src/core/aspects/qabstractaspect.cpp
+++ b/src/core/aspects/qabstractaspect.cpp
@@ -87,6 +87,7 @@ void QAbstractAspectPrivate::unregisterBackendType(const QMetaObject &mo)
/*!
* \class Qt3DCore::QAbstractAspect
+ * \inheaderfile Qt3DCore/QAbstractAspect
* \inherits QObject
* \inmodule Qt3DCore
* \brief QAbstractAspect is the base class for aspects that provide a vertical slice of behavior.
diff --git a/src/core/aspects/qabstractaspect.h b/src/core/aspects/qabstractaspect.h
index a7292e5c6..86938d2d2 100644
--- a/src/core/aspects/qabstractaspect.h
+++ b/src/core/aspects/qabstractaspect.h
@@ -107,6 +107,7 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE \
namespace Qt3DCore { \
typedef QAbstractAspect *(*AspectCreateFunction)(QObject *); \
+ QT_DEPRECATED QT3DCORESHARED_EXPORT void qt3d_QAspectFactory_addDefaultFactory(const QString &, const QMetaObject *, AspectCreateFunction); \
QT3DCORESHARED_EXPORT void qt3d_QAspectFactory_addDefaultFactory(const QLatin1String &, const QMetaObject *, AspectCreateFunction); \
} \
QT_END_NAMESPACE \
diff --git a/src/core/aspects/qaspectengine.cpp b/src/core/aspects/qaspectengine.cpp
index 81ee707bd..15f975332 100644
--- a/src/core/aspects/qaspectengine.cpp
+++ b/src/core/aspects/qaspectengine.cpp
@@ -124,6 +124,7 @@ void QAspectEnginePrivate::generateCreationChanges(QNode *root)
/*!
* \class Qt3DCore::QAspectEngine
+ * \inheaderfile Qt3DCore/QAspectEngine
* \inherits QObject
* \inmodule Qt3DCore
*
diff --git a/src/core/aspects/qaspectfactory.cpp b/src/core/aspects/qaspectfactory.cpp
index 0830a24e9..3135e1653 100644
--- a/src/core/aspects/qaspectfactory.cpp
+++ b/src/core/aspects/qaspectfactory.cpp
@@ -62,6 +62,15 @@ QT3DCORESHARED_EXPORT void qt3d_QAspectFactory_addDefaultFactory(const QLatin1St
defaultAspectNames->insert(metaObject, name);
}
+QT3DCORESHARED_EXPORT void qt3d_QAspectFactory_addDefaultFactory(const QString &name,
+ const QMetaObject *metaObject,
+ QAspectFactory::CreateFunction factory)
+{
+ return qt3d_QAspectFactory_addDefaultFactory(QLatin1String(name.toLatin1()),
+ metaObject,
+ factory);
+}
+
QAspectFactory::QAspectFactory()
: m_factories(*defaultFactories),
m_aspectNames(*defaultAspectNames)
diff --git a/src/core/changes/qcomponentaddedchange.cpp b/src/core/changes/qcomponentaddedchange.cpp
index 1ad25651b..8d7ce425a 100644
--- a/src/core/changes/qcomponentaddedchange.cpp
+++ b/src/core/changes/qcomponentaddedchange.cpp
@@ -57,6 +57,7 @@ QComponentAddedChangePrivate::QComponentAddedChangePrivate(const QEntity *entity
/*!
* \class Qt3DCore::QComponentAddedChange
+ * \inheaderfile Qt3DCore/QComponentAddedChange
* \inherits Qt3DCore::QSceneChange
* \inmodule Qt3DCore
* \brief The QComponentAddedChange class is used to notify when a component is added to an entity
diff --git a/src/core/changes/qcomponentremovedchange.cpp b/src/core/changes/qcomponentremovedchange.cpp
index e1625ac93..5b5ef247a 100644
--- a/src/core/changes/qcomponentremovedchange.cpp
+++ b/src/core/changes/qcomponentremovedchange.cpp
@@ -57,6 +57,7 @@ QComponentRemovedChangePrivate::QComponentRemovedChangePrivate(const QEntity *en
/*!
* \class Qt3DCore::QComponentRemovedChange
+ * \inheaderfile Qt3DCore/QComponentRemovedChange
* \inherits Qt3DCore::QSceneChange
* \inmodule Qt3DCore
* \brief The QComponentRemovedChange class is used to notify when a component is removed from an entity
diff --git a/src/core/changes/qdynamicpropertyupdatedchange.cpp b/src/core/changes/qdynamicpropertyupdatedchange.cpp
index 3931d942c..fd174097c 100644
--- a/src/core/changes/qdynamicpropertyupdatedchange.cpp
+++ b/src/core/changes/qdynamicpropertyupdatedchange.cpp
@@ -55,6 +55,7 @@ QDynamicPropertyUpdatedChangePrivate::~QDynamicPropertyUpdatedChangePrivate()
/*!
* \class Qt3DCore::QDynamicPropertyUpdatedChange
+ * \inheaderfile Qt3DCore/QDynamicPropertyUpdatedChange
* \inherits Qt3DCore::QPropertyUpdatedChangeBase
* \inmodule Qt3DCore
* \brief The QDynamicPropertyUpdatedChange class is used to notify when a dynamic property value is updated
diff --git a/src/core/changes/qnodecreatedchange.cpp b/src/core/changes/qnodecreatedchange.cpp
index 06e85fbfc..a77721cdc 100644
--- a/src/core/changes/qnodecreatedchange.cpp
+++ b/src/core/changes/qnodecreatedchange.cpp
@@ -53,6 +53,7 @@ QNodeCreatedChangeBasePrivate::QNodeCreatedChangeBasePrivate(const QNode *node)
/*!
* \class Qt3DCore::QNodeCreatedChangeBase
+ * \inheaderfile Qt3DCore/QNodeCreatedChangeBase
* \inherits Qt3DCore::QSceneChange
* \inmodule Qt3DCore
* \brief The QNodeCreatedChangeBase class is the base class for all NodeCreated QSceneChange events
@@ -120,6 +121,7 @@ bool QNodeCreatedChangeBase::isNodeEnabled() const Q_DECL_NOTHROW
/*!
* \class Qt3DCore::QNodeCreatedChange
+ * \inheaderfile Qt3DCore/QNodeCreatedChange
* \inherits Qt3DCore::QNodeCreatedChangeBase
* \since 5.7
* \inmodule Qt3DCore
diff --git a/src/core/changes/qnodedestroyedchange.cpp b/src/core/changes/qnodedestroyedchange.cpp
index 96403f237..2d304dcbc 100644
--- a/src/core/changes/qnodedestroyedchange.cpp
+++ b/src/core/changes/qnodedestroyedchange.cpp
@@ -43,6 +43,7 @@ namespace Qt3DCore {
/*!
* \class Qt3DCore::QNodeDestroyedChange
+ * \inheaderfile Qt3DCore/QNodeDestroyedChange
* \inherits Qt3DCore::QSceneChange
* \since 5.7
* \inmodule Qt3DCore
diff --git a/src/core/changes/qpropertynodeaddedchange.cpp b/src/core/changes/qpropertynodeaddedchange.cpp
index 539c6a54a..e159276dd 100644
--- a/src/core/changes/qpropertynodeaddedchange.cpp
+++ b/src/core/changes/qpropertynodeaddedchange.cpp
@@ -53,6 +53,7 @@ QPropertyNodeAddedChangePrivate::QPropertyNodeAddedChangePrivate()
/*!
* \class Qt3DCore::QPropertyNodeAddedChange
+ * \inheaderfile Qt3DCore/QPropertyNodeAddedChange
* \inherits Qt3DCore::QStaticPropertyValueAddedChangeBase
* \inmodule Qt3DCore
* \brief Used to notify when a node is added to a property
diff --git a/src/core/changes/qpropertynoderemovedchange.cpp b/src/core/changes/qpropertynoderemovedchange.cpp
index af08635e4..a7b4e95f3 100644
--- a/src/core/changes/qpropertynoderemovedchange.cpp
+++ b/src/core/changes/qpropertynoderemovedchange.cpp
@@ -54,6 +54,7 @@ QPropertyNodeRemovedChangePrivate::QPropertyNodeRemovedChangePrivate()
/*!
* \class Qt3DCore::QPropertyNodeRemovedChange
+ * \inheaderfile Qt3DCore/QPropertyNodeRemovedChange
* \inherits Qt3DCore::QStaticPropertyValueRemovedChangeBase
* \inmodule Qt3DCore
* \brief The QPropertyNodeRemovedChange class is used to notify when a node is removed from a property
diff --git a/src/core/changes/qpropertyupdatedchange.cpp b/src/core/changes/qpropertyupdatedchange.cpp
index 66e7461b9..c6025efbc 100644
--- a/src/core/changes/qpropertyupdatedchange.cpp
+++ b/src/core/changes/qpropertyupdatedchange.cpp
@@ -55,6 +55,7 @@ QPropertyUpdatedChangePrivate::~QPropertyUpdatedChangePrivate()
/*!
* \class Qt3DCore::QPropertyUpdatedChange
+ * \inheaderfile Qt3DCore/QPropertyUpdatedChange
* \inherits Qt3DCore::QStaticPropertyUpdatedChangeBase
* \inmodule Qt3DCore
* \brief The QPropertyUpdatedChange class is used to notify when a property value is updated
diff --git a/src/core/changes/qpropertyupdatedchangebase.cpp b/src/core/changes/qpropertyupdatedchangebase.cpp
index ab278c3f4..18f2039fc 100644
--- a/src/core/changes/qpropertyupdatedchangebase.cpp
+++ b/src/core/changes/qpropertyupdatedchangebase.cpp
@@ -55,6 +55,7 @@ QPropertyUpdatedChangeBasePrivate::~QPropertyUpdatedChangeBasePrivate()
/*!
* \class Qt3DCore::QPropertyUpdatedChangeBase
+ * \inheaderfile Qt3DCore/QPropertyUpdatedChangeBase
* \inmodule Qt3DCore
* \brief The QPropertyUpdatedChangeBase class is the base class for all PropertyUpdated QSceneChange events
*
diff --git a/src/core/changes/qpropertyvalueaddedchange.cpp b/src/core/changes/qpropertyvalueaddedchange.cpp
index 3c1fb7c62..b7438fcbe 100644
--- a/src/core/changes/qpropertyvalueaddedchange.cpp
+++ b/src/core/changes/qpropertyvalueaddedchange.cpp
@@ -52,6 +52,7 @@ QPropertyValueAddedChangePrivate::QPropertyValueAddedChangePrivate()
/*!
* \class Qt3DCore::QPropertyValueAddedChange
+ * \inheaderfile Qt3DCore/QPropertyValueAddedChange
* \inherits Qt3DCore::QStaticPropertyValueAddedChangeBase
* \inmodule Qt3DCore
* \brief Used to notify when a value is added to a property
diff --git a/src/core/changes/qpropertyvalueaddedchangebase.cpp b/src/core/changes/qpropertyvalueaddedchangebase.cpp
index cff918d80..26dcd5555 100644
--- a/src/core/changes/qpropertyvalueaddedchangebase.cpp
+++ b/src/core/changes/qpropertyvalueaddedchangebase.cpp
@@ -55,6 +55,7 @@ QPropertyValueAddedChangeBasePrivate::~QPropertyValueAddedChangeBasePrivate()
/*!
* \class Qt3DCore::QPropertyValueAddedChangeBase
+ * \inheaderfile Qt3DCore/QPropertyValueAddedChangeBase
* \inmodule Qt3DCore
* \brief The QPropertyValueAddedChangeBase class is the base class for all PropertyValueAdded QSceneChange events
*
diff --git a/src/core/changes/qpropertyvalueremovedchange.cpp b/src/core/changes/qpropertyvalueremovedchange.cpp
index 2512e4785..6e8a1f817 100644
--- a/src/core/changes/qpropertyvalueremovedchange.cpp
+++ b/src/core/changes/qpropertyvalueremovedchange.cpp
@@ -52,6 +52,7 @@ QPropertyValueRemovedChangePrivate::QPropertyValueRemovedChangePrivate()
/*!
* \class Qt3DCore::QPropertyValueRemovedChange
+ * \inheaderfile Qt3DCore/QPropertyValueRemovedChange
* \inherits Qt3DCore::QStaticPropertyValueRemovedChangeBase
* \inmodule Qt3DCore
* \brief Used to notify when a value is added to a property
diff --git a/src/core/changes/qpropertyvalueremovedchangebase.cpp b/src/core/changes/qpropertyvalueremovedchangebase.cpp
index 0a62c43c8..8115d6e22 100644
--- a/src/core/changes/qpropertyvalueremovedchangebase.cpp
+++ b/src/core/changes/qpropertyvalueremovedchangebase.cpp
@@ -55,6 +55,7 @@ QPropertyValueRemovedChangeBasePrivate::~QPropertyValueRemovedChangeBasePrivate(
/*!
* \class Qt3DCore::QPropertyValueRemovedChangeBase
+ * \inheaderfile Qt3DCore/QPropertyValueRemovedChangeBase
* \inmodule Qt3DCore
* \brief The QPropertyValueRemovedChangeBase class is the base class for all PropertyValueRemoved QSceneChange events
*
diff --git a/src/core/changes/qscenechange.cpp b/src/core/changes/qscenechange.cpp
index 311c26340..959518904 100644
--- a/src/core/changes/qscenechange.cpp
+++ b/src/core/changes/qscenechange.cpp
@@ -74,6 +74,7 @@ QSceneChangePrivate::~QSceneChangePrivate()
/*!
* \class Qt3DCore::QSceneChange
+ * \inheaderfile Qt3DCore/QSceneChange
* \inmodule Qt3DCore
* \brief The base class for changes that can be sent and received by Qt3D's change notification system
*/
diff --git a/src/core/changes/qstaticpropertyupdatedchangebase.cpp b/src/core/changes/qstaticpropertyupdatedchangebase.cpp
index 887e9d799..409d80add 100644
--- a/src/core/changes/qstaticpropertyupdatedchangebase.cpp
+++ b/src/core/changes/qstaticpropertyupdatedchangebase.cpp
@@ -57,6 +57,7 @@ QStaticPropertyUpdatedChangeBasePrivate::~QStaticPropertyUpdatedChangeBasePrivat
/*!
* \class Qt3DCore::QStaticPropertyUpdatedChangeBase
+ * \inheaderfile Qt3DCore/QStaticPropertyUpdatedChangeBase
* \inmodule Qt3DCore
* \since 5.7
* \brief The QStaticPropertyUpdatedChangeBase class is the base class for all static PropertyUpdated QSceneChange events
diff --git a/src/core/changes/qstaticpropertyvalueaddedchangebase.cpp b/src/core/changes/qstaticpropertyvalueaddedchangebase.cpp
index f79372040..4fb658459 100644
--- a/src/core/changes/qstaticpropertyvalueaddedchangebase.cpp
+++ b/src/core/changes/qstaticpropertyvalueaddedchangebase.cpp
@@ -52,6 +52,7 @@ QStaticPropertyValueAddedChangeBasePrivate::QStaticPropertyValueAddedChangeBaseP
/*!
* \class Qt3DCore::QStaticPropertyValueAddedChangeBase
+ * \inheaderfile Qt3DCore/QStaticPropertyValueAddedChangeBase
* \inmodule Qt3DCore
* \since 5.7
* \brief The QStaticPropertyValueAddedChangeBase class is the base class for all static PropertyValueAdded QSceneChange events
diff --git a/src/core/changes/qstaticpropertyvalueremovedchangebase.cpp b/src/core/changes/qstaticpropertyvalueremovedchangebase.cpp
index 44fa89a36..622eb6524 100644
--- a/src/core/changes/qstaticpropertyvalueremovedchangebase.cpp
+++ b/src/core/changes/qstaticpropertyvalueremovedchangebase.cpp
@@ -52,6 +52,7 @@ QStaticPropertyValueRemovedChangeBasePrivate::QStaticPropertyValueRemovedChangeB
/*!
* \class Qt3DCore::QStaticPropertyValueRemovedChangeBase
+ * \inheaderfile Qt3DCore/QStaticPropertyValueRemovedChangeBase
* \inmodule Qt3DCore
* \since 5.7
* \brief The QStaticPropertyValueRemovedChangeBase class is the base class for all static PropertyValueRemoved QSceneChange events
diff --git a/src/core/configure.json b/src/core/configure.json
new file mode 100644
index 000000000..b1c173cc3
--- /dev/null
+++ b/src/core/configure.json
@@ -0,0 +1,35 @@
+{
+ "module": "3dcore",
+ "testDir": "../../config.tests",
+
+ "libraries": {
+ "assimp": {
+ "label": "Assimp",
+ "test": "assimp",
+ "sources": [
+ { "type": "pkgConfig", "args": "assimp" },
+ "-lassimp"
+ ]
+ }
+ },
+
+ "features": {
+ "system-assimp": {
+ "label": "System Assimp",
+ "condition": "libs.assimp",
+ "output": [ "privateFeature" ]
+ }
+ },
+
+ "report": [
+ ],
+
+ "summary": [
+ {
+ "section": "Qt 3D",
+ "entries": [
+ "system-assimp"
+ ]
+ }
+ ]
+}
diff --git a/src/core/core.pro b/src/core/core.pro
index d7205f08a..64350be1b 100644
--- a/src/core/core.pro
+++ b/src/core/core.pro
@@ -7,7 +7,6 @@ QT = core-private gui-private network
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/core/jobs/qaspectjob.cpp b/src/core/jobs/qaspectjob.cpp
index 94a747867..59f48e9bf 100644
--- a/src/core/jobs/qaspectjob.cpp
+++ b/src/core/jobs/qaspectjob.cpp
@@ -70,6 +70,7 @@ QAspectJob::QAspectJob()
/*!
* \class Qt3DCore::QAspectJob
+ * \inheaderfile Qt3DCore/QAspectJob
* \inmodule Qt3DCore
* \brief The base class for jobs executed in an aspect
*/
diff --git a/src/core/nodes/qabstractnodefactory.cpp b/src/core/nodes/qabstractnodefactory.cpp
index 2bd39f333..41d82cf38 100644
--- a/src/core/nodes/qabstractnodefactory.cpp
+++ b/src/core/nodes/qabstractnodefactory.cpp
@@ -45,6 +45,7 @@ namespace Qt3DCore {
/*!
* \class Qt3DCore::QAbstractNodeFactory
+ * \inheaderfile Qt3DCore/QAbstractNodeFactory
* \inmodule Qt3DCore
*
* TODO
diff --git a/src/core/nodes/qbackendnode.cpp b/src/core/nodes/qbackendnode.cpp
index d8289df63..6970794b8 100644
--- a/src/core/nodes/qbackendnode.cpp
+++ b/src/core/nodes/qbackendnode.cpp
@@ -94,6 +94,7 @@ QBackendNodePrivate *QBackendNodePrivate::get(QBackendNode *n)
/*!
* \class Qt3DCore::QBackendNodeMapper
+ * \inheaderfile Qt3DCore/QBackendNodeMapper
* \inmodule Qt3DCore
*
* \brief Creates and maps backend nodes to their respective frontend nodes
@@ -123,6 +124,7 @@ QBackendNodePrivate *QBackendNodePrivate::get(QBackendNode *n)
/*!
* \class Qt3DCore::QBackendNode
+ * \inheaderfile Qt3DCore/QBackendNode
* \inmodule Qt3DCore
*
* \brief The base class for all Qt3D backend nodes
diff --git a/src/core/nodes/qnodeid.cpp b/src/core/nodes/qnodeid.cpp
index dee5d4ff4..f41627734 100644
--- a/src/core/nodes/qnodeid.cpp
+++ b/src/core/nodes/qnodeid.cpp
@@ -45,6 +45,7 @@ namespace Qt3DCore {
/*!
* \class Qt3DCore::QNodeId
+ * \inheaderfile Qt3DCore/QNodeId
* \inmodule Qt3DCore
* \brief Uniquely identifies a QNode
*/
diff --git a/src/core/nodes/qnodeid.h b/src/core/nodes/qnodeid.h
index c33638ce9..7e8b1c97c 100644
--- a/src/core/nodes/qnodeid.h
+++ b/src/core/nodes/qnodeid.h
@@ -116,7 +116,7 @@ inline Q_DECL_CONSTEXPR uint qHash(QNodeId id, uint seed = 0) Q_DECL_NOTHROW
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DCore::QNodeId)
+Q_DECLARE_METATYPE(Qt3DCore::QNodeId) // LCOV_EXCL_LINE
#endif // QT3DCORE_QNODEID_H
diff --git a/src/core/qlockableobserverinterface_p.h b/src/core/qlockableobserverinterface_p.h
index 1d6878c22..b33a84ec4 100644
--- a/src/core/qlockableobserverinterface_p.h
+++ b/src/core/qlockableobserverinterface_p.h
@@ -72,6 +72,6 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DCore::QLockableObserverInterface *)
+Q_DECLARE_METATYPE(Qt3DCore::QLockableObserverInterface *) // LCOV_EXCL_LINE
#endif // QT3DCORE_QLOCKABLEOBSERVERINTERFACE_P_H
diff --git a/src/core/qobserverinterface_p.h b/src/core/qobserverinterface_p.h
index 9763883fb..f2ed52aab 100644
--- a/src/core/qobserverinterface_p.h
+++ b/src/core/qobserverinterface_p.h
@@ -68,6 +68,6 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DCore::QObserverInterface *)
+Q_DECLARE_METATYPE(Qt3DCore::QObserverInterface *) // LCOV_EXCL_LINE
#endif // QT3DCORE_QOBSERVERINTERFACE_P_H
diff --git a/src/core/qpostman_p.h b/src/core/qpostman_p.h
index edfe69c29..4fe788960 100644
--- a/src/core/qpostman_p.h
+++ b/src/core/qpostman_p.h
@@ -94,6 +94,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DCore::QAbstractPostman*)
+Q_DECLARE_METATYPE(Qt3DCore::QAbstractPostman*) // LCOV_EXCL_LINE
#endif // QT3DCORE_QPOSTMAN_P_H
diff --git a/src/core/qscene_p.h b/src/core/qscene_p.h
index 59c609de7..6b4009538 100644
--- a/src/core/qscene_p.h
+++ b/src/core/qscene_p.h
@@ -101,6 +101,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DCore::QScene*)
+Q_DECLARE_METATYPE(Qt3DCore::QScene*) // LCOV_EXCL_LINE
#endif // QT3DCORE_QSCENE_P_H
diff --git a/src/core/qsceneobserverinterface_p.h b/src/core/qsceneobserverinterface_p.h
index 4cbe9e3f0..77b1c3626 100644
--- a/src/core/qsceneobserverinterface_p.h
+++ b/src/core/qsceneobserverinterface_p.h
@@ -76,6 +76,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DCore::QSceneObserverInterface *)
+Q_DECLARE_METATYPE(Qt3DCore::QSceneObserverInterface *) // LCOV_EXCL_LINE
#endif // QT3DCORE_QSCENEOBSERVERINTERFACE_P_H
diff --git a/src/core/qt3dcore_global.h b/src/core/qt3dcore_global.h
index 725df149b..64a59dd4c 100644
--- a/src/core/qt3dcore_global.h
+++ b/src/core/qt3dcore_global.h
@@ -66,6 +66,12 @@ QT_BEGIN_NAMESPACE
namespace InnerNS { \
/*end*/
+#define QT3D_DECLARE_TYPEINFO_3(OuterNS, InnerNS, InnerMostNS, Class, Flags) \
+ } /* InnerMostNS */ \
+ QT3D_DECLARE_TYPEINFO_2(OuterNS, InnerNS, InnerMostNS :: Class, Flags) \
+ namespace InnerMostNS { \
+ /*end*/
+
#define QT3D_DECLARE_SHARED(NS, Class) \
inline void swap(Class &lhs, Class &rhs) \
Q_DECL_NOEXCEPT_EXPR(noexcept(lhs.swap(rhs))) \
diff --git a/src/core/resources/qframeallocator.cpp b/src/core/resources/qframeallocator.cpp
index ff15dadf6..61a82a2b4 100644
--- a/src/core/resources/qframeallocator.cpp
+++ b/src/core/resources/qframeallocator.cpp
@@ -147,25 +147,30 @@ void QFixedFrameAllocator::init(uint blockSize, uchar pageSize)
void *QFixedFrameAllocator::allocate()
{
- Q_ASSERT(m_blockSize && m_nbrBlock);
- if (m_lastAllocatedChunck == nullptr ||
- m_lastAllocatedChunck->m_blocksAvailable == 0) {
- int i = 0;
- for (; i < m_chunks.size(); i++) {
- if (m_chunks[i].m_blocksAvailable > 0) {
- m_lastAllocatedChunck = m_chunks.begin() + i;
- break;
- }
- }
- if (i == m_chunks.size()) {
- m_chunks.resize(m_chunks.size() + 1);
- QFrameChunk &newChunk = m_chunks.last();
- newChunk.init(m_blockSize, m_nbrBlock);
- m_lastAllocatedChunck = &newChunk;
- m_lastFreedChunck = m_lastAllocatedChunck;
+ Q_ASSERT(m_blockSize);
+ return scan().allocate(m_blockSize);
+}
+
+QFrameChunk &QFixedFrameAllocator::scan()
+{
+ Q_ASSERT(m_blockSize);
+ Q_ASSERT(m_nbrBlock);
+
+ if (m_lastAllocatedChunck && m_lastAllocatedChunck->m_blocksAvailable)
+ return *m_lastAllocatedChunck;
+
+ for (int i = 0; i < m_chunks.size(); i++) {
+ if (m_chunks[i].m_blocksAvailable > 0) {
+ m_lastAllocatedChunck = m_chunks.begin() + i;
+ return *m_lastAllocatedChunck;
}
}
- return m_lastAllocatedChunck->allocate(m_blockSize);
+ m_chunks.resize(m_chunks.size() + 1);
+ QFrameChunk &newChunk = m_chunks.last();
+ newChunk.init(m_blockSize, m_nbrBlock);
+ m_lastAllocatedChunck = &newChunk;
+ m_lastFreedChunck = &newChunk;
+ return newChunk;
}
void QFixedFrameAllocator::deallocate(void *ptr)
diff --git a/src/core/resources/qframeallocator_p_p.h b/src/core/resources/qframeallocator_p_p.h
index b49def87a..bf4e0a2b1 100644
--- a/src/core/resources/qframeallocator_p_p.h
+++ b/src/core/resources/qframeallocator_p_p.h
@@ -96,6 +96,9 @@ public:
inline uint blockSize() const { return m_blockSize; }
private:
+ QFrameChunk &scan();
+
+private:
uint m_blockSize;
uchar m_nbrBlock;
QVector<QFrameChunk> m_chunks;
diff --git a/src/core/transforms/qtransform.cpp b/src/core/transforms/qtransform.cpp
index 85fe7f9f1..a765b8096 100644
--- a/src/core/transforms/qtransform.cpp
+++ b/src/core/transforms/qtransform.cpp
@@ -169,6 +169,7 @@ QTransformPrivate::~QTransformPrivate()
/*!
* \class Qt3DCore::QTransform
+ * \inheaderfile Qt3DCore/QTransform
* \inmodule Qt3DCore
* \inherits Qt3DCore::QComponent
* \since 5.6
diff --git a/src/doc/src/qt3d-index.qdoc b/src/doc/src/qt3d-index.qdoc
index 5d56a3136..f14909cec 100644
--- a/src/doc/src/qt3d-index.qdoc
+++ b/src/doc/src/qt3d-index.qdoc
@@ -78,7 +78,7 @@
A Qt Quick application requires also additional dependencies:
\badcode
- QT += 3dcore 3drenderer 3dinput qml quick 3dquick
+ QT += 3dcore 3drender 3dinput 3dlogic 3dextras qml quick 3dquick
\endcode
\section1 Overview
@@ -108,4 +108,17 @@
\li iOS - Supported since (Qt 5.7)
\li WinRT - Not supported yet
\endlist
+
+ \section1 Licenses and Attributions
+
+ Qt 3D is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under the
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
+
+ Furthermore Qt 3D contains third party
+ modules under following permissive licenses:
+
+ \generatelist{groupsbymodule attributions-qt3d}
*/
diff --git a/src/doc/src/qt3d-overview.qdoc b/src/doc/src/qt3d-overview.qdoc
index e22e2ba4e..e1f3d8629 100644
--- a/src/doc/src/qt3d-overview.qdoc
+++ b/src/doc/src/qt3d-overview.qdoc
@@ -98,7 +98,6 @@
fragment shaders. Compute shaders are planned for a future release.
For examples of using shaders, see the Simple Shaders QML Example,
- \l {Qt 3D: Tessellation Modes QML Example},
\l {Qt 3D: Shadow Map QML Example}, \l{Qt 3D: Wireframe QML Example}, and
\l {Qt 3D: Wave QML Example}.
diff --git a/src/extras/defaults/qfirstpersoncameracontroller.cpp b/src/extras/defaults/qfirstpersoncameracontroller.cpp
index 19446d3ba..e31448eb8 100644
--- a/src/extras/defaults/qfirstpersoncameracontroller.cpp
+++ b/src/extras/defaults/qfirstpersoncameracontroller.cpp
@@ -277,7 +277,19 @@ void QFirstPersonCameraController::setCamera(Qt3DRender::QCamera *camera)
{
Q_D(QFirstPersonCameraController);
if (d->m_camera != camera) {
+
+ if (d->m_camera)
+ d->unregisterDestructionHelper(d->m_camera);
+
+ if (camera && !camera->parent())
+ camera->setParent(this);
+
d->m_camera = camera;
+
+ // Ensures proper bookkeeping
+ if (d->m_camera)
+ d->registerDestructionHelper(d->m_camera, &QFirstPersonCameraController::setCamera, d->m_camera);
+
emit cameraChanged();
}
}
diff --git a/src/extras/defaults/qorbitcameracontroller.cpp b/src/extras/defaults/qorbitcameracontroller.cpp
index e340941a8..95b0e19dc 100644
--- a/src/extras/defaults/qorbitcameracontroller.cpp
+++ b/src/extras/defaults/qorbitcameracontroller.cpp
@@ -346,7 +346,19 @@ void QOrbitCameraController::setCamera(Qt3DRender::QCamera *camera)
{
Q_D(QOrbitCameraController);
if (d->m_camera != camera) {
+
+ if (d->m_camera)
+ d->unregisterDestructionHelper(d->m_camera);
+
+ if (camera && !camera->parent())
+ camera->setParent(this);
+
d->m_camera = camera;
+
+ // Ensures proper bookkeeping
+ if (d->m_camera)
+ d->registerDestructionHelper(d->m_camera, &QOrbitCameraController::setCamera, d->m_camera);
+
emit cameraChanged();
}
}
diff --git a/src/extras/defaults/qskyboxentity.cpp b/src/extras/defaults/qskyboxentity.cpp
index f4b26ae9e..e81c6ad91 100644
--- a/src/extras/defaults/qskyboxentity.cpp
+++ b/src/extras/defaults/qskyboxentity.cpp
@@ -187,13 +187,14 @@ void QSkyboxEntityPrivate::reloadTexture()
}
/*!
- * \class Qt3DRender::QSkyboxEntity
- * \inmodule Qt3DRender
+ * \class Qt3DExtras::QSkyboxEntity
+ * \inheaderfile Qt3DExtras/QSkyboxEntity
+ * \inmodule Qt3DExtras
*
- * \brief Qt3DRender::QSkyboxEntity is a convenience Qt3DCore::QEntity subclass that can
+ * \brief Qt3DExtras::QSkyboxEntity is a convenience Qt3DCore::QEntity subclass that can
* be used to insert a skybox in a 3D scene.
*
- * By specifying a base name and an extension, Qt3DCore::QSkyboxEntity
+ * By specifying a base name and an extension, Qt3DExtras::QSkyboxEntity
* will take care of building a TextureCubeMap to be rendered at runtime. The
* images in the source directory should match the pattern:
* \b base name + * "_posx|_posy|_posz|_negx|_negy|_negz" + extension
@@ -207,7 +208,7 @@ void QSkyboxEntityPrivate::reloadTexture()
*/
/*!
- * Constructs a new Qt3DCore::QSkyboxEntity object with \a parent as parent.
+ * Constructs a new Qt3DExtras::QSkyboxEntity object with \a parent as parent.
*/
QSkyboxEntity::QSkyboxEntity(QNode *parent)
: QEntity(*new QSkyboxEntityPrivate, parent)
diff --git a/src/extras/geometries/qconegeometry.cpp b/src/extras/geometries/qconegeometry.cpp
index 9db7e2b46..a86d10f6b 100644
--- a/src/extras/geometries/qconegeometry.cpp
+++ b/src/extras/geometries/qconegeometry.cpp
@@ -39,6 +39,7 @@
/*!
* \class Qt3DExtras::QConeGeometry
+ * \inheaderfile Qt3DExtras/QConeGeometry
* \inmodule Qt3DExtras
* \brief The QConeGeometry class allows creation of a cone in 3D space.
* \since 5.7
@@ -70,6 +71,16 @@ namespace Qt3DExtras {
namespace {
+int faceCount(int slices, int rings, int capCount)
+{
+ return (slices * 2) * (rings - 1) + slices * capCount;
+}
+
+int vertexCount(int slices, int rings, int capCount)
+{
+ return (slices + 1) * rings + capCount * (slices + 2);
+}
+
void createSidesVertices(float *&verticesPtr,
int rings,
int slices,
@@ -227,10 +238,8 @@ public:
QByteArray operator ()() Q_DECL_OVERRIDE
{
- int verticesCount = 0;
-
- verticesCount = ( m_slices + 1 ) * m_rings // Sides
- + (m_hasTopEndcap + m_hasBottomEndcap) * (m_slices + 1) + 2; // endcaps
+ const int verticesCount =
+ vertexCount(m_slices, m_rings, (m_hasTopEndcap + m_hasBottomEndcap));
// vec3 pos, vec2 texCoord, vec3 normal
const quint32 vertexSize = (3 + 2 + 3) * sizeof(float);
@@ -289,10 +298,7 @@ public:
QByteArray operator ()() Q_DECL_OVERRIDE
{
- int facesCount = 0;
-
- facesCount = (m_slices * 2) * m_rings // 2 x tris per side, for all rings
- + m_slices * (m_hasTopEndcap + m_hasBottomEndcap); // endcaps
+ const int facesCount = faceCount(m_slices, m_rings, (m_hasTopEndcap + m_hasBottomEndcap));
const int indicesCount = facesCount * 3;
const int indexSize = sizeof(quint16);
@@ -366,11 +372,8 @@ void QConeGeometryPrivate::init()
// vec3 pos, vec2 tex, vec3 normal
const quint32 elementSize = 3 + 2 + 3;
const quint32 stride = elementSize * sizeof(float);
- const int faces = (m_slices + 1) * (m_rings + 1);
- int nVerts = 0;
-
- nVerts = (m_slices * 2) * m_rings // Sides
- + m_slices * (m_hasTopEndcap + m_hasBottomEndcap); // endcaps
+ const int faces = faceCount(m_slices, m_rings, (m_hasTopEndcap + m_hasBottomEndcap));
+ const int nVerts = vertexCount(m_slices, m_rings, (m_hasTopEndcap + m_hasBottomEndcap));
m_positionAttribute->setName(QAttribute::defaultPositionAttributeName());
m_positionAttribute->setVertexBaseType(QAttribute::Float);
@@ -518,7 +521,9 @@ QConeGeometry::~QConeGeometry()
void QConeGeometry::updateVertices()
{
Q_D(QConeGeometry);
- const int nVerts = (d->m_slices + 1) * (d->m_rings + 1);
+ const int nVerts = vertexCount(d->m_slices, d->m_rings,
+ (d->m_hasTopEndcap + d->m_hasBottomEndcap));
+
d->m_positionAttribute->setCount(nVerts);
d->m_texCoordAttribute->setCount(nVerts);
d->m_normalAttribute->setCount(nVerts);
@@ -532,10 +537,8 @@ void QConeGeometry::updateVertices()
void QConeGeometry::updateIndices()
{
Q_D(QConeGeometry);
- int faces = 0;
-
- faces = (d->m_slices * 2) * d->m_rings // 2 x tris per side, for all rings
- + d->m_slices * (d->m_hasTopEndcap + d->m_hasBottomEndcap); // 2 x endcaps
+ const int faces = faceCount(d->m_slices, d->m_rings,
+ (d->m_hasTopEndcap + d->m_hasBottomEndcap));
d->m_indexAttribute->setCount(faces * 3);
d->m_indexBuffer->setDataGenerator(QSharedPointer<ConeIndexDataFunctor>::create(d->m_hasTopEndcap, d->m_hasBottomEndcap, d->m_rings, d->m_slices,
diff --git a/src/extras/geometries/qconemesh.cpp b/src/extras/geometries/qconemesh.cpp
index 385c469e0..8baa19217 100644
--- a/src/extras/geometries/qconemesh.cpp
+++ b/src/extras/geometries/qconemesh.cpp
@@ -104,6 +104,7 @@ namespace Qt3DExtras {
/*!
* \class Qt3DExtras::QConeMesh
+ * \inheaderfile Qt3DExtras/QConeMesh
* \inmodule Qt3DExtras
*
* \inherits Qt3DRender::QGeometryRenderer
diff --git a/src/extras/geometries/qcuboidgeometry.cpp b/src/extras/geometries/qcuboidgeometry.cpp
index 0f7b5220f..28743858a 100644
--- a/src/extras/geometries/qcuboidgeometry.cpp
+++ b/src/extras/geometries/qcuboidgeometry.cpp
@@ -645,6 +645,7 @@ void QCuboidGeometryPrivate::init()
/*!
* \class Qt3DExtras::QCuboidGeometry
+ * \inheaderfile Qt3DExtras/QCuboidGeometry
* \inmodule Qt3DExtras
* \brief The QCuboidGeometry class allows creation of a cuboid in 3D space.
* \since 5.7
diff --git a/src/extras/geometries/qcuboidmesh.cpp b/src/extras/geometries/qcuboidmesh.cpp
index 7df77ec63..88c735746 100644
--- a/src/extras/geometries/qcuboidmesh.cpp
+++ b/src/extras/geometries/qcuboidmesh.cpp
@@ -95,6 +95,7 @@ namespace Qt3DExtras {
/*!
* \class Qt3DExtras::QCuboidMesh
+ * \inheaderfile Qt3DExtras/QCuboidMesh
* \inmodule Qt3DExtras
*
* \inherits Qt3DRender::QGeometryRenderer
diff --git a/src/extras/geometries/qcylindergeometry.cpp b/src/extras/geometries/qcylindergeometry.cpp
index 136258162..29f7ea7e0 100644
--- a/src/extras/geometries/qcylindergeometry.cpp
+++ b/src/extras/geometries/qcylindergeometry.cpp
@@ -57,6 +57,17 @@ namespace Qt3DExtras {
namespace {
+int faceCount(int slices, int rings)
+{
+ return (slices * 2) * (rings - 1) // two tris per side, for each pair of adjacent rings
+ + slices * 2; // two caps
+}
+
+int vertexCount(int slices, int rings)
+{
+ return (slices + 1) * rings + 2 * (slices + 1) + 2;
+}
+
void createSidesVertices(float *&verticesPtr,
int rings,
int slices,
@@ -180,7 +191,7 @@ public:
QByteArray operator ()() Q_DECL_OVERRIDE
{
- const int verticesCount = (m_slices + 1) * m_rings + 2 * (m_slices + 1) + 2;
+ const int verticesCount = vertexCount(m_slices, m_rings);
// vec3 pos, vec2 texCoord, vec3 normal
const quint32 vertexSize = (3 + 2 + 3) * sizeof(float);
@@ -227,8 +238,7 @@ public:
QByteArray operator ()() Q_DECL_OVERRIDE
{
- const int facesCount = (m_slices * 2) * (m_rings - 1) // two tris per side, for each pair of adjacent rings
- + m_slices * 2; // two caps
+ const int facesCount = faceCount(m_slices, m_rings);
const int indicesCount = facesCount * 3;
const int indexSize = sizeof(quint16);
Q_ASSERT(indicesCount < 65536);
@@ -292,8 +302,8 @@ void QCylinderGeometryPrivate::init()
// vec3 pos, vec2 tex, vec3 normal
const quint32 elementSize = 3 + 2 + 3;
const quint32 stride = elementSize * sizeof(float);
- const int nVerts = (m_slices + 1) * m_rings + 2 * (m_slices + 1) + 2;
- const int faces = (m_slices * 2) * (m_rings - 1) + (m_slices * 2);
+ const int nVerts = vertexCount(m_slices, m_rings);
+ const int faces = faceCount(m_slices, m_rings);
m_positionAttribute->setName(QAttribute::defaultPositionAttributeName());
m_positionAttribute->setVertexBaseType(QAttribute::Float);
@@ -396,6 +406,7 @@ void QCylinderGeometryPrivate::init()
/*!
* \class Qt3DExtras::QCylinderGeometry
+ * \inheaderfile Qt3DExtras/QCylinderGeometry
* \inmodule Qt3DExtras
* \brief The QCylinderGeometry class allows creation of a cylinder in 3D space.
* \since 5.7
@@ -439,7 +450,7 @@ QCylinderGeometry::~QCylinderGeometry()
void QCylinderGeometry::updateVertices()
{
Q_D(QCylinderGeometry);
- const int nVerts = (d->m_slices + 1) * (d->m_rings + 1);
+ const int nVerts = vertexCount(d->m_slices, d->m_rings);
d->m_positionAttribute->setCount(nVerts);
d->m_texCoordAttribute->setCount(nVerts);
d->m_normalAttribute->setCount(nVerts);
@@ -453,7 +464,7 @@ void QCylinderGeometry::updateVertices()
void QCylinderGeometry::updateIndices()
{
Q_D(QCylinderGeometry);
- const int faces = (d->m_slices * 2) * (d->m_rings - 1) + (2 * d->m_slices);
+ const int faces = faceCount(d->m_slices, d->m_rings);
d->m_indexAttribute->setCount(faces * 3);
d->m_indexBuffer->setDataGenerator(QSharedPointer<CylinderIndexDataFunctor>::create(d->m_rings, d->m_slices, d->m_length));
}
diff --git a/src/extras/geometries/qcylindermesh.cpp b/src/extras/geometries/qcylindermesh.cpp
index 875d8ed9a..9b0ded28b 100644
--- a/src/extras/geometries/qcylindermesh.cpp
+++ b/src/extras/geometries/qcylindermesh.cpp
@@ -89,6 +89,7 @@ namespace Qt3DExtras {
/*!
* \class Qt3DExtras::QCylinderMesh
+ * \inheaderfile Qt3DExtras/QCylinderMesh
* \inmodule Qt3DExtras
*
* \inherits Qt3DRender::QGeometryRenderer
diff --git a/src/extras/geometries/qplanegeometry.cpp b/src/extras/geometries/qplanegeometry.cpp
index 74c90cf1b..16b401d3d 100644
--- a/src/extras/geometries/qplanegeometry.cpp
+++ b/src/extras/geometries/qplanegeometry.cpp
@@ -266,6 +266,7 @@ public:
/*!
* \class Qt3DExtras::QPlaneGeometry
+ * \inheaderfile Qt3DExtras/QPlaneGeometry
* \inmodule Qt3DExtras
* \brief The QPlaneGeometry class allows creation of a plane in 3D space.
* \since 5.7
diff --git a/src/extras/geometries/qplanemesh.cpp b/src/extras/geometries/qplanemesh.cpp
index f14d7cb97..120aed6df 100644
--- a/src/extras/geometries/qplanemesh.cpp
+++ b/src/extras/geometries/qplanemesh.cpp
@@ -73,6 +73,7 @@ namespace Qt3DExtras {
/*!
* \class Qt3DExtras::QPlaneMesh
+ * \inheaderfile Qt3DExtras/QPlaneMesh
* \inmodule Qt3DExtras
*
* \inherits Qt3DRender::QGeometryRenderer
diff --git a/src/extras/geometries/qspheregeometry.cpp b/src/extras/geometries/qspheregeometry.cpp
index 277d4fcb9..a79eb8074 100644
--- a/src/extras/geometries/qspheregeometry.cpp
+++ b/src/extras/geometries/qspheregeometry.cpp
@@ -380,6 +380,7 @@ void QSphereGeometryPrivate::init()
/*!
* \class Qt3DExtras::QSphereGeometry
+ * \inheaderfile Qt3DExtras/QSphereGeometry
* \inmodule Qt3DExtras
* \brief The QSphereGeometry class allows creation of a sphere in 3D space.
* \since 5.7
diff --git a/src/extras/geometries/qspheremesh.cpp b/src/extras/geometries/qspheremesh.cpp
index 90cf5a872..988a95990 100644
--- a/src/extras/geometries/qspheremesh.cpp
+++ b/src/extras/geometries/qspheremesh.cpp
@@ -79,6 +79,7 @@ namespace Qt3DExtras {
/*!
* \class Qt3DExtras::QSphereMesh
+ * \inheaderfile Qt3DExtras/QSphereMesh
* \inmodule Qt3DExtras
*
* \inherits Qt3DRender::QGeometryRenderer
diff --git a/src/extras/geometries/qtorusgeometry.cpp b/src/extras/geometries/qtorusgeometry.cpp
index ebc944e72..08afce1b0 100644
--- a/src/extras/geometries/qtorusgeometry.cpp
+++ b/src/extras/geometries/qtorusgeometry.cpp
@@ -276,8 +276,8 @@ void QTorusGeometryPrivate::init()
m_normalAttribute->setCount(nVerts);
m_tangentAttribute->setName(QAttribute::defaultTangentAttributeName());
- m_tangentAttribute->setDataType(QAttribute::Float);
- m_tangentAttribute->setDataSize(4);
+ m_tangentAttribute->setVertexBaseType(QAttribute::Float);
+ m_tangentAttribute->setVertexSize(4);
m_tangentAttribute->setAttributeType(QAttribute::VertexAttribute);
m_tangentAttribute->setBuffer(m_vertexBuffer);
m_tangentAttribute->setByteStride(stride);
@@ -360,6 +360,7 @@ void QTorusGeometryPrivate::init()
/*!
* \class Qt3DExtras::QTorusGeometry
+ * \inheaderfile Qt3DExtras/QTorusGeometry
* \inmodule Qt3DExtras
* \brief The QTorusGeometry class allows creation of a torus in 3D space.
* \since 5.7
diff --git a/src/extras/geometries/qtorusmesh.cpp b/src/extras/geometries/qtorusmesh.cpp
index a77631b73..96fce9ec0 100644
--- a/src/extras/geometries/qtorusmesh.cpp
+++ b/src/extras/geometries/qtorusmesh.cpp
@@ -82,6 +82,7 @@ namespace Qt3DExtras {
/*!
* \class Qt3DExtras::QTorusMesh
+ * \inheaderfile Qt3DExtras/QTorusMesh
* \inmodule Qt3DExtras
*
* \inherits Qt3DRender::QGeometryRenderer
diff --git a/src/input/backend/abstractaxisinput.cpp b/src/input/backend/abstractaxisinput.cpp
index 1038a64b1..5cb209f25 100644
--- a/src/input/backend/abstractaxisinput.cpp
+++ b/src/input/backend/abstractaxisinput.cpp
@@ -40,7 +40,9 @@
#include "abstractaxisinput_p.h"
#include <Qt3DInput/qabstractaxisinput.h>
#include <Qt3DInput/qabstractphysicaldevice.h>
+#include <Qt3DInput/private/inputhandler_p.h>
#include <Qt3DInput/private/qabstractaxisinput_p.h>
+#include <Qt3DInput/private/qinputdeviceintegration_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
diff --git a/src/input/backend/abstractaxisinput_p.h b/src/input/backend/abstractaxisinput_p.h
index 3e9b2287c..8ce43bce8 100644
--- a/src/input/backend/abstractaxisinput_p.h
+++ b/src/input/backend/abstractaxisinput_p.h
@@ -58,8 +58,12 @@ QT_BEGIN_NAMESPACE
namespace Qt3DInput {
+class QAbstractPhysicalDeviceBackendNode;
+
namespace Input {
+class InputHandler;
+
class Q_AUTOTEST_EXPORT AbstractAxisInput : public Qt3DCore::QBackendNode
{
public:
@@ -68,6 +72,8 @@ public:
inline Qt3DCore::QNodeId sourceDevice() const { return m_sourceDevice; }
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+ virtual float process(InputHandler *inputHandler, qint64 currentTime) = 0;
+
protected:
AbstractAxisInput();
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_OVERRIDE;
diff --git a/src/input/backend/action.cpp b/src/input/backend/action.cpp
index 67ccda11b..b7fa8740e 100644
--- a/src/input/backend/action.cpp
+++ b/src/input/backend/action.cpp
@@ -73,7 +73,7 @@ void Action::cleanup()
void Action::setActionTriggered(bool actionTriggered)
{
- if (actionTriggered != m_actionTriggered) {
+ if (isEnabled() && (actionTriggered != m_actionTriggered)) {
m_actionTriggered = actionTriggered;
// Send change to the frontend
diff --git a/src/input/backend/actioninput.cpp b/src/input/backend/actioninput.cpp
index c22d20730..b120c789e 100644
--- a/src/input/backend/actioninput.cpp
+++ b/src/input/backend/actioninput.cpp
@@ -39,11 +39,10 @@
#include "actioninput_p.h"
#include <Qt3DInput/qactioninput.h>
-#include <Qt3DInput/qabstractphysicaldevice.h>
#include <Qt3DInput/private/qactioninput_p.h>
-#include <Qt3DInput/private/qinputdeviceintegration_p.h>
#include <Qt3DInput/private/inputhandler_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DInput/private/utils_p.h>
QT_BEGIN_NAMESPACE
@@ -76,11 +75,10 @@ void ActionInput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == Qt3DCore::PropertyUpdated) {
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("sourceDevice")) {
+ if (propertyChange->propertyName() == QByteArrayLiteral("sourceDevice"))
m_sourceDevice = propertyChange->value().value<Qt3DCore::QNodeId>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("buttons")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("buttons"))
m_buttons = propertyChange->value().value<QVector<int>>();
- }
}
AbstractActionInput::sceneChangeEvent(e);
}
@@ -89,15 +87,10 @@ bool ActionInput::process(InputHandler *inputHandler, qint64 currentTime)
{
Q_UNUSED(currentTime);
- QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = nullptr;
-
- const auto integrations = inputHandler->inputDeviceIntegrations();
- for (QInputDeviceIntegration *integration : integrations) {
- physicalDeviceBackend = integration->physicalDevice(sourceDevice());
- if (physicalDeviceBackend)
- break;
- }
+ if (!isEnabled())
+ return false;
+ QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = Utils::physicalDeviceForInput(this, inputHandler);
if (!physicalDeviceBackend)
return false;
diff --git a/src/input/backend/analogaxisinput.cpp b/src/input/backend/analogaxisinput.cpp
index 713390992..914604e33 100644
--- a/src/input/backend/analogaxisinput.cpp
+++ b/src/input/backend/analogaxisinput.cpp
@@ -40,8 +40,10 @@
#include "analogaxisinput_p.h"
#include <Qt3DInput/qanalogaxisinput.h>
#include <Qt3DInput/qabstractphysicaldevice.h>
+#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p.h>
#include <Qt3DInput/private/qanalogaxisinput_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DInput/private/utils_p.h>
QT_BEGIN_NAMESPACE
@@ -80,6 +82,23 @@ void AnalogAxisInput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
AbstractAxisInput::sceneChangeEvent(e);
}
+float AnalogAxisInput::process(InputHandler *inputHandler, qint64 currentTime)
+{
+ Q_UNUSED(currentTime);
+
+ if (!isEnabled())
+ return 0.0f;
+
+ if (m_axis == -1)
+ return 0.0f;
+
+ QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = Utils::physicalDeviceForInput(this, inputHandler);
+ if (!physicalDeviceBackend)
+ return 0.0f;
+
+ return physicalDeviceBackend->processedAxisValue(m_axis);
+}
+
} // Input
} // Qt3DInput
diff --git a/src/input/backend/analogaxisinput_p.h b/src/input/backend/analogaxisinput_p.h
index 8febb10e7..154ef5378 100644
--- a/src/input/backend/analogaxisinput_p.h
+++ b/src/input/backend/analogaxisinput_p.h
@@ -68,6 +68,8 @@ public:
inline int axis() const { return m_axis; }
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL;
+ float process(InputHandler *inputHandler, qint64 currentTime) Q_DECL_OVERRIDE;
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
diff --git a/src/input/backend/axis.cpp b/src/input/backend/axis.cpp
index b64173626..4239749c1 100644
--- a/src/input/backend/axis.cpp
+++ b/src/input/backend/axis.cpp
@@ -73,7 +73,7 @@ void Axis::cleanup()
void Axis::setAxisValue(float axisValue)
{
- if (axisValue != m_axisValue) {
+ if (isEnabled() && (axisValue != m_axisValue)) {
m_axisValue = axisValue;
// Send a change to the frontend
diff --git a/src/input/backend/backend.pri b/src/input/backend/backend.pri
index 5c22f0e50..846fb1705 100644
--- a/src/input/backend/backend.pri
+++ b/src/input/backend/backend.pri
@@ -31,7 +31,10 @@ HEADERS += \
$$PWD/inputsequence_p.h \
$$PWD/inputsettings_p.h \
$$PWD/eventsourcesetterhelper_p.h \
- $$PWD/job_common_p.h
+ $$PWD/job_common_p.h \
+ $$PWD/physicaldeviceproxy_p.h \
+ $$PWD/loadproxydevicejob_p.h \
+ $$PWD/utils_p.h
SOURCES += \
$$PWD/keyboarddevice.cpp \
@@ -61,6 +64,8 @@ SOURCES += \
$$PWD/inputchord.cpp \
$$PWD/inputsequence.cpp \
$$PWD/inputsettings.cpp \
- $$PWD/eventsourcesetterhelper.cpp
+ $$PWD/eventsourcesetterhelper.cpp \
+ $$PWD/physicaldeviceproxy.cpp \
+ $$PWD/loadproxydevicejob.cpp
INCLUDEPATH += $$PWD
diff --git a/src/input/backend/buttonaxisinput.cpp b/src/input/backend/buttonaxisinput.cpp
index 6042b2eff..99fa99852 100644
--- a/src/input/backend/buttonaxisinput.cpp
+++ b/src/input/backend/buttonaxisinput.cpp
@@ -40,8 +40,10 @@
#include "buttonaxisinput_p.h"
#include <Qt3DInput/qbuttonaxisinput.h>
#include <Qt3DInput/qabstractphysicaldevice.h>
+#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p.h>
#include <Qt3DInput/private/qbuttonaxisinput_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DInput/private/utils_p.h>
QT_BEGIN_NAMESPACE
@@ -114,6 +116,43 @@ void ButtonAxisInput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
AbstractAxisInput::sceneChangeEvent(e);
}
+namespace {
+
+bool anyOfRequiredButtonsPressed(const QVector<int> &buttons, QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend)
+{
+ bool validButtonWasPressed = false;
+ for (int button : buttons) {
+ if (physicalDeviceBackend->isButtonPressed(button)) {
+ validButtonWasPressed = true;
+ break;
+ }
+ }
+ return validButtonWasPressed;
+}
+
+} // anonymous
+
+float ButtonAxisInput::process(InputHandler *inputHandler, qint64 currentTime)
+{
+ if (!isEnabled())
+ return 0.0f;
+
+ if (m_buttons.isEmpty())
+ return 0.0f;
+
+ QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = Utils::physicalDeviceForInput(this, inputHandler);
+ if (!physicalDeviceBackend)
+ return 0.0f;
+
+ // TO DO: Linear Curver for the progression of the scale value
+ if (anyOfRequiredButtonsPressed(m_buttons, physicalDeviceBackend))
+ updateSpeedRatio(currentTime, ButtonAxisInput::Accelerate);
+ else if (m_speedRatio != 0.0f)
+ updateSpeedRatio(currentTime, ButtonAxisInput::Decelerate);
+
+ return m_speedRatio * m_scale;
+}
+
} // Input
} // Qt3DInput
diff --git a/src/input/backend/buttonaxisinput_p.h b/src/input/backend/buttonaxisinput_p.h
index 9e82a6ebc..05724567c 100644
--- a/src/input/backend/buttonaxisinput_p.h
+++ b/src/input/backend/buttonaxisinput_p.h
@@ -78,11 +78,12 @@ public:
inline float speedRatio() const { return m_speedRatio; }
inline qint64 lastUpdateTime() const { return m_lastUpdateTime; }
- void updateSpeedRatio(qint64 currentTime, UpdateType type);
-
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_FINAL;
+ float process(InputHandler *inputHandler, qint64 currentTime) Q_DECL_OVERRIDE;
+
private:
+ void updateSpeedRatio(qint64 currentTime, UpdateType type);
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
QVector<int> m_buttons;
diff --git a/src/input/backend/handle_types_p.h b/src/input/backend/handle_types_p.h
index d81a1225b..cc78a68ba 100644
--- a/src/input/backend/handle_types_p.h
+++ b/src/input/backend/handle_types_p.h
@@ -72,6 +72,7 @@ class InputSequence;
class InputChord;
class LogicalDevice;
class GenericDeviceBackendNode;
+class PhysicalDeviceProxy;
typedef Qt3DCore::QHandle<KeyboardDevice, 8> HKeyboardDevice;
typedef Qt3DCore::QHandle<KeyboardHandler, 16> HKeyboardHandler;
@@ -87,6 +88,7 @@ typedef Qt3DCore::QHandle<InputSequence, 16> HInputSequence;
typedef Qt3DCore::QHandle<InputChord, 16> HInputChord;
typedef Qt3DCore::QHandle<LogicalDevice, 16> HLogicalDevice;
typedef Qt3DCore::QHandle<GenericDeviceBackendNode, 8> HGenericDeviceBackendNode;
+typedef Qt3DCore::QHandle<PhysicalDeviceProxy, 16> HPhysicalDeviceProxy;
} // namespace Input
} // namespace Qt3DInput
diff --git a/src/input/backend/inputchord.cpp b/src/input/backend/inputchord.cpp
index a37bb8ea4..ebcf79737 100644
--- a/src/input/backend/inputchord.cpp
+++ b/src/input/backend/inputchord.cpp
@@ -136,6 +136,9 @@ void InputChord::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
bool InputChord::process(InputHandler *inputHandler, qint64 currentTime)
{
+ if (!isEnabled())
+ return false;
+
const qint64 startTime = m_startTime;
bool triggered = false;
int activeInputs = 0;
diff --git a/src/input/backend/inputhandler.cpp b/src/input/backend/inputhandler.cpp
index fe2a04bd7..82b5c7c7c 100644
--- a/src/input/backend/inputhandler.cpp
+++ b/src/input/backend/inputhandler.cpp
@@ -47,6 +47,7 @@
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include "inputsettings_p.h"
#include "eventsourcesetterhelper_p.h"
+#include <Qt3DInput/private/qinputdeviceintegration_p.h>
QT_BEGIN_NAMESPACE
@@ -72,6 +73,7 @@ InputHandler::InputHandler()
, m_inputSequenceManager(new InputSequenceManager())
, m_logicalDeviceManager(new LogicalDeviceManager())
, m_genericPhysicalDeviceBackendNodeManager(new GenericDeviceBackendNodeManager)
+ , m_physicalDeviceProxyManager(new PhysicalDeviceProxyManager())
, m_settings(nullptr)
, m_eventSourceSetter(new Qt3DInput::Input::EventSourceSetterHelper(this))
{
@@ -100,6 +102,7 @@ InputHandler::~InputHandler()
delete m_inputSequenceManager;
delete m_logicalDeviceManager;
delete m_genericPhysicalDeviceBackendNodeManager;
+ delete m_physicalDeviceProxyManager;
}
// Called in MainThread (by the EventSourceHelperSetter)
@@ -300,6 +303,16 @@ EventSourceSetterHelper *InputHandler::eventSourceHelper() const
return m_eventSourceSetter.data();
}
+QAbstractPhysicalDevice *Qt3DInput::Input::InputHandler::createPhysicalDevice(const QString &name)
+{
+ QAbstractPhysicalDevice *device = nullptr;
+ for (Qt3DInput::QInputDeviceIntegration *integration : qAsConst(m_inputDeviceIntegrations)) {
+ if ((device = integration->createPhysicalDevice(name)) != nullptr)
+ break;
+ }
+ return device;
+}
+
void InputHandler::updateEventSource()
{
if (m_settings != nullptr) {
diff --git a/src/input/backend/inputhandler_p.h b/src/input/backend/inputhandler_p.h
index 2cfb56e3f..1628f3975 100644
--- a/src/input/backend/inputhandler_p.h
+++ b/src/input/backend/inputhandler_p.h
@@ -67,6 +67,7 @@ class QNodeId;
namespace Qt3DInput {
class QInputDeviceIntegration;
+class QAbstractPhysicalDevice;
namespace Input {
@@ -88,6 +89,7 @@ class InputSequenceManager;
class LogicalDeviceManager;
class GenericPhysicalDeviceManager;
class GenericDeviceBackendNodeManager;
+class PhysicalDeviceProxyManager;
class InputSettings;
class EventSourceSetterHelper;
@@ -111,6 +113,7 @@ public:
inline InputSequenceManager *inputSequenceManager() const { return m_inputSequenceManager; }
inline LogicalDeviceManager *logicalDeviceManager() const { return m_logicalDeviceManager; }
inline GenericDeviceBackendNodeManager *genericDeviceBackendNodeManager() const { return m_genericPhysicalDeviceBackendNodeManager; }
+ inline PhysicalDeviceProxyManager *physicalDeviceProxyManager() const { return m_physicalDeviceProxyManager; }
inline InputSettings *inputSettings() const { return m_settings; }
void appendKeyEvent(const QT_PREPEND_NAMESPACE(QKeyEvent) &event);
@@ -144,6 +147,8 @@ public:
void setEventSourceHelper(EventSourceSetterHelper *helper);
EventSourceSetterHelper *eventSourceHelper() const;
+ QAbstractPhysicalDevice *createPhysicalDevice(const QString &name);
+
void updateEventSource();
AbstractActionInput *lookupActionInput(Qt3DCore::QNodeId id) const;
@@ -175,6 +180,7 @@ private:
InputSequenceManager *m_inputSequenceManager;
LogicalDeviceManager *m_logicalDeviceManager;
GenericDeviceBackendNodeManager *m_genericPhysicalDeviceBackendNodeManager;
+ PhysicalDeviceProxyManager *m_physicalDeviceProxyManager;
QVector<Qt3DInput::QInputDeviceIntegration *> m_inputDeviceIntegrations;
InputSettings *m_settings;
QScopedPointer<EventSourceSetterHelper> m_eventSourceSetter;
diff --git a/src/input/backend/inputmanagers_p.h b/src/input/backend/inputmanagers_p.h
index 9473dbf45..d162ea519 100644
--- a/src/input/backend/inputmanagers_p.h
+++ b/src/input/backend/inputmanagers_p.h
@@ -68,6 +68,7 @@
#include <Qt3DInput/private/buttonaxisinput_p.h>
#include <Qt3DInput/private/logicaldevice_p.h>
#include <Qt3DInput/private/genericdevicebackendnode_p.h>
+#include <Qt3DInput/private/physicaldeviceproxy_p.h>
QT_BEGIN_NAMESPACE
@@ -221,6 +222,22 @@ public:
GenericDeviceBackendNodeManager() {}
};
+class Q_AUTOTEST_EXPORT PhysicalDeviceProxyManager : public Qt3DCore::QResourceManager<
+ PhysicalDeviceProxy,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy>
+{
+public:
+ PhysicalDeviceProxyManager() {}
+
+ void addPendingProxyToLoad(Qt3DCore::QNodeId id) { m_pendingProxies.push_back(id); }
+ QVector<Qt3DCore::QNodeId> takePendingProxiesToLoad() { return std::move(m_pendingProxies); }
+
+private:
+ QVector<Qt3DCore::QNodeId> m_pendingProxies;
+};
+
} // namespace Input
} // namespace Qt3DInput
diff --git a/src/input/backend/inputsequence.cpp b/src/input/backend/inputsequence.cpp
index 378a7d33d..ee31cb1de 100644
--- a/src/input/backend/inputsequence.cpp
+++ b/src/input/backend/inputsequence.cpp
@@ -164,6 +164,9 @@ void InputSequence::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
bool InputSequence::process(InputHandler *inputHandler, qint64 currentTime)
{
+ if (!isEnabled())
+ return false;
+
if (m_startTime != 0) {
// Check if we are still inside the time limit for the sequence
if ((currentTime - m_startTime) > m_timeout) {
diff --git a/src/input/backend/job_common_p.h b/src/input/backend/job_common_p.h
index 56bf3ee2d..589c75fb9 100644
--- a/src/input/backend/job_common_p.h
+++ b/src/input/backend/job_common_p.h
@@ -65,7 +65,8 @@ namespace JobTypes {
AssignKeyboardFocus = 1024,
KeyEventDispatcher,
MouseEventDispatcher,
- UpdateAxisAction
+ UpdateAxisAction,
+ DeviceProxyLoading
};
} // JobTypes
diff --git a/src/input/backend/loadproxydevicejob.cpp b/src/input/backend/loadproxydevicejob.cpp
new file mode 100644
index 000000000..622d7ab83
--- /dev/null
+++ b/src/input/backend/loadproxydevicejob.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "loadproxydevicejob_p.h"
+#include <Qt3DInput/private/inputhandler_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include "job_common_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+namespace Input {
+
+LoadProxyDeviceJob::LoadProxyDeviceJob()
+ : Qt3DCore::QAspectJob()
+ , m_inputHandler(nullptr)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::DeviceProxyLoading, 0);
+
+}
+
+LoadProxyDeviceJob::~LoadProxyDeviceJob()
+{
+}
+
+void LoadProxyDeviceJob::setProxiesToLoad(const QVector<Qt3DCore::QNodeId> &wrappers)
+{
+ m_proxies = wrappers;
+}
+
+void LoadProxyDeviceJob::setInputHandler(InputHandler *handler)
+{
+ m_inputHandler = handler;
+}
+
+InputHandler *LoadProxyDeviceJob::inputHandler() const
+{
+ return m_inputHandler;
+}
+
+QVector<Qt3DCore::QNodeId> LoadProxyDeviceJob::proxies() const
+{
+ return m_proxies;
+}
+
+void LoadProxyDeviceJob::run()
+{
+ Q_ASSERT(m_inputHandler);
+ for (const Qt3DCore::QNodeId id : qAsConst(m_proxies)) {
+ PhysicalDeviceProxy *proxy = m_inputHandler->physicalDeviceProxyManager()->lookupResource(id);
+ QAbstractPhysicalDevice *device = m_inputHandler->createPhysicalDevice(proxy->deviceName());
+ if (device != nullptr)
+ proxy->setDevice(device);
+ }
+ m_proxies.clear();
+}
+
+} // namespace Input
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
diff --git a/src/input/backend/loadproxydevicejob_p.h b/src/input/backend/loadproxydevicejob_p.h
new file mode 100644
index 000000000..67431f3ae
--- /dev/null
+++ b/src/input/backend/loadproxydevicejob_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DINPUT_INPUT_LOADPROXYDEVICEJOB_P_H
+#define QT3DINPUT_INPUT_LOADPROXYDEVICEJOB_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DCore/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+namespace Input {
+
+class InputHandler;
+
+class Q_AUTOTEST_EXPORT LoadProxyDeviceJob : public Qt3DCore::QAspectJob
+{
+public:
+ LoadProxyDeviceJob();
+ ~LoadProxyDeviceJob();
+
+ void setProxiesToLoad(const QVector<Qt3DCore::QNodeId> &proxies);
+ void setInputHandler(InputHandler *handler);
+
+ InputHandler *inputHandler() const;
+ QVector<Qt3DCore::QNodeId> proxies() const;
+
+ void run() Q_DECL_FINAL;
+private:
+ InputHandler *m_inputHandler;
+ QVector<Qt3DCore::QNodeId> m_proxies;
+};
+
+typedef QSharedPointer<LoadProxyDeviceJob> LoadProxyDeviceJobPtr;
+
+} // namespace Input
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
+
+#endif // QT3DINPUT_INPUT_LOADPROXYDEVICEJOB_P_H
diff --git a/src/input/backend/mousedevice.cpp b/src/input/backend/mousedevice.cpp
index e649824a4..918fdecb0 100644
--- a/src/input/backend/mousedevice.cpp
+++ b/src/input/backend/mousedevice.cpp
@@ -77,6 +77,11 @@ void MouseDevice::setInputHandler(InputHandler *handler)
m_inputHandler = handler;
}
+InputHandler *MouseDevice::inputHandler() const
+{
+ return m_inputHandler;
+}
+
float MouseDevice::axisValue(int axisIdentifier) const
{
switch (axisIdentifier) {
@@ -109,6 +114,26 @@ bool MouseDevice::isButtonPressed(int buttonIdentifier) const
return false;
}
+MouseDevice::MouseState MouseDevice::mouseState() const
+{
+ return m_mouseState;
+}
+
+QPointF MouseDevice::previousPos() const
+{
+ return m_previousPos;
+}
+
+bool MouseDevice::wasPressed() const
+{
+ return m_wasPressed;
+}
+
+float MouseDevice::sensitivity() const
+{
+ return m_sensitivity;
+}
+
void MouseDevice::updateWheelEvents(const QList<QT_PREPEND_NAMESPACE (QWheelEvent)> &events)
{
// Reset axis values before we accumulate new values for this frame
diff --git a/src/input/backend/mousedevice_p.h b/src/input/backend/mousedevice_p.h
index 02a6d916e..8b85ee34a 100644
--- a/src/input/backend/mousedevice_p.h
+++ b/src/input/backend/mousedevice_p.h
@@ -64,28 +64,9 @@ namespace Input {
class InputHandler;
-class MouseDevice : public Qt3DInput::QAbstractPhysicalDeviceBackendNode
+class Q_AUTOTEST_EXPORT MouseDevice : public Qt3DInput::QAbstractPhysicalDeviceBackendNode
{
public:
- MouseDevice();
- ~MouseDevice();
-
- void setInputHandler(InputHandler *handler);
-
- float axisValue(int axisIdentifier) const Q_DECL_OVERRIDE;
- bool isButtonPressed(int buttonIdentifier) const Q_DECL_OVERRIDE;
-
- void updateMouseEvents(const QList<QT_PREPEND_NAMESPACE(QMouseEvent)> &events);
- void updateWheelEvents(const QList<QT_PREPEND_NAMESPACE(QWheelEvent)> &events);
-
-protected:
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
-
-private:
- void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
-
- InputHandler *m_inputHandler;
-
struct MouseState {
MouseState()
@@ -107,6 +88,30 @@ private:
bool centerPressed;
};
+ MouseDevice();
+ ~MouseDevice();
+
+ void setInputHandler(InputHandler *handler);
+ InputHandler *inputHandler() const;
+
+ float axisValue(int axisIdentifier) const Q_DECL_OVERRIDE;
+ bool isButtonPressed(int buttonIdentifier) const Q_DECL_OVERRIDE;
+
+ void updateMouseEvents(const QList<QT_PREPEND_NAMESPACE(QMouseEvent)> &events);
+ void updateWheelEvents(const QList<QT_PREPEND_NAMESPACE(QWheelEvent)> &events);
+
+ MouseState mouseState() const;
+ QPointF previousPos() const;
+ bool wasPressed() const;
+ float sensitivity() const;
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ InputHandler *m_inputHandler;
+
MouseState m_mouseState;
QPointF m_previousPos;
bool m_wasPressed;
diff --git a/src/input/backend/physicaldeviceproxy.cpp b/src/input/backend/physicaldeviceproxy.cpp
new file mode 100644
index 000000000..2e46309fd
--- /dev/null
+++ b/src/input/backend/physicaldeviceproxy.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "physicaldeviceproxy_p.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DInput/qabstractphysicaldevice.h>
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+
+namespace Input {
+
+PhysicalDeviceProxy::PhysicalDeviceProxy()
+ : QBackendNode(QBackendNode::ReadWrite)
+ , m_manager(nullptr)
+{
+}
+
+void PhysicalDeviceProxy::cleanup()
+{
+ QBackendNode::setEnabled(false);
+ m_deviceName.clear();
+ m_manager = nullptr;
+ m_physicalDeviceId = Qt3DCore::QNodeId();
+}
+
+QString PhysicalDeviceProxy::deviceName() const
+{
+ return m_deviceName;
+}
+
+void PhysicalDeviceProxy::setManager(PhysicalDeviceProxyManager *manager)
+{
+ m_manager = manager;
+}
+
+PhysicalDeviceProxyManager *PhysicalDeviceProxy::manager() const
+{
+ return m_manager;
+}
+
+void PhysicalDeviceProxy::setDevice(QAbstractPhysicalDevice *device)
+{
+ m_physicalDeviceId = Qt3DCore::QNodeId();
+ // Move the device to the main thread
+ if (device != nullptr) {
+ m_physicalDeviceId = device->id();
+ device->moveToThread(QCoreApplication::instance()->thread());
+ }
+
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("device");
+ e->setValue(QVariant::fromValue(device));
+ notifyObservers(e);
+}
+
+Qt3DCore::QNodeId PhysicalDeviceProxy::physicalDeviceId() const
+{
+ return m_physicalDeviceId;
+}
+
+void PhysicalDeviceProxy::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractPhysicalDeviceProxyData>>(change);
+ const QAbstractPhysicalDeviceProxyData &data = typedChange->data;
+ m_deviceName = data.deviceName;
+
+ // Request to load the actual device
+ m_manager->addPendingProxyToLoad(peerId());
+}
+
+PhysicalDeviceProxyNodeFunctor::PhysicalDeviceProxyNodeFunctor(PhysicalDeviceProxyManager *manager)
+ : m_manager(manager)
+{
+}
+
+Qt3DCore::QBackendNode *PhysicalDeviceProxyNodeFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
+{
+ HPhysicalDeviceProxy handle = m_manager->getOrAcquireHandle(change->subjectId());
+ PhysicalDeviceProxy *backend = m_manager->data(handle);
+ backend->setManager(m_manager);
+ return backend;
+}
+
+Qt3DCore::QBackendNode *PhysicalDeviceProxyNodeFunctor::get(Qt3DCore::QNodeId id) const
+{
+ return m_manager->lookupResource(id);
+}
+
+void PhysicalDeviceProxyNodeFunctor::destroy(Qt3DCore::QNodeId id) const
+{
+ m_manager->releaseResource(id);
+}
+
+} // namespace Input
+
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
+
diff --git a/src/input/backend/physicaldeviceproxy_p.h b/src/input/backend/physicaldeviceproxy_p.h
new file mode 100644
index 000000000..0c714167e
--- /dev/null
+++ b/src/input/backend/physicaldeviceproxy_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DINPUT_INPUT_PHYSICALDEVICEPROXY_P_H
+#define QT3DINPUT_INPUT_PHYSICALDEVICEPROXY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qbackendnode.h>
+#include <Qt3DCore/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+
+class QAbstractPhysicalDevice;
+
+namespace Input {
+
+class PhysicalDeviceProxyManager;
+
+class Q_AUTOTEST_EXPORT PhysicalDeviceProxy : public Qt3DCore::QBackendNode
+{
+public:
+ PhysicalDeviceProxy();
+ void cleanup();
+
+ QString deviceName() const;
+
+ void setManager(PhysicalDeviceProxyManager *manager);
+ PhysicalDeviceProxyManager *manager() const;
+
+ // Called from a job to update the frontend
+ void setDevice(QAbstractPhysicalDevice *device);
+ Qt3DCore::QNodeId physicalDeviceId() const;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ QString m_deviceName;
+ PhysicalDeviceProxyManager *m_manager;
+ Qt3DCore::QNodeId m_physicalDeviceId;
+};
+
+class PhysicalDeviceProxyNodeFunctor: public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit PhysicalDeviceProxyNodeFunctor(PhysicalDeviceProxyManager *manager);
+
+ Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL;
+ Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL;
+ void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL;
+
+private:
+ PhysicalDeviceProxyManager *m_manager;
+};
+
+} // namespace Input
+
+} // namespace Qt3DInput
+
+QT_END_NAMESPACE
+
+#endif // QT3DINPUT_INPUT_PHYSICALDEVICEPROXY_P_H
diff --git a/src/input/backend/updateaxisactionjob.cpp b/src/input/backend/updateaxisactionjob.cpp
index bbd36228e..4e990ff0e 100644
--- a/src/input/backend/updateaxisactionjob.cpp
+++ b/src/input/backend/updateaxisactionjob.cpp
@@ -40,8 +40,6 @@
#include "updateaxisactionjob_p.h"
#include <Qt3DInput/private/inputhandler_p.h>
#include <Qt3DInput/private/inputmanagers_p.h>
-#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p.h>
-#include <Qt3DInput/private/qinputdeviceintegration_p.h>
#include <Qt3DInput/private/job_common_p.h>
QT_BEGIN_NAMESPACE
@@ -50,22 +48,6 @@ namespace Qt3DInput {
namespace Input {
-namespace {
-
-bool anyOfRequiredButtonsPressed(const QVector<int> &buttons, QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend)
-{
- bool validButtonWasPressed = false;
- for (int button : buttons) {
- if (physicalDeviceBackend->isButtonPressed(button)) {
- validButtonWasPressed = true;
- break;
- }
- }
- return validButtonWasPressed;
-}
-
-} // anonymous
-
UpdateAxisActionJob::UpdateAxisActionJob(qint64 currentTime, InputHandler *handler, HLogicalDevice handle)
: Qt3DCore::QAspectJob()
, m_currentTime(currentTime)
@@ -118,39 +100,8 @@ void UpdateAxisActionJob::updateAxis(LogicalDevice *device)
float axisValue = 0.0f;
const auto axisInputIds = axis->inputs();
- for (const Qt3DCore::QNodeId axisInputId : axisInputIds) {
- AnalogAxisInput *analogInput = m_handler->analogAxisInputManager()->lookupResource(axisInputId);
- if (analogInput) {
- QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = findAxisInputPhysicalDevice(analogInput);
- if (physicalDeviceBackend && analogInput->axis() != -1) {
- // Update the value
- axisValue += physicalDeviceBackend->processedAxisValue(analogInput->axis());
- }
- continue;
- }
-
- ButtonAxisInput *buttonInput = m_handler->buttonAxisInputManager()->lookupResource(axisInputId);
- if (buttonInput) {
- QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = findAxisInputPhysicalDevice(buttonInput);
- if (physicalDeviceBackend != nullptr) {
- // Update the value
- const QVector<int> buttons = buttonInput ? buttonInput->buttons() : QVector<int>();
- if (!buttons.isEmpty()) {
- // TO DO: Linear Curver for the progression of the scale value
- if (anyOfRequiredButtonsPressed(buttons, physicalDeviceBackend))
- buttonInput->updateSpeedRatio(m_currentTime, ButtonAxisInput::Accelerate);
- else if (buttonInput->speedRatio() != 0.0f)
- buttonInput->updateSpeedRatio(m_currentTime, ButtonAxisInput::Decelerate);
-
- axisValue += buttonInput->speedRatio() * buttonInput->scale();
- }
- }
-
- continue;
- }
-
- Q_UNREACHABLE();
- }
+ for (const Qt3DCore::QNodeId axisInputId : axisInputIds)
+ axisValue += processAxisInput(axisInputId);
// Clamp the axisValue -1/1
axisValue = qMin(1.0f, qMax(axisValue, -1.0f));
@@ -158,16 +109,18 @@ void UpdateAxisActionJob::updateAxis(LogicalDevice *device)
}
}
-QAbstractPhysicalDeviceBackendNode *UpdateAxisActionJob::findAxisInputPhysicalDevice(AbstractAxisInput *axisInput)
+float UpdateAxisActionJob::processAxisInput(const Qt3DCore::QNodeId axisInputId)
{
- const auto integrations = m_handler->inputDeviceIntegrations();
- for (QInputDeviceIntegration *integration : integrations) {
- QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = integration->physicalDevice(axisInput->sourceDevice());
- if (physicalDeviceBackend)
- return physicalDeviceBackend;
- }
+ AnalogAxisInput *analogInput = m_handler->analogAxisInputManager()->lookupResource(axisInputId);
+ if (analogInput)
+ return analogInput->process(m_handler, m_currentTime);
+
+ ButtonAxisInput *buttonInput = m_handler->buttonAxisInputManager()->lookupResource(axisInputId);
+ if (buttonInput)
+ return buttonInput->process(m_handler, m_currentTime);
- return nullptr;
+ Q_UNREACHABLE();
+ return 0.0f;
}
} // Input
diff --git a/src/input/backend/updateaxisactionjob_p.h b/src/input/backend/updateaxisactionjob_p.h
index 3b71e7a88..ea590a1b2 100644
--- a/src/input/backend/updateaxisactionjob_p.h
+++ b/src/input/backend/updateaxisactionjob_p.h
@@ -77,14 +77,14 @@ private:
void updateAction(LogicalDevice *device);
bool processActionInput(const Qt3DCore::QNodeId actionInputId);
void updateAxis(LogicalDevice *device);
- QAbstractPhysicalDeviceBackendNode *findAxisInputPhysicalDevice(AbstractAxisInput *axisInput);
+ float processAxisInput(const Qt3DCore::QNodeId axisInputId);
const qint64 m_currentTime;
InputHandler *m_handler;
HLogicalDevice m_handle;
};
-typedef QScopedPointer<UpdateAxisActionJob> UpdateAxisActionJobPtr;
+typedef QSharedPointer<UpdateAxisActionJob> UpdateAxisActionJobPtr;
} // Input
diff --git a/src/input/backend/utils_p.h b/src/input/backend/utils_p.h
new file mode 100644
index 000000000..65363ab0a
--- /dev/null
+++ b/src/input/backend/utils_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DINPUT_INPUT_UTILS_P_H
+#define QT3DINPUT_INPUT_UTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DInput/private/inputhandler_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DInput/private/physicaldeviceproxy_p.h>
+#include <Qt3DInput/private/qinputdeviceintegration_p.h>
+#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+
+namespace Input {
+
+namespace Utils {
+
+template<class InputClass>
+QAbstractPhysicalDeviceBackendNode *physicalDeviceForInput(InputClass *input, InputHandler *handler)
+{
+ // Note: the source device can be a proxy
+ // in which case sourceDeviceId should be the proxy's device id
+ Qt3DCore::QNodeId sourceDeviceId = input->sourceDevice();
+
+ {
+ PhysicalDeviceProxy *deviceProxy = nullptr;
+ if ((deviceProxy = handler->physicalDeviceProxyManager()->lookupResource(sourceDeviceId)) != nullptr)
+ sourceDeviceId = deviceProxy->physicalDeviceId();
+ }
+
+ // Early return if the sourceDeviceId is null
+ if (!sourceDeviceId.isNull()) {
+ const auto integrations = handler->inputDeviceIntegrations();
+ for (QInputDeviceIntegration *integration : integrations) {
+ QAbstractPhysicalDeviceBackendNode *physicalDeviceBackend = integration->physicalDevice(sourceDeviceId);
+ if (physicalDeviceBackend)
+ return physicalDeviceBackend;
+ }
+ }
+
+ return nullptr;
+}
+
+} // Utils
+
+} // Input
+
+} // Qt3DInput
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DINPUT_INPUT_UTILS_P_H
diff --git a/src/input/frontend/frontend.pri b/src/input/frontend/frontend.pri
index 67c93d2b9..ecde941a3 100644
--- a/src/input/frontend/frontend.pri
+++ b/src/input/frontend/frontend.pri
@@ -45,7 +45,9 @@ HEADERS += \
$$PWD/qphysicaldevicecreatedchange.h \
$$PWD/qphysicaldevicecreatedchange_p.h \
$$PWD/qaxisaccumulator.h \
- $$PWD/qaxisaccumulator_p.h
+ $$PWD/qaxisaccumulator_p.h \
+ $$PWD/qabstractphysicaldeviceproxy_p.h \
+ $$PWD/qabstractphysicaldeviceproxy_p_p.h
SOURCES += \
@@ -74,7 +76,8 @@ SOURCES += \
$$PWD/qinputsequence.cpp \
$$PWD/qinputsettings.cpp \
$$PWD/qphysicaldevicecreatedchange.cpp \
- $$PWD/qaxisaccumulator.cpp
+ $$PWD/qaxisaccumulator.cpp \
+ $$PWD/qabstractphysicaldeviceproxy.cpp
qtHaveModule(gamepad) {
QT += gamepad
diff --git a/src/input/frontend/qabstractaxisinput.cpp b/src/input/frontend/qabstractaxisinput.cpp
index 46d889cb4..bcce50a33 100644
--- a/src/input/frontend/qabstractaxisinput.cpp
+++ b/src/input/frontend/qabstractaxisinput.cpp
@@ -55,6 +55,7 @@ namespace Qt3DInput {
/*!
* \class Qt3DInput::QAbstractAxisInput
+ * \inheaderfile Qt3DInput/QAbstractAxisInput
* \inmodule Qt3DInput
* \brief QAbstractActionInput is the base class for all Axis Input.
* \since 5.5
diff --git a/src/input/frontend/qabstractphysicaldeviceproxy.cpp b/src/input/frontend/qabstractphysicaldeviceproxy.cpp
new file mode 100644
index 000000000..03e59761b
--- /dev/null
+++ b/src/input/frontend/qabstractphysicaldeviceproxy.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractphysicaldeviceproxy_p.h"
+#include "qabstractphysicaldeviceproxy_p_p.h"
+#include <Qt3DInput/qphysicaldevicecreatedchange.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+
+/*!
+ \internal
+ */
+QAbstractPhysicalDeviceProxyPrivate::QAbstractPhysicalDeviceProxyPrivate(const QString &deviceName)
+ : QAbstractPhysicalDevicePrivate()
+ , m_deviceName(deviceName)
+ , m_status(QAbstractPhysicalDeviceProxy::NotFound)
+ , m_device(nullptr)
+{
+}
+
+/*!
+ \internal
+ */
+QAbstractPhysicalDeviceProxyPrivate::~QAbstractPhysicalDeviceProxyPrivate()
+{
+}
+
+/*!
+ \internal
+ */
+void QAbstractPhysicalDeviceProxyPrivate::setStatus(QAbstractPhysicalDeviceProxy::DeviceStatus status)
+{
+ if (status != m_status) {
+ m_status = status;
+ emit q_func()->statusChanged(status);
+ }
+}
+
+/*!
+ \class Qt3DInput::QAbstractPhysicalDeviceProxy
+ \inmodule Qt3DInput
+
+ \brief Qt3DInput::QAbstractPhysicalDeviceProxy acts as a proxy
+ for an actual Qt3DInput::QQAbstractPhysicalDevice device.
+
+ Qt3DInput::QAbstractPhysicalDeviceProxy can be used to facilitate
+ exposing a physical device to users. It alleviates the need to introspect
+ the axis and buttons based on their names.
+
+ It is typcally used through subclassing allowing to set the device name and
+ defining enums for the various axis and buttons of your targeted device.
+
+ At runtime, the status property will be updated to reflect whether an
+ actual device matching the device name could be created.
+
+ \since 5.8
+ */
+
+QString QAbstractPhysicalDeviceProxy::deviceName() const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ return d->m_deviceName;
+}
+
+QAbstractPhysicalDeviceProxy::DeviceStatus QAbstractPhysicalDeviceProxy::status() const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ return d->m_status;
+}
+
+int QAbstractPhysicalDeviceProxy::axisCount() const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ if (d->m_device != nullptr)
+ return d->m_device->axisCount();
+ return 0;
+}
+
+int QAbstractPhysicalDeviceProxy::buttonCount() const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ if (d->m_device != nullptr)
+ return d->m_device->buttonCount();
+ return 0;
+}
+
+QStringList QAbstractPhysicalDeviceProxy::axisNames() const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ if (d->m_device != nullptr)
+ return d->m_device->axisNames();
+ return QStringList();
+}
+
+QStringList QAbstractPhysicalDeviceProxy::buttonNames() const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ if (d->m_device != nullptr)
+ return d->m_device->buttonNames();
+ return QStringList();
+}
+
+int QAbstractPhysicalDeviceProxy::axisIdentifier(const QString &name) const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ if (d->m_device != nullptr)
+ return d->m_device->axisIdentifier(name);
+ return -1;
+}
+
+int QAbstractPhysicalDeviceProxy::buttonIdentifier(const QString &name) const
+{
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ if (d->m_device != nullptr)
+ return d->m_device->buttonIdentifier(name);
+ return -1;
+}
+
+/*!
+ \internal
+ */
+void QAbstractPhysicalDeviceProxy::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ Q_D(QAbstractPhysicalDeviceProxy);
+ Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (e->type() == Qt3DCore::PropertyUpdated) {
+ if (e->propertyName() == QByteArrayLiteral("device")) {
+ QAbstractPhysicalDevice *device = e->value().value<Qt3DInput::QAbstractPhysicalDevice *>();
+ QAbstractPhysicalDevice *oldDevice = d->m_device;
+ setDevice(device);
+ // Delete the old device if it existed
+ if (oldDevice != nullptr)
+ delete oldDevice;
+ }
+ }
+ QAbstractPhysicalDevice::sceneChangeEvent(change);
+}
+
+/*!
+ \internal
+ */
+QAbstractPhysicalDeviceProxy::QAbstractPhysicalDeviceProxy(QAbstractPhysicalDeviceProxyPrivate &dd, Qt3DCore::QNode *parent)
+ : QAbstractPhysicalDevice(dd, parent)
+{
+}
+
+/*!
+ \internal
+ */
+Qt3DCore::QNodeCreatedChangeBasePtr QAbstractPhysicalDeviceProxy::createNodeCreationChange() const
+{
+ auto creationChange = QPhysicalDeviceCreatedChangePtr<QAbstractPhysicalDeviceProxyData>::create(this);
+ QAbstractPhysicalDeviceProxyData &data = creationChange->data;
+
+ Q_D(const QAbstractPhysicalDeviceProxy);
+ data.deviceName = d->m_deviceName;
+
+ return creationChange;
+}
+
+/*!
+ \internal
+ */
+void QAbstractPhysicalDeviceProxy::setDevice(QAbstractPhysicalDevice *device)
+{
+ Q_D(QAbstractPhysicalDeviceProxy);
+
+ // Note: technically book keeping could be optional since we are the parent
+ // of the device. But who knows if someone plays with the object tree...
+
+ // Unset bookkeeper
+ if (d->m_device != nullptr) {
+ // Note: we cannot delete the device here as we don't how if we are
+ // called by the bookkeeper (in which case we would do a double free)
+ // or by the sceneChangeEvent
+ d->unregisterDestructionHelper(d->m_device);
+ d->setStatus(QAbstractPhysicalDeviceProxy::NotFound);
+ }
+
+ // Set parent so that node is created in the backend
+ if (device != nullptr && device->parent() == nullptr)
+ device->setParent(this);
+
+ d->m_device = device;
+
+ // Set bookkeeper
+ if (device != nullptr) {
+ d->setStatus(QAbstractPhysicalDeviceProxy::Ready);
+ d->registerDestructionHelper(d->m_device, &QAbstractPhysicalDeviceProxy::setDevice, d->m_device);
+ }
+}
+
+} // Qt3DInput
+
+QT_END_NAMESPACE
diff --git a/src/input/frontend/qabstractphysicaldeviceproxy_p.h b/src/input/frontend/qabstractphysicaldeviceproxy_p.h
new file mode 100644
index 000000000..1175f53bb
--- /dev/null
+++ b/src/input/frontend/qabstractphysicaldeviceproxy_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DINPUT_QABSTRACTPHYSICALDEVICEPROXY_P_H
+#define QT3DINPUT_QABSTRACTPHYSICALDEVICEPROXY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DInput/qabstractphysicaldevice.h>
+#include <Qt3DInput/private/qt3dinput_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+
+class QAbstractPhysicalDeviceProxyPrivate;
+
+class QT3DINPUTSHARED_PRIVATE_EXPORT QAbstractPhysicalDeviceProxy : public QAbstractPhysicalDevice
+{
+ Q_OBJECT
+ Q_PROPERTY(QString deviceName READ deviceName CONSTANT)
+ Q_PROPERTY(QAbstractPhysicalDeviceProxy::DeviceStatus status READ status NOTIFY statusChanged)
+
+public:
+ enum DeviceStatus {
+ Ready = 0,
+ NotFound
+ };
+ Q_ENUM(DeviceStatus) // LCOV_EXCL_LINE
+
+ QString deviceName() const;
+ DeviceStatus status() const;
+
+ int axisCount() const Q_DECL_OVERRIDE;
+ int buttonCount() const Q_DECL_OVERRIDE;
+ QStringList axisNames() const Q_DECL_OVERRIDE;
+ QStringList buttonNames() const Q_DECL_OVERRIDE;
+ int axisIdentifier(const QString &name) const Q_DECL_OVERRIDE;
+ int buttonIdentifier(const QString &name) const Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void statusChanged(QAbstractPhysicalDeviceProxy::DeviceStatus status);
+
+protected:
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
+
+ QAbstractPhysicalDeviceProxy(QAbstractPhysicalDeviceProxyPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+
+private:
+ void setDevice(QAbstractPhysicalDevice *device);
+ Q_DECLARE_PRIVATE(QAbstractPhysicalDeviceProxy)
+
+};
+
+} // Qt3DInput
+
+QT_END_NAMESPACE
+
+#endif // QT3DINPUT_QABSTRACTPHYSICALDEVICEPROXY_P_H
diff --git a/src/input/frontend/qabstractphysicaldeviceproxy_p_p.h b/src/input/frontend/qabstractphysicaldeviceproxy_p_p.h
new file mode 100644
index 000000000..2ba8f3bde
--- /dev/null
+++ b/src/input/frontend/qabstractphysicaldeviceproxy_p_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DINPUT_QABSTRACTPHYSICALDEVICEPROXY_P_P_H
+#define QT3DINPUT_QABSTRACTPHYSICALDEVICEPROXY_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DInput/private/qabstractphysicaldevice_p.h>
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h>
+#include <Qt3DInput/private/qt3dinput_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+
+class QAbstractPhysicalDeviceProxy;
+class QAbstractPhysicalDevice;
+
+class QT3DINPUTSHARED_PRIVATE_EXPORT QAbstractPhysicalDeviceProxyPrivate : public QAbstractPhysicalDevicePrivate
+{
+public:
+ explicit QAbstractPhysicalDeviceProxyPrivate(const QString &deviceName);
+ ~QAbstractPhysicalDeviceProxyPrivate();
+
+ Q_DECLARE_PUBLIC(QAbstractPhysicalDeviceProxy)
+ QString m_deviceName;
+ QAbstractPhysicalDeviceProxy::DeviceStatus m_status;
+ QAbstractPhysicalDevice *m_device;
+
+ void setStatus(QAbstractPhysicalDeviceProxy::DeviceStatus status);
+};
+
+struct QAbstractPhysicalDeviceProxyData
+{
+ QString deviceName;
+};
+
+} // Qt3DInput
+
+QT_END_NAMESPACE
+
+#endif // QT3DINPUT_QABSTRACTPHYSICALDEVICEPROXY_P_P_H
diff --git a/src/input/frontend/qaction.cpp b/src/input/frontend/qaction.cpp
index edbe68163..3a6e6dc4f 100644
--- a/src/input/frontend/qaction.cpp
+++ b/src/input/frontend/qaction.cpp
@@ -89,6 +89,8 @@ QAction::~QAction()
\property QAction::active
Holds \c true if the action is active.
+
+ Note this property is not updated when the action is disabled.
*/
bool QAction::isActive() const
{
diff --git a/src/input/frontend/qanalogaxisinput.cpp b/src/input/frontend/qanalogaxisinput.cpp
index 2486072b8..6d50af45c 100644
--- a/src/input/frontend/qanalogaxisinput.cpp
+++ b/src/input/frontend/qanalogaxisinput.cpp
@@ -57,6 +57,7 @@ namespace Qt3DInput {
/*!
* \class Qt3DInput::QAnalogAxisInput
+ * \inheaderfile Qt3DInput/QAnalogAxisInput
* \inmodule Qt3DInput
* \brief An axis input controlled by an analog input
* \since 5.7
diff --git a/src/input/frontend/qaxis.cpp b/src/input/frontend/qaxis.cpp
index 88f31ff62..6b19e43fe 100644
--- a/src/input/frontend/qaxis.cpp
+++ b/src/input/frontend/qaxis.cpp
@@ -72,6 +72,8 @@ namespace Qt3DInput {
\readonly
Holds the value of the axis.
+
+ Note this property is not updated when the axis is disabled.
*/
/*!
diff --git a/src/input/frontend/qaxisaccumulator.h b/src/input/frontend/qaxisaccumulator.h
index c62e4c35f..461f21c4a 100644
--- a/src/input/frontend/qaxisaccumulator.h
+++ b/src/input/frontend/qaxisaccumulator.h
@@ -63,7 +63,7 @@ public:
Velocity,
Acceleration
};
- Q_ENUM(SourceAxisType)
+ Q_ENUM(SourceAxisType) // LCOV_EXCL_LINE
QAxisAccumulator(Qt3DCore::QNode *parent = nullptr);
~QAxisAccumulator();
diff --git a/src/input/frontend/qbuttonaxisinput.cpp b/src/input/frontend/qbuttonaxisinput.cpp
index aaf1b6a1c..e6bfe4f8c 100644
--- a/src/input/frontend/qbuttonaxisinput.cpp
+++ b/src/input/frontend/qbuttonaxisinput.cpp
@@ -57,6 +57,7 @@ namespace Qt3DInput {
/*!
* \class Qt3DInput::QButtonAxisInput
+ * \inheaderfile Qt3DInput/QButtonAxisInput
* \inmodule Qt3DInput
* \brief An axis input controlled by buttons
* \since 5.7
diff --git a/src/input/frontend/qinputaspect.cpp b/src/input/frontend/qinputaspect.cpp
index d0e91a362..5ad5c644c 100644
--- a/src/input/frontend/qinputaspect.cpp
+++ b/src/input/frontend/qinputaspect.cpp
@@ -70,6 +70,7 @@
#include <Qt3DInput/qinputsequence.h>
#include <Qt3DInput/qlogicaldevice.h>
#include <Qt3DInput/qabstractphysicaldevice.h>
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h>
#include <Qt3DInput/private/axis_p.h>
#include <Qt3DInput/private/action_p.h>
#include <Qt3DInput/private/axissetting_p.h>
@@ -84,6 +85,7 @@
#include <Qt3DInput/private/genericdevicebackendnode_p.h>
#include <Qt3DInput/private/inputsettings_p.h>
#include <Qt3DInput/private/eventsourcesetterhelper_p.h>
+#include <Qt3DInput/private/loadproxydevicejob_p.h>
#ifdef HAVE_QGAMEPAD
# include <Qt3DInput/private/qgamepadinput_p.h>
@@ -142,6 +144,7 @@ QInputAspect::QInputAspect(QInputAspectPrivate &dd, QObject *parent)
registerBackendType<QLogicalDevice>(QBackendNodeMapperPtr(new Input::LogicalDeviceNodeFunctor(d_func()->m_inputHandler->logicalDeviceManager())));
registerBackendType<QGenericInputDevice>(QBackendNodeMapperPtr(new Input::GenericDeviceBackendFunctor(this, d_func()->m_inputHandler.data())));
registerBackendType<QInputSettings>(QBackendNodeMapperPtr(new Input::InputSettingsFunctor(d_func()->m_inputHandler.data())));
+ registerBackendType<QAbstractPhysicalDeviceProxy>(QBackendNodeMapperPtr(new Input::PhysicalDeviceProxyNodeFunctor(d_func()->m_inputHandler->physicalDeviceProxyManager())));
#ifdef HAVE_QGAMEPAD
registerBackendType<QGamepadInput>(QBackendNodeMapperPtr(new Input::GenericDeviceBackendFunctor(this, d_func()->m_inputHandler.data())));
@@ -188,13 +191,7 @@ void QInputAspectPrivate::loadInputDevicePlugins()
QAbstractPhysicalDevice *QInputAspect::createPhysicalDevice(const QString &name)
{
Q_D(QInputAspect);
- const auto integrations = d->m_inputHandler->inputDeviceIntegrations();
- QAbstractPhysicalDevice *device = nullptr;
- for (Qt3DInput::QInputDeviceIntegration *integration : integrations) {
- if ((device = integration->createPhysicalDevice(name)) != nullptr)
- break;
- }
- return device;
+ return d->m_inputHandler->createPhysicalDevice(name);
}
/*!
@@ -227,6 +224,16 @@ QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time)
for (QInputDeviceIntegration *integration : integrations)
jobs += integration->jobsToExecute(time);
+ const QVector<Qt3DCore::QNodeId> proxiesToLoad = d->m_inputHandler->physicalDeviceProxyManager()->takePendingProxiesToLoad();
+ if (!proxiesToLoad.isEmpty()) {
+ // Since loading wrappers occurs quite rarely, no point in keeping the job in a
+ // member variable
+ auto loadWrappersJob = Input::LoadProxyDeviceJobPtr::create();
+ loadWrappersJob->setProxiesToLoad(std::move(proxiesToLoad));
+ loadWrappersJob->setInputHandler(d->m_inputHandler.data());
+ jobs.push_back(loadWrappersJob);
+ }
+
// All the jobs added up until this point are independents
// but the axis action jobs will be dependent on these
const QVector<QAspectJobPtr> dependsOnJobs = jobs;
@@ -234,6 +241,10 @@ QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time)
// Jobs that update Axis/Action (store combined axis/action value)
const auto devHandles = d->m_inputHandler->logicalDeviceManager()->activeDevices();
for (Input::HLogicalDevice devHandle : devHandles) {
+ const auto device = d->m_inputHandler->logicalDeviceManager()->data(devHandle);
+ if (!device->isEnabled())
+ continue;
+
QAspectJobPtr updateAxisActionJob(new Input::UpdateAxisActionJob(time, d->m_inputHandler.data(), devHandle));
jobs += updateAxisActionJob;
for (const QAspectJobPtr &job : dependsOnJobs)
diff --git a/src/input/frontend/qinputsettings.cpp b/src/input/frontend/qinputsettings.cpp
index 34ed3b438..47c835cea 100644
--- a/src/input/frontend/qinputsettings.cpp
+++ b/src/input/frontend/qinputsettings.cpp
@@ -115,18 +115,18 @@ void QInputSettings::setEventSource(QObject *eventSource)
Q_D(QInputSettings);
if (d->m_eventSource != eventSource) {
if (d->m_eventSource)
- QObject::disconnect(m_connection);
+ QObject::disconnect(d->m_connection);
d->m_eventSource = eventSource;
emit eventSourceChanged(eventSource);
- m_connection = QObject::connect(eventSource, &QObject::destroyed,
- this, &QInputSettings::eventSourceDestroyed);
+ d->m_connection = QObject::connect(eventSource, &QObject::destroyed,
+ this, &QInputSettings::eventSourceDestroyed);
}
}
void QInputSettings::eventSourceDestroyed()
{
Q_D(QInputSettings);
- QObject::disconnect(m_connection);
+ QObject::disconnect(d->m_connection);
d->m_eventSource = nullptr;
emit eventSourceChanged(nullptr);
}
diff --git a/src/input/frontend/qinputsettings.h b/src/input/frontend/qinputsettings.h
index 2fb3651c3..9e0ea7b6b 100644
--- a/src/input/frontend/qinputsettings.h
+++ b/src/input/frontend/qinputsettings.h
@@ -69,8 +69,6 @@ private:
Q_DECLARE_PRIVATE(QInputSettings)
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
void eventSourceDestroyed();
-
- QMetaObject::Connection m_connection;
};
} // Qt3DInput
diff --git a/src/input/frontend/qinputsettings_p.h b/src/input/frontend/qinputsettings_p.h
index e1ba18542..13757ac0b 100644
--- a/src/input/frontend/qinputsettings_p.h
+++ b/src/input/frontend/qinputsettings_p.h
@@ -64,6 +64,7 @@ public:
QInputSettingsPrivate();
QObject *m_eventSource;
+ QMetaObject::Connection m_connection;
};
struct QInputSettingsData
diff --git a/src/input/frontend/qmousedevice.cpp b/src/input/frontend/qmousedevice.cpp
index 56d3731ce..744d289f3 100644
--- a/src/input/frontend/qmousedevice.cpp
+++ b/src/input/frontend/qmousedevice.cpp
@@ -40,6 +40,7 @@
#include "qmousedevice.h"
#include "qmousedevice_p.h"
#include <Qt3DInput/qphysicaldevicecreatedchange.h>
+#include <Qt3DInput/qmouseevent.h>
#include <Qt3DCore/qentity.h>
QT_BEGIN_NAMESPACE
@@ -104,12 +105,6 @@ QMouseDevicePrivate::QMouseDevicePrivate()
Default is 0.1.
*/
-/*!
- \property Qt3DInput::QMouseDevice::sensitivity
-
- Holds the sensitivity of the mouse device.
- Default is 0.1.
- */
/*!
Constructs a new QMouseDevice instance with parent \a parent.
@@ -187,6 +182,23 @@ int QMouseDevice::axisIdentifier(const QString &name) const
return -1;
}
+int QMouseDevice::buttonIdentifier(const QString &name) const
+{
+ if (name == QLatin1String("Left"))
+ return Qt3DInput::QMouseEvent::LeftButton;
+ if (name == QLatin1String("Right"))
+ return Qt3DInput::QMouseEvent::RightButton;
+ if (name == QLatin1String("Center"))
+ return Qt3DInput::QMouseEvent::MiddleButton;
+ return -1;
+}
+
+/*!
+ \property Qt3DInput::QMouseDevice::sensitivity
+
+ Holds the sensitivity of the mouse device.
+ The default is 0.1.
+*/
float QMouseDevice::sensitivity() const
{
Q_D(const QMouseDevice);
diff --git a/src/input/frontend/qmousedevice.h b/src/input/frontend/qmousedevice.h
index 7a1f6332a..620c41edc 100644
--- a/src/input/frontend/qmousedevice.h
+++ b/src/input/frontend/qmousedevice.h
@@ -67,13 +67,14 @@ public:
WheelX,
WheelY
};
- Q_ENUM(Axis)
+ Q_ENUM(Axis) // LCOV_EXCL_LINE
int axisCount() const Q_DECL_FINAL;
int buttonCount() const Q_DECL_FINAL;
QStringList axisNames() const Q_DECL_FINAL;
QStringList buttonNames() const Q_DECL_FINAL;
int axisIdentifier(const QString &name) const Q_DECL_FINAL;
+ int buttonIdentifier(const QString &name) const Q_DECL_FINAL;
float sensitivity() const;
@@ -95,6 +96,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DInput::QMouseDevice*)
+Q_DECLARE_METATYPE(Qt3DInput::QMouseDevice*) // LCOV_EXCL_LINE
#endif // QT3DINPUT_QMOUSEDEVICE_H
diff --git a/src/input/frontend/qmouseevent.cpp b/src/input/frontend/qmouseevent.cpp
index ff557ba8a..b1574f623 100644
--- a/src/input/frontend/qmouseevent.cpp
+++ b/src/input/frontend/qmouseevent.cpp
@@ -107,6 +107,7 @@ namespace Qt3DInput {
/*!
* \class Qt3DInput::QMouseEvent
+ * \inheaderfile Qt3DInput/QMouseEvent
* \inmodule Qt3DInput
*
* \brief The Qt3DCore::QMouseEvent contains parameters that describe a mouse event.
@@ -335,6 +336,7 @@ QMouseEvent::Modifiers QMouseEvent::modifiers() const
/*!
* \class Qt3DInput::QWheelEvent
+ * \inheaderfile Qt3DInput/QWheelEvent
* \inmodule Qt3DInput
*
* \brief The QWheelEvent class contains parameters that describe a mouse wheel event.
diff --git a/src/input/frontend/qmouseevent.h b/src/input/frontend/qmouseevent.h
index 337ae06d8..c1051dc1f 100644
--- a/src/input/frontend/qmouseevent.h
+++ b/src/input/frontend/qmouseevent.h
@@ -68,7 +68,7 @@ public:
BackButton = Qt::BackButton,
NoButton = Qt::NoButton
};
- Q_ENUM(Buttons)
+ Q_ENUM(Buttons) // LCOV_EXCL_LINE
enum Modifiers {
NoModifier = Qt::NoModifier,
@@ -78,7 +78,7 @@ public:
MetaModifier = Qt::MetaModifier,
KeypadModifier = Qt::KeypadModifier
};
- Q_ENUM(Modifiers)
+ Q_ENUM(Modifiers) // LCOV_EXCL_LINE
explicit QMouseEvent(const QT_PREPEND_NAMESPACE(QMouseEvent) &e);
~QMouseEvent();
@@ -118,7 +118,7 @@ public:
BackButton = Qt::BackButton,
NoButton = Qt::NoButton
};
- Q_ENUM(Buttons)
+ Q_ENUM(Buttons) // LCOV_EXCL_LINE
enum Modifiers {
NoModifier = Qt::NoModifier,
@@ -128,7 +128,7 @@ public:
MetaModifier = Qt::MetaModifier,
KeypadModifier = Qt::KeypadModifier
};
- Q_ENUM(Modifiers)
+ Q_ENUM(Modifiers) // LCOV_EXCL_LINE
explicit QWheelEvent(const QT_PREPEND_NAMESPACE(QWheelEvent) &e);
~QWheelEvent();
@@ -153,7 +153,7 @@ typedef QSharedPointer<QWheelEvent> QWheelEventPtr;
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DInput::QMouseEvent*)
-Q_DECLARE_METATYPE(Qt3DInput::QWheelEvent*)
+Q_DECLARE_METATYPE(Qt3DInput::QMouseEvent*) // LCOV_EXCL_LINE
+Q_DECLARE_METATYPE(Qt3DInput::QWheelEvent*) // LCOV_EXCL_LINE
#endif // QT3DINPUT_QMOUSEEVENT_H
diff --git a/src/input/frontend/qmousehandler.cpp b/src/input/frontend/qmousehandler.cpp
index 99e224142..75e68b819 100644
--- a/src/input/frontend/qmousehandler.cpp
+++ b/src/input/frontend/qmousehandler.cpp
@@ -109,6 +109,7 @@ void QMouseHandlerPrivate::mouseEvent(const QMouseEventPtr &event)
/*!
* \class Qt3DInput::QMouseHandler
+ * \inheaderfile Qt3DInput/QMouseHandler
* \inmodule Qt3DInput
*
* \brief Provides a means of being notified about mouse events when attached to
diff --git a/src/logic/logic.pro b/src/logic/logic.pro
index 50ff01748..ed9ef1424 100644
--- a/src/logic/logic.pro
+++ b/src/logic/logic.pro
@@ -7,7 +7,6 @@ QT = core-private gui-private 3dcore 3dcore-private
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
index 1ec6963bd..dba13a291 100644
--- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp
+++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
@@ -78,8 +78,6 @@ namespace Qt3DRender {
format into a Qt3D scene.
It should be noted that Assimp aiString is explicitly defined to be UTF-8.
-
- \sa GLTFPIO
*/
Q_LOGGING_CATEGORY(AssimpImporterLog, "Qt3D.AssimpImporter")
diff --git a/src/plugins/sceneparsers/gltf/gltfparser.cpp b/src/plugins/sceneparsers/gltf/gltfparser.cpp
new file mode 100644
index 000000000..e42ebb510
--- /dev/null
+++ b/src/plugins/sceneparsers/gltf/gltfparser.cpp
@@ -0,0 +1,1560 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gltfparser.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonObject>
+
+#include <QtGui/QVector2D>
+
+#include <Qt3DCore/QCameraLens>
+#include <Qt3DCore/QEntity>
+#include <Qt3DCore/QTransform>
+
+#include <Qt3DRender/private/qurlhelper_p.h>
+
+#include <Qt3DRender/QAlphaCoverage>
+#include <Qt3DRender/QBlendEquation>
+#include <Qt3DRender/QBlendStateSeparate>
+#include <Qt3DRender/QColorMask>
+#include <Qt3DRender/QCullFace>
+#include <Qt3DRender/QDepthMask>
+#include <Qt3DRender/QDepthTest>
+#include <Qt3DRender/QEffect>
+#include <Qt3DRender/QFrontFace>
+#include <Qt3DRender/QGeometry>
+#include <Qt3DRender/QGeometryRenderer>
+#include <Qt3DRender/QMaterial>
+#include <Qt3DRender/QGraphicsApiFilter>
+#include <Qt3DRender/QParameter>
+#include <Qt3DRender/QParameterMapping>
+#include <Qt3DRender/QPolygonOffset>
+#include <Qt3DRender/QRenderState>
+#include <Qt3DRender/QScissorTest>
+#include <Qt3DRender/QShaderProgram>
+#include <Qt3DRender/QTechnique>
+#include <Qt3DRender/QTexture>
+
+#include <Qt3DRender/QPhongMaterial>
+#include <Qt3DRender/QDiffuseMapMaterial>
+#include <Qt3DRender/QDiffuseSpecularMapMaterial>
+#include <Qt3DRender/QNormalDiffuseMapMaterial>
+#include <Qt3DRender/QNormalDiffuseSpecularMapMaterial>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+
+Q_LOGGING_CATEGORY(GLTFParserLog, "Qt3D.GLTFParser")
+
+namespace {
+
+const QString KEY_CAMERA = QStringLiteral("camera");
+const QString KEY_CAMERAS = QStringLiteral("cameras");
+const QString KEY_SCENES = QStringLiteral("scenes");
+const QString KEY_NODES = QStringLiteral("nodes");
+const QString KEY_MESHES = QStringLiteral("meshes");
+const QString KEY_CHILDREN = QStringLiteral("children");
+const QString KEY_MATRIX = QStringLiteral("matrix");
+const QString KEY_ROTATION = QStringLiteral("rotation");
+const QString KEY_SCALE = QStringLiteral("scale");
+const QString KEY_TRANSLATION = QStringLiteral("translation");
+const QString KEY_TYPE = QStringLiteral("type");
+const QString KEY_PERSPECTIVE =QStringLiteral("perspective");
+const QString KEY_NAME = QStringLiteral("name");
+const QString KEY_COUNT = QStringLiteral("count");
+const QString KEY_YFOV = QStringLiteral("yfov");
+const QString KEY_ZNEAR = QStringLiteral("znear");
+const QString KEY_ZFAR = QStringLiteral("zfar");
+const QString KEY_MATERIALS = QStringLiteral("materials");
+const QString KEY_EXTENSIONS = QStringLiteral("extensions");
+const QString KEY_COMMON_MAT = QStringLiteral("KHR_materials_common");
+const QString KEY_TECHNIQUE = QStringLiteral("technique");
+const QString KEY_VALUES = QStringLiteral("values");
+const QString KEY_BUFFERS = QStringLiteral("buffers");
+const QString KEY_SHADERS = QStringLiteral("shaders");
+const QString KEY_PROGRAMS = QStringLiteral("programs");
+const QString KEY_PROGRAM = QStringLiteral("program");
+const QString KEY_TECHNIQUES = QStringLiteral("techniques");
+const QString KEY_ACCESSORS = QStringLiteral("accessors");
+const QString KEY_IMAGES = QStringLiteral("images");
+const QString KEY_TEXTURES = QStringLiteral("textures");
+const QString KEY_SCENE = QStringLiteral("scene");
+const QString KEY_BUFFER = QStringLiteral("buffer");
+const QString KEY_TARGET = QStringLiteral("target");
+const QString KEY_BYTE_OFFSET = QStringLiteral("byteOffset");
+const QString KEY_BYTE_LENGTH = QStringLiteral("byteLength");
+const QString KEY_BYTE_STRIDE = QStringLiteral("byteStride");
+const QString KEY_PRIMITIVES = QStringLiteral("primitives");
+const QString KEY_MODE = QStringLiteral("mode");
+const QString KEY_MATERIAL = QStringLiteral("material");
+const QString KEY_ATTRIBUTES = QStringLiteral("attributes");
+const QString KEY_INDICES = QStringLiteral("indices");
+const QString KEY_URI = QStringLiteral("uri");
+const QString KEY_FORMAT = QStringLiteral("format");
+const QString KEY_PASSES = QStringLiteral("passes");
+const QString KEY_SOURCE = QStringLiteral("source");
+const QString KEY_SAMPLER = QStringLiteral("sampler");
+const QString KEY_SAMPLERS = QStringLiteral("samplers");
+const QString KEY_SEMANTIC = QStringLiteral("semantic");
+const QString KEY_STATES = QStringLiteral("states");
+const QString KEY_UNIFORMS = QStringLiteral("uniforms");
+const QString KEY_PARAMETERS = QStringLiteral("parameters");
+const QString KEY_WRAP_S = QStringLiteral("wrapS");
+const QString KEY_MIN_FILTER = QStringLiteral("minFilter");
+const QString KEY_MAG_FILTER = QStringLiteral("magFilter");
+
+const QString KEY_INSTANCE_TECHNIQUE = QStringLiteral("instanceTechnique");
+const QString KEY_INSTANCE_PROGRAM = QStringLiteral("instanceProgram");
+const QString KEY_BUFFER_VIEWS = QStringLiteral("bufferViews");
+const QString KEY_BUFFER_VIEW = QStringLiteral("bufferView");
+const QString KEY_VERTEX_SHADER = QStringLiteral("vertexShader");
+const QString KEY_FRAGMENT_SHADER = QStringLiteral("fragmentShader");
+const QString KEY_INTERNAL_FORMAT = QStringLiteral("internalFormat");
+const QString KEY_COMPONENT_TYPE = QStringLiteral("componentType");
+const QString KEY_ASPECT_RATIO = QStringLiteral("aspect_ratio");
+const QString KEY_VALUE = QStringLiteral("value");
+const QString KEY_ENABLE = QStringLiteral("enable");
+const QString KEY_FUNCTIONS = QStringLiteral("functions");
+const QString KEY_TECHNIQUE_CORE = QStringLiteral("techniqueCore");
+const QString KEY_TECHNIQUE_GL2 = QStringLiteral("techniqueGL2");
+
+} // of anonymous namespace
+
+GLTFParser::GLTFParser() : QAbstractSceneParser(),
+ m_parseDone(false)
+{
+}
+
+GLTFParser::~GLTFParser()
+{
+
+}
+
+void GLTFParser::setBasePath(const QString& path)
+{
+ m_basePath = path;
+}
+
+bool GLTFParser::setJSON(const QJsonDocument &json )
+{
+ if ( !json.isObject() ) {
+ return false;
+ }
+
+ m_json = json;
+ m_parseDone = false;
+
+ cleanup();
+
+ return true;
+}
+
+/*!
+ * Sets the \a path used by the parser to load the scene file.
+ * If the file is valid, parsing is automatically triggered.
+ */
+void GLTFParser::setSource(const QUrl &source)
+{
+ const QString path = QUrlHelper::urlToLocalFileOrQrc(source);
+ QFile f(path);
+ if (Q_UNLIKELY(!f.open(QIODevice::ReadOnly))) {
+ qCWarning(GLTFParserLog) << "cannot open " << path << ": " << f.errorString();
+ return;
+ }
+
+ QByteArray jsonData = f.readAll();
+ QJsonDocument sceneDocument = QJsonDocument::fromBinaryData(jsonData);
+ if (sceneDocument.isNull())
+ sceneDocument = QJsonDocument::fromJson(jsonData);
+
+ if (!setJSON(sceneDocument)) {
+ qCWarning(GLTFParserLog) << "not a JSON document";
+ return;
+ }
+
+ setBasePath(QFileInfo(path).dir().absolutePath());
+}
+
+/*!
+ * Returns true if the extension of \a path is supported by the
+ * GLTF parser.
+ */
+bool GLTFParser::isExtensionSupported(const QUrl &source) const
+{
+ const QString path = QUrlHelper::urlToLocalFileOrQrc(source);
+ return GLTFParser::isGLTFPath(path);
+}
+
+Qt3DCore::QEntity* GLTFParser::node(const QString &id)
+{
+ QJsonObject nodes = m_json.object().value(KEY_NODES).toObject();
+ if (!nodes.contains(id)) {
+ qCWarning(GLTFParserLog) << "unknown node" << id << "in GLTF file" << m_basePath;
+ return NULL;
+ }
+
+ QJsonObject jsonObj = nodes.value(id).toObject();
+ QEntity* result = Q_NULLPTR;
+
+ // Qt3D has a limitation that a QEntity can only have 1 mesh and 1 material component
+ // So if the node has only 1 mesh, we only create 1 QEntity
+ // Otherwise if there are n meshes, there is 1 QEntity, with n children for each mesh/material combo
+ if (jsonObj.contains(KEY_MESHES)) {
+ QVector<QEntity *> entities;
+
+ Q_FOREACH (QJsonValue mesh, jsonObj.value(KEY_MESHES).toArray()) {
+ if (!m_meshDict.contains(mesh.toString())) {
+ qCWarning(GLTFParserLog) << "node" << id << "references unknown mesh" << mesh.toString();
+ continue;
+ }
+
+ Q_FOREACH (QGeometryRenderer *geometryRenderer, m_meshDict.values(mesh.toString())) {
+ QEntity *entity = new QEntity;
+ entity->addComponent(geometryRenderer);
+ QMaterial *mat = material(m_meshMaterialDict[geometryRenderer]);
+ if (mat)
+ entity->addComponent(mat);
+ entities.append(entity);
+ }
+
+ }
+
+ if (entities.count() == 1) {
+ result = entities.first();
+ } else {
+ result = new QEntity;
+ Q_FOREACH (QEntity *entity, entities) {
+ entity->setParent(result);
+ }
+ }
+ }
+
+ //If the entity contains no meshes, results will still be null here
+ if (result == Q_NULLPTR)
+ result = new QEntity;
+
+ if ( jsonObj.contains(KEY_CHILDREN) ) {
+ Q_FOREACH (QJsonValue c, jsonObj.value(KEY_CHILDREN).toArray()) {
+ QEntity* child = node(c.toString());
+ if (!child)
+ continue;
+ child->setParent(result);
+ }
+ }
+
+ renameFromJson(jsonObj, result);
+
+
+ // Node Transforms
+ Qt3DCore::QTransform *trans = Q_NULLPTR;
+ if ( jsonObj.contains(KEY_MATRIX) ) {
+ QMatrix4x4 m(Qt::Uninitialized);
+
+ QJsonArray matrixValues = jsonObj.value(KEY_MATRIX).toArray();
+ for (int i=0; i<16; ++i) {
+ double v = matrixValues.at( i ).toDouble();
+ m(i % 4, i >> 2) = v;
+ }
+
+ // ADD MATRIX TRANSFORM COMPONENT TO ENTITY
+ if (trans == Q_NULLPTR)
+ trans = new Qt3DCore::QTransform;
+ trans->setMatrix(m);
+ }
+
+ // Rotation quaternion
+ if (jsonObj.contains(KEY_ROTATION)) {
+ if (trans == Q_NULLPTR)
+ trans = new Qt3DCore::QTransform;
+
+ QJsonArray quaternionValues = jsonObj.value(KEY_ROTATION).toArray();
+ QQuaternion quaternion(quaternionValues[0].toDouble(),
+ quaternionValues[1].toDouble(),
+ quaternionValues[2].toDouble(),
+ quaternionValues[3].toDouble());
+ trans->setRotation(quaternion);
+ }
+
+ // Translation
+ if (jsonObj.contains(KEY_TRANSLATION)) {
+ if (trans == Q_NULLPTR)
+ trans = new Qt3DCore::QTransform;
+
+ QJsonArray translationValues = jsonObj.value(KEY_TRANSLATION).toArray();
+ trans->setTranslation(QVector3D(translationValues[0].toDouble(),
+ translationValues[1].toDouble(),
+ translationValues[2].toDouble()));
+ }
+
+ // Scale
+ if (jsonObj.contains(KEY_SCALE)) {
+ if (trans == Q_NULLPTR)
+ trans = new Qt3DCore::QTransform;
+
+ QJsonArray scaleValues = jsonObj.value(KEY_SCALE).toArray();
+ trans->setScale3D(QVector3D(scaleValues[0].toDouble(),
+ scaleValues[1].toDouble(),
+ scaleValues[2].toDouble()));
+ }
+
+ // Add the Transform component
+ if (trans != Q_NULLPTR)
+ result->addComponent(trans);
+
+ if ( jsonObj.contains(KEY_CAMERA) ) {
+ QCameraLens* cam = camera( jsonObj.value(KEY_CAMERA).toString() );
+ if (!cam) {
+ qCWarning(GLTFParserLog) << "failed to build camera:" << jsonObj.value(KEY_CAMERA)
+ << "on node" << id;
+ } else {
+ result->addComponent(cam);
+ }
+ } // of have camera attribute
+
+ return result;
+}
+
+Qt3DCore::QEntity* GLTFParser::scene(const QString &id)
+{
+ parse();
+
+ QJsonObject scenes = m_json.object().value(KEY_SCENES).toObject();
+ if (!scenes.contains(id)) {
+ if (!id.isNull())
+ qCWarning(GLTFParserLog) << "GLTF: no such scene" << id << "in file" << m_basePath;
+ return defaultScene();
+ }
+
+ QJsonObject sceneObj = scenes.value(id).toObject();
+ QEntity* sceneEntity = new QEntity;
+ Q_FOREACH (QJsonValue nnv, sceneObj.value(KEY_NODES).toArray()) {
+ QString nodeName = nnv.toString();
+ QEntity* child = node(nodeName);
+ if (!child)
+ continue;
+ child->setParent(sceneEntity);
+ }
+
+ return sceneEntity;
+}
+
+GLTFParser::BufferData::BufferData()
+ : length(0)
+ , data(Q_NULLPTR)
+{
+}
+
+GLTFParser::BufferData::BufferData(QJsonObject json)
+{
+ path = json.value(KEY_URI).toString();
+ length = json.value(KEY_BYTE_LENGTH).toInt();
+ data = Q_NULLPTR;
+}
+
+GLTFParser::ParameterData::ParameterData() :
+ type(0)
+{
+
+}
+
+GLTFParser::ParameterData::ParameterData(QJsonObject json)
+{
+ type = json.value(KEY_TYPE).toInt();
+ semantic = json.value(KEY_SEMANTIC).toString();
+}
+
+GLTFParser::AccessorData::AccessorData()
+ : type(QAttribute::Float)
+ , dataSize(0)
+ , count(0)
+ , offset(0)
+ , stride(0)
+{
+
+}
+
+GLTFParser::AccessorData::AccessorData(const QJsonObject &json)
+{
+ bufferViewName = json.value(KEY_BUFFER_VIEW).toString();
+ offset = 0;
+ stride = 0;
+ int componentType = json.value(KEY_COMPONENT_TYPE).toInt();
+ type = accessorTypeFromJSON(componentType);
+ count = json.value(KEY_COUNT).toInt();
+ dataSize = accessorDataSizeFromJson(json.value(KEY_TYPE).toString());
+
+ if ( json.contains(KEY_BYTE_OFFSET))
+ offset = json.value(KEY_BYTE_OFFSET).toInt();
+ if ( json.contains(KEY_BYTE_STRIDE))
+ stride = json.value(KEY_BYTE_STRIDE).toInt();
+}
+
+bool GLTFParser::isGLTFPath(const QString& path)
+{
+ QFileInfo finfo(path);
+ if (!finfo.exists())
+ return false;
+
+ // might need to detect other things in the future, but would
+ // prefer to avoid doing a full parse.
+ QString suffix = finfo.suffix().toLower();
+ return (suffix == QStringLiteral("json") || suffix == QStringLiteral("gltf") || suffix == QStringLiteral("qgltf"));
+}
+
+void GLTFParser::renameFromJson(const QJsonObject &json, QObject * const object)
+{
+ if ( json.contains(KEY_NAME) )
+ object->setObjectName( json.value(KEY_NAME).toString() );
+}
+
+QString GLTFParser::standardUniformNamefromSemantic(const QString &semantic)
+{
+ //Standard Uniforms
+ //if (semantic == QStringLiteral("LOCAL"));
+ if (semantic == QStringLiteral("MODEL"))
+ return QStringLiteral("modelMatrix");
+ if (semantic == QStringLiteral("VIEW"))
+ return QStringLiteral("viewMatrix");
+ if (semantic == QStringLiteral("PROJECTION"))
+ return QStringLiteral("projectionMatrix");
+ if (semantic == QStringLiteral("MODELVIEW"))
+ return QStringLiteral("modelView");
+ if (semantic == QStringLiteral("MODELVIEWPROJECTION"))
+ return QStringLiteral("modelViewProjection");
+ if (semantic == QStringLiteral("MODELINVERSE"))
+ return QStringLiteral("inverseModelMatrix");
+ if (semantic == QStringLiteral("VIEWINVERSE"))
+ return QStringLiteral("inverViewMatrix");
+ if (semantic == QStringLiteral("PROJECTIONINVERSE"))
+ return QStringLiteral("inverseProjectionMatrix");
+ if (semantic == QStringLiteral("MODELVIEWPROJECTIONINVERSE"))
+ return QStringLiteral("inverseModelViewProjection");
+ if (semantic == QStringLiteral("MODELINVERSETRANSPOSE"))
+ return QStringLiteral("modelNormalMatrix");
+ if (semantic == QStringLiteral("MODELVIEWINVERSETRANSPOSE"))
+ return QStringLiteral("modelViewNormal");
+ if (semantic == QStringLiteral("VIEWPORT"))
+ return QStringLiteral("viewportMatrix");
+
+ return QString();
+}
+
+QString GLTFParser::standardAttributeNameFromSemantic(const QString &semantic)
+{
+ //Standard Attributes
+ if (semantic.startsWith(QStringLiteral("POSITION")))
+ return QAttribute::defaultPositionAttributeName();
+ if (semantic.startsWith(QStringLiteral("NORMAL")))
+ return QAttribute::defaultNormalAttributeName();
+ if (semantic.startsWith(QStringLiteral("TEXCOORD")))
+ return QAttribute::defaultTextureCoordinateAttributeName();
+ if (semantic.startsWith(QStringLiteral("COLOR")))
+ return QAttribute::defaultColorAttributeName();
+ if (semantic.startsWith(QStringLiteral("TANGENT")))
+ return QAttribute::defaultTangentAttributeName();
+
+// if (semantic.startsWith(QStringLiteral("JOINT")));
+// if (semantic.startsWith(QStringLiteral("JOINTMATRIX")));
+// if (semantic.startsWith(QStringLiteral("WEIGHT")));
+
+ return QString();
+}
+
+QParameter *GLTFParser::parameterFromTechnique(QTechnique *technique, const QString &parameterName)
+{
+ Q_FOREACH (QParameter *parameter, technique->parameters()) {
+ if (parameter->name() == parameterName) {
+ return parameter;
+ }
+ }
+
+ return Q_NULLPTR;
+}
+
+Qt3DCore::QEntity* GLTFParser::defaultScene()
+{
+ if (m_defaultScene.isEmpty()) {
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "no default scene";
+ return NULL;
+ }
+
+ return scene(m_defaultScene);
+}
+
+QMaterial *GLTFParser::materialWithCustomShader(const QString &id, const QJsonObject &jsonObj)
+{
+ //Default ES2 Technique
+ QString techniqueName = jsonObj.value(KEY_TECHNIQUE).toString();
+ if (!m_techniques.contains(techniqueName)) {
+ qCWarning(GLTFParserLog) << "unknown technique" << techniqueName
+ << "for material" << id << "in GLTF file" << m_basePath;
+ return NULL;
+ }
+ QTechnique *technique = m_techniques.value(techniqueName);
+ technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES);
+ technique->graphicsApiFilter()->setMajorVersion(2);
+ technique->graphicsApiFilter()->setMinorVersion(0);
+ technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
+
+
+ //Optional Core technique
+ QTechnique *coreTechnique = Q_NULLPTR;
+ QTechnique *gl2Technique = Q_NULLPTR;
+ QString coreTechniqueName = jsonObj.value(KEY_TECHNIQUE_CORE).toString();
+ if (!coreTechniqueName.isNull()) {
+ if (!m_techniques.contains(coreTechniqueName)) {
+ qCWarning(GLTFParserLog) << "unknown technique" << coreTechniqueName
+ << "for material" << id << "in GLTF file" << m_basePath;
+ } else {
+ coreTechnique = m_techniques.value(coreTechniqueName);
+ coreTechnique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ coreTechnique->graphicsApiFilter()->setMajorVersion(3);
+ coreTechnique->graphicsApiFilter()->setMinorVersion(1);
+ coreTechnique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+ }
+ }
+ //Optional GL2 technique
+ QString gl2TechniqueName = jsonObj.value(KEY_TECHNIQUE_GL2).toString();
+ if (!gl2TechniqueName.isNull()) {
+ if (!m_techniques.contains(gl2TechniqueName)) {
+ qCWarning(GLTFParserLog) << "unknown technique" << gl2TechniqueName
+ << "for material" << id << "in GLTF file" << m_basePath;
+ } else {
+ gl2Technique = m_techniques.value(gl2TechniqueName);
+ gl2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl2Technique->graphicsApiFilter()->setMajorVersion(2);
+ gl2Technique->graphicsApiFilter()->setMinorVersion(0);
+ gl2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
+ }
+ }
+
+
+ // glTF doesn't deal in effects, but we need a trivial one to wrap
+ // up our techniques
+ // However we need to create a unique effect for each material instead
+ // of caching because QMaterial does not keep up with effects
+ // its not the parent of.
+ QEffect* effect = new QEffect;
+ effect->setObjectName(techniqueName);
+ effect->addTechnique(technique);
+ if (coreTechnique != Q_NULLPTR)
+ effect->addTechnique(coreTechnique);
+ if (gl2Technique != Q_NULLPTR)
+ effect->addTechnique(gl2Technique);
+
+ QMaterial* mat = new QMaterial;
+ mat->setEffect(effect);
+
+ renameFromJson(jsonObj, mat);
+
+ QJsonObject values = jsonObj.value(KEY_VALUES).toObject();
+ Q_FOREACH (QString vName, values.keys()) {
+ QParameter *param = parameterFromTechnique(technique, vName);
+
+ if (param == Q_NULLPTR && coreTechnique != Q_NULLPTR) {
+ param = parameterFromTechnique(coreTechnique, vName);
+ }
+
+ if (param == Q_NULLPTR && gl2Technique != Q_NULLPTR) {
+ param = parameterFromTechnique(gl2Technique, vName);
+ }
+
+ if (param == Q_NULLPTR) {
+ qCWarning(GLTFParserLog) << "unknown parameter:" << vName << "in technique" << techniqueName
+ << "processing material" << id;
+ continue;
+ }
+
+ ParameterData paramData = m_parameterDataDict.value(param);
+ QVariant var = parameterValueFromJSON(paramData.type, values.value(vName));
+
+ mat->addParameter(new QParameter(param->name(), var));
+ } // of material technique-instance values iteration
+
+ return mat;
+}
+
+static inline QVariant vec4ToRgb(const QVariant &vec4Var)
+{
+ const QVector4D v = vec4Var.value<QVector4D>();
+ return QVariant(QColor::fromRgbF(v.x(), v.y(), v.z()));
+}
+
+QMaterial *GLTFParser::commonMaterial(const QJsonObject &jsonObj)
+{
+ QVariantHash params;
+ bool hasDiffuseMap = false;
+ bool hasSpecularMap = false;
+ bool hasNormalMap = false;
+
+ QJsonObject values = jsonObj.value(KEY_VALUES).toObject();
+ Q_FOREACH (const QString &vName, values.keys()) {
+ const QJsonValue val = values.value(vName);
+ QVariant var;
+ QString propertyName = vName;
+ if (vName == QStringLiteral("ambient") && val.isArray()) {
+ var = vec4ToRgb(parameterValueFromJSON(GL_FLOAT_VEC4, val));
+ } else if (vName == QStringLiteral("diffuse")) {
+ if (val.isString()) {
+ var = parameterValueFromJSON(GL_SAMPLER_2D, val);
+ hasDiffuseMap = true;
+ } else if (val.isArray()) {
+ var = vec4ToRgb(parameterValueFromJSON(GL_FLOAT_VEC4, val));
+ }
+ } else if (vName == QStringLiteral("specular")) {
+ if (val.isString()) {
+ var = parameterValueFromJSON(GL_SAMPLER_2D, val);
+ hasSpecularMap = true;
+ } else if (val.isArray()) {
+ var = vec4ToRgb(parameterValueFromJSON(GL_FLOAT_VEC4, val));
+ }
+ } else if (vName == QStringLiteral("shininess") && val.isDouble()) {
+ var = parameterValueFromJSON(GL_FLOAT, val);
+ } else if (vName == QStringLiteral("normalmap") && val.isString()) {
+ var = parameterValueFromJSON(GL_SAMPLER_2D, val);
+ propertyName = QStringLiteral("normal");
+ hasNormalMap = true;
+ } else if (vName == QStringLiteral("transparency")) {
+ qCWarning(GLTFParserLog) << "Semi-transparent common materials are not currently supported, ignoring alpha";
+ }
+ if (var.isValid())
+ params[propertyName] = var;
+ }
+
+ QMaterial *mat = Q_NULLPTR;
+ if (hasNormalMap) {
+ if (hasSpecularMap) {
+ mat = new QNormalDiffuseSpecularMapMaterial;
+ } else {
+ if (hasDiffuseMap)
+ mat = new QNormalDiffuseMapMaterial;
+ else
+ qCWarning(GLTFParserLog) << "Common material with normal and specular maps needs a diffuse map as well";
+ }
+ } else {
+ if (hasSpecularMap) {
+ if (hasDiffuseMap)
+ mat = new QDiffuseSpecularMapMaterial;
+ else
+ qCWarning(GLTFParserLog) << "Common material with specular map needs a diffuse map as well";
+ } else if (hasDiffuseMap) {
+ mat = new QDiffuseMapMaterial;
+ } else {
+ mat = new QPhongMaterial;
+ }
+ }
+
+ if (mat) {
+ for (QVariantHash::const_iterator it = params.constBegin(), itEnd = params.constEnd(); it != itEnd; ++it)
+ mat->setProperty(it.key().toUtf8(), it.value());
+ } else {
+ qCWarning(GLTFParserLog) << "Could not find a suitable built-in material for KHR_materials_common";
+ }
+
+ return mat;
+}
+
+QMaterial* GLTFParser::material(const QString &id)
+{
+ if (m_materialCache.contains(id))
+ return m_materialCache.value(id);
+
+ QJsonObject mats = m_json.object().value(KEY_MATERIALS).toObject();
+ if (!mats.contains(id)) {
+ qCWarning(GLTFParserLog) << "unknown material" << id << "in GLTF file" << m_basePath;
+ return NULL;
+ }
+
+ QJsonObject jsonObj = mats.value(id).toObject();
+
+ QMaterial *mat = Q_NULLPTR;
+
+ // Prefer common materials over custom shaders.
+ if (jsonObj.contains(KEY_EXTENSIONS)) {
+ QJsonObject extensions = jsonObj.value(KEY_EXTENSIONS).toObject();
+ if (extensions.contains(KEY_COMMON_MAT))
+ mat = commonMaterial(extensions.value(KEY_COMMON_MAT).toObject());
+ }
+
+ if (!mat)
+ mat = materialWithCustomShader(id, jsonObj);
+
+ m_materialCache[id] = mat;
+ return mat;
+}
+
+QCameraLens* GLTFParser::camera(const QString &id) const
+{
+ QJsonObject cams = m_json.object().value(KEY_CAMERAS).toObject();
+ if (!cams.contains(id)) {
+ qCWarning(GLTFParserLog) << "unknown camera" << id << "in GLTF file" << m_basePath;
+ return Q_NULLPTR;
+ }
+
+ QJsonObject jsonObj = cams.value(id).toObject();
+ QString camTy = jsonObj.value(KEY_TYPE).toString();
+
+ if (camTy == QStringLiteral("perspective")) {
+ if (!jsonObj.contains(KEY_PERSPECTIVE)) {
+ qCWarning(GLTFParserLog) << "camera:" << id << "missing 'perspective' object";
+ return Q_NULLPTR;
+ }
+
+ QJsonObject pObj = jsonObj.value(KEY_PERSPECTIVE).toObject();
+ double aspectRatio = pObj.value(KEY_ASPECT_RATIO).toDouble();
+ double yfov = pObj.value(KEY_YFOV).toDouble();
+ double frustumNear = pObj.value(KEY_ZNEAR).toDouble();
+ double frustumFar = pObj.value(KEY_ZFAR).toDouble();
+
+ QCameraLens* result = new QCameraLens;
+ result->setPerspectiveProjection(yfov, aspectRatio, frustumNear, frustumFar);
+ return result;
+ } else if (camTy == QStringLiteral("orthographic")) {
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "implement me";
+
+ return Q_NULLPTR;
+ } else {
+ qCWarning(GLTFParserLog) << "camera:" << id << "has unsupported type:" << camTy;
+ return Q_NULLPTR;
+ }
+}
+
+
+void GLTFParser::parse()
+{
+ if (m_parseDone)
+ return;
+
+ QJsonObject buffers = m_json.object().value(KEY_BUFFERS).toObject();
+ Q_FOREACH (QString nm, buffers.keys()) {
+ processJSONBuffer( nm, buffers.value(nm).toObject() );
+ }
+
+ QJsonObject views = m_json.object().value(KEY_BUFFER_VIEWS).toObject();
+ loadBufferData();
+ Q_FOREACH (QString nm, views.keys()) {
+ processJSONBufferView( nm, views.value(nm).toObject() );
+ }
+ unloadBufferData();
+
+ QJsonObject shaders = m_json.object().value(KEY_SHADERS).toObject();
+ Q_FOREACH (QString nm, shaders.keys()) {
+ processJSONShader( nm, shaders.value(nm).toObject() );
+ }
+
+ QJsonObject programs = m_json.object().value(KEY_PROGRAMS).toObject();
+ Q_FOREACH (QString nm, programs.keys()) {
+ processJSONProgram( nm, programs.value(nm).toObject() );
+ }
+
+ QJsonObject techniques = m_json.object().value(KEY_TECHNIQUES).toObject();
+ Q_FOREACH (QString nm, techniques.keys()) {
+ processJSONTechnique( nm, techniques.value(nm).toObject() );
+ }
+
+ QJsonObject attrs = m_json.object().value(KEY_ACCESSORS).toObject();
+ Q_FOREACH (QString nm, attrs.keys()) {
+ processJSONAccessor( nm, attrs.value(nm).toObject() );
+ }
+
+ QJsonObject meshes = m_json.object().value(KEY_MESHES).toObject();
+ Q_FOREACH (QString nm, meshes.keys()) {
+ processJSONMesh( nm, meshes.value(nm).toObject() );
+ }
+
+ QJsonObject images = m_json.object().value(KEY_IMAGES).toObject();
+ Q_FOREACH (QString nm, images.keys()) {
+ processJSONImage( nm, images.value(nm).toObject() );
+ }
+
+ QJsonObject textures = m_json.object().value(KEY_TEXTURES).toObject();
+ Q_FOREACH (QString nm, textures.keys()) {
+ processJSONTexture(nm, textures.value(nm).toObject() );
+ }
+
+ m_defaultScene = m_json.object().value(KEY_SCENE).toString();
+ m_parseDone = true;
+}
+
+void GLTFParser::cleanup()
+{
+ m_meshDict.clear();
+ m_meshMaterialDict.clear();
+ m_accessorDict.clear();
+ //Check for Materials with no parent
+ Q_FOREACH (QMaterial *material, m_materialCache.values()) {
+ if (material->parent() == Q_NULLPTR)
+ delete material;
+ }
+ m_materialCache.clear();
+ m_bufferDatas.clear();
+ m_buffers.clear();
+ m_shaderPaths.clear();
+ //Check for ShaderPrograms with no parent
+ Q_FOREACH (QShaderProgram *program, m_programs.values()) {
+ if (program->parent() == Q_NULLPTR)
+ delete program;
+ }
+ m_programs.clear();
+ //Check for Techniques with no parent
+ Q_FOREACH (QTechnique *technique, m_techniques.values()) {
+ if (technique->parent() == Q_NULLPTR)
+ delete technique;
+ }
+ m_techniques.clear();
+ //Check for Textures with no parent
+ Q_FOREACH (QAbstractTextureProvider *texture, m_textures.values()) {
+ if (texture->parent() == Q_NULLPTR)
+ delete texture;
+ }
+ m_textures.clear();
+ m_imagePaths.clear();
+ m_defaultScene.clear();
+ m_parameterDataDict.clear();
+}
+
+void GLTFParser::processJSONBuffer(const QString &id, const QJsonObject& json)
+{
+ // simply cache buffers for lookup by buffer-views
+ m_bufferDatas[id] = BufferData(json);
+}
+
+void GLTFParser::processJSONBufferView(const QString &id, const QJsonObject& json)
+{
+ QString bufName = json.value(KEY_BUFFER).toString();
+ if (!m_bufferDatas.contains(bufName)) {
+ qCWarning(GLTFParserLog) << "unknown buffer:" << bufName << "processing view:" << id;
+ return;
+ }
+
+ int target = json.value(KEY_TARGET).toInt();
+ QBuffer::BufferType ty(QBuffer::VertexBuffer);
+
+ switch (target) {
+ case GL_ARRAY_BUFFER: ty = QBuffer::VertexBuffer; break;
+ case GL_ELEMENT_ARRAY_BUFFER: ty = QBuffer::IndexBuffer; break;
+ default:
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "buffer" << id << "unsupported target:" << target;
+ return;
+ }
+
+ quint64 offset = 0;
+ if (json.contains(KEY_BYTE_OFFSET)) {
+ offset = json.value(KEY_BYTE_OFFSET).toInt();
+ qCDebug(GLTFParserLog) << "bv:" << id << "has offset:" << offset;
+ }
+
+ quint64 len = json.value(KEY_BYTE_LENGTH).toInt();
+
+ QByteArray bytes(m_bufferDatas[bufName].data->mid(offset, len));
+ if (bytes.count() != (int) len) {
+ qCWarning(GLTFParserLog) << "failed to read sufficient bytes from:" << m_bufferDatas[bufName].path
+ << "for view" << id;
+ }
+
+ QBuffer *b(new QBuffer(ty));
+ b->setData(bytes);
+ m_buffers[id] = b;
+}
+
+void GLTFParser::processJSONShader(const QString &id, const QJsonObject &jsonObject)
+{
+ // shaders are trivial for the moment, defer the real work
+ // to the program section
+ QString path = jsonObject.value(KEY_URI).toString();
+
+ QFileInfo info(m_basePath, path);
+ if (!info.exists()) {
+ qCWarning(GLTFParserLog) << "can't find shader" << id << "from path" << path;
+ return;
+ }
+
+ m_shaderPaths[id] = info.absoluteFilePath();
+}
+
+void GLTFParser::processJSONProgram(const QString &id, const QJsonObject &jsonObject)
+{
+ QShaderProgram* prog = new QShaderProgram;
+ prog->setObjectName(id);
+
+ QString fragName = jsonObject.value(KEY_FRAGMENT_SHADER).toString(),
+ vertName = jsonObject.value(KEY_VERTEX_SHADER).toString();
+ if (!m_shaderPaths.contains(fragName) || !m_shaderPaths.contains(vertName)) {
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "program:" << id << "missing shader:"
+ << fragName << vertName;
+ return;
+ }
+
+ prog->setFragmentShaderCode(QShaderProgram::loadSource(QUrl::fromLocalFile(m_shaderPaths[fragName])));
+ prog->setVertexShaderCode(QShaderProgram::loadSource(QUrl::fromLocalFile(m_shaderPaths[vertName])));
+ m_programs[id] = prog;
+}
+
+void GLTFParser::processJSONTechnique(const QString &id, const QJsonObject &jsonObject )
+{
+ QTechnique *t = new QTechnique;
+ t->setObjectName(id);
+
+ // Parameters
+ QHash<QString, QParameter*> paramDict;
+ QJsonObject params = jsonObject.value(KEY_PARAMETERS).toObject();
+ Q_FOREACH (QString pname, params.keys()) {
+ QJsonObject po = params.value(pname).toObject();
+
+ //QString semantic = po.value(KEY_SEMANTIC).toString();
+ QParameter *p = new QParameter(t);
+ p->setName(pname);
+ m_parameterDataDict.insert(p, ParameterData(po));
+
+ //If the parameter has default value, set it
+ QJsonValue value = po.value(KEY_VALUE);
+ if (!value.isUndefined()) {
+ int dataType = po.value(KEY_TYPE).toInt();
+ p->setValue(parameterValueFromJSON(dataType, value));
+ }
+
+ t->addParameter(p);
+
+ paramDict[pname] = p;
+ } // of parameters iteration
+
+ // Program
+ QString programName = jsonObject.value(KEY_PROGRAM).toString();
+ if (!m_programs.contains(programName)) {
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "technique" << id
+ << ": missing program" << programName;
+ }
+
+ QRenderPass* pass = new QRenderPass;
+ pass->setShaderProgram(m_programs[programName]);
+
+ // Attributes
+ QJsonObject attrs = jsonObject.value(KEY_ATTRIBUTES).toObject();
+ Q_FOREACH ( QString shaderAttributeName, attrs.keys() ) {
+ QString pname = attrs.value(shaderAttributeName).toString();
+ QParameter *parameter = paramDict.value(pname, Q_NULLPTR);
+ QString attributeName = pname;
+ if (parameter == Q_NULLPTR) {
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "attribute " << pname
+ << "defined in instanceProgram but not as parameter";
+ continue;
+ }
+ //Check if the parameter has a standard attribute semantic
+ QString standardAttributeName = standardAttributeNameFromSemantic(m_parameterDataDict[parameter].semantic);
+ if (!standardAttributeName.isNull()) {
+ attributeName = standardAttributeName;
+ t->removeParameter(parameter);
+ m_parameterDataDict.remove(parameter);
+ delete parameter;
+ }
+
+ pass->addBinding(new QParameterMapping(attributeName, shaderAttributeName, QParameterMapping::Attribute));
+ } // of program-instance attributes
+
+ // Uniforms
+ QJsonObject uniforms = jsonObject.value(KEY_UNIFORMS).toObject();
+ Q_FOREACH (QString shaderUniformName, uniforms.keys()) {
+ QString pname = uniforms.value(shaderUniformName).toString();
+ QParameter *parameter = paramDict.value(pname, Q_NULLPTR);
+ if (parameter == Q_NULLPTR) {
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "uniform " << pname
+ << "defined in instanceProgram but not as parameter";
+ continue;
+ }
+ //Check if the parameter has a standard uniform semantic
+ QString standardUniformName = standardUniformNamefromSemantic(m_parameterDataDict[parameter].semantic);
+ if (standardUniformName.isNull()) {
+ pass->addBinding(new QParameterMapping(pname, shaderUniformName, QParameterMapping::Uniform));
+ } else {
+ pass->addBinding(new QParameterMapping(standardUniformName, shaderUniformName, QParameterMapping::StandardUniform));
+ t->removeParameter(parameter);
+ m_parameterDataDict.remove(parameter);
+ delete parameter;
+ }
+ } // of program-instance uniforms
+
+
+ // States
+ QJsonObject states = jsonObject.value(KEY_STATES).toObject();
+
+ //Process states to enable
+ QJsonArray enableStatesArray = states.value(KEY_ENABLE).toArray();
+ QVector<int> enableStates;
+ Q_FOREACH (QJsonValue enableValue, enableStatesArray) {
+ enableStates.append(enableValue.toInt());
+ }
+
+ //Process the list of state functions
+ QJsonObject functions = states.value(KEY_FUNCTIONS).toObject();
+ Q_FOREACH (QString functionName, functions.keys()) {
+ int enableStateType = 0;
+ QRenderState *renderState = buildState(functionName, functions.value(functionName), enableStateType);
+ if (renderState != Q_NULLPTR) {
+ //Remove the need to set a default state values for enableStateType
+ enableStates.removeOne(enableStateType);
+ pass->addRenderState(renderState);
+ }
+ }
+
+ //Create render states with default values for any remaining enable states
+ Q_FOREACH (int enableState, enableStates) {
+ QRenderState *renderState = buildStateEnable(enableState);
+ if (renderState != Q_NULLPTR)
+ pass->addRenderState(renderState);
+ }
+
+
+ t->addPass(pass);
+
+ m_techniques[id] = t;
+}
+
+void GLTFParser::processJSONAccessor( const QString &id, const QJsonObject& json )
+{
+ m_accessorDict[id] = AccessorData(json);
+}
+
+void GLTFParser::processJSONMesh(const QString &id, const QJsonObject &json)
+{
+ QJsonArray primitivesArray = json.value(KEY_PRIMITIVES).toArray();
+ Q_FOREACH (QJsonValue primitiveValue, primitivesArray) {
+ QJsonObject primitiveObject = primitiveValue.toObject();
+ int type = primitiveObject.value(KEY_MODE).toInt();
+ QString material = primitiveObject.value(KEY_MATERIAL).toString();
+
+ if ( material.isEmpty()) {
+ qCWarning(GLTFParserLog) << "malformed primitive on " << id << ", missing material value"
+ << material;
+ continue;
+ }
+
+ QGeometryRenderer *geometryRenderer = new QGeometryRenderer;
+ QGeometry *meshGeometry = new QGeometry(geometryRenderer);
+
+ //Set Primitive Type
+ geometryRenderer->setPrimitiveType(static_cast<QGeometryRenderer::PrimitiveType>(type));
+
+ //Save Material for mesh
+ m_meshMaterialDict[geometryRenderer] = material;
+
+ QJsonObject attrs = primitiveObject.value(KEY_ATTRIBUTES).toObject();
+ Q_FOREACH (QString attrName, attrs.keys()) {
+ QString k = attrs.value(attrName).toString();
+ if (!m_accessorDict.contains(k)) {
+ qCWarning(GLTFParserLog) << "unknown attribute accessor:" << k << "on mesh" << id;
+ continue;
+ }
+
+ QString attributeName = standardAttributeNameFromSemantic(attrName);
+ if (attributeName.isEmpty())
+ attributeName = attrName;
+
+ //Get buffer handle for accessor
+ QBuffer *buffer = m_buffers.value(m_accessorDict[k].bufferViewName, Q_NULLPTR);
+ if (buffer == Q_NULLPTR) {
+ qCWarning(GLTFParserLog) << "unknown buffer-view:" << m_accessorDict[k].bufferViewName << "processing accessor:" << id;
+ continue;
+ }
+
+ QAttribute *attribute = new QAttribute(buffer,
+ attributeName,
+ m_accessorDict[k].type,
+ m_accessorDict[k].dataSize,
+ m_accessorDict[k].count,
+ m_accessorDict[k].offset,
+ m_accessorDict[k].stride);
+ attribute->setAttributeType(QAttribute::VertexAttribute);
+ meshGeometry->addAttribute(attribute);
+ }
+
+ if ( primitiveObject.contains(KEY_INDICES)) {
+ QString k = primitiveObject.value(KEY_INDICES).toString();
+ if (!m_accessorDict.contains(k)) {
+ qCWarning(GLTFParserLog) << "unknown index accessor:" << k << "on mesh" << id;
+ } else {
+ //Get buffer handle for accessor
+ QBuffer *buffer = m_buffers.value(m_accessorDict[k].bufferViewName, Q_NULLPTR);
+ if (buffer == Q_NULLPTR) {
+ qCWarning(GLTFParserLog) << "unknown buffer-view:" << m_accessorDict[k].bufferViewName << "processing accessor:" << id;
+ continue;
+ }
+
+ QAttribute *attribute = new QAttribute(buffer,
+ m_accessorDict[k].type,
+ m_accessorDict[k].dataSize,
+ m_accessorDict[k].count,
+ m_accessorDict[k].offset,
+ m_accessorDict[k].stride);
+ attribute->setAttributeType(QAttribute::IndexAttribute);
+ meshGeometry->addAttribute(attribute);
+ }
+ } // of has indices
+
+ geometryRenderer->setGeometry(meshGeometry);
+
+ m_meshDict.insert( id, geometryRenderer);
+ } // of primitives iteration
+}
+
+void GLTFParser::processJSONImage(const QString &id, const QJsonObject &jsonObject)
+{
+ QString path = jsonObject.value(KEY_URI).toString();
+ QFileInfo info(m_basePath, path);
+ if (!info.exists()) {
+ qCWarning(GLTFParserLog) << "can't find image" << id << "from path" << path;
+ return;
+ }
+
+ m_imagePaths[id] = info.absoluteFilePath();
+}
+
+void GLTFParser::processJSONTexture(const QString &id, const QJsonObject &jsonObject)
+{
+ int target = jsonObject.value(KEY_TARGET).toInt(GL_TEXTURE_2D);
+ //TODO: support other targets that GL_TEXTURE_2D (though the spec doesn't support anything else)
+ if (target != GL_TEXTURE_2D) {
+ qCWarning(GLTFParserLog) << "unsupported texture target: " << target;
+ return;
+ }
+
+ QTexture2D* tex = new QTexture2D;
+
+ // TODO: Choose suitable internal format - may vary on OpenGL context type
+ //int pixelFormat = jsonObj.value(KEY_FORMAT).toInt(GL_RGBA);
+ int internalFormat = jsonObject.value(KEY_INTERNAL_FORMAT).toInt(GL_RGBA);
+
+ tex->setFormat(static_cast<QAbstractTextureProvider::TextureFormat>(internalFormat));
+
+ QString samplerId = jsonObject.value(KEY_SAMPLER).toString();
+ QString source = jsonObject.value(KEY_SOURCE).toString();
+ if (!m_imagePaths.contains(source)) {
+ qCWarning(GLTFParserLog) << "texture" << id << "references missing image" << source;
+ return;
+ }
+
+ QTextureImage *texImage = new QTextureImage(tex);
+ texImage->setSource(QUrl::fromLocalFile(m_imagePaths[source]));
+ tex->addTextureImage(texImage);
+
+ QJsonObject samplersDict(m_json.object().value(KEY_SAMPLERS).toObject());
+ if (!samplersDict.contains(samplerId)) {
+ qCWarning(GLTFParserLog) << "texture" << id << "references unknown sampler" << samplerId;
+ return;
+ }
+
+ QJsonObject sampler = samplersDict.value(samplerId).toObject();
+
+ tex->setWrapMode(QTextureWrapMode(static_cast<QTextureWrapMode::WrapMode>(sampler.value(KEY_WRAP_S).toInt())));
+ tex->setMinificationFilter(static_cast<QAbstractTextureProvider::Filter>(sampler.value(KEY_MIN_FILTER).toInt()));
+ if (tex->minificationFilter() == QAbstractTextureProvider::NearestMipMapLinear ||
+ tex->minificationFilter() == QAbstractTextureProvider::LinearMipMapNearest ||
+ tex->minificationFilter() == QAbstractTextureProvider::NearestMipMapNearest ||
+ tex->minificationFilter() == QAbstractTextureProvider::LinearMipMapLinear) {
+
+ tex->setGenerateMipMaps(true);
+ }
+ tex->setMagnificationFilter(static_cast<QAbstractTextureProvider::Filter>(sampler.value(KEY_MAG_FILTER).toInt()));
+
+ m_textures[id] = tex;
+}
+
+void GLTFParser::loadBufferData()
+{
+ Q_FOREACH (QString bufferName, m_bufferDatas.keys()) {
+ if (m_bufferDatas[bufferName].data == Q_NULLPTR) {
+ QFile* bufferFile = resolveLocalData(m_bufferDatas[bufferName].path);
+ QByteArray *data = new QByteArray(bufferFile->readAll());
+ m_bufferDatas[bufferName].data = data;
+ delete bufferFile;
+ }
+ }
+}
+
+void GLTFParser::unloadBufferData()
+{
+ Q_FOREACH (QString bufferName, m_bufferDatas.keys()) {
+ QByteArray *data = m_bufferDatas[bufferName].data;
+ delete data;
+ }
+}
+
+QFile *GLTFParser::resolveLocalData(QString path) const
+{
+ QDir d(m_basePath);
+ Q_ASSERT(d.exists());
+
+ QString absPath = d.absoluteFilePath(path);
+ QFile* f = new QFile(absPath);
+ f->open(QIODevice::ReadOnly);
+ return f;
+}
+
+QVariant GLTFParser::parameterValueFromJSON(int type, const QJsonValue &value) const
+{
+ if (value.isBool()) {
+ if (type == GL_BOOL)
+ return QVariant(static_cast<GLboolean>(value.toBool()));
+ } else if (value.isString()) {
+ if (type == GL_SAMPLER_2D) {
+ //Textures are special because we need to do a lookup to return the
+ //QAbstractTextureProvider
+ QString textureId = value.toString();
+ if (!m_textures.contains(textureId)) {
+ qCWarning(GLTFParserLog) << "unknown texture" << textureId;
+ return QVariant();
+ } else {
+ return QVariant::fromValue(m_textures.value(textureId));
+ }
+ }
+ } else if (value.isDouble()) {
+ switch (type) {
+ case GL_BYTE:
+ return QVariant(static_cast<GLbyte>(value.toInt()));
+ case GL_UNSIGNED_BYTE:
+ return QVariant(static_cast<GLubyte>(value.toInt()));
+ case GL_SHORT:
+ return QVariant(static_cast<GLshort>(value.toInt()));
+ case GL_UNSIGNED_SHORT:
+ return QVariant(static_cast<GLushort>(value.toInt()));
+ case GL_INT:
+ return QVariant(static_cast<GLint>(value.toInt()));
+ case GL_UNSIGNED_INT:
+ return QVariant(static_cast<GLuint>(value.toInt()));
+ case GL_FLOAT:
+ return QVariant(static_cast<GLfloat>(value.toDouble()));
+ }
+ } else if (value.isArray()) {
+
+ QJsonArray valueArray = value.toArray();
+
+ QVector2D vector2D;
+ QVector3D vector3D;
+ QVector4D vector4D;
+ QVector<float> dataMat2(4, 0.0f);
+ QVector<float> dataMat3(9, 0.0f);
+
+ switch (type) {
+ case GL_BYTE:
+ return QVariant(static_cast<GLbyte>(valueArray.first().toInt()));
+ case GL_UNSIGNED_BYTE:
+ return QVariant(static_cast<GLubyte>(valueArray.first().toInt()));
+ case GL_SHORT:
+ return QVariant(static_cast<GLshort>(valueArray.first().toInt()));
+ case GL_UNSIGNED_SHORT:
+ return QVariant(static_cast<GLushort>(valueArray.first().toInt()));
+ case GL_INT:
+ return QVariant(static_cast<GLint>(valueArray.first().toInt()));
+ case GL_UNSIGNED_INT:
+ return QVariant(static_cast<GLuint>(valueArray.first().toInt()));
+ case GL_FLOAT:
+ return QVariant(static_cast<GLfloat>(valueArray.first().toDouble()));
+ case GL_FLOAT_VEC2:
+ vector2D.setX(static_cast<GLfloat>(valueArray.at(0).toDouble()));
+ vector2D.setY(static_cast<GLfloat>(valueArray.at(1).toDouble()));
+ return QVariant(vector2D);
+ case GL_FLOAT_VEC3:
+ vector3D.setX(static_cast<GLfloat>(valueArray.at(0).toDouble()));
+ vector3D.setY(static_cast<GLfloat>(valueArray.at(1).toDouble()));
+ vector3D.setZ(static_cast<GLfloat>(valueArray.at(2).toDouble()));
+ return QVariant(vector3D);
+ case GL_FLOAT_VEC4:
+ vector4D.setX(static_cast<GLfloat>(valueArray.at(0).toDouble()));
+ vector4D.setY(static_cast<GLfloat>(valueArray.at(1).toDouble()));
+ vector4D.setZ(static_cast<GLfloat>(valueArray.at(2).toDouble()));
+ vector4D.setW(static_cast<GLfloat>(valueArray.at(3).toDouble()));
+ return QVariant(vector4D);
+ case GL_INT_VEC2:
+ vector2D.setX(static_cast<GLint>(valueArray.at(0).toInt()));
+ vector2D.setY(static_cast<GLint>(valueArray.at(1).toInt()));
+ return QVariant(vector2D);
+ case GL_INT_VEC3:
+ vector3D.setX(static_cast<GLint>(valueArray.at(0).toInt()));
+ vector3D.setY(static_cast<GLint>(valueArray.at(1).toInt()));
+ vector3D.setZ(static_cast<GLint>(valueArray.at(2).toInt()));
+ return QVariant(vector3D);
+ case GL_INT_VEC4:
+ vector4D.setX(static_cast<GLint>(valueArray.at(0).toInt()));
+ vector4D.setY(static_cast<GLint>(valueArray.at(1).toInt()));
+ vector4D.setZ(static_cast<GLint>(valueArray.at(2).toInt()));
+ vector4D.setW(static_cast<GLint>(valueArray.at(3).toInt()));
+ return QVariant(vector4D);
+ case GL_BOOL:
+ return QVariant(static_cast<GLboolean>(valueArray.first().toBool()));
+ case GL_BOOL_VEC2:
+ vector2D.setX(static_cast<GLboolean>(valueArray.at(0).toBool()));
+ vector2D.setY(static_cast<GLboolean>(valueArray.at(1).toBool()));
+ return QVariant(vector2D);
+ case GL_BOOL_VEC3:
+ vector3D.setX(static_cast<GLboolean>(valueArray.at(0).toBool()));
+ vector3D.setY(static_cast<GLboolean>(valueArray.at(1).toBool()));
+ vector3D.setZ(static_cast<GLboolean>(valueArray.at(2).toBool()));
+ return QVariant(vector3D);
+ case GL_BOOL_VEC4:
+ vector4D.setX(static_cast<GLboolean>(valueArray.at(0).toBool()));
+ vector4D.setY(static_cast<GLboolean>(valueArray.at(1).toBool()));
+ vector4D.setZ(static_cast<GLboolean>(valueArray.at(2).toBool()));
+ vector4D.setW(static_cast<GLboolean>(valueArray.at(3).toBool()));
+ return QVariant(vector4D);
+ case GL_FLOAT_MAT2:
+ //Matrix2x2 is in Row Major ordering (so we need to convert)
+ dataMat2[0] = static_cast<GLfloat>(valueArray.at(0).toDouble());
+ dataMat2[1] = static_cast<GLfloat>(valueArray.at(2).toDouble());
+ dataMat2[2] = static_cast<GLfloat>(valueArray.at(1).toDouble());
+ dataMat2[3] = static_cast<GLfloat>(valueArray.at(3).toDouble());
+ return QVariant::fromValue(QMatrix2x2(dataMat2.constData()));
+ case GL_FLOAT_MAT3:
+ //Matrix3x3 is in Row Major ordering (so we need to convert)
+ dataMat3[0] = static_cast<GLfloat>(valueArray.at(0).toDouble());
+ dataMat3[1] = static_cast<GLfloat>(valueArray.at(3).toDouble());
+ dataMat3[2] = static_cast<GLfloat>(valueArray.at(6).toDouble());
+ dataMat3[3] = static_cast<GLfloat>(valueArray.at(1).toDouble());
+ dataMat3[4] = static_cast<GLfloat>(valueArray.at(4).toDouble());
+ dataMat3[5] = static_cast<GLfloat>(valueArray.at(7).toDouble());
+ dataMat3[6] = static_cast<GLfloat>(valueArray.at(2).toDouble());
+ dataMat3[7] = static_cast<GLfloat>(valueArray.at(5).toDouble());
+ dataMat3[8] = static_cast<GLfloat>(valueArray.at(8).toDouble());
+ return QVariant::fromValue(QMatrix3x3(dataMat3.constData()));
+ case GL_FLOAT_MAT4:
+ //Matrix4x4 is Column Major ordering
+ return QVariant(QMatrix4x4(static_cast<GLfloat>(valueArray.at(0).toDouble()),
+ static_cast<GLfloat>(valueArray.at(1).toDouble()),
+ static_cast<GLfloat>(valueArray.at(2).toDouble()),
+ static_cast<GLfloat>(valueArray.at(3).toDouble()),
+ static_cast<GLfloat>(valueArray.at(4).toDouble()),
+ static_cast<GLfloat>(valueArray.at(5).toDouble()),
+ static_cast<GLfloat>(valueArray.at(6).toDouble()),
+ static_cast<GLfloat>(valueArray.at(7).toDouble()),
+ static_cast<GLfloat>(valueArray.at(8).toDouble()),
+ static_cast<GLfloat>(valueArray.at(9).toDouble()),
+ static_cast<GLfloat>(valueArray.at(10).toDouble()),
+ static_cast<GLfloat>(valueArray.at(11).toDouble()),
+ static_cast<GLfloat>(valueArray.at(12).toDouble()),
+ static_cast<GLfloat>(valueArray.at(13).toDouble()),
+ static_cast<GLfloat>(valueArray.at(14).toDouble()),
+ static_cast<GLfloat>(valueArray.at(15).toDouble())));
+ case GL_SAMPLER_2D:
+ return QVariant(valueArray.at(0).toString());
+ }
+ }
+ return QVariant();
+}
+
+QAttribute::DataType GLTFParser::accessorTypeFromJSON(int componentType)
+{
+ if (componentType == GL_BYTE) {
+ return QAttribute::Byte;
+ } else if (componentType == GL_UNSIGNED_BYTE) {
+ return QAttribute::UnsignedByte;
+ } else if (componentType == GL_SHORT) {
+ return QAttribute::Short;
+ } else if (componentType == GL_UNSIGNED_SHORT) {
+ return QAttribute::UnsignedShort;
+ } else if (componentType == GL_UNSIGNED_INT) {
+ return QAttribute::UnsignedInt;
+ } else if (componentType == GL_FLOAT) {
+ return QAttribute::Float;
+ }
+
+ //There shouldn't be an invalid case here
+ qCWarning(GLTFParserLog) << "unsupported accessor type" << componentType;
+ return QAttribute::Float;
+}
+
+uint GLTFParser::accessorDataSizeFromJson(const QString &type)
+{
+ QString typeName = type.toUpper();
+ if (typeName == "SCALAR")
+ return 1;
+ if (typeName == "VEC2")
+ return 2;
+ if (typeName == "VEC3")
+ return 3;
+ if (typeName == "VEC4")
+ return 4;
+ if (typeName == "MAT2")
+ return 4;
+ if (typeName == "MAT3")
+ return 9;
+ if (typeName == "MAT4")
+ return 16;
+
+ return 0;
+}
+
+QRenderState *GLTFParser::buildStateEnable(int state)
+{
+ int type = 0;
+ //By calling buildState with QJsonValue(), a Render State with
+ //default values is created.
+
+ if (state == GL_BLEND) {
+ //It doesn't make sense to handle this state alone
+ return Q_NULLPTR;
+ }
+
+ if (state == GL_CULL_FACE) {
+ return buildState(QStringLiteral("cullFace"), QJsonValue(), type);
+ }
+
+ if (state == GL_DEPTH_TEST) {
+ return buildState(QStringLiteral("depthFunc"), QJsonValue(), type);
+ }
+
+ if (state == GL_POLYGON_OFFSET_FILL) {
+ return buildState(QStringLiteral("polygonOffset"), QJsonValue(), type);
+ }
+
+ if (state == GL_SAMPLE_ALPHA_TO_COVERAGE) {
+ return new QAlphaCoverage();
+ }
+
+ if (state == GL_SCISSOR_TEST) {
+ return buildState(QStringLiteral("scissor"), QJsonValue(), type);
+ }
+
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << state;
+
+ return Q_NULLPTR;
+}
+
+QRenderState* GLTFParser::buildState(const QString& functionName, const QJsonValue &value, int &type)
+{
+ type = -1;
+ QJsonArray values = value.toArray();
+
+ if (functionName == QStringLiteral("blendColor")) {
+ type = GL_BLEND;
+ //TODO: support render state blendColor
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName;
+ return Q_NULLPTR;
+ }
+
+ if (functionName == QStringLiteral("blendEquationSeparate")) {
+ type = GL_BLEND;
+ //TODO: support settings blendEquation alpha
+ QBlendEquation *blendEquation = new QBlendEquation;
+ blendEquation->setMode((QBlendEquation::BlendMode)values.at(0).toInt(GL_FUNC_ADD));
+ return blendEquation;
+ }
+
+ if (functionName == QStringLiteral("blendFuncSeparate")) {
+ type = GL_BLEND;
+ QBlendStateSeparate *blendState = new QBlendStateSeparate;
+ blendState->setSrcRGB((QBlendState::Blending)values.at(0).toInt(GL_ONE));
+ blendState->setSrcAlpha((QBlendState::Blending)values.at(1).toInt(GL_ONE));
+ blendState->setDstRGB((QBlendState::Blending)values.at(2).toInt(GL_ZERO));
+ blendState->setDstAlpha((QBlendState::Blending)values.at(3).toInt(GL_ZERO));
+ return blendState;
+ }
+
+ if (functionName == QStringLiteral("colorMask")) {
+ QColorMask *colorMask = new QColorMask;
+ colorMask->setRed(values.at(0).toBool(true));
+ colorMask->setGreen(values.at(1).toBool(true));
+ colorMask->setBlue(values.at(2).toBool(true));
+ colorMask->setAlpha(values.at(3).toBool(true));
+ return colorMask;
+ }
+
+ if (functionName == QStringLiteral("cullFace")) {
+ type = GL_CULL_FACE;
+ QCullFace *cullFace = new QCullFace;
+ cullFace->setMode((QCullFace::CullingMode)values.at(0).toInt(GL_BACK));
+ return cullFace;
+ }
+
+ if (functionName == QStringLiteral("depthFunc")) {
+ type = GL_DEPTH_TEST;
+ QDepthTest *depthTest = new QDepthTest;
+ depthTest->setFunc((QDepthTest::DepthFunc)values.at(0).toInt(GL_LESS));
+ return depthTest;
+ }
+
+ if (functionName == QStringLiteral("depthMask")) {
+ QDepthMask *depthMask = new QDepthMask;
+ depthMask->setMask(values.at(0).toBool(true));
+ }
+
+ if (functionName == QStringLiteral("depthRange")) {
+ //TODO: support render state depthRange
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName;
+ return Q_NULLPTR;
+ }
+
+ if (functionName == QStringLiteral("frontFace")) {
+ QFrontFace *frontFace = new QFrontFace;
+ frontFace->setDirection((QFrontFace::FaceDir)values.at(0).toInt(GL_CCW));
+ return frontFace;
+ }
+
+ if (functionName == QStringLiteral("lineWidth")) {
+ //TODO: support render state lineWidth
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName;
+ return Q_NULLPTR;
+ }
+
+ if (functionName == QStringLiteral("polygonOffset")) {
+ type = GL_POLYGON_OFFSET_FILL;
+ QPolygonOffset *polygonOffset = new QPolygonOffset;
+ polygonOffset->setFactor((float)values.at(0).toDouble(0.0f));
+ polygonOffset->setUnits((float)values.at(1).toDouble(0.0f));
+ return polygonOffset;
+ }
+
+ if (functionName == QStringLiteral("scissor")) {
+ type = GL_SCISSOR_TEST;
+ QScissorTest *scissorTest = new QScissorTest;
+ scissorTest->setLeft(values.at(0).toDouble(0.0f));
+ scissorTest->setBottom(values.at(1).toDouble(0.0f));
+ scissorTest->setWidth(values.at(2).toDouble(0.0f));
+ scissorTest->setHeight(values.at(3).toDouble(0.0f));
+ return scissorTest;
+ }
+
+ qCWarning(GLTFParserLog) << Q_FUNC_INFO << "unsupported render state:" << functionName;
+ return Q_NULLPTR;
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/imports/render/plugins.qmltypes b/src/quick3d/imports/render/plugins.qmltypes
index a6528daed..9e6e5fe38 100644
--- a/src/quick3d/imports/render/plugins.qmltypes
+++ b/src/quick3d/imports/render/plugins.qmltypes
@@ -780,7 +780,7 @@ Module {
"OneMinusConstantColor": 32770,
"OneMinusConstantAlpha": 32772,
"OneMinusSource1Alpha": 32773,
- "OneMinusSource1Color0": 32774
+ "OneMinusSource1Color": 32774
}
}
Property { name: "sourceRgb"; type: "Blending" }
diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
index 3eb89efe7..28416d894 100644
--- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
+++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
@@ -219,7 +219,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri)
Qt3DRender::Quick::registerExtendedType<Qt3DRender::QViewport, Qt3DRender::Render::Quick::Quick3DViewport>("QViewport", "Qt3D.Render/Viewport", uri, 2, 0, "Viewport");
Qt3DRender::Quick::registerExtendedType<Qt3DRender::QRenderTargetSelector, Qt3DRender::Render::Quick::Quick3DRenderTargetSelector>("QRenderTargetSelector", "Qt3D.Render/RenderTargetSelector", uri, 2, 0, "RenderTargetSelector");
qmlRegisterType<Qt3DRender::QClearBuffers>(uri, 2, 0, "ClearBuffers");
- qmlRegisterUncreatableType<Qt3DRender::QFrameGraphNode>(uri, 2, 0, "FrameGraphNode", QStringLiteral("FrameGraphNode is a base class"));
+ qmlRegisterType<Qt3DRender::QFrameGraphNode>(uri, 2, 0, "FrameGraphNode");
Qt3DRender::Quick::registerExtendedType<Qt3DRender::QRenderStateSet, Qt3DRender::Render::Quick::Quick3DStateSet>("QRenderStateSet", "Qt3D.Render/RenderStateSet", uri, 2, 0, "RenderStateSet");
qmlRegisterType<Qt3DRender::QNoDraw>(uri, 2, 0, "NoDraw");
qmlRegisterType<Qt3DRender::QFrustumCulling>(uri, 2, 0, "FrustumCulling");
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index c03e77018..4a5c959c4 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -273,19 +273,11 @@ void Scene3DItem::setMultisample(bool enable)
QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *)
{
// If the render aspect wasn't created yet, do so now
- if (!m_renderAspect) {
+ if (m_renderAspect == nullptr) {
m_renderAspect = new QRenderAspect(QRenderAspect::Synchronous);
m_aspectEngine->registerAspect(m_renderAspect);
}
- // If the node already exists
- // we delete it and recreate it
- // as we need to resize the FBO
- if (node) {
- delete node;
- node = nullptr;
- }
-
if (m_renderer == nullptr) {
m_renderer = new Scene3DRenderer(this, m_aspectEngine, m_renderAspect);
m_renderer->setCleanerHelper(m_rendererCleaner);
@@ -294,9 +286,13 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode
// The main thread is blocked, it is now time to sync data between the renderer and the item.
m_renderer->synchronize();
- Scene3DSGNode *fboNode = new Scene3DSGNode();
+ Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node);
+ if (fboNode == nullptr) {
+ fboNode = new Scene3DSGNode();
+ m_renderer->setSGNode(fboNode);
+ }
fboNode->setRect(boundingRect());
- m_renderer->setSGNode(fboNode);
+
return fboNode;
}
diff --git a/src/quick3d/imports/scene3d/scene3ditem_p.h b/src/quick3d/imports/scene3d/scene3ditem_p.h
index bb141b423..09859a763 100644
--- a/src/quick3d/imports/scene3d/scene3ditem_p.h
+++ b/src/quick3d/imports/scene3d/scene3ditem_p.h
@@ -93,7 +93,7 @@ public:
AutomaticAspectRatio,
UserAspectRatio
};
- Q_ENUM(CameraAspectRatioMode);
+ Q_ENUM(CameraAspectRatioMode); // LCOV_EXCL_LINE
CameraAspectRatioMode cameraAspectRatioMode() const;
public Q_SLOTS:
diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp
index 86f8a7681..3065b19ac 100644
--- a/src/quick3d/imports/scene3d/scene3drenderer.cpp
+++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp
@@ -70,7 +70,7 @@ public:
~ContextSaver()
{
- if (m_context)
+ if (m_context && m_context->surface() != m_surface)
m_context->makeCurrent(m_surface);
}
@@ -129,6 +129,7 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp
QObject::connect(m_item->window(), &QQuickWindow::beforeRendering, this, &Scene3DRenderer::render, Qt::DirectConnection);
QObject::connect(m_item, &QQuickItem::windowChanged, this, &Scene3DRenderer::onWindowChangedQueued, Qt::QueuedConnection);
+ Q_ASSERT(QOpenGLContext::currentContext());
ContextSaver saver;
static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderInitialize(saver.context());
scheduleRootEntityChange();
@@ -183,8 +184,10 @@ void Scene3DRenderer::shutdown()
// Exit the simulation loop so no more jobs are asked for. Once this
// returns it is safe to shutdown the renderer.
- auto engineD = Qt3DCore::QAspectEnginePrivate::get(m_aspectEngine);
- engineD->exitSimulationLoop();
+ if (m_aspectEngine) {
+ auto engineD = Qt3DCore::QAspectEnginePrivate::get(m_aspectEngine);
+ engineD->exitSimulationLoop();
+ }
// Shutdown the Renderer Aspect while the OpenGL context
// is still valid
@@ -231,17 +234,17 @@ void Scene3DRenderer::render()
const QSize boundingRectSize = m_item->boundingRect().size().toSize();
const QSize currentSize = boundingRectSize * window->effectiveDevicePixelRatio();
- const bool forceRecreate = currentSize != m_lastSize || m_multisample != m_lastMultisample;
+ const bool sizeHasChanged = currentSize != m_lastSize;
+ const bool multisampleHasChanged = m_multisample != m_lastMultisample;
+ const bool forceRecreate = sizeHasChanged || multisampleHasChanged;
- if (currentSize != m_lastSize)
+ if (sizeHasChanged)
m_item->setItemArea(boundingRectSize);
// Rebuild FBO and textures if never created or a resize has occurred
if ((m_multisampledFBO.isNull() || forceRecreate) && m_multisample) {
- qCDebug(Scene3D) << Q_FUNC_INFO << "Creating multisample framebuffer";
m_multisampledFBO.reset(createMultisampledFramebufferObject(currentSize));
if (m_multisampledFBO->format().samples() == 0 || !QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) {
- qCDebug(Scene3D) << Q_FUNC_INFO << "Failed to create multisample framebuffer";
m_multisample = false;
m_multisampledFBO.reset(nullptr);
}
@@ -258,18 +261,21 @@ void Scene3DRenderer::render()
m_lastSize = currentSize;
m_lastMultisample = m_multisample;
- //Only try to use MSAA when available
- if (m_multisample) {
- // Bind FBO
+ // Bind FBO
+ if (m_multisample) //Only try to use MSAA when available
m_multisampledFBO->bind();
+ else
+ m_finalFBO->bind();
- // Render Qt3D Scene
- static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous();
+ // Render Qt3D Scene
+ static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous();
- // We may have called doneCurrent() so restore the context.
- if (saver.context()->surface() != saver.surface())
- saver.context()->makeCurrent(saver.surface());
+ // We may have called doneCurrent() so restore the context if the rendering surface was changed
+ // Note: keep in mind that the ContextSave also restores the surface when destroyed
+ if (saver.context()->surface() != saver.surface())
+ saver.context()->makeCurrent(saver.surface());
+ if (m_multisample) {
// Blit multisampled FBO with non multisampled FBO with texture attachment
const QRect dstRect(QPoint(0, 0), m_finalFBO->size());
const QRect srcRect(QPoint(0, 0), m_multisampledFBO->size());
@@ -279,24 +285,11 @@ void Scene3DRenderer::render()
GL_NEAREST,
0, 0,
QOpenGLFramebufferObject::DontRestoreFramebufferBinding);
-
- // Restore QtQuick FBO
- m_multisampledFBO->bindDefault();
- } else {
- // Bind FBO
- m_finalFBO->bind();
-
- // Render Qt3D Scene
- static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous();
-
- // We may have called doneCurrent() so restore the context.
- if (saver.context()->surface() != saver.surface())
- saver.context()->makeCurrent(saver.surface());
-
- // Restore QtQuick FBO
- m_finalFBO->bindDefault();
}
+ // Restore QtQuick FBO
+ QOpenGLFramebufferObject::bindDefault();
+
// Reset the state used by the Qt Quick scenegraph to avoid any
// interference when rendering the rest of the UI.
window->resetOpenGLState();
diff --git a/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp b/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp
index b95290a3c..ce69e471a 100644
--- a/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp
+++ b/src/quick3d/quick3d/items/quick3dnodeinstantiator.cpp
@@ -148,7 +148,7 @@ void Quick3DNodeInstantiatorPrivate::_q_createdItem(int idx, QObject *item)
Q_Q(Quick3DNodeInstantiator);
if (m_objects.contains(item)) //Case when it was created synchronously in regenerate
return;
- static_cast<QNode *>(item)->setParent(q);
+ static_cast<QNode *>(item)->setParent(q->parentNode());
m_objects.insert(idx, item);
if (m_objects.count() == 1)
q->objectChanged();
@@ -247,10 +247,10 @@ Quick3DNodeInstantiator::Quick3DNodeInstantiator(QNode *parent)
}
/*!
- \qmlsignal Qt3D.Core::NodeInstantiator::objectAdded(int index, QtObject node)
+ \qmlsignal Qt3D.Core::NodeInstantiator::objectAdded(int index, QtObject object)
This signal is emitted when a node is added to the NodeInstantiator. The \a index
- parameter holds the index which the node has been given, and the \a node
+ parameter holds the index which the node has been given, and the \a object
parameter holds the \l Node that has been added.
The corresponding handler is \c onNodeAdded.
diff --git a/src/quick3d/quick3d/qqmlaspectengine.cpp b/src/quick3d/quick3d/qqmlaspectengine.cpp
index 690f256a0..4b694d26e 100644
--- a/src/quick3d/quick3d/qqmlaspectengine.cpp
+++ b/src/quick3d/quick3d/qqmlaspectengine.cpp
@@ -65,6 +65,7 @@ QQmlAspectEnginePrivate::QQmlAspectEnginePrivate()
/*!
* \class Qt3DCore::Quick::QQmlAspectEngine
+ * \inheaderfile Qt3DQuick/QQmlAspectEngine
* \inmodule Qt3DCore
*
* \brief The QQmlAspectEngine provides an environment for the QAspectEngine and
diff --git a/src/quick3d/quick3d/qquaternionanimation_p.h b/src/quick3d/quick3d/qquaternionanimation_p.h
index 92056f24e..3c5f092c4 100644
--- a/src/quick3d/quick3d/qquaternionanimation_p.h
+++ b/src/quick3d/quick3d/qquaternionanimation_p.h
@@ -83,7 +83,7 @@ public:
Slerp = 0,
Nlerp
};
- Q_ENUM(Type)
+ Q_ENUM(Type) // LCOV_EXCL_LINE
QQuaternionAnimation(QObject *parent = 0);
diff --git a/src/quick3d/quick3d/quick3d.pro b/src/quick3d/quick3d/quick3d.pro
index fc3ef19ee..f8d25b4a5 100644
--- a/src/quick3d/quick3d/quick3d.pro
+++ b/src/quick3d/quick3d/quick3d.pro
@@ -7,7 +7,6 @@ QT += core-private gui-private qml qml-private quick quick-private 3dcore 3
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/quick3d/quick3dextras/qt3dquickwindow.h b/src/quick3d/quick3dextras/qt3dquickwindow.h
index d278a3194..a8703093e 100644
--- a/src/quick3d/quick3dextras/qt3dquickwindow.h
+++ b/src/quick3d/quick3dextras/qt3dquickwindow.h
@@ -104,7 +104,7 @@ public:
AutomaticAspectRatio,
UserAspectRatio
};
- Q_ENUM(CameraAspectRatioMode);
+ Q_ENUM(CameraAspectRatioMode); // LCOV_EXCL_LINE
void setCameraAspectRatioMode(CameraAspectRatioMode mode);
CameraAspectRatioMode cameraAspectRatioMode() const;
diff --git a/src/quick3d/quick3dextras/quick3dextras.pro b/src/quick3d/quick3dextras/quick3dextras.pro
index e0e339e8a..8965e9f5d 100644
--- a/src/quick3d/quick3dextras/quick3dextras.pro
+++ b/src/quick3d/quick3dextras/quick3dextras.pro
@@ -8,7 +8,6 @@ CONFIG -= precompile_header
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/quick3d/quick3dinput/quick3dinput.pro b/src/quick3d/quick3dinput/quick3dinput.pro
index 661a7f792..f0e1a7c6b 100644
--- a/src/quick3d/quick3dinput/quick3dinput.pro
+++ b/src/quick3d/quick3dinput/quick3dinput.pro
@@ -8,7 +8,6 @@ CONFIG -= precompile_header
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/quick3d/quick3drender/items/quick3dshaderdata_p.h b/src/quick3d/quick3drender/items/quick3dshaderdata_p.h
index 72c117c90..15e127b78 100644
--- a/src/quick3d/quick3drender/items/quick3dshaderdata_p.h
+++ b/src/quick3d/quick3drender/items/quick3dshaderdata_p.h
@@ -76,6 +76,6 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::Quick::Quick3DShaderData*)
+Q_DECLARE_METATYPE(Qt3DRender::Render::Quick::Quick3DShaderData*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_QUICK_QUICK3DSHADERDATA_P_H
diff --git a/src/quick3d/quick3drender/items/quick3dshaderdataarray_p.h b/src/quick3d/quick3drender/items/quick3dshaderdataarray_p.h
index effd18b32..9d33df208 100644
--- a/src/quick3d/quick3drender/items/quick3dshaderdataarray_p.h
+++ b/src/quick3d/quick3drender/items/quick3dshaderdataarray_p.h
@@ -93,6 +93,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::Quick::Quick3DShaderDataArray*)
+Q_DECLARE_METATYPE(Qt3DRender::Render::Quick::Quick3DShaderDataArray*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_QUICK_QUICK3DSHADERDATAARRAY_P_H
diff --git a/src/quick3d/quick3drender/quick3drender.pro b/src/quick3d/quick3drender/quick3drender.pro
index 3079bc494..88d7a9556 100644
--- a/src/quick3d/quick3drender/quick3drender.pro
+++ b/src/quick3d/quick3drender/quick3drender.pro
@@ -8,7 +8,6 @@ CONFIG -= precompile_header
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index 8d922c0d1..4ae2dc058 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -60,7 +60,6 @@
#include <Qt3DRender/private/layer_p.h>
#include <Qt3DRender/private/material_p.h>
#include <Qt3DRender/private/shader_p.h>
-#include <Qt3DRender/private/technique_p.h>
#include <Qt3DRender/private/texture_p.h>
#include <Qt3DRender/private/transform_p.h>
#include <Qt3DRender/private/rendertarget_p.h>
@@ -90,7 +89,7 @@ class AttachmentManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
AttachmentManager() {}
@@ -100,7 +99,8 @@ class CameraManager : public Qt3DCore::QResourceManager<
CameraLens,
Qt3DCore::QNodeId,
8,
- Qt3DCore::ArrayAllocatingPolicy>
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
{
public:
CameraManager() {}
@@ -111,7 +111,7 @@ class FilterKeyManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
@@ -123,7 +123,7 @@ class EffectManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
EffectManager() {}
@@ -132,7 +132,9 @@ public:
class Q_AUTOTEST_EXPORT EntityManager : public Qt3DCore::QResourceManager<
Entity,
Qt3DCore::QNodeId,
- 16>
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
{
public:
EntityManager() {}
@@ -168,7 +170,7 @@ class LayerManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
LayerManager() {}
@@ -179,13 +181,18 @@ class MaterialManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
MaterialManager() {}
};
-class MatrixManager : public Qt3DCore::QResourceManager<QMatrix4x4, Qt3DCore::QNodeId, 16>
+class MatrixManager : public Qt3DCore::QResourceManager<
+ QMatrix4x4,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
{
public:
MatrixManager() {}
@@ -196,29 +203,18 @@ class ShaderManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
ShaderManager() {}
};
-class TechniqueManager : public Qt3DCore::QResourceManager<
- Technique,
- Qt3DCore::QNodeId,
- 16,
- Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
-{
-public:
- TechniqueManager() {}
-};
-
class TextureManager : public Qt3DCore::QResourceManager<
Texture,
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
TextureManager() {}
@@ -229,7 +225,7 @@ class TransformManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
TransformManager() {}
@@ -238,7 +234,9 @@ public:
class VAOManager : public Qt3DCore::QResourceManager<
OpenGLVertexArrayObject,
QPair<HGeometry, HShader>,
- 16>
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
{
public:
VAOManager() {}
@@ -249,7 +247,7 @@ class RenderTargetManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
8,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
RenderTargetManager() {}
@@ -260,7 +258,7 @@ class RenderPassManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
RenderPassManager() {}
@@ -272,7 +270,7 @@ class ParameterManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
ParameterManager() {}
@@ -283,7 +281,7 @@ class ShaderDataManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
ShaderDataManager() {}
@@ -294,7 +292,7 @@ class GLBufferManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
};
@@ -303,7 +301,7 @@ class TextureImageManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
};
@@ -312,7 +310,7 @@ class AttributeManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
20,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
};
@@ -321,7 +319,7 @@ class GeometryManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
};
@@ -330,7 +328,7 @@ class ObjectPickerManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
};
@@ -350,7 +348,7 @@ class LightManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
LightManager() {}
@@ -361,7 +359,7 @@ class ComputeCommandManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
public:
ComputeCommandManager() {}
@@ -372,7 +370,7 @@ class RenderStateManager : public Qt3DCore::QResourceManager<
Qt3DCore::QNodeId,
16,
Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+ Qt3DCore::NonLockingPolicy>
{
};
@@ -387,7 +385,6 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Layer, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Material, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Shader, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::RenderTarget, Q_REQUIRES_CLEANUP)
-Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Technique, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Texture, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::RenderPass, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::TextureImage, Q_REQUIRES_CLEANUP)
@@ -396,6 +393,8 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Geometry, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ObjectPicker, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::BoundingVolumeDebug, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::ComputeCommand, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Parameter, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Transform, Q_REQUIRES_CLEANUP)
QT_END_NAMESPACE
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index 66e526d41..0234db979 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -42,8 +42,10 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/scenemanager_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/gltexturemanager_p.h>
#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/techniquemanager_p.h>
#include <QOpenGLVertexArrayObject>
@@ -64,7 +66,10 @@ NodeManagers::NodeManagers()
, m_effectManager(new EffectManager())
, m_renderPassManager(new RenderPassManager())
, m_textureManager(new TextureManager())
+ , m_textureImageManager(new TextureImageManager())
, m_textureDataManager(new TextureDataManager())
+ , m_textureImageDataManager(new TextureImageDataManager())
+ , m_glTextureManager(new GLTextureManager(m_textureImageManager, m_textureDataManager, m_textureImageDataManager))
, m_layerManager(new LayerManager())
, m_filterKeyManager(new FilterKeyManager())
, m_frameGraphManager(new FrameGraphManager())
@@ -75,7 +80,6 @@ NodeManagers::NodeManagers()
, m_parameterManager(new ParameterManager())
, m_shaderDataManager(new ShaderDataManager())
, m_glBufferManager(new GLBufferManager())
- , m_textureImageManager(new TextureImageManager())
, m_bufferManager(new BufferManager())
, m_attributeManager(new AttributeManager())
, m_geometryManager(new GeometryManager())
@@ -98,8 +102,10 @@ NodeManagers::~NodeManagers()
delete m_techniqueManager;
delete m_effectManager;
delete m_renderPassManager;
+ delete m_glTextureManager;
delete m_textureManager;
delete m_textureDataManager;
+ delete m_textureImageDataManager;
delete m_layerManager;
delete m_filterKeyManager;
delete m_frameGraphManager;
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index 0675df5d9..7e1259a1d 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -90,8 +90,10 @@ class TextureImageManager;
class FilterKeyManager;
class FrameGraphManager;
class TransformManager;
+class GLTextureManager;
class TextureManager;
class TextureDataManager;
+class TextureImageDataManager;
class LayerManager;
class LightManager;
class ComputeCommandManager;
@@ -176,8 +178,10 @@ public:
inline TechniqueManager *techniqueManager() const Q_DECL_NOEXCEPT { return m_techniqueManager; }
inline EffectManager *effectManager() const Q_DECL_NOEXCEPT { return m_effectManager; }
inline RenderPassManager *renderPassManager() const Q_DECL_NOEXCEPT { return m_renderPassManager; }
+ inline GLTextureManager *glTextureManager() const Q_DECL_NOEXCEPT { return m_glTextureManager; }
inline TextureManager *textureManager() const Q_DECL_NOEXCEPT { return m_textureManager; }
inline TextureDataManager *textureDataManager() const Q_DECL_NOEXCEPT { return m_textureDataManager; }
+ inline TextureImageDataManager *textureImageDataManager() const Q_DECL_NOEXCEPT { return m_textureImageDataManager; }
inline LayerManager *layerManager() const Q_DECL_NOEXCEPT { return m_layerManager; }
inline FilterKeyManager *filterKeyManager() const Q_DECL_NOEXCEPT { return m_filterKeyManager; }
inline FrameGraphManager *frameGraphManager() const Q_DECL_NOEXCEPT { return m_frameGraphManager; }
@@ -210,7 +214,10 @@ private:
EffectManager *m_effectManager;
RenderPassManager *m_renderPassManager;
TextureManager *m_textureManager;
+ TextureImageManager *m_textureImageManager;
TextureDataManager *m_textureDataManager;
+ TextureImageDataManager *m_textureImageDataManager;
+ GLTextureManager *m_glTextureManager;
LayerManager *m_layerManager;
FilterKeyManager *m_filterKeyManager;
FrameGraphManager *m_frameGraphManager;
@@ -221,7 +228,6 @@ private:
ParameterManager *m_parameterManager;
ShaderDataManager *m_shaderDataManager;
GLBufferManager *m_glBufferManager;
- TextureImageManager *m_textureImageManager;
BufferManager *m_bufferManager;
AttributeManager *m_attributeManager;
GeometryManager *m_geometryManager;
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index a55a72d8b..9dc208f8b 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -37,7 +37,8 @@ HEADERS += \
$$PWD/rendertargetoutput_p.h \
$$PWD/commandexecuter_p.h \
$$PWD/uniform_p.h \
- $$PWD/shaderparameterpack_p.h
+ $$PWD/shaderparameterpack_p.h \
+ $$PWD/renderviewbuilder_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -68,5 +69,6 @@ SOURCES += \
$$PWD/commandexecuter.cpp \
$$PWD/openglvertexarrayobject.cpp \
$$PWD/uniform.cpp \
- $$PWD/shaderparameterpack.cpp
+ $$PWD/shaderparameterpack.cpp \
+ $$PWD/renderviewbuilder.cpp
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 152c35199..1a36c52db 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -75,7 +75,10 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/gltexturemanager_p.h>
+#include <Qt3DRender/private/gltexture_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/openglvertexarrayobject_p.h>
#include <Qt3DRender/private/platformsurfacefilter_p.h>
#include <Qt3DRender/private/loadbufferjob_p.h>
@@ -150,19 +153,22 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_changeSet(0)
, m_lastFrameCorrect(0)
, m_glContext(nullptr)
- , m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create(this))
+ , m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create())
, m_time(0)
, m_settings(nullptr)
- , m_framePreparationJob(Render::FramePreparationJobPtr::create())
+ , m_updateShaderDataTransformJob(Render::UpdateShaderDataTransformJobPtr::create())
, m_cleanupJob(Render::FrameCleanupJobPtr::create())
, m_worldTransformJob(Render::UpdateWorldTransformJobPtr::create())
, m_expandBoundingVolumeJob(Render::ExpandBoundingVolumeJobPtr::create())
, m_calculateBoundingVolumeJob(Render::CalculateBoundingVolumeJobPtr::create())
, m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
+ , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
+ , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
, m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
, m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
, m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering))
+ , m_ownedContext(false)
#ifdef QT3D_JOBS_RUN_STATS
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
@@ -178,10 +184,12 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_updateWorldBoundingVolumeJob->addDependency(m_worldTransformJob);
m_updateWorldBoundingVolumeJob->addDependency(m_calculateBoundingVolumeJob);
m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob);
- m_framePreparationJob->addDependency(m_worldTransformJob);
+ m_updateShaderDataTransformJob->addDependency(m_worldTransformJob);
// All world stuff depends on the RenderEntity's localBoundingVolume
- m_pickBoundingVolumeJob->addDependency(m_framePreparationJob);
+ m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
+
+ m_filterCompatibleTechniqueJob->setRenderer(this);
m_defaultRenderStateSet = new RenderStateSet;
m_defaultRenderStateSet->addState(RenderStateSet::createState<DepthTest>(GL_LESS));
@@ -224,12 +232,14 @@ void Renderer::setNodeManagers(NodeManagers *managers)
{
m_nodesManager = managers;
- m_framePreparationJob->setManagers(m_nodesManager);
+ m_updateShaderDataTransformJob->setManagers(m_nodesManager);
m_cleanupJob->setManagers(m_nodesManager);
m_calculateBoundingVolumeJob->setManagers(m_nodesManager);
m_pickBoundingVolumeJob->setManagers(m_nodesManager);
m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager());
m_sendRenderCaptureJob->setManagers(m_nodesManager);
+ m_updateMeshTriangleListJob->setManagers(m_nodesManager);
+ m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
}
NodeManagers *Renderer::nodeManagers() const
@@ -273,6 +283,7 @@ void Renderer::initialize()
qCDebug(Backend) << "OpenGL context created with actual format" << ctx->format();
else
qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed";
+ m_ownedContext = true;
}
// Note: we don't have a surface at this point
@@ -322,6 +333,12 @@ void Renderer::shutdown()
void Renderer::releaseGraphicsResources()
{
// Clean up the graphics context and any resources
+ const QVector<GLTexture*> activeTextures = m_nodesManager->glTextureManager()->activeResources();
+ for (GLTexture *tex : activeTextures)
+ tex->destroyGLTexture();
+
+ // TO DO: Do the same thing with buffers
+
m_graphicsContext.reset(nullptr);
qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown";
}
@@ -359,7 +376,6 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
qCDebug(Backend) << Q_FUNC_INFO << "DUMPING SCENE";
// Set the scene root on the jobs
- m_framePreparationJob->setRoot(m_renderSceneRoot);
m_worldTransformJob->setRoot(m_renderSceneRoot);
m_expandBoundingVolumeJob->setRoot(m_renderSceneRoot);
m_calculateBoundingVolumeJob->setRoot(m_renderSceneRoot);
@@ -443,15 +459,26 @@ void Renderer::doRender()
clearDirtyBits(changesToUnset);
{ // Scoped to destroy surfaceLock
- QSurface *surface = renderViews.first()->surface();
+ QSurface *surface = nullptr;
+ for (const Render::RenderView *rv: renderViews) {
+ surface = rv->surface();
+ if (surface)
+ break;
+ }
+
SurfaceLocker surfaceLock(surface);
const bool surfaceIsValid = (surface && surfaceLock.isSurfaceValid());
- if (surfaceIsValid && m_graphicsContext->beginDrawing(surface)) {
+ if (surfaceIsValid) {
+ // Reset state for each draw if we don't have complete control of the context
+ if (!m_ownedContext)
+ m_graphicsContext->setCurrentStateSet(nullptr);
+ if (m_graphicsContext->beginDrawing(surface)) {
// 1) Execute commands for buffer uploads, texture updates, shader loading first
updateGLResources();
// 2) Update VAO and copy data into commands to allow concurrent submission
prepareCommandsSubmission(renderViews);
preprocessingComplete = true;
+ }
}
}
// 2) Proceed to next frame and start preparing frame n + 1
@@ -725,7 +752,9 @@ void Renderer::lookForDirtyTextures()
const QVector<HTexture> activeTextureHandles = m_nodesManager->textureManager()->activeHandles();
for (HTexture handle: activeTextureHandles) {
Texture *texture = m_nodesManager->textureManager()->data(handle);
- if (texture->isDirty())
+ // Dirty meaning that something has changed on the texture
+ // either properties, parameters, generator or a texture image
+ if (texture->dirtyFlags() != Texture::NotDirty)
m_dirtyTextures.push_back(handle);
}
}
@@ -777,10 +806,89 @@ void Renderer::updateGLResources()
for (HTexture handle: activeTextureHandles) {
Texture *texture = m_nodesManager->textureManager()->data(handle);
// Upload/Update texture
- texture->getOrCreateGLTexture();
+ updateTexture(texture);
+ }
+}
+
+void Renderer::updateTexture(Texture *texture)
+{
+ // For implementing unique, non-shared, non-cached textures.
+ // for now, every texture is shared by default
+
+ bool isUnique = false;
+
+ // TO DO: Update the vector once per frame (or in a job)
+ const QVector<HAttachment> activeRenderTargetOutputs = m_nodesManager->attachmentManager()->activeHandles();
+ // A texture is unique if it's being reference by a render target output
+ for (const HAttachment attachmentHandle : activeRenderTargetOutputs) {
+ RenderTargetOutput *attachment = m_nodesManager->attachmentManager()->data(attachmentHandle);
+ if (attachment->textureUuid() == texture->peerId()) {
+ isUnique = true;
+ break;
+ }
+ }
+
+ // Try to find the associated GLTexture for the backend Texture
+ GLTextureManager *glTextureManager = m_nodesManager->glTextureManager();
+ GLTexture *glTexture = glTextureManager->lookupResource(texture->peerId());
+
+ // No GLTexture associated yet -> create it
+ if (glTexture == nullptr) {
+ if (isUnique)
+ glTextureManager->createUnique(texture);
+ else
+ glTextureManager->getOrCreateShared(texture);
+ texture->unsetDirty();
+ return;
+ }
+
+ // if this texture is a shared texture, we might need to look for a new TextureImpl
+ // and abandon the old one
+ if (glTextureManager->isShared(glTexture)) {
+ glTextureManager->abandon(glTexture, texture);
+ // Check if a shared texture should become unique
+ if (isUnique)
+ glTextureManager->createUnique(texture);
+ else
+ glTextureManager->getOrCreateShared(texture);
+ texture->unsetDirty();
+ return;
+ }
+
+ // this texture node is the only one referring to the GLTexture.
+ // we could thus directly modify the texture. Instead, for non-unique textures,
+ // we first see if there is already a matching texture present.
+ if (!isUnique) {
+ GLTexture *newSharedTex = glTextureManager->findMatchingShared(texture);
+ if (newSharedTex && newSharedTex != glTexture) {
+ glTextureManager->abandon(glTexture, texture);
+ glTextureManager->adoptShared(newSharedTex, texture);
+ texture->unsetDirty();
+ return;
+ }
}
+
+ // we hold a reference to a unique or exclusive access to a shared texture
+ // we can thus modify the texture directly.
+ const Texture::DirtyFlags dirtyFlags = texture->dirtyFlags();
+
+ if (dirtyFlags.testFlag(Texture::DirtyProperties) &&
+ !glTextureManager->setProperties(glTexture, texture->properties()))
+ qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setProperties failed, should be non-shared";
+
+ if (dirtyFlags.testFlag(Texture::DirtyParameters) &&
+ !glTextureManager->setParameters(glTexture, texture->parameters()))
+ qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setParameters failed, should be non-shared";
+
+ if (dirtyFlags.testFlag(Texture::DirtyGenerators) &&
+ !glTextureManager->setImages(glTexture, texture->textureImages()))
+ qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared";
+
+ // Unset the dirty flag on the texture
+ texture->unsetDirty();
}
+
// Happens in RenderThread context when all RenderViewJobs are done
// Returns the id of the last bound FBO
Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Render::RenderView *> &renderViews)
@@ -798,7 +906,12 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// We might not want to render on the default FBO
uint lastBoundFBOId = m_graphicsContext->boundFrameBufferObject();
QSurface *surface = nullptr;
- QSurface *previousSurface = renderViews.first()->surface();
+ QSurface *previousSurface = nullptr;
+ for (const Render::RenderView *rv: renderViews) {
+ previousSurface = rv->surface();
+ if (previousSurface)
+ break;
+ }
QSurface *lastUsedSurface = nullptr;
for (int i = 0; i < renderViewsCount; ++i) {
@@ -986,6 +1099,10 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
for (const QAspectJobPtr &bufferJob : bufferJobs)
m_calculateBoundingVolumeJob->addDependency(bufferJob);
+ // Set values on pickBoundingVolumeJob
+ m_pickBoundingVolumeJob->setFrameGraphRoot(frameGraphRoot());
+ m_pickBoundingVolumeJob->setRenderSettings(settings());
+ m_pickBoundingVolumeJob->setMouseEvents(pendingPickingEvents());
// Traverse the current framegraph. For each leaf node create a
// RenderView and set its configuration then create a job to
@@ -1003,13 +1120,15 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
}
// Add jobs
- renderBinJobs.push_back(m_framePreparationJob);
+ renderBinJobs.push_back(m_updateShaderDataTransformJob);
+ renderBinJobs.push_back(m_updateMeshTriangleListJob);
renderBinJobs.push_back(m_expandBoundingVolumeJob);
renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
renderBinJobs.push_back(m_calculateBoundingVolumeJob);
renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_cleanupJob);
renderBinJobs.push_back(m_sendRenderCaptureJob);
+ renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
@@ -1262,6 +1381,13 @@ void Renderer::cleanGraphicsResources()
const QVector<Qt3DCore::QNodeId> buffersToRelease = std::move(m_nodesManager->bufferManager()->buffersToRelease());
for (Qt3DCore::QNodeId bufferId : buffersToRelease)
m_graphicsContext->releaseBuffer(bufferId);
+
+ // Delete abandoned textures
+ const QVector<GLTexture*> abandonedTextures = m_nodesManager->glTextureManager()->takeAbandonedTextures();
+ for (GLTexture *tex : abandonedTextures) {
+ tex->destroyGLTexture();
+ delete tex;
+ }
}
QList<QMouseEvent> Renderer::pendingPickingEvents() const
@@ -1274,6 +1400,11 @@ const GraphicsApiFilterData *Renderer::contextInfo() const
return m_graphicsContext->contextInfo();
}
+GraphicsContext *Renderer::graphicsContext() const
+{
+ return m_graphicsContext.data();
+}
+
void Renderer::addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId)
{
if (!m_pendingRenderCaptureSendRequests.contains(nodeId))
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 9f78df772..87e8ec116 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -65,12 +65,14 @@
#include <Qt3DRender/private/expandboundingvolumejob_p.h>
#include <Qt3DRender/private/updateworldtransformjob_p.h>
#include <Qt3DRender/private/calcboundingvolumejob_p.h>
-#include <Qt3DRender/private/framepreparationjob_p.h>
+#include <Qt3DRender/private/updateshaderdatatransformjob_p.h>
#include <Qt3DRender/private/framecleanupjob_p.h>
#include <Qt3DRender/private/updateworldboundingvolumejob_p.h>
#include <Qt3DRender/private/platformsurfacefilter_p.h>
#include <Qt3DRender/private/sendrendercapturejob_p.h>
#include <Qt3DRender/private/genericlambdajob_p.h>
+#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
+#include <Qt3DRender/private/filtercompatibletechniquejob_p.h>
#include <QHash>
#include <QMatrix4x4>
@@ -183,10 +185,12 @@ public:
inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; }
inline ExpandBoundingVolumeJobPtr expandBoundingVolumeJob() const { return m_expandBoundingVolumeJob; }
- inline FramePreparationJobPtr framePreparationJob() const { return m_framePreparationJob; }
+ inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; }
inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; }
inline UpdateWorldTransformJobPtr updateWorldTransformJob() const { return m_worldTransformJob; }
inline UpdateWorldBoundingVolumeJobPtr updateWorldBoundingVolumeJob() const { return m_updateWorldBoundingVolumeJob; }
+ inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
+ inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const Q_DECL_OVERRIDE;
@@ -196,6 +200,8 @@ public:
virtual RenderSettings *settings() const Q_DECL_OVERRIDE;
void updateGLResources();
+ void updateTexture(Texture *texture);
+
void prepareCommandsSubmission(const QVector<RenderView *> &renderViews);
bool executeCommandsSubmission(const RenderView *rv);
void updateVAOWithAttributes(Geometry *geometry,
@@ -208,6 +214,7 @@ public:
void setOpenGLContext(QOpenGLContext *context);
const GraphicsApiFilterData *contextInfo() const;
+ GraphicsContext *graphicsContext() const;
inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; }
@@ -284,13 +291,15 @@ private:
RenderSettings *m_settings;
- FramePreparationJobPtr m_framePreparationJob;
+ UpdateShaderDataTransformJobPtr m_updateShaderDataTransformJob;
FrameCleanupJobPtr m_cleanupJob;
UpdateWorldTransformJobPtr m_worldTransformJob;
ExpandBoundingVolumeJobPtr m_expandBoundingVolumeJob;
CalculateBoundingVolumeJobPtr m_calculateBoundingVolumeJob;
UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob;
SendRenderCaptureJobPtr m_sendRenderCaptureJob;
+ UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
+ FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
QVector<Qt3DCore::QNodeId> m_pendingRenderCaptureSendRequests;
@@ -312,6 +321,8 @@ private:
QVector<HShader> m_dirtyShaders;
QVector<HTexture> m_dirtyTextures;
+ bool m_ownedContext;
+
#ifdef QT3D_JOBS_RUN_STATS
QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter;
friend class Qt3DRender::Debug::CommandExecuter;
diff --git a/src/render/backend/rendertarget_p.h b/src/render/backend/rendertarget_p.h
index df73cab9a..2248edbdb 100644
--- a/src/render/backend/rendertarget_p.h
+++ b/src/render/backend/rendertarget_p.h
@@ -65,7 +65,7 @@ namespace Render {
class RenderTargetManager;
-class RenderTarget : public BackendNode
+class Q_AUTOTEST_EXPORT RenderTarget : public BackendNode
{
public:
RenderTarget();
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 7e9b695ed..ef01d27aa 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -586,11 +586,10 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c
// ShaderData/Buffers would be handled as UBO/SSBO and would therefore
// not be in the default uniform block
if (value.valueType() == UniformValue::NodeId) {
- Texture *tex = nullptr;
const Qt3DCore::QNodeId texId = *value.constData<Qt3DCore::QNodeId>();
- if ((tex = m_manager->textureManager()->lookupResource(texId))
- != nullptr) {
- uniformPack.setTexture(nameId, tex->peerId());
+ const Texture *tex = m_manager->textureManager()->lookupResource(texId);
+ if (tex != nullptr) {
+ uniformPack.setTexture(nameId, texId);
UniformValue::Texture textureValue;
textureValue.nodeId = texId;
uniformPack.setUniform(nameId, UniformValue(textureValue));
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
new file mode 100644
index 000000000..34bd8e61b
--- /dev/null
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -0,0 +1,510 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "renderviewbuilder_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+const int RenderViewBuilder::m_optimalParallelJobCount = std::max(QThread::idealThreadCount(), 2);
+
+namespace {
+
+class SyncRenderViewCommandBuilders
+{
+public:
+ explicit SyncRenderViewCommandBuilders(const RenderViewInitializerJobPtr &renderViewJob,
+ const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs,
+ Renderer *renderer)
+ : m_renderViewJob(renderViewJob)
+ , m_renderViewBuilderJobs(renderViewBuilderJobs)
+ , m_renderer(renderer)
+ {}
+
+ void operator()()
+ {
+ // Append all the commands and sort them
+ RenderView *rv = m_renderViewJob->renderView();
+
+ int totalCommandCount = 0;
+ for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ totalCommandCount += renderViewCommandBuilder->commands().size();
+
+ QVector<RenderCommand *> commands;
+ commands.reserve(totalCommandCount);
+
+ // Reduction
+ for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ commands += std::move(renderViewCommandBuilder->commands());
+ rv->setCommands(commands);
+
+ // Sort the commands
+ rv->sort();
+
+ // Enqueue our fully populated RenderView with the RenderThread
+ m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
+ }
+
+private:
+ RenderViewInitializerJobPtr m_renderViewJob;
+ QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+ Renderer *m_renderer;
+};
+
+class SyncFrustumCulling
+{
+public:
+ explicit SyncFrustumCulling(const RenderViewInitializerJobPtr &renderViewJob,
+ const FrustumCullingJobPtr &frustumCulling)
+ : m_renderViewJob(renderViewJob)
+ , m_frustumCullingJob(frustumCulling)
+ {}
+
+ void operator()()
+ {
+ RenderView *rv = m_renderViewJob->renderView();
+
+ // Update matrices now that all transforms have been updated
+ rv->updateMatrices();
+
+ // Frustum culling
+ m_frustumCullingJob->setViewProjection(rv->viewProjectionMatrix());
+ }
+
+private:
+ RenderViewInitializerJobPtr m_renderViewJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+};
+
+class SyncRenderViewInitialization
+{
+public:
+ explicit SyncRenderViewInitialization(const RenderViewInitializerJobPtr &renderViewJob,
+ const FrustumCullingJobPtr &frustumCullingJob,
+ const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
+ const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
+ : m_renderViewJob(renderViewJob)
+ , m_frustumCullingJob(frustumCullingJob)
+ , m_filterEntityByLayerJob(filterEntityByLayerJob)
+ , m_materialGathererJobs(materialGathererJobs)
+ , m_renderViewBuilderJobs(renderViewBuilderJobs)
+ {}
+
+ void operator()()
+ {
+ RenderView *rv = m_renderViewJob->renderView();
+
+ // Layer filtering
+ m_filterEntityByLayerJob->setHasLayerFilter(rv->hasLayerFilter());
+ m_filterEntityByLayerJob->setLayers(rv->layerFilter());
+
+ // Material Parameter building
+ for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) {
+ materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
+ materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
+ }
+
+ // Command builders
+ for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ renderViewCommandBuilder->setRenderView(rv);
+
+ // Set whether frustum culling is enabled or not
+ m_frustumCullingJob->setActive(rv->frustumCulling());
+ }
+
+private:
+ RenderViewInitializerJobPtr m_renderViewJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+ FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
+ QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+};
+
+class SyncRenderCommandBuilding
+{
+public:
+ explicit SyncRenderCommandBuilding(const RenderViewInitializerJobPtr &renderViewJob,
+ const FrustumCullingJobPtr &frustumCullingJob,
+ const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ const LightGathererPtr &lightGathererJob,
+ const RenderableEntityFilterPtr &renderableEntityFilterJob,
+ const ComputableEntityFilterPtr &computableEntityFilterJob,
+ const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
+ const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
+ : m_renderViewJob(renderViewJob)
+ , m_frustumCullingJob(frustumCullingJob)
+ , m_filterEntityByLayerJob(filterEntityByLayerJob)
+ , m_lightGathererJob(lightGathererJob)
+ , m_renderableEntityFilterJob(renderableEntityFilterJob)
+ , m_computableEntityFilterJob(computableEntityFilterJob)
+ , m_materialGathererJobs(materialGathererJobs)
+ , m_renderViewBuilderJobs(renderViewBuilderJobs)
+ {}
+
+ void operator()()
+ {
+ // Set the result of previous job computations
+ // for final RenderCommand building
+ RenderView *rv = m_renderViewJob->renderView();
+
+ if (!rv->noDraw()) {
+ // Set the light sources
+ rv->setLightSources(std::move(m_lightGathererJob->lights()));
+
+ // Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector
+ QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
+
+ // We sort the vector so that the removal can then be performed linearly
+ if (!rv->isCompute()) {
+ QVector<Entity *> renderableEntities = std::move(m_renderableEntityFilterJob->filteredEntities());
+ std::sort(renderableEntities.begin(), renderableEntities.end());
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities);
+
+ if (rv->frustumCulling())
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
+
+ // Split among the number of command builders
+ const int packetSize = renderableEntities.size() / RenderViewBuilder::optimalJobCount();
+ for (auto i = 0, m = RenderViewBuilder::optimalJobCount(); i < m; ++i) {
+ const RenderViewBuilderJobPtr renderViewCommandBuilder = m_renderViewBuilderJobs.at(i);
+ if (i == m - 1)
+ renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize + renderableEntities.size() % m));
+ else
+ renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize));
+ }
+ } else {
+ QVector<Entity *> computableEntities = std::move(m_computableEntityFilterJob->filteredEntities());
+ std::sort(computableEntities.begin(), computableEntities.end());
+ RenderViewBuilder::removeEntitiesNotInSubset(computableEntities, filteredEntities);
+
+ // Split among the number of command builders
+ const int packetSize = computableEntities.size() / RenderViewBuilder::optimalJobCount();
+ for (auto i = 0, m = RenderViewBuilder::optimalJobCount(); i < m; ++i) {
+ const RenderViewBuilderJobPtr renderViewCommandBuilder = m_renderViewBuilderJobs.at(i);
+ if (i == m - 1)
+ renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize + computableEntities.size() % m));
+ else
+ renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize));
+ }
+ }
+
+ // Reduction
+ QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params;
+ for (const auto materialGatherer : qAsConst(m_materialGathererJobs))
+ params.unite(materialGatherer->materialToPassAndParameter());
+ // Set all required data on the RenderView for final processing
+ rv->setMaterialParameterTable(std::move(params));
+ }
+ }
+
+private:
+ RenderViewInitializerJobPtr m_renderViewJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+ FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ LightGathererPtr m_lightGathererJob;
+ RenderableEntityFilterPtr m_renderableEntityFilterJob;
+ ComputableEntityFilterPtr m_computableEntityFilterJob;
+ QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
+ QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+};
+
+class SetClearDrawBufferIndex
+{
+public:
+ explicit SetClearDrawBufferIndex(const RenderViewInitializerJobPtr &renderViewJob)
+ : m_renderViewJob(renderViewJob)
+ {}
+
+ void operator()()
+ {
+ RenderView *rv = m_renderViewJob->renderView();
+ QVector<ClearBufferInfo> &clearBuffersInfo = rv->specificClearColorBufferInfo();
+ const AttachmentPack &attachmentPack = rv->attachmentPack();
+ for (ClearBufferInfo &clearBufferInfo : clearBuffersInfo)
+ clearBufferInfo.drawBufferIndex = attachmentPack.getDrawBufferIndex(clearBufferInfo.attchmentPoint);
+
+ }
+
+private:
+ RenderViewInitializerJobPtr m_renderViewJob;
+};
+
+} // anonymous
+
+RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer)
+ : m_renderViewIndex(renderViewIndex)
+ , m_renderer(renderer)
+ , m_renderViewJob(RenderViewInitializerJobPtr::create())
+ , m_filterEntityByLayerJob(Render::FilterLayerEntityJobPtr::create())
+ , m_lightGathererJob(Render::LightGathererPtr::create())
+ , m_renderableEntityFilterJob(RenderableEntityFilterPtr::create())
+ , m_computableEntityFilterJob(ComputableEntityFilterPtr::create())
+ , m_frustumCullingJob(Render::FrustumCullingJobPtr::create())
+ , m_syncFrustumCullingJob(SynchronizerJobPtr::create(SyncFrustumCulling(m_renderViewJob, m_frustumCullingJob), JobTypes::SyncFrustumCulling))
+ , m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex))
+{
+ // Init what we can here
+ EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager();
+ m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers());
+ m_renderableEntityFilterJob->setManager(entityManager);
+ m_computableEntityFilterJob->setManager(entityManager);
+ m_frustumCullingJob->setRoot(m_renderer->sceneRoot());
+ m_lightGathererJob->setManager(entityManager);
+ m_renderViewJob->setRenderer(m_renderer);
+ m_renderViewJob->setFrameGraphLeafNode(leafNode);
+ m_renderViewJob->setSubmitOrderIndex(m_renderViewIndex);
+
+ // RenderCommand building is the most consuming task -> split it
+ // Estimate the number of jobs to create based on the number of entities
+ m_renderViewBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount);
+ for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) {
+ auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create();
+ renderViewCommandBuilder->setIndex(m_renderViewIndex);
+ renderViewCommandBuilder->setRenderer(m_renderer);
+ m_renderViewBuilderJobs.push_back(renderViewCommandBuilder);
+ }
+
+ // Since Material gathering is an heavy task, we split it
+ const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles();
+ const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount;
+ const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount;
+ m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount);
+ for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) {
+ auto materialGatherer = Render::MaterialParameterGathererJobPtr::create();
+ materialGatherer->setNodeManagers(m_renderer->nodeManagers());
+ materialGatherer->setRenderer(m_renderer);
+ if (i == RenderViewBuilder::m_optimalParallelJobCount - 1)
+ materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements));
+ else
+ materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob));
+ m_materialGathererJobs.push_back(materialGatherer);
+ }
+
+ m_syncRenderViewInitializationJob = SynchronizerJobPtr::create(SyncRenderViewInitialization(m_renderViewJob,
+ m_frustumCullingJob,
+ m_filterEntityByLayerJob,
+ m_materialGathererJobs,
+ m_renderViewBuilderJobs),
+ JobTypes::SyncRenderViewInitialization);
+
+ m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob,
+ m_frustumCullingJob,
+ m_filterEntityByLayerJob,
+ m_lightGathererJob,
+ m_renderableEntityFilterJob,
+ m_computableEntityFilterJob,
+ m_materialGathererJobs,
+ m_renderViewBuilderJobs),
+ JobTypes::SyncRenderViewCommandBuilding);
+
+ m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob,
+ m_renderViewBuilderJobs,
+ m_renderer),
+ JobTypes::SyncRenderViewCommandBuilder);
+}
+
+RenderViewInitializerJobPtr RenderViewBuilder::renderViewJob() const
+{
+ return m_renderViewJob;
+}
+
+FilterLayerEntityJobPtr RenderViewBuilder::filterEntityByLayerJob() const
+{
+ return m_filterEntityByLayerJob;
+}
+
+LightGathererPtr RenderViewBuilder::lightGathererJob() const
+{
+ return m_lightGathererJob;
+}
+
+RenderableEntityFilterPtr RenderViewBuilder::renderableEntityFilterJob() const
+{
+ return m_renderableEntityFilterJob;
+}
+
+ComputableEntityFilterPtr RenderViewBuilder::computableEntityFilterJob() const
+{
+ return m_computableEntityFilterJob;
+}
+
+FrustumCullingJobPtr RenderViewBuilder::frustumCullingJob() const
+{
+ return m_frustumCullingJob;
+}
+
+QVector<RenderViewBuilderJobPtr> RenderViewBuilder::renderViewBuilderJobs() const
+{
+ return m_renderViewBuilderJobs;
+}
+
+QVector<MaterialParameterGathererJobPtr> RenderViewBuilder::materialGathererJobs() const
+{
+ return m_materialGathererJobs;
+}
+
+SynchronizerJobPtr RenderViewBuilder::syncRenderViewInitializationJob() const
+{
+ return m_syncRenderViewInitializationJob;
+}
+
+SynchronizerJobPtr RenderViewBuilder::syncFrustumCullingJob() const
+{
+ return m_syncFrustumCullingJob;
+}
+
+SynchronizerJobPtr RenderViewBuilder::syncRenderCommandBuildingJob() const
+{
+ return m_syncRenderCommandBuildingJob;
+}
+
+SynchronizerJobPtr RenderViewBuilder::syncRenderViewCommandBuildersJob() const
+{
+ return m_syncRenderViewCommandBuildersJob;
+}
+
+SynchronizerJobPtr RenderViewBuilder::setClearDrawBufferIndexJob() const
+{
+ return m_setClearDrawBufferIndexJob;
+}
+
+QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
+{
+ QVector<Qt3DCore::QAspectJobPtr> jobs;
+
+ jobs.reserve(m_materialGathererJobs.size() + m_renderViewBuilderJobs.size() + 11);
+
+ // Set dependencies
+ m_syncFrustumCullingJob->addDependency(m_renderer->updateWorldTransformJob());
+ m_syncFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob());
+ m_syncFrustumCullingJob->addDependency(m_syncRenderViewInitializationJob);
+
+ m_frustumCullingJob->addDependency(m_renderer->expandBoundingVolumeJob());
+ m_frustumCullingJob->addDependency(m_syncFrustumCullingJob);
+
+ m_setClearDrawBufferIndexJob->addDependency(m_syncRenderViewInitializationJob);
+
+ m_syncRenderViewInitializationJob->addDependency(m_renderViewJob);
+
+ m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob);
+
+ m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
+ for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) {
+ materialGatherer->addDependency(m_syncRenderViewInitializationJob);
+ m_syncRenderCommandBuildingJob->addDependency(materialGatherer);
+ }
+ m_syncRenderCommandBuildingJob->addDependency(m_renderableEntityFilterJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_computableEntityFilterJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_filterEntityByLayerJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_lightGathererJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob);
+
+ for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) {
+ renderViewCommandBuilder->addDependency(m_syncRenderCommandBuildingJob);
+ m_syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder);
+ }
+
+ m_renderer->frameCleanupJob()->addDependency(m_syncRenderViewCommandBuildersJob);
+ m_renderer->frameCleanupJob()->addDependency(m_setClearDrawBufferIndexJob);
+
+ // Add jobs
+ jobs.push_back(m_renderViewJob); // Step 1
+ jobs.push_back(m_renderableEntityFilterJob); // Step 1
+ jobs.push_back(m_lightGathererJob); // Step 1
+
+ // Note: do it only if OpenGL 4.3+ available
+ jobs.push_back(m_computableEntityFilterJob); // Step 1
+
+ jobs.push_back(m_syncRenderViewInitializationJob); // Step 2
+
+ jobs.push_back(m_syncFrustumCullingJob); // Step 3
+ jobs.push_back(m_filterEntityByLayerJob); // Step 3
+ jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3
+
+ for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
+ jobs.push_back(materialGatherer);
+
+ jobs.push_back(m_frustumCullingJob); // Step 4
+ jobs.push_back(m_syncRenderCommandBuildingJob); // Step 4
+
+ for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5
+ jobs.push_back(renderViewCommandBuilder);
+
+ jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 6
+
+ return jobs;
+}
+
+Renderer *RenderViewBuilder::renderer() const
+{
+ return m_renderer;
+}
+
+int RenderViewBuilder::renderViewIndex() const
+{
+ return m_renderViewIndex;
+}
+
+int RenderViewBuilder::optimalJobCount()
+{
+ return RenderViewBuilder::m_optimalParallelJobCount;
+}
+
+void RenderViewBuilder::removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset)
+{
+ // Note: assumes entities was sorted already
+ std::sort(subset.begin(), subset.end());
+
+ for (auto i = entities.size() - 1, j = subset.size() - 1; i >= 0; --i) {
+ while (j >= 0 && subset.at(j) > entities.at(i))
+ --j;
+ if (j < 0 || entities.at(i) != subset.at(j))
+ entities.removeAt(i);
+ }
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/renderviewbuilder_p.h b/src/render/backend/renderviewbuilder_p.h
new file mode 100644
index 000000000..6f09a6282
--- /dev/null
+++ b/src/render/backend/renderviewbuilder_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_RENDERVIEWBUILDER_H
+#define QT3DRENDER_RENDER_RENDERVIEWBUILDER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <functional>
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DRender/private/filterentitybycomponentjob_p.h>
+#include <Qt3DRender/private/filterlayerentityjob_p.h>
+#include <Qt3DRender/private/genericlambdajob_p.h>
+#include <Qt3DRender/private/materialparametergathererjob_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/renderviewbuilderjob_p.h>
+#include <Qt3DRender/private/renderview_p.h>
+#include <Qt3DRender/private/frustumcullingjob_p.h>
+#include <Qt3DRender/private/lightgatherer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Renderer;
+
+using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>;
+using ComputableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>;
+using RenderableEntityFilterPtr = FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>;
+
+class Q_AUTOTEST_EXPORT RenderViewBuilder
+{
+public:
+ explicit RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer);
+
+ RenderViewInitializerJobPtr renderViewJob() const;
+ FilterLayerEntityJobPtr filterEntityByLayerJob() const;
+ LightGathererPtr lightGathererJob() const;
+ RenderableEntityFilterPtr renderableEntityFilterJob() const;
+ ComputableEntityFilterPtr computableEntityFilterJob() const;
+ FrustumCullingJobPtr frustumCullingJob() const;
+ QVector<RenderViewBuilderJobPtr> renderViewBuilderJobs() const;
+ QVector<MaterialParameterGathererJobPtr> materialGathererJobs() const;
+ SynchronizerJobPtr syncRenderViewInitializationJob() const;
+ SynchronizerJobPtr syncFrustumCullingJob() const;
+ SynchronizerJobPtr syncRenderCommandBuildingJob() const;
+ SynchronizerJobPtr syncRenderViewCommandBuildersJob() const;
+ SynchronizerJobPtr setClearDrawBufferIndexJob() const;
+
+ QVector<Qt3DCore::QAspectJobPtr> buildJobHierachy() const;
+
+ Renderer *renderer() const;
+ int renderViewIndex() const;
+
+ static int optimalJobCount();
+ static void removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset);
+
+private:
+ const int m_renderViewIndex;
+ Renderer *m_renderer;
+
+ RenderViewInitializerJobPtr m_renderViewJob;
+ FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ LightGathererPtr m_lightGathererJob;
+ RenderableEntityFilterPtr m_renderableEntityFilterJob;
+ ComputableEntityFilterPtr m_computableEntityFilterJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+ QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+ QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
+
+ SynchronizerJobPtr m_syncRenderViewInitializationJob;
+ SynchronizerJobPtr m_syncFrustumCullingJob;
+ SynchronizerJobPtr m_syncRenderCommandBuildingJob;
+ SynchronizerJobPtr m_syncRenderViewCommandBuildersJob;
+ SynchronizerJobPtr m_setClearDrawBufferIndexJob;
+
+ static const int m_optimalParallelJobCount;
+};
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RENDERVIEWBUILDER_H
diff --git a/src/render/backend/transform.cpp b/src/render/backend/transform.cpp
index ef6942f54..636c2d103 100644
--- a/src/render/backend/transform.cpp
+++ b/src/render/backend/transform.cpp
@@ -59,6 +59,15 @@ Transform::Transform()
{
}
+void Transform::cleanup()
+{
+ m_rotation = QQuaternion();
+ m_scale = QVector3D();
+ m_translation = QVector3D();
+ m_transformMatrix = QMatrix4x4();
+ QBackendNode::setEnabled(false);
+}
+
void Transform::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QTransformData>>(change);
@@ -74,6 +83,21 @@ QMatrix4x4 Transform::transformMatrix() const
return m_transformMatrix;
}
+QVector3D Transform::scale() const
+{
+ return m_scale;
+}
+
+QQuaternion Transform::rotation() const
+{
+ return m_rotation;
+}
+
+QVector3D Transform::translation() const
+{
+ return m_translation;
+}
+
void Transform::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
// TODO: Flag the matrix as dirty and update all matrices batched in a job
diff --git a/src/render/backend/transform_p.h b/src/render/backend/transform_p.h
index a36005d2d..4b58e3cae 100644
--- a/src/render/backend/transform_p.h
+++ b/src/render/backend/transform_p.h
@@ -65,12 +65,17 @@ namespace Render {
class Renderer;
class TransformManager;
-class Transform : public BackendNode
+class Q_AUTOTEST_EXPORT Transform : public BackendNode
{
public:
Transform();
+ void cleanup();
QMatrix4x4 transformMatrix() const;
+ QVector3D scale() const;
+ QQuaternion rotation() const;
+ QVector3D translation() const;
+
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
void updateMatrix();
diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h
index 5ce0f1574..cc394041b 100644
--- a/src/render/backend/triangleboundingvolume_p.h
+++ b/src/render/backend/triangleboundingvolume_p.h
@@ -108,6 +108,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::TriangleBoundingVolume*)
+Q_DECLARE_METATYPE(Qt3DRender::Render::TriangleBoundingVolume*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_TRIANGLEBOUNDINGVOLUME_P_H
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index 24b7b88ef..0369f3f5e 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -48,8 +48,57 @@ namespace {
const int qNodeIdTypeId = qMetaTypeId<Qt3DCore::QNodeId>();
+// glUniform*fv/glUniform*iv/glUniform*uiv -> only handles sizeof(float)/sizeof(int)
+int byteSizeForMetaType(int type)
+{
+ switch (type) {
+ case QMetaType::Bool:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::ULongLong:
+ case QMetaType::LongLong:
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ return sizeof(int);
+
+ case QMetaType::Float:
+ case QMetaType::Double: // Assumes conversion to float
+ return sizeof(float);
+
+ case QMetaType::QPoint:
+ case QMetaType::QSize:
+ return 2 * sizeof(int);
+
+ case QMetaType::QRect:
+ return 4 * sizeof(int);
+
+ case QMetaType::QPointF:
+ case QMetaType::QSizeF:
+ case QMetaType::QVector2D:
+ return 2 * sizeof(float);
+
+ case QMetaType::QVector3D:
+ return 3 * sizeof(float);
+
+ case QMetaType::QRectF:
+ case QMetaType::QVector4D:
+ case QMetaType::QColor:
+ return 4 * sizeof(float);
+
+ case QMetaType::QMatrix4x4:
+ return 16 * sizeof(float);
+ default:
+ Q_UNREACHABLE();
+ return -1;
+ }
}
+} // anonymous
+
UniformValue UniformValue::fromVariant(const QVariant &variant)
{
// Texture/Buffer case
@@ -153,6 +202,28 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
memcpy(v.data<float>(), mat44.constData(), 16 * sizeof(float));
break;
}
+ case QMetaType::QVariantList: {
+ const QVariantList variants = variant.toList();
+ if (variants.size() < 1)
+ break;
+
+ const int listEntryType = variants.first().userType();
+ const int stride = byteSizeForMetaType(listEntryType) / sizeof(float);
+ // Resize v.m_data
+ v.m_data.resize(stride * variants.size());
+
+ int idx = 0;
+ for (const QVariant &variant : variants) {
+ Q_ASSERT_X(variant.userType() == listEntryType,
+ Q_FUNC_INFO,
+ "Uniform array doesn't contain elements of the same type");
+ UniformValue vi = UniformValue::fromVariant(variant);
+ memcpy(v.data<float>() + idx, vi.data<float>(), stride * sizeof(float));
+ idx += stride;
+ }
+ break;
+ }
+
default:
Q_UNREACHABLE();
}
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index dc16365a0..56a50aea2 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -206,6 +206,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::UniformType)
+Q_DECLARE_METATYPE(Qt3DRender::Render::UniformType) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_UNIFORM_P_H
diff --git a/src/render/framegraph/framegraphvisitor.cpp b/src/render/framegraph/framegraphvisitor.cpp
index 4d955724d..d31e9cddd 100644
--- a/src/render/framegraph/framegraphvisitor.cpp
+++ b/src/render/framegraph/framegraphvisitor.cpp
@@ -43,15 +43,7 @@
#include "framegraphnode_p.h"
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/filterentitybycomponentjob_p.h>
-#include <Qt3DRender/private/filterlayerentityjob_p.h>
-#include <Qt3DRender/private/genericlambdajob_p.h>
-#include <Qt3DRender/private/materialparametergathererjob_p.h>
-#include <Qt3DRender/private/nodemanagers_p.h>
-#include <Qt3DRender/private/renderviewbuilderjob_p.h>
-#include <Qt3DRender/private/renderview_p.h>
-#include <Qt3DRender/private/frustumcullingjob_p.h>
-#include <Qt3DRender/private/lightgatherer_p.h>
+#include <Qt3DRender/private/renderviewbuilder_p.h>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
@@ -106,283 +98,8 @@ void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
// TODO: Pass in only framegraph config that has changed from previous
// index RenderViewJob.
if (fgChildIds.empty()) {
- // 1) Prepare parameter pack for all possible Pass Filter / Technique Filter
- // At most 1 of each per RenderView -> not very frequent -> doesn't need to be in a job
-
- // 1) Update all the ShaderData
-
- // 1) RenderView initialization from
- // 2) One job to filter out the Entities in a layers (no dependency)
- // 2) -> One job to filter out only the Entities with a QDispatchCompute
- // 2) -> One job to filter out only the Entities with a GeometryRenderer
- // 2) -> n job to create all ParameterInfoList for each Material
- // 2) -> One job to perform frustrum culling of layered filtered entities
-
- // -> 3) Merge Parameter pack 1 / 2 + Material
- // -> 4) n job to prepare the commands
- // -> One job to sort the RenderCommands
- // -> One job to set the active uniforms / build the ParameterPack
-
- // GenericLambdaJob will be used to sync data between jobs and their dependencies
- // Prefer linear iteration over tree traversal
-
- const int currentRenderViewIndex = m_renderviewIndex++;
- const int optimalParallelJobCount = std::max(QThread::idealThreadCount(), 2);
- auto renderViewJob = RenderViewInitializerJobPtr::create();
- auto filterEntityByLayer = Render::FilterLayerEntityJobPtr::create();
- auto lightGatherer = Render::LightGathererPtr::create();
- auto renderableEntityFilterer = Render::FilterEntityByComponentJobPtr<Render::GeometryRenderer, Render::Material>::create();
-
- // Note: do it only if OpenGL 4.3+ available
- auto computeEntityFilterer = Render::FilterEntityByComponentJobPtr<Render::ComputeCommand, Render::Material>::create();
-
- auto frustumCulling = Render::FrustumCullingJobPtr::create();
-
- // Copy for lambda capture
- Renderer *renderer = m_renderer;
-
- // Init what we can here
- EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager();
- filterEntityByLayer->setManager(m_renderer->nodeManagers());
- renderableEntityFilterer->setManager(entityManager);
- computeEntityFilterer->setManager(entityManager);
- frustumCulling->setRoot(m_renderer->sceneRoot());
- lightGatherer->setManager(entityManager);
- renderViewJob->setRenderer(m_renderer);
- renderViewJob->setFrameGraphLeafNode(node);
- renderViewJob->setSubmitOrderIndex(currentRenderViewIndex);
-
- // RenderCommand building is the most consuming task -> split it
- QVector<Render::RenderViewBuilderJobPtr> renderViewCommandBuilders;
- // Estimate the number of jobs to create based on the number of entities
- renderViewCommandBuilders.reserve(optimalParallelJobCount);
- for (auto i = 0; i < optimalParallelJobCount; ++i) {
- auto renderViewCommandBuilder = Render::RenderViewBuilderJobPtr::create();
- renderViewCommandBuilder->setIndex(currentRenderViewIndex);
- renderViewCommandBuilder->setRenderer(m_renderer);
- renderViewCommandBuilders.push_back(renderViewCommandBuilder);
- }
-
- // Since Material gathering is an heavy task, we split it
- QVector<Render::MaterialParameterGathererJobPtr> materialGatherers;
- { // Scoped to avoid copy in lambdas
- const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles();
- const int elementsPerJob = materialHandles.size() / optimalParallelJobCount;
- const int lastRemaingElements = materialHandles.size() % optimalParallelJobCount;
- materialGatherers.reserve(optimalParallelJobCount);
- for (auto i = 0; i < optimalParallelJobCount; ++i) {
- auto materialGatherer = Render::MaterialParameterGathererJobPtr::create();
- materialGatherer->setNodeManagers(m_renderer->nodeManagers());
- materialGatherer->setRenderer(m_renderer);
- if (i == optimalParallelJobCount - 1)
- materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements));
- else
- materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob));
- materialGatherers.push_back(materialGatherer);
- }
- }
-
- // Copy shared ptr -> this is called once the FrameGraphBranch was used to fill initial data in the RenderView
- auto syncRenderViewInitialization = [=] () {
- RenderView *rv = renderViewJob->renderView();
-
- // Layer filtering
- filterEntityByLayer->setHasLayerFilter(rv->hasLayerFilter());
-
- if (rv->hasLayerFilter())
- filterEntityByLayer->setLayers(rv->layerFilter());
-
- // Material Parameter building
- for (const auto materialGatherer : qAsConst(materialGatherers)) {
- materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
- materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
- }
-
- // Command builders
- for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders))
- renderViewCommandBuilder->setRenderView(rv);
-
- // Set whether frustum culling is enabled or not
- frustumCulling->setActive(rv->frustumCulling());
- };
-
- // Copy shared ptr -> this is called once the FrameGraphBranch was used to fill initial data in the RenderView
- auto syncFrustumCulling = [=] () {
- RenderView *rv = renderViewJob->renderView();
-
- // Update matrices now that all transforms have been updated
- rv->updateMatrices();
-
- // Frustum culling
- frustumCulling->setViewProjection(rv->viewProjectionMatrix());
- };
-
- // Copy shared ptr -> this is called after filtering / culling / parameter setting has been performed
- auto syncForRenderCommandBuilding = [=] () {
- // Set the result of previous job computations
- // for final RenderCommand building
- RenderView *rv = renderViewJob->renderView();
-
- if (!rv->noDraw()) {
- // Set the light sources
- rv->setLightSources(std::move(lightGatherer->lights()));
-
- // Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector
- QVector<Entity *> filteredEntities = filterEntityByLayer->filteredEntities();
-
- // We sort the vector so that the removal can then be performed linearly
- if (!rv->isCompute()) {
- QVector<Entity *> renderableEntities = std::move(renderableEntityFilterer->filteredEntities());
- std::sort(renderableEntities.begin(), renderableEntities.end());
- std::sort(filteredEntities.begin(), filteredEntities.end());
-
- for (auto i = renderableEntities.size() - 1, j = filteredEntities.size() - 1; i >= 0; --i) {
- while (j >= 0 && filteredEntities.at(j) > renderableEntities.at(i))
- --j;
- if (j < 0 || renderableEntities.at(i) != filteredEntities.at(j))
- renderableEntities.removeAt(i);
- }
-
- if (rv->frustumCulling()) {
- QVector<Entity *> visibleEntities = frustumCulling->visibleEntities();
- std::sort(visibleEntities.begin(), visibleEntities.end());
-
- for (auto i = renderableEntities.size() - 1, j = visibleEntities.size() - 1; i >= 0; --i) {
- while (j >= 0 && visibleEntities.at(j) > renderableEntities.at(i))
- --j;
- if (j < 0 || renderableEntities.at(i) != visibleEntities.at(j))
- renderableEntities.removeAt(i);
- }
- }
- // Split among the number of command builders
- const int packetSize = renderableEntities.size() / optimalParallelJobCount;
- for (auto i = 0; i < optimalParallelJobCount; ++i) {
- const RenderViewBuilderJobPtr renderViewCommandBuilder = renderViewCommandBuilders.at(i);
- if (i == optimalParallelJobCount - 1)
- renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize + renderableEntities.size() % optimalParallelJobCount));
- else
- renderViewCommandBuilder->setRenderables(renderableEntities.mid(i * packetSize, packetSize));
- }
-
- } else {
- QVector<Entity *> computableEntities = std::move(computeEntityFilterer->filteredEntities());
- std::sort(computableEntities.begin(), computableEntities.end());
-
- for (auto i = computableEntities.size() - 1, j = filteredEntities.size() - 1; i >= 0; --i) {
- while (j >= 0 && filteredEntities.at(j) > computableEntities.at(i))
- --j;
- if (j < 0 || computableEntities.at(i) != filteredEntities.at(j))
- computableEntities.removeAt(i);
- }
-
- // Split among the number of command builders
- const int packetSize = computableEntities.size() / optimalParallelJobCount;
- for (auto i = 0; i < optimalParallelJobCount; ++i) {
- const RenderViewBuilderJobPtr renderViewCommandBuilder = renderViewCommandBuilders.at(i);
- if (i == optimalParallelJobCount - 1)
- renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize + computableEntities.size() % optimalParallelJobCount));
- else
- renderViewCommandBuilder->setRenderables(computableEntities.mid(i * packetSize, packetSize));
- }
- }
-
- // Reduction
- QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params;
- for (const auto materialGatherer : qAsConst(materialGatherers))
- params.unite(materialGatherer->materialToPassAndParameter());
- // Set all required data on the RenderView for final processing
- rv->setMaterialParameterTable(std::move(params));
- }
- };
-
- // Called after each RenderViewBuilder has built its RenderCommands
- auto syncRenderViewCommandBuilders = [=] () {
- // Append all the commands and sort them
- RenderView *rv = renderViewJob->renderView();
-
- int totalCommandCount = 0;
- for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders))
- totalCommandCount += renderViewCommandBuilder->commands().size();
-
- QVector<RenderCommand *> commands;
- commands.reserve(totalCommandCount);
-
- // Reduction
- for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders))
- commands += std::move(renderViewCommandBuilder->commands());
- rv->setCommands(commands);
-
- // Sort the commands
- rv->sort();
-
- // Enqueue our fully populated RenderView with the RenderThread
- renderer->enqueueRenderView(rv, currentRenderViewIndex);
- };
-
- auto setClearBufferDrawIndex = [=] () {
- RenderView *rv = renderViewJob->renderView();
- QVector<ClearBufferInfo> &clearBuffersInfo = rv->specificClearColorBufferInfo();
- const AttachmentPack &attachmentPack = rv->attachmentPack();
- for (ClearBufferInfo &clearBufferInfo : clearBuffersInfo)
- clearBufferInfo.drawBufferIndex = attachmentPack.getDrawBufferIndex(clearBufferInfo.attchmentPoint);
- };
-
- auto syncRenderViewCommandBuildingJob = GenericLambdaJobPtr<decltype(syncForRenderCommandBuilding)>::create(syncForRenderCommandBuilding, JobTypes::SyncRenderViewCommandBuilding);
- auto syncRenderViewInitializationJob = GenericLambdaJobPtr<decltype(syncRenderViewInitialization)>::create(syncRenderViewInitialization, JobTypes::SyncRenderViewInitialization);
- auto syncRenderViewCommandBuildersJob = GenericLambdaJobPtr<decltype(syncRenderViewCommandBuilders)>::create(syncRenderViewCommandBuilders, JobTypes::SyncRenderViewCommandBuilder);
- auto syncFrustumCullingJob = GenericLambdaJobPtr<decltype(syncFrustumCulling)>::create(syncFrustumCulling, JobTypes::SyncFrustumCulling);
- auto setClearBufferDrawIndexJob = GenericLambdaJobPtr<decltype(setClearBufferDrawIndex)>::create(setClearBufferDrawIndex, JobTypes::ClearBufferDrawIndex);
-
- // Set dependencies
- syncFrustumCullingJob->addDependency(renderer->updateWorldTransformJob());
- syncFrustumCullingJob->addDependency(syncRenderViewInitializationJob);
-
- frustumCulling->addDependency(renderer->expandBoundingVolumeJob());
- frustumCulling->addDependency(syncFrustumCullingJob);
-
- setClearBufferDrawIndexJob->addDependency(syncRenderViewInitializationJob);
-
- syncRenderViewInitializationJob->addDependency(renderViewJob);
-
- filterEntityByLayer->addDependency(syncRenderViewInitializationJob);
-
- syncRenderViewCommandBuildingJob->addDependency(syncRenderViewInitializationJob);
- for (const auto materialGatherer : qAsConst(materialGatherers)) {
- materialGatherer->addDependency(syncRenderViewInitializationJob);
- syncRenderViewCommandBuildingJob->addDependency(materialGatherer);
- }
- syncRenderViewCommandBuildingJob->addDependency(renderableEntityFilterer);
- syncRenderViewCommandBuildingJob->addDependency(computeEntityFilterer);
- syncRenderViewCommandBuildingJob->addDependency(filterEntityByLayer);
- syncRenderViewCommandBuildingJob->addDependency(lightGatherer);
- syncRenderViewCommandBuildingJob->addDependency(frustumCulling);
-
- for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders)) {
- renderViewCommandBuilder->addDependency(syncRenderViewCommandBuildingJob);
- syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder);
- }
- renderer->frameCleanupJob()->addDependency(syncRenderViewCommandBuildersJob);
- renderer->frameCleanupJob()->addDependency(setClearBufferDrawIndexJob);
-
- // Add jobs
- m_jobs->push_back(renderViewJob);
- m_jobs->push_back(filterEntityByLayer);
- m_jobs->push_back(renderableEntityFilterer);
- m_jobs->push_back(computeEntityFilterer);
- m_jobs->push_back(syncRenderViewInitializationJob);
- m_jobs->push_back(syncRenderViewCommandBuildingJob);
- m_jobs->push_back(frustumCulling);
- m_jobs->push_back(lightGatherer);
- m_jobs->push_back(syncRenderViewCommandBuildersJob);
- m_jobs->push_back(syncFrustumCullingJob);
- m_jobs->push_back(setClearBufferDrawIndexJob);
-
- for (const auto materialGatherer : qAsConst(materialGatherers))
- m_jobs->push_back(materialGatherer);
-
- for (const auto renderViewCommandBuilder : qAsConst(renderViewCommandBuilders))
- m_jobs->push_back(renderViewCommandBuilder);
-
+ RenderViewBuilder builder(node, m_renderviewIndex++, m_renderer);
+ m_jobs->append(builder.buildJobHierachy());
}
}
diff --git a/src/render/framegraph/qclearbuffers.h b/src/render/framegraph/qclearbuffers.h
index d45af9ce0..91828c222 100644
--- a/src/render/framegraph/qclearbuffers.h
+++ b/src/render/framegraph/qclearbuffers.h
@@ -74,7 +74,7 @@ public:
ColorDepthStencilBuffer = ColorBuffer | DepthStencilBuffer,
AllBuffers = 0xFFFFFFFF
};
- Q_ENUM(BufferType)
+ Q_ENUM(BufferType) // LCOV_EXCL_LINE
Q_DECLARE_FLAGS(BufferTypeFlags, BufferType)
BufferType buffers() const;
diff --git a/src/render/framegraph/qdispatchcompute.cpp b/src/render/framegraph/qdispatchcompute.cpp
index abb4d7bdb..ca656c114 100644
--- a/src/render/framegraph/qdispatchcompute.cpp
+++ b/src/render/framegraph/qdispatchcompute.cpp
@@ -44,12 +44,18 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- \class Qt3DRender::QDispatchCompute
- \inmodule Qt3DRender
- \since 5.7
- \ingroup framegraph
+ \class Qt3DRender::QDispatchCompute
+ \inmodule Qt3DRender
+ \since 5.7
+ \ingroup framegraph
+ \brief FrameGraph node to issue work for the compute shader on GPU
- \brief Allows a glDispatchCompute call to be issued to do work in a compute shader on the GPU.
+ A Qt3DRender::QDispatchCompute allows work to be issued for the compute shader to
+ run on the GPU. The workGroupX, workGroupY and workGroupZ properties specify the work group
+ sizes for the compute shader invocation. QComputeCommand components need to be added
+ to entities to instruct Qt3D to select the materials and geometry from the entities
+ for the compute invocation. The work group sizes for the shader invocation will be
+ the maximum of the work group sizes specified in QDispatchCompute and QComputeCommand.
*/
@@ -59,11 +65,33 @@ namespace Qt3DRender {
\instantiates Qt3DRender::QDispatchCompute
\inherits FrameGraphNode
\since 5.7
- \qmlabstract Allows a glDispatchCompute call to be issued to do work in a compute shader on the GPU.
+ \brief FrameGraph node to issue work for the compute shader on GPU
+
+ A DispatchCompute allows work to be issued for the compute shader to run on the GPU.
+ The workGroupX, workGroupY and workGroupZ properties specify the work group sizes for
+ the compute shader invocation. ComputeCommand components need to be added
+ to entities to instruct Qt3D to select the materials and geometry from the entities
+ for the compute invocation. The work group sizes for the shader invocation will be
+ the maximum of the work group sizes specified in DispatchCompute and ComputeCommand.
*/
/*!
- The constructor creates an instance with the specified \a parent.
+ \qmlproperty int DispatchCompute::workGroupX
+ Specifies X workgroup size.
+ */
+
+/*!
+ \qmlproperty int DispatchCompute::workGroupY
+ Specifies Y workgroup size.
+ */
+
+/*!
+ \qmlproperty int DispatchCompute::workGroupZ
+ Specifies Z workgroup size.
+ */
+
+/*!
+ The constructor creates an instance with the specified \a parent.
*/
QDispatchCompute::QDispatchCompute(Qt3DCore::QNode *parent)
: QFrameGraphNode(*new QDispatchComputePrivate(), parent)
diff --git a/src/render/framegraph/qframegraphnode.cpp b/src/render/framegraph/qframegraphnode.cpp
index c60c859ac..36a9f737a 100644
--- a/src/render/framegraph/qframegraphnode.cpp
+++ b/src/render/framegraph/qframegraphnode.cpp
@@ -56,8 +56,10 @@ QFrameGraphNodePrivate::QFrameGraphNodePrivate()
\brief Base class of all FrameGraph configuration nodes.
- This is an abstract class so it cannot be instanced directly
- but rather through one of its subclasses.
+ This class is rarely instanced directly since it doesn't provide
+ any frame graph specific behavior, although it can be convenient
+ to use for grouping other nodes together in dynamic frame graphs.
+ The actual behavior comes from the subclasses.
The subclasses are:
\table
@@ -112,8 +114,10 @@ QFrameGraphNodePrivate::QFrameGraphNodePrivate()
\since 5.5
\brief Base class of all FrameGraph configuration nodes.
- This is an abstract class so it cannot be instanced directly
- but rather through one of its subclasses.
+ This class is rarely instanced directly since it doesn't provide
+ any frame graph specific behavior, although it can be convenient
+ to use for grouping other nodes together in dynamic frame graphs.
+ The actual behavior comes from the subclasses.
The subclasses are:
\table
diff --git a/src/render/framegraph/qfrustumculling.cpp b/src/render/framegraph/qfrustumculling.cpp
index 5ba96926e..1d95892b3 100644
--- a/src/render/framegraph/qfrustumculling.cpp
+++ b/src/render/framegraph/qfrustumculling.cpp
@@ -43,13 +43,20 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- \class Qt3DRender::QFrustumCulling
- \inmodule Qt3DRender
- \since 5.7
- \ingroup framegraph
+ \class Qt3DRender::QFrustumCulling
+ \inmodule Qt3DRender
+ \since 5.7
+ \ingroup framegraph
+ \brief Enable frustum culling for the FrameGraph
+
+ A QFrustumCulling class enables frustum culling of the drawable entities based on
+ the camera view and QGeometry bounds of the entities. If QFrustumCulling is present in
+ the FrameGraph, only the entities whose QGeometry bounds intersect with the camera
+ frustum, i.e. the view of the camera, are drawn. If QFrustumCulling is not present,
+ all drawable entities will be drawn. The camera is selected by a QCameraSelector
+ frame graph node in the current hierarchy. Frustum culling can save a lot of GPU
+ processing time when the rendered scene is complex.
- \brief If present, only tries to draw entities that are in the view of the camera.
- The camera is selected by a QCameraSelector frame graph node in the current hierarchy.
\sa QCameraSelector
*/
@@ -59,13 +66,21 @@ namespace Qt3DRender {
\instantiates Qt3DRender::QFrustumCulling
\inherits FrameGraphNode
\since 5.7
- \qmlabstract If present, only tries to draw entities that are in the view of the camera.
- The camera is selected by a CameraSelector frame graph node in the current hierarchy
+ \brief Enable frustum culling for the FrameGraph
+
+ A FrustumCulling type enables frustum culling of the drawable entities based on
+ the camera view and Geometry bounds of the entities. If FrustumCulling is present in
+ the FrameGraph, only the entities whose Geometry bounds intersect with the camera
+ frustum, i.e. the view of the camera, are drawn. If FrustumCulling is not present,
+ all drawable entities will be drawn. The camera is selected by a CameraSelector
+ frame graph node in the current hierarchy. Frustum culling can save a lot of GPU
+ processing time when the rendered scene is complex.
+
\sa CameraSelector
*/
/*!
- The constructor creates an instance with the specified \a parent.
+ The constructor creates an instance with the specified \a parent.
*/
QFrustumCulling::QFrustumCulling(Qt3DCore::QNode *parent)
: QFrameGraphNode(parent)
diff --git a/src/render/framegraph/qnodraw.cpp b/src/render/framegraph/qnodraw.cpp
index 21634d1cb..46756557e 100644
--- a/src/render/framegraph/qnodraw.cpp
+++ b/src/render/framegraph/qnodraw.cpp
@@ -44,19 +44,42 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QNoDraw
- * \inmodule Qt3DRender
- *
- * \brief When a QNoDraw node is present in a FrameGraph branch, this
- * prevents the renderer from rendering any primitive.
- *
- * QNoDraw should be used when the FrameGraph needs to set up some render
- * states or clear some buffers without requiring any mesh to be drawn. It has
- * the same effect as having a Qt3DRender::QRenderPassFilter that matches none of
- * available Qt3DRender::QRenderPass instances of the scene without the overhead cost
- * of actually performing the filtering.
- *
- * \since 5.5
+ \class Qt3DRender::QNoDraw
+ \inmodule Qt3DRender
+
+ \brief When a Qt3DRender::QNoDraw node is present in a FrameGraph branch, this
+ prevents the renderer from rendering any primitive.
+
+ Qt3DRender::QNoDraw should be used when the FrameGraph needs to set up some render
+ states or clear some buffers without requiring any mesh to be drawn. It has
+ the same effect as having a Qt3DRender::QRenderPassFilter that matches none of
+ available Qt3DRender::QRenderPass instances of the scene without the overhead cost
+ of actually performing the filtering.
+
+ When disabled, a Qt3DRender::QNoDraw node won't prevent the scene from
+ being rendered. Toggling the enabled property is therefore a way to make a
+ Qt3DRender::QNoDraw active or inactive.
+
+ Qt3DRender::QNoDraw is usually used as a child of a
+ Qt3DRendeR::QClearBuffers node to prevent from drawing the scene when there
+ are multiple render passes.
+
+ \code
+ Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport();
+ Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(viewport);
+
+ Qt3DRender::QClearBuffers *clearBuffers = new Qt3DRender::QClearBuffers(cameraSelector);
+ clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer);
+
+ Qt3DRender::QNoDraw *noDraw = new Qt3DRender::QNoDraw(clearBuffers);
+
+ Qt3DRender::QRenderPassFilter *mainPass = new Qt3DRender::QRenderPassFilter(cameraSelector);
+ ....
+ Qt3DRender::QRenderPassFilter *previewPass = new Qt3DRender::QRenderPassFilter(cameraSelector);
+ ....
+ \endcode
+
+ \since 5.5
*/
/*!
@@ -66,7 +89,39 @@ namespace Qt3DRender {
\inqmlmodule Qt3D.Render
\since 5.5
\brief When a NoDraw node is present in a FrameGraph branch, this
- * prevents the renderer from rendering any primitive.
+ prevents the renderer from rendering any primitive.
+
+ NoDraw should be used when the FrameGraph needs to set up some render
+ states or clear some buffers without requiring any mesh to be drawn. It has
+ the same effect as having a Qt3DRender::QRenderPassFilter that matches none
+ of available Qt3DRender::QRenderPass instances of the scene without the
+ overhead cost of actually performing the filtering.
+
+ When disabled, a NoDraw node won't prevent the scene from being rendered.
+ Toggling the enabled property is therefore a way to make a NoDraw active or
+ inactive.
+
+ NoDraw is usually used as a child of a ClearBuffers node to prevent from
+ drawing the scene when there are multiple render passes.
+
+ \code
+
+ Viewport {
+ CameraSelector {
+ ClearBuffers {
+ buffers: ClearBuffers.ColorDepthBuffer
+ NoDraw { } // Prevents from drawing anything
+ }
+ RenderPassFilter {
+ ...
+ }
+ RenderPassFilter {
+ ...
+ }
+ }
+ }
+
+ \endcode
*/
/*!
diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp
index c4a42ff8a..62164b3ce 100644
--- a/src/render/framegraph/qrendercapture.cpp
+++ b/src/render/framegraph/qrendercapture.cpp
@@ -45,6 +45,7 @@ namespace Qt3DRender {
/*!
* \class Qt3DRender::QRenderCapture
+ * \inheaderfile Qt3DRender/QRenderCapture
* \inmodule Qt3DRender
*
* \brief Frame graph node for render capture
@@ -68,6 +69,7 @@ namespace Qt3DRender {
/*!
* \class Qt3DRender::QRenderCaptureReply
+ * \inheaderfile Qt3DRender/QRenderCaptureReply
* \inmodule Qt3DRender
*
* \brief Receives the result of render capture request.
diff --git a/src/render/framegraph/qrendercapture_p.h b/src/render/framegraph/qrendercapture_p.h
index 09d983ede..0d7c2d3af 100644
--- a/src/render/framegraph/qrendercapture_p.h
+++ b/src/render/framegraph/qrendercapture_p.h
@@ -99,6 +99,6 @@ typedef QSharedPointer<RenderCaptureData> RenderCaptureDataPtr;
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::RenderCaptureDataPtr)
+Q_DECLARE_METATYPE(Qt3DRender::RenderCaptureDataPtr) // LCOV_EXCL_LINE
#endif // QRENDERCAPTURE_P_H
diff --git a/src/render/framegraph/qrenderstateset.cpp b/src/render/framegraph/qrenderstateset.cpp
index 845fb5d91..35ac7fd04 100644
--- a/src/render/framegraph/qrenderstateset.cpp
+++ b/src/render/framegraph/qrenderstateset.cpp
@@ -58,6 +58,7 @@ QRenderStateSetPrivate::QRenderStateSetPrivate()
/*!
* \class Qt3DRender::QRenderStateSet
+ * \inheaderfile Qt3DRender/QRenderStateSet
* \inmodule Qt3DRender
*
* \brief The QRenderStateSet \l {QFrameGraphNode}{FrameGraph} node offers a way of
diff --git a/src/render/framegraph/qrendersurfaceselector.cpp b/src/render/framegraph/qrendersurfaceselector.cpp
index 905669ff9..2de878933 100644
--- a/src/render/framegraph/qrendersurfaceselector.cpp
+++ b/src/render/framegraph/qrendersurfaceselector.cpp
@@ -216,7 +216,6 @@ void QRenderSurfaceSelector::setSurface(QObject *surfaceObject)
QWindow *window = qobject_cast<QWindow *>(surfaceObject);
if (window) {
surface = static_cast<QSurface *>(window);
- setSurfacePixelRatio(window->devicePixelRatio());
} else {
QOffscreenSurface *offscreen = qobject_cast<QOffscreenSurface *>(surfaceObject);
if (offscreen)
@@ -272,6 +271,7 @@ void QRenderSurfaceSelector::setSurface(QObject *surfaceObject)
if (screen && surfacePixelRatio() != screen->devicePixelRatio())
setSurfacePixelRatio(screen->devicePixelRatio());
});
+ setSurfacePixelRatio(window->devicePixelRatio());
}
break;
@@ -301,6 +301,8 @@ QSize QRenderSurfaceSelector::externalRenderTargetSize() const
void QRenderSurfaceSelector::setSurfacePixelRatio(float ratio)
{
Q_D(QRenderSurfaceSelector);
+ if (d->m_surfacePixelRatio == ratio)
+ return;
d->m_surfacePixelRatio = ratio;
emit surfacePixelRatioChanged(ratio);
}
@@ -317,8 +319,10 @@ float QRenderSurfaceSelector::surfacePixelRatio() const
void QRenderSurfaceSelector::setExternalRenderTargetSize(const QSize &size)
{
Q_D(QRenderSurfaceSelector);
- d->setExternalRenderTargetSize(size);
- emit externalRenderTargetSizeChanged(size);
+ if (size != d->m_externalRenderTargetSize) {
+ d->setExternalRenderTargetSize(size);
+ emit externalRenderTargetSizeChanged(size);
+ }
}
Qt3DCore::QNodeCreatedChangeBasePtr QRenderSurfaceSelector::createNodeCreationChange() const
diff --git a/src/render/framegraph/qrendertargetselector.cpp b/src/render/framegraph/qrendertargetselector.cpp
index a413bbf56..f129d6e1e 100644
--- a/src/render/framegraph/qrendertargetselector.cpp
+++ b/src/render/framegraph/qrendertargetselector.cpp
@@ -49,23 +49,38 @@ using namespace Qt3DCore;
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QRenderTargetSelector
- * \inmodule Qt3DRender
- * \brief Provides a way of specifying a render target
- * \since 5.7
- *
- * \inherits Qt3DRender::QFrameGraphNode
- *
+ \class Qt3DRender::QRenderTargetSelector
+ \inmodule Qt3DRender
+ \since 5.7
+ \brief Provides a way of specifying a render target
+
+ A Qt3DRender::QRenderTargetSelector is used to select active Qt3DRender::QRenderTarget
+ for the FrameGraph. When QRenderTargetSelector is present in the FrameGraph,
+ the rendering is directed into QTexture objects or draw buffers instead of the surface
+ specified in the Qt3DRender::QRenderSurfaceSelector. A render buffer is automatically
+ generated for an attachment point if drawBuffers contain attachment point that any
+ output in the QRenderTarget do not specify. If the drawBuffers is empty,
+ the renderer will default to using all the outputs in QRenderTarget.
*/
/*!
- * \qmltype RenderTargetSelector
- * \inqmlmodule Qt3D.Render
- * \since 5.7
- * \ingroup
- * \instantiates Qt3DRender::QRenderTargetSelector
- * \brief RenderTargetSelector
- *
+ \qmltype RenderTargetSelector
+ \inqmlmodule Qt3D.Render
+ \since 5.7
+ \instantiates Qt3DRender::QRenderTargetSelector
+ \inherits FrameGraphNode
+ \brief Provides a way of specifying a render target
+
+ A RenderTargetSelector is used to select active RenderTarget
+ for the FrameGraph. When RenderTargetSelector is present in the FrameGraph,
+ the rendering is directed into Texture objects or draw buffers instead of the surface
+ specified in the RenderSurfaceSelector.
+ */
+/*!
+ \qmlproperty list<variant> RenderTargetSelector::drawBuffers
+ Holds the list of draw buffers enabled for the RenderTarget.
+
+ \sa Qt3DRender::QRenderTargetOutput::AttachmentPoint
*/
QRenderTargetSelectorPrivate::QRenderTargetSelectorPrivate()
@@ -75,7 +90,7 @@ QRenderTargetSelectorPrivate::QRenderTargetSelectorPrivate()
}
/*!
- * Constructs QRenderTargetSelector with given \a parent.
+ Constructs QRenderTargetSelector with given \a parent.
*/
QRenderTargetSelector::QRenderTargetSelector(QNode *parent)
: QFrameGraphNode(*new QRenderTargetSelectorPrivate, parent)
@@ -88,13 +103,13 @@ QRenderTargetSelector::~QRenderTargetSelector()
}
/*!
- * \property QRenderTargetSelector::target
- * Specifies the target to be rendered
+ \property QRenderTargetSelector::target
+ Holds the current render target
*/
-/*! \qmlproperty QWindow Qt3D.Render::RenderTargetSelector::target
- *
- * the target to be rendered
+/*! \qmlproperty RenderTarget Qt3D.Render::RenderTargetSelector::target
+
+ Holds the current render target
*/
void QRenderTargetSelector::setTarget(QRenderTarget *target)
{
@@ -124,15 +139,13 @@ QRenderTarget *QRenderTargetSelector::target() const
}
/*!
- * \internal
- * Sets the draw buffers \a buffers to be used. The draw buffers should be
- * matching the Qt3DRender::QRenderTargetOutput::RenderAttachmentType
- * defined in the attachments of the Qt3DRender::QRenderTarget associated to the
- * Qt3DRender::QRenderTargetSelector instance.
- *
- * \note At render time, if no draw buffer has been specified, the renderer will
- * default to using all the attachments' draw buffers.
- *
+ Sets the draw \a buffers to be used. The draw buffers should be
+ matching the Qt3DRender::QRenderTargetOutput::AttachmentPoint
+ defined in the attachments of the Qt3DRender::QRenderTarget associated to the
+ Qt3DRender::QRenderTargetSelector instance.
+
+ \note At render time, if no draw buffer has been specified, the renderer will
+ default to using all the attachments' draw buffers.
*/
void QRenderTargetSelector::setOutputs(const QVector<QRenderTargetOutput::AttachmentPoint> &buffers)
{
@@ -150,7 +163,7 @@ void QRenderTargetSelector::setOutputs(const QVector<QRenderTargetOutput::Attach
}
/*!
- * Returns the list of draw buffers for the current Qt3DRender::QRenderTargetSelector instance.
+ \return the list of draw buffers for the current Qt3DRender::QRenderTargetSelector instance.
*/
QVector<QRenderTargetOutput::AttachmentPoint> QRenderTargetSelector::outputs() const
{
diff --git a/src/render/framegraph/qrendertargetselector.h b/src/render/framegraph/qrendertargetselector.h
index a92fe1335..68fbe2666 100644
--- a/src/render/framegraph/qrendertargetselector.h
+++ b/src/render/framegraph/qrendertargetselector.h
@@ -83,6 +83,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QVector<Qt3DRender::QRenderTargetOutput::AttachmentPoint>)
+Q_DECLARE_METATYPE(QVector<Qt3DRender::QRenderTargetOutput::AttachmentPoint>) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QRENDERTARGETSELECTOR_H
diff --git a/src/render/framegraph/qsortcriterion.h b/src/render/framegraph/qsortcriterion.h
index bf2821550..230f111f9 100644
--- a/src/render/framegraph/qsortcriterion.h
+++ b/src/render/framegraph/qsortcriterion.h
@@ -61,7 +61,7 @@ public:
BackToFront = (1 << 1),
Material = (1 << 2)
};
- Q_ENUM(SortType)
+ Q_ENUM(SortType) // LCOV_EXCL_LINE
SortType sort() const;
diff --git a/src/render/framegraph/qsortpolicy.h b/src/render/framegraph/qsortpolicy.h
index 010fa461b..2d96bdbd6 100644
--- a/src/render/framegraph/qsortpolicy.h
+++ b/src/render/framegraph/qsortpolicy.h
@@ -61,7 +61,7 @@ public:
BackToFront = (1 << 1),
Material = (1 << 2)
};
- Q_ENUM(SortType)
+ Q_ENUM(SortType) // LCOV_EXCL_LINE
QVector<SortType> sortTypes() const;
QVector<int> sortTypesInt() const;
diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp
index 250666939..f123fd74c 100644
--- a/src/render/framegraph/rendercapture.cpp
+++ b/src/render/framegraph/rendercapture.cpp
@@ -50,6 +50,12 @@ RenderCapture::RenderCapture()
}
+void RenderCapture::requestCapture(int captureId)
+{
+ QMutexLocker lock(&m_mutex);
+ m_requestedCaptures.push_back(captureId);
+}
+
bool RenderCapture::wasCaptureRequested() const
{
return m_requestedCaptures.size() > 0 && isEnabled();
@@ -65,8 +71,7 @@ void RenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (e->type() == Qt3DCore::PropertyUpdated) {
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureRequest")) {
- QMutexLocker lock(&m_mutex);
- m_requestedCaptures.push_back(propertyChange->value().toInt());
+ requestCapture(propertyChange->value().toInt());
}
}
markDirty(AbstractRenderer::AllDirty);
diff --git a/src/render/framegraph/rendercapture_p.h b/src/render/framegraph/rendercapture_p.h
index 97bdc9d8b..e2b87474c 100644
--- a/src/render/framegraph/rendercapture_p.h
+++ b/src/render/framegraph/rendercapture_p.h
@@ -57,11 +57,12 @@ namespace Qt3DRender {
namespace Render {
-class RenderCapture : public FrameGraphNode
+class Q_AUTOTEST_EXPORT RenderCapture : public FrameGraphNode
{
public:
RenderCapture();
+ void requestCapture(int captureId);
bool wasCaptureRequested() const;
void acknowledgeCaptureRequest();
void addRenderCapture(const QImage &image);
diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp
index 7a1f133a8..b9e180b97 100644
--- a/src/render/frontend/qcamera.cpp
+++ b/src/render/frontend/qcamera.cpp
@@ -62,6 +62,7 @@ QCameraPrivate::QCameraPrivate()
/*!
* \class Qt3DRender::QCamera
+ * \inheaderfile Qt3DRender/QCamera
* \brief The QCamera class defines a view point through which the scene will be
* rendered.
* \inmodule Qt3DRender
diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h
index 9c2997ba0..f5bd49fa2 100644
--- a/src/render/frontend/qcamera.h
+++ b/src/render/frontend/qcamera.h
@@ -87,7 +87,7 @@ public:
TranslateViewCenter,
DontTranslateViewCenter
};
- Q_ENUM(CameraTranslationOption)
+ Q_ENUM(CameraTranslationOption) // LCOV_EXCL_LINE
QCameraLens *lens() const;
Qt3DCore::QTransform *transform() const;
diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp
index 4725251b5..269bc8d16 100644
--- a/src/render/frontend/qcameralens.cpp
+++ b/src/render/frontend/qcameralens.cpp
@@ -46,6 +46,7 @@ namespace Qt3DRender {
/*!
* \class Qt3DRender::QCameraLens
+ * \inheaderfile Qt3DRender/QCameraLens
* \inmodule Qt3DRender
*
* \brief Qt3DRender::QCameraLens specifies the projection matrix that will be used to
diff --git a/src/render/frontend/qcameralens.h b/src/render/frontend/qcameralens.h
index 6739369dc..ad414cada 100644
--- a/src/render/frontend/qcameralens.h
+++ b/src/render/frontend/qcameralens.h
@@ -77,7 +77,7 @@ public:
FrustumProjection,
CustomProjection
};
- Q_ENUM(ProjectionType)
+ Q_ENUM(ProjectionType) // LCOV_EXCL_LINE
ProjectionType projectionType() const;
float nearPlane() const;
diff --git a/src/render/frontend/qcomputecommand.cpp b/src/render/frontend/qcomputecommand.cpp
index 0bd2f629b..c36e4039c 100644
--- a/src/render/frontend/qcomputecommand.cpp
+++ b/src/render/frontend/qcomputecommand.cpp
@@ -45,10 +45,61 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QComputeCommand
- * \brief The QComputerCommand class
- * \since 5.7
- * \inmodule Qt3DRender
+ \class Qt3DRender::QComputeCommand
+ \since 5.7
+ \inmodule Qt3DRender
+ \brief QComponent to issue work for the compute shader on GPU
+
+ A Qt3DRender::QComputeCommand is used to issue work for the compute shader.
+ The compute shader is specified in the QMaterial component of the same entity the
+ QComputeCommand is added to. The workGroupX, workGroupY and workGroupZ properties
+ specify the work group sizes for the compute shader invocation. Qt3DRender::QDispatchCompute
+ node needs to be present in the FrameGraph to actually issue the commands.
+ */
+
+/*!
+ \qmltype ComputeCommand
+ \since 5.7
+ \inmodule Qt3DRender
+ \inherits Component3D
+ \instantiates Qt3DRender::QComputeCommand
+ \brief Component to issue work for the compute shader on GPU
+
+ A ComputeCommand is used to issue work for the compute shader.
+ The compute shader is specified in the Material component of the same entity the
+ ComputeCommand is added to. The workGroupX, workGroupY and workGroupZ properties
+ specify the work group sizes for the compute shader invocation. DispatchCompute
+ node needs to be present in the FrameGraph to actually issue the commands.
+ */
+
+/*!
+ \qmlproperty int ComputeCommand::workGroupX
+ Specifies X workgroup size.
+ */
+
+/*!
+ \qmlproperty int ComputeCommand::workGroupY
+ Specifies Y workgroup size.
+ */
+
+/*!
+ \qmlproperty int ComputeCommand::workGroupZ
+ Specifies Z workgroup size.
+ */
+
+/*!
+ \property QComputeCommand::workGroupX
+ Specifies X workgroup size.
+ */
+
+/*!
+ \property QComputeCommand::workGroupY
+ Specifies Y workgroup size.
+ */
+
+/*!
+ \property QComputeCommand::workGroupZ
+ Specifies Z workgroup size.
*/
QComputeCommandPrivate::QComputeCommandPrivate()
@@ -60,9 +111,8 @@ QComputeCommandPrivate::QComputeCommandPrivate()
}
/*!
- * The constructor creates a new Qt3DRender::QComputeCommand instance with the
- * specified \a parent.
- * \param parent
+ The constructor creates a new Qt3DRender::QComputeCommand instance with the
+ specified \a parent.
*/
QComputeCommand::QComputeCommand(Qt3DCore::QNode *parent)
: Qt3DCore::QComponent(*new QComputeCommandPrivate, parent)
@@ -74,27 +124,18 @@ QComputeCommand::~QComputeCommand()
{
}
-/*!
- * \return the workgroup size for the first dimension.
- */
int QComputeCommand::workGroupX() const
{
Q_D(const QComputeCommand);
return d->m_workGroupX;
}
-/*!
- * \return the workgroup size for the second dimension.
- */
int QComputeCommand::workGroupY() const
{
Q_D(const QComputeCommand);
return d->m_workGroupY;
}
-/*!
- * \return the workgroup size for the third dimension.
- */
int QComputeCommand::workGroupZ() const
{
Q_D(const QComputeCommand);
@@ -102,8 +143,7 @@ int QComputeCommand::workGroupZ() const
}
/*!
- * Sets the workgroup for the first dimension to \a workGroupX.
- * \param workGroupX
+ Sets the workgroup for the first dimension to \a workGroupX.
*/
void QComputeCommand::setWorkGroupX(int workGroupX)
{
@@ -115,8 +155,7 @@ void QComputeCommand::setWorkGroupX(int workGroupX)
}
/*!
- * Sets the workgroup for the second dimension to \a workGroupY.
- * \param workGroupY
+ Sets the workgroup for the second dimension to \a workGroupY.
*/
void QComputeCommand::setWorkGroupY(int workGroupY)
{
@@ -128,8 +167,7 @@ void QComputeCommand::setWorkGroupY(int workGroupY)
}
/*!
- * Sets the workgroup for the third dimension to \a workGroupZ.
- * \param workGroupZ
+ Sets the workgroup for the third dimension to \a workGroupZ.
*/
void QComputeCommand::setWorkGroupZ(int workGroupZ)
{
diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp
index c1524547c..f4fd2c683 100644
--- a/src/render/frontend/qpickingsettings.cpp
+++ b/src/render/frontend/qpickingsettings.cpp
@@ -77,6 +77,8 @@ QPickingSettingsPrivate::QPickingSettingsPrivate()
QPickingSettings::QPickingSettings(Qt3DCore::QNode *parent)
: Qt3DCore::QNode(*new QPickingSettingsPrivate, parent)
{
+ // Block all notifications for this class as it should have been a QObject
+ blockNotifications(true);
}
/*! \internal */
diff --git a/src/render/frontend/qpickingsettings.h b/src/render/frontend/qpickingsettings.h
index ebafcd07f..655bf952a 100644
--- a/src/render/frontend/qpickingsettings.h
+++ b/src/render/frontend/qpickingsettings.h
@@ -49,6 +49,8 @@ namespace Qt3DRender {
class QPickingSettingsPrivate;
+// TO DO: Qt 6 -> Make this a QObject
+
class QT3DRENDERSHARED_EXPORT QPickingSettings : public Qt3DCore::QNode
{
Q_OBJECT
@@ -64,20 +66,20 @@ public:
BoundingVolumePicking,
TrianglePicking
};
- Q_ENUM(PickMethod)
+ Q_ENUM(PickMethod) // LCOV_EXCL_LINE
enum PickResultMode {
NearestPick,
AllPicks
};
- Q_ENUM(PickResultMode)
+ Q_ENUM(PickResultMode) // LCOV_EXCL_LINE
enum FaceOrientationPickingMode {
FrontFace = 0x01,
BackFace = 0x02,
FrontAndBackFace = 0x03
};
- Q_ENUM(FaceOrientationPickingMode)
+ Q_ENUM(FaceOrientationPickingMode) // LCOV_EXCL_LINE
PickMethod pickMethod() const;
PickResultMode pickResultMode() const;
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index fec781eaf..6a7ecd193 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -120,6 +120,7 @@
#include <Qt3DRender/private/rendersettings_p.h>
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
+#include <Qt3DRender/private/technique_p.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
@@ -140,6 +141,7 @@ namespace Qt3DRender {
/*!
* \class Qt3DRender::QRenderAspect
+ * \inheaderfile Qt3DRender/QRenderAspect
* \brief The QRenderAspect class
* \since 5.7
* \inmodule Qt3DRender
@@ -196,8 +198,8 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QGeometryRenderer>(QSharedPointer<Render::GeometryRendererFunctor>::create(m_renderer, m_nodeManagers->geometryRendererManager()));
// Textures
- q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureDataManager()));
- q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureDataManager()));
+ q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager()));
+ q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager()));
// Material system
q->registerBackendType<QEffect>(QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(m_renderer, m_nodeManagers->effectManager()));
@@ -208,9 +210,10 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QRenderPass>(QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(m_renderer, m_nodeManagers->renderPassManager()));
q->registerBackendType<QShaderData>(QSharedPointer<Render::RenderShaderDataFunctor>::create(m_renderer, m_nodeManagers));
q->registerBackendType<QShaderProgram>(QSharedPointer<Render::NodeFunctor<Render::Shader, Render::ShaderManager> >::create(m_renderer, m_nodeManagers->shaderManager()));
- q->registerBackendType<QTechnique>(QSharedPointer<Render::NodeFunctor<Render::Technique, Render::TechniqueManager> >::create(m_renderer, m_nodeManagers->techniqueManager()));
+ q->registerBackendType<QTechnique>(QSharedPointer<Render::TechniqueFunctor>::create(m_renderer, m_nodeManagers));
// Framegraph
+ q->registerBackendType<QFrameGraphNode>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::FrameGraphNode, QFrameGraphNode> >::create(m_renderer, m_nodeManagers->frameGraphManager()));
q->registerBackendType<QCameraSelector>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::CameraSelector, QCameraSelector> >::create(m_renderer, m_nodeManagers->frameGraphManager()));
q->registerBackendType<QClearBuffers>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ClearBuffers, QClearBuffers> >::create(m_renderer, m_nodeManagers->frameGraphManager()));
q->registerBackendType<QDispatchCompute>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::DispatchCompute, QDispatchCompute> >::create(m_renderer, m_nodeManagers->frameGraphManager()));
@@ -360,7 +363,7 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
// QChangeArbiter::syncChanges() that happens just before the render aspect is
// asked for jobs to execute (this function). If that is the case, the RenderSettings will
// be null and we should not generate any jobs.
- if (d->m_renderer != nullptr && d->m_renderer->isRunning() && d->m_renderer->settings()) {
+ if (d->m_renderer->isRunning() && d->m_renderer->settings()) {
// don't spawn any jobs, if the renderer decides to skip this frame
if (!d->m_renderer->shouldRender()) {
d->m_renderer->skipNextFrame();
@@ -369,9 +372,16 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
Render::NodeManagers *manager = d->m_renderer->nodeManagers();
- const QVector<QNodeId> texturesPending = std::move(manager->textureDataManager()->texturesPending());
- for (const QNodeId textureId : texturesPending) {
- auto loadTextureJob = Render::LoadTextureDataJobPtr::create(textureId);
+ // Launch texture generator jobs
+ const QVector<QTextureImageDataGeneratorPtr> pendingImgGen = manager->textureImageDataManager()->pendingGenerators();
+ for (const QTextureImageDataGeneratorPtr &imgGen : pendingImgGen) {
+ auto loadTextureJob = Render::LoadTextureDataJobPtr::create(imgGen);
+ loadTextureJob->setNodeManagers(manager);
+ jobs.append(loadTextureJob);
+ }
+ const QVector<QTextureGeneratorPtr> pendingTexGen = manager->textureDataManager()->pendingGenerators();
+ for (const QTextureGeneratorPtr &texGen : pendingTexGen) {
+ auto loadTextureJob = Render::LoadTextureDataJobPtr::create(texGen);
loadTextureJob->setNodeManagers(manager);
jobs.append(loadTextureJob);
}
diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp
index 616c3a64e..aa10a7ef3 100644
--- a/src/render/frontend/qrendersettings.cpp
+++ b/src/render/frontend/qrendersettings.cpp
@@ -71,6 +71,14 @@ namespace Qt3DRender {
\l{Qt 3D Render Framegraph}{FrameGraph}.
*/
+/*!
+ \enum QRenderSettings::RenderPolicy
+
+ This enum type describes types of render policies available.
+ \value Always Always try to render (default)
+ \value OnDemand Only render when something changes
+*/
+
/*! \internal */
QRenderSettingsPrivate::QRenderSettingsPrivate()
: Qt3DCore::QComponentPrivate()
diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h
index 3d32dda6b..71da7c562 100644
--- a/src/render/frontend/qrendersettings.h
+++ b/src/render/frontend/qrendersettings.h
@@ -68,7 +68,7 @@ public:
OnDemand,
Always
};
- Q_ENUM(RenderPolicy)
+ Q_ENUM(RenderPolicy) // LCOV_EXCL_LINE
QPickingSettings* pickingSettings();
QFrameGraphNode *activeFrameGraph() const;
diff --git a/src/render/frontend/qrendertarget.cpp b/src/render/frontend/qrendertarget.cpp
index 44414e904..bdf8b5fa1 100644
--- a/src/render/frontend/qrendertarget.cpp
+++ b/src/render/frontend/qrendertarget.cpp
@@ -51,13 +51,40 @@ using namespace Qt3DCore;
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QRenderTarget
- * \brief The QRenderTarget class encapsulates a target (usually a frame buffer
- * object) which the renderer can render into.
- * \since 5.7
- * \inmodule Qt3DRender
+ \class Qt3DRender::QRenderTarget
+ \brief The QRenderTarget class encapsulates a target (usually a frame buffer
+ object) which the renderer can render into.
+ \since 5.7
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QRenderTarget comprises of Qt3DRender::QRenderTargetOutput objects,
+ which specify the the buffers the render target is rendering to. The user can
+ specify MRT(Multiple Render Targets) by attaching multiple textures to different
+ attachment points. The results are undefined if the user tries to attach multiple
+ textures to the same attachment point. At render time, only the draw buffers specified
+ in the Qt3DRender::QRenderTargetSelector are used.
+
+ */
+/*!
+ \qmltype RenderTarget
+ \brief The RenderTarget class encapsulates a target (usually a frame buffer
+ object) which the renderer can render into.
+ \since 5.7
+ \inmodule Qt3D.Render
+ \instantiates Qt3DRender::QRenderTarget
+
+ A RenderTarget comprises of RenderTargetOutput objects, which specify the the buffers
+ the render target is rendering to. The user can specify MRT(Multiple Render Targets)
+ by attaching multiple textures to different attachment points. The results are undefined
+ if the user tries to attach multiple textures to the same attachment point. At render
+ time, only the draw buffers specified in the RenderTargetSelector are used.
*/
+/*!
+ \qmlproperty list<RenderTargetOutput> RenderTarget::attachments
+ Holds the attachments for the RenderTarget.
+*/
+
/*! \internal */
QRenderTargetPrivate::QRenderTargetPrivate()
: QComponentPrivate()
@@ -65,8 +92,8 @@ QRenderTargetPrivate::QRenderTargetPrivate()
}
/*!
- * The constructor creates a new QRenderTarget::QRenderTarget instance with
- * the specified \a parent.
+ The constructor creates a new QRenderTarget::QRenderTarget instance with
+ the specified \a parent.
*/
QRenderTarget::QRenderTarget(QNode *parent)
: QComponent(*new QRenderTargetPrivate, parent)
@@ -85,8 +112,7 @@ QRenderTarget::QRenderTarget(QRenderTargetPrivate &dd, QNode *parent)
}
/*!
- * Adds a chosen output via \a output.
- * \param output
+ Adds a chosen output via \a output.
*/
void QRenderTarget::addOutput(QRenderTargetOutput *output)
{
@@ -109,8 +135,7 @@ void QRenderTarget::addOutput(QRenderTargetOutput *output)
}
/*!
- * Removes a chosen output via \a output.
- * \param output
+ Removes a chosen output via \a output.
*/
void QRenderTarget::removeOutput(QRenderTargetOutput *output)
{
@@ -127,7 +152,7 @@ void QRenderTarget::removeOutput(QRenderTargetOutput *output)
}
/*!
- * \return the chosen outputs.
+ \return the chosen outputs.
*/
QVector<QRenderTargetOutput *> QRenderTarget::outputs() const
{
diff --git a/src/render/frontend/qrendertargetoutput.cpp b/src/render/frontend/qrendertargetoutput.cpp
index 55b788a23..6d65ec08e 100644
--- a/src/render/frontend/qrendertargetoutput.cpp
+++ b/src/render/frontend/qrendertargetoutput.cpp
@@ -47,13 +47,141 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QRenderTargetOutput
- * \brief The QRenderTargetOutput class allows the specification of an attachment
- * of a render target (whether it is a color texture, a depth texture, etc... ).
- * \since 5.7
- * \inmodule Qt3DRender
+ \class Qt3DRender::QRenderTargetOutput
+ \brief The QRenderTargetOutput class allows the specification of an attachment
+ of a render target (whether it is a color texture, a depth texture, etc... ).
+ \since 5.7
+ \inmodule Qt3DRender
+
+ A QRenderTargetOutput specifies the attachment point and parameters for texture
+ that is attached to render target. In addition to the attachment point, texture
+ miplevel, layer and cubemap face can be specified. The texture attached to the
+ QRenderTargetOutput must be compatible with the given parameters.
+ */
+
+/*!
+ \qmltype RenderTargetOutput
+ \brief The RenderTargetOutput type allows the specification of an attachment
+ of a render target (whether it is a color texture, a depth texture, etc... ).
+ \since 5.7
+ \inmodule Qt3D.Render
+ \inherits Node
+ \instantiates Qt3DRender::QRenderTargetOutput
+
+ A RenderTargetOutput specifies the attachment point and parameters for texture
+ that is attached to render target. In addition to the attachment point, texture
+ miplevel, layer and cubemap face can be specified. The texture attached to the
+ RenderTargetOutput must be compatible with the given parameters.
*/
+/*!
+ \enum QRenderTargetOutput::AttachmentPoint
+
+ This enumeration specifies the values for the attachment point.
+
+ \value Color0 Color attachment point at index 0
+ \value Color1 Color attachment point at index 1
+ \value Color2 Color attachment point at index 2
+ \value Color3 Color attachment point at index 3
+ \value Color4 Color attachment point at index 4
+ \value Color5 Color attachment point at index 5
+ \value Color6 Color attachment point at index 6
+ \value Color7 Color attachment point at index 7
+ \value Color8 Color attachment point at index 8
+ \value Color9 Color attachment point at index 9
+ \value Color10 Color attachment point at index 10
+ \value Color11 Color attachment point at index 11
+ \value Color12 Color attachment point at index 12
+ \value Color13 Color attachment point at index 13
+ \value Color14 Color attachment point at index 14
+ \value Color15 Color attachment point at index 15
+ \value Depth Depth attachment point
+ \value Stencil Stencil attachment point
+ \value DepthStencil DepthStencil attachment point
+*/
+
+/*!
+ \qmlproperty enumeration RenderTargetOutput::attachmentPoint
+ Holds the attachment point of the RenderTargetOutput.
+ \list
+ \li RenderTargetOutput.Color0
+ \li RenderTargetOutput.Color1
+ \li RenderTargetOutput.Color2
+ \li RenderTargetOutput.Color3
+ \li RenderTargetOutput.Color4
+ \li RenderTargetOutput.Color5
+ \li RenderTargetOutput.Color6
+ \li RenderTargetOutput.Color7
+ \li RenderTargetOutput.Color8
+ \li RenderTargetOutput.Color9
+ \li RenderTargetOutput.Color10
+ \li RenderTargetOutput.Color11
+ \li RenderTargetOutput.Color12
+ \li RenderTargetOutput.Color13
+ \li RenderTargetOutput.Color14
+ \li RenderTargetOutput.Color15
+ \li RenderTargetOutput.Depth
+ \li RenderTargetOutput.Stencil
+ \li RenderTargetOutput.DepthStencil
+ \endlist
+
+ \sa Qt3DRender::QRenderTargetOutput::AttachmentPoint
+*/
+
+/*!
+ \qmlproperty Texture RenderTargetOutput::texture
+ Holds the texture attached to the attachment point.
+*/
+
+/*!
+ \qmlproperty int RenderTargetOutput::mipLevel
+ Holds the miplevel of the attached texture the rendering is directed to.
+*/
+
+/*!
+ \qmlproperty int RenderTargetOutput::layer
+ Holds the layer of the attached texture the rendering is directed to.
+*/
+
+/*!
+ \qmlproperty enumeration RenderTargetOutput::face
+ Holds the face of the attached cubemap texture the rendering is directed to.
+ \list
+ \li Texture.CubeMapPositiveX
+ \li Texture.CubeMapNegativeX
+ \li Texture.CubeMapPositiveY
+ \li Texture.CubeMapNegativeY
+ \li Texture.CubeMapPositiveZ
+ \li Texture.CubeMapNegativeZ
+ \endlist
+ \sa Qt3DRender::QAbstractTexture::CubeMapFace
+*/
+
+/*!
+ \property QRenderTargetOutput::attachmentPoint
+ Holds the attachment point of the QRenderTargetOutput.
+*/
+
+/*!
+ \property QRenderTargetOutput::texture
+ Holds the texture attached to the attachment point.
+*/
+
+/*!
+ \property QRenderTargetOutput::mipLevel
+ Holds the miplevel of the attached texture the rendering is directed to.
+*/
+
+/*!
+ \property QRenderTargetOutput::layer
+ Holds the layer of the attached texture the rendering is directed to.
+*/
+
+/*!
+ \property QRenderTargetOutput::face
+ Holds the face of the attached cubemap texture the rendering is directed to.
+*/
+
/*! \internal */
QRenderTargetOutputPrivate::QRenderTargetOutputPrivate()
: QNodePrivate()
@@ -66,9 +194,8 @@ QRenderTargetOutputPrivate::QRenderTargetOutputPrivate()
}
/*!
- * The constructor creates a new QRenderTargetOutput::QRenderTargetOutput instance
- * with the specified \a parent.
- * \param parent
+ The constructor creates a new QRenderTargetOutput::QRenderTargetOutput instance
+ with the specified \a parent.
*/
QRenderTargetOutput::QRenderTargetOutput(QNode *parent)
: QNode(*new QRenderTargetOutputPrivate, parent)
@@ -86,10 +213,6 @@ QRenderTargetOutput::QRenderTargetOutput(QRenderTargetOutputPrivate &dd, QNode *
{
}
-/*!
- * Sets the attachment point to \a attachmentPoint.
- * \param attachmentPoint
- */
void QRenderTargetOutput::setAttachmentPoint(QRenderTargetOutput::AttachmentPoint attachmentPoint)
{
Q_D(QRenderTargetOutput);
@@ -99,9 +222,6 @@ void QRenderTargetOutput::setAttachmentPoint(QRenderTargetOutput::AttachmentPoin
}
}
-/*!
- * \return the current attachment point.
- */
QRenderTargetOutput::AttachmentPoint QRenderTargetOutput::attachmentPoint() const
{
Q_D(const QRenderTargetOutput);
@@ -130,19 +250,12 @@ void QRenderTargetOutput::setTexture(QAbstractTexture *texture)
}
}
-/*!
- * \return the current texture.
- */
QAbstractTexture *QRenderTargetOutput::texture() const
{
Q_D(const QRenderTargetOutput);
return d->m_texture;
}
-/*!
- * Sets the required mip level to \a level.
- * \param level
- */
void QRenderTargetOutput::setMipLevel(int level)
{
Q_D(QRenderTargetOutput);
@@ -152,19 +265,12 @@ void QRenderTargetOutput::setMipLevel(int level)
}
}
-/*!
- * \return the current mip level.
- */
int QRenderTargetOutput::mipLevel() const
{
Q_D(const QRenderTargetOutput);
return d->m_mipLevel;
}
-/*!
- * Sets the required layer to \a layer.
- * \param layer
- */
void QRenderTargetOutput::setLayer(int layer)
{
Q_D(QRenderTargetOutput);
@@ -174,19 +280,12 @@ void QRenderTargetOutput::setLayer(int layer)
}
}
-/*!
- * \return the current layer.
- */
int QRenderTargetOutput::layer() const
{
Q_D(const QRenderTargetOutput);
return d->m_layer;
}
-/*!
- * Sets the required cubemap face to \a face.
- * \param face
- */
void QRenderTargetOutput::setFace(QAbstractTexture::CubeMapFace face)
{
Q_D(QRenderTargetOutput);
@@ -196,9 +295,6 @@ void QRenderTargetOutput::setFace(QAbstractTexture::CubeMapFace face)
}
}
-/*!
- * \return the current cubemap face.
- */
QAbstractTexture::CubeMapFace QRenderTargetOutput::face() const
{
Q_D(const QRenderTargetOutput);
diff --git a/src/render/frontend/qrendertargetoutput.h b/src/render/frontend/qrendertargetoutput.h
index 0f8f11156..f2feea536 100644
--- a/src/render/frontend/qrendertargetoutput.h
+++ b/src/render/frontend/qrendertargetoutput.h
@@ -82,7 +82,7 @@ public:
Stencil,
DepthStencil
};
- Q_ENUM(AttachmentPoint)
+ Q_ENUM(AttachmentPoint) // LCOV_EXCL_LINE
explicit QRenderTargetOutput(Qt3DCore::QNode *parent = nullptr);
~QRenderTargetOutput();
@@ -119,6 +119,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QRenderTargetOutput::AttachmentPoint)
+Q_DECLARE_METATYPE(Qt3DRender::QRenderTargetOutput::AttachmentPoint) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QRENDERTARGETOUTPUT_H
diff --git a/src/render/frontend/sphere_p.h b/src/render/frontend/sphere_p.h
index de93faa05..a30a12741 100644
--- a/src/render/frontend/sphere_p.h
+++ b/src/render/frontend/sphere_p.h
@@ -163,6 +163,6 @@ inline bool intersects(const Sphere &a, const Sphere &b)
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::Sphere)
+Q_DECLARE_METATYPE(Qt3DRender::Render::Sphere) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_SPHERE_H
diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp
index 70266ac52..1efacdfe0 100644
--- a/src/render/geometry/geometryrenderer.cpp
+++ b/src/render/geometry/geometryrenderer.cpp
@@ -241,7 +241,7 @@ Qt3DCore::QBackendNode *GeometryRendererFunctor::get(Qt3DCore::QNodeId id) const
void GeometryRendererFunctor::destroy(Qt3DCore::QNodeId id) const
{
- return m_manager->releaseResource(id);
+ m_manager->releaseResource(id);
}
} // namespace Render
diff --git a/src/render/geometry/qattribute.cpp b/src/render/geometry/qattribute.cpp
index ef439f2b4..8723f5177 100644
--- a/src/render/geometry/qattribute.cpp
+++ b/src/render/geometry/qattribute.cpp
@@ -75,6 +75,7 @@ QAttributePrivate::QAttributePrivate()
/*!
* \class Qt3DRender::QAttribute
+ * \inheaderfile Qt3DRender/QAttribute
* \inmodule Qt3DRender
*
* \inherits Qt3DCore::QNode
@@ -86,7 +87,7 @@ QAttributePrivate::QAttributePrivate()
* will ensure your geometry will be compatible with picking and the various
* materials provided in the Qt3DExtras module.
*
- * \sa QBuffer.
+ * \sa QBuffer
*/
/*!
diff --git a/src/render/geometry/qattribute.h b/src/render/geometry/qattribute.h
index e907c64e1..3e413c659 100644
--- a/src/render/geometry/qattribute.h
+++ b/src/render/geometry/qattribute.h
@@ -65,6 +65,11 @@ class QT3DRENDERSHARED_EXPORT QAttribute : public Qt3DCore::QNode
Q_PROPERTY(uint byteOffset READ byteOffset WRITE setByteOffset NOTIFY byteOffsetChanged)
Q_PROPERTY(uint divisor READ divisor WRITE setDivisor NOTIFY divisorChanged)
Q_PROPERTY(AttributeType attributeType READ attributeType WRITE setAttributeType NOTIFY attributeTypeChanged)
+ Q_PROPERTY(QString defaultPositionAttributeName READ defaultPositionAttributeName CONSTANT)
+ Q_PROPERTY(QString defaultNormalAttributeName READ defaultNormalAttributeName CONSTANT)
+ Q_PROPERTY(QString defaultColorAttributeName READ defaultColorAttributeName CONSTANT)
+ Q_PROPERTY(QString defaultTextureCoordinateAttributeName READ defaultTextureCoordinateAttributeName CONSTANT)
+ Q_PROPERTY(QString defaultTangentAttributeName READ defaultTangentAttributeName CONSTANT)
public:
enum AttributeType {
@@ -72,7 +77,7 @@ public:
IndexAttribute
};
- Q_ENUM(AttributeType)
+ Q_ENUM(AttributeType) // LCOV_EXCL_LINE
enum VertexBaseType {
Byte = 0,
@@ -85,7 +90,7 @@ public:
Float,
Double
};
- Q_ENUM(VertexBaseType)
+ Q_ENUM(VertexBaseType) // LCOV_EXCL_LINE
explicit QAttribute(QNode *parent = nullptr);
explicit QAttribute(QBuffer *buf, VertexBaseType vertexBaseType, uint vertexSize, uint count, uint offset = 0, uint stride = 0, QNode *parent = nullptr);
diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp
index e63798027..02417f978 100644
--- a/src/render/geometry/qbuffer.cpp
+++ b/src/render/geometry/qbuffer.cpp
@@ -89,6 +89,7 @@ QBufferPrivate::QBufferPrivate()
/*!
* \class Qt3DRender::QBuffer
+ * \inheaderfile Qt3DRender/QBuffer
* \inmodule Qt3DRender
*
* \inherits Qt3DCore::QNode
@@ -110,6 +111,91 @@ QBufferPrivate::QBufferPrivate()
* This signal is emitted with \a bytes when data changes.
*/
+/*!
+ \class Qt3DRender::QBufferDataGenerator
+ \inmodule Qt3DRender
+
+ \inherits Qt3DRender::QAbstractFunctor
+
+ \brief Provides a mechanism to generate buffer data from a job.
+
+ The Qt3DRender::QBufferDataGenerator should be subclassed to provide a way
+ to fill the data of a Qt3DRender::QBuffer. Such functors are executed at
+ runtime in a Qt 3D job (likely in parallel with many other jobs). When
+ providing a functor you must implement the operator() which will be called
+ to generate the actual data. You must make sure that you have stored copies
+ of anything you might need for it to execute properly. You should also
+ implement the operator==. It will be used to compare with other functors
+ and based on that allow the renderer to decide if a new functor should be
+ executed or not.
+
+ \note functors are useful when you can build data from a few set of
+ attributes (e.g: building a sphere from a radius property). If you already
+ have access to the buffer data, using Qt3DRender::QBuffer::setData() is
+ likely more efficient.
+
+ \code
+
+ QByteArray createSphereMeshVertexData(float radius, int rings, int slices)
+ {
+ ...
+ }
+
+ class SphereVertexDataFunctor : public QBufferDataGenerator
+ {
+ public:
+ SphereVertexDataFunctor(int rings, int slices, float radius)
+ : m_rings(rings)
+ , m_slices(slices)
+ , m_radius(radius)
+ {}
+
+ QByteArray operator ()() Q_DECL_OVERRIDE
+ {
+ return createSphereMeshVertexData(m_radius, m_rings, m_slices);
+ }
+
+ bool operator ==(const QBufferDataGenerator &other) const Q_DECL_OVERRIDE
+ {
+ const SphereVertexDataFunctor *otherFunctor = functor_cast<SphereVertexDataFunctor>(&other);
+ if (otherFunctor != nullptr)
+ return (otherFunctor->m_rings == m_rings &&
+ otherFunctor->m_slices == m_slices &&
+ otherFunctor->m_radius == m_radius);
+ return false;
+ }
+
+ QT3D_FUNCTOR(SphereVertexDataFunctor)
+
+ private:
+ int m_rings;
+ int m_slices;
+ float m_radius;
+ };
+
+ \endcode
+
+ The QT3D_FUNCTOR macro should be added when subclassing. This allows you to
+ use functor_cast in your comparison operator to make sure that the other
+ functor is of the same type as the one your are trying to compare against.
+*/
+
+/*!
+ \fn Qt3DRender::QBufferDataGenerator::operator()()
+
+ Should be implemented to return the buffer data as a QByteArray when called.
+ */
+
+/*!
+ \fn Qt3DRender::QBufferDataGenerator::operator ==(const QBufferDataGenerator &other) const
+
+ Should be reimplemented to return true when two generators are identical,
+ false otherwise.
+
+ \note The renderer uses this comparison to decide whether data for a buffer
+ needs to be reuploaded or not when the functor on a Qt3DRender::QBuffer
+ changes.
+ */
/*!
* \enum QBuffer::BufferType
@@ -157,7 +243,7 @@ QBufferPrivate::QBufferPrivate()
/*!
* \typedef Qt3DRender::QBufferDataGeneratorPtr
- * \relates QBuffer
+ * \relates Qt3DRender::QBuffer
*/
/*!
@@ -204,7 +290,7 @@ void QBuffer::setData(const QByteArray &bytes)
}
/*!
- * \Update the data.
+ * Updates the data by replacing it with \a bytes at \a offset.
*/
void QBuffer::updateData(int offset, const QByteArray &bytes)
{
diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h
index cf8bdcfb9..3827b04c9 100644
--- a/src/render/geometry/qbuffer.h
+++ b/src/render/geometry/qbuffer.h
@@ -70,7 +70,7 @@ public:
UniformBuffer = 0x8A11, // GL_UNIFORM_BUFFER
ShaderStorageBuffer = 0x90D2 // GL_SHADER_STORAGE_BUFFER
};
- Q_ENUM(BufferType)
+ Q_ENUM(BufferType) // LCOV_EXCL_LINE
enum UsageType
{
@@ -84,7 +84,7 @@ public:
DynamicRead = 0x88E9, // GL_DYNAMIC_READ
DynamicCopy = 0x88EA // GL_DYNAMIC_COPY
};
- Q_ENUM(UsageType)
+ Q_ENUM(UsageType) // LCOV_EXCL_LINE
explicit QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = nullptr);
~QBuffer();
diff --git a/src/render/geometry/qbuffer_p.h b/src/render/geometry/qbuffer_p.h
index 7759a279f..eb69730b8 100644
--- a/src/render/geometry/qbuffer_p.h
+++ b/src/render/geometry/qbuffer_p.h
@@ -94,6 +94,6 @@ struct QBufferUpdate
} // namespace Qt3DRender
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QBufferUpdate)
+Q_DECLARE_METATYPE(Qt3DRender::QBufferUpdate) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QBUFFER_P_H
diff --git a/src/render/geometry/qbufferdatagenerator.h b/src/render/geometry/qbufferdatagenerator.h
index 2b37ec24d..702f396d4 100644
--- a/src/render/geometry/qbufferdatagenerator.h
+++ b/src/render/geometry/qbufferdatagenerator.h
@@ -62,7 +62,7 @@ typedef QSharedPointer<QBufferDataGenerator> QBufferDataGeneratorPtr;
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QBufferDataGeneratorPtr)
+Q_DECLARE_METATYPE(Qt3DRender::QBufferDataGeneratorPtr) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QBUFFERDATAGENERATOR
diff --git a/src/render/geometry/qgeometry.cpp b/src/render/geometry/qgeometry.cpp
index 9b6b9a8e7..3f3065533 100644
--- a/src/render/geometry/qgeometry.cpp
+++ b/src/render/geometry/qgeometry.cpp
@@ -80,6 +80,7 @@ QGeometryPrivate::~QGeometryPrivate()
/*!
* \class Qt3DRender::QGeometry
+ * \inheaderfile Qt3DRender/QGeometry
* \inmodule Qt3DRender
*
* \inherits Qt3DCore::QNode
@@ -90,7 +91,7 @@ QGeometryPrivate::~QGeometryPrivate()
* \typedef Qt3DRender::QAttributeList
* \relates Qt3DRender::QGeometry
*
- * A vector of {QAttribute}s.
+ * A vector of \l {Qt3DRender::}{QAttribute}s.
*/
/*!
@@ -171,7 +172,7 @@ void QGeometry::setBoundingVolumePositionAttribute(QAttribute *boundingVolumePos
/*!
* \property QGeometry::boundingVolumePositionAttribute
*
- * Holds atribute used to compute the bounding volume .
+ * Holds the attribute used to compute the bounding volume.
*/
QAttribute *QGeometry::boundingVolumePositionAttribute() const
{
diff --git a/src/render/geometry/qgeometryfactory.h b/src/render/geometry/qgeometryfactory.h
index affcc0e52..d5d88a45d 100644
--- a/src/render/geometry/qgeometryfactory.h
+++ b/src/render/geometry/qgeometryfactory.h
@@ -64,7 +64,7 @@ typedef QSharedPointer<QGeometryFactory> QGeometryFactoryPtr;
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QGeometryFactoryPtr)
+Q_DECLARE_METATYPE(Qt3DRender::QGeometryFactoryPtr) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QGEOMETRYFACTORY
diff --git a/src/render/geometry/qgeometryrenderer.cpp b/src/render/geometry/qgeometryrenderer.cpp
index ddc1b1b23..970f555d3 100644
--- a/src/render/geometry/qgeometryrenderer.cpp
+++ b/src/render/geometry/qgeometryrenderer.cpp
@@ -138,6 +138,7 @@ QGeometryRendererPrivate::~QGeometryRendererPrivate()
/*!
* \class Qt3DRender::QGeometryRenderer
+ * \inheaderfile Qt3DRender/QGeometryRenderer
* \inmodule Qt3DRender
*
* \inherits Qt3DCore::QComponent
diff --git a/src/render/geometry/qgeometryrenderer.h b/src/render/geometry/qgeometryrenderer.h
index be3bb6146..28d580990 100644
--- a/src/render/geometry/qgeometryrenderer.h
+++ b/src/render/geometry/qgeometryrenderer.h
@@ -85,7 +85,7 @@ public:
TriangleStripAdjacency = 0x000D,
Patches = 0x000E
};
- Q_ENUM(PrimitiveType)
+ Q_ENUM(PrimitiveType) // LCOV_EXCL_LINE
// how to figure out index count and all the fancy stuff that QMeshData provides for us?
// also how to figure out which attribute(s?) hold the indices?
diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp
index 89e72ea45..6e98d0e9a 100644
--- a/src/render/geometry/qmesh.cpp
+++ b/src/render/geometry/qmesh.cpp
@@ -52,20 +52,6 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class MeshFunctor : public QGeometryFactory
-{
-public :
- MeshFunctor(const QUrl &sourcePath, const QString &meshName = QString());
- QGeometry *operator()() Q_DECL_OVERRIDE;
- bool operator ==(const QGeometryFactory &other) const Q_DECL_OVERRIDE;
- QT3D_FUNCTOR(MeshFunctor)
-
-private:
- QUrl m_sourcePath;
- QString m_meshName;
-};
-
-
QMeshPrivate::QMeshPrivate()
: QGeometryRendererPrivate()
{
@@ -92,6 +78,7 @@ QMeshPrivate::QMeshPrivate()
/*!
* \class Qt3DRender::QMesh
+ * \inheaderfile Qt3DRender/QMesh
* \inmodule Qt3DRender
*
* \inherits Qt3DRender::QGeometryRenderer
@@ -126,7 +113,9 @@ void QMesh::setSource(const QUrl& source)
d->m_source = source;
// update the functor
QGeometryRenderer::setGeometryFactory(QGeometryFactoryPtr(new MeshFunctor(d->m_source, d->m_meshName)));
+ const bool blocked = blockNotifications(true);
emit sourceChanged(source);
+ blockNotifications(blocked);
}
/*!
@@ -148,7 +137,9 @@ void QMesh::setMeshName(const QString &meshName)
d->m_meshName = meshName;
// update the functor
QGeometryRenderer::setGeometryFactory(QGeometryFactoryPtr(new MeshFunctor(d->m_source, d->m_meshName)));
+ const bool blocked = blockNotifications(true);
emit meshNameChanged(meshName);
+ blockNotifications(blocked);
}
/*!
diff --git a/src/render/geometry/qmesh_p.h b/src/render/geometry/qmesh_p.h
index c9a6cc1e8..a621525cc 100644
--- a/src/render/geometry/qmesh_p.h
+++ b/src/render/geometry/qmesh_p.h
@@ -71,6 +71,21 @@ public:
QString m_meshName;
};
+
+class Q_AUTOTEST_EXPORT MeshFunctor : public QGeometryFactory
+{
+public :
+ MeshFunctor(const QUrl &sourcePath, const QString &meshName = QString());
+ QGeometry *operator()() Q_DECL_OVERRIDE;
+ bool operator ==(const QGeometryFactory &other) const Q_DECL_OVERRIDE;
+ QT3D_FUNCTOR(MeshFunctor)
+
+private:
+ QUrl m_sourcePath;
+ QString m_meshName;
+};
+
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index eac323f16..b258c083c 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -45,7 +45,7 @@
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/private/material_p.h>
-#include <Qt3DRender/private/texture_p.h>
+#include <Qt3DRender/private/gltexture_p.h>
#include <Qt3DRender/private/buffer_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/rendercommand_p.h>
@@ -56,6 +56,7 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/gltexturemanager_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
#include <Qt3DRender/private/qbuffer_p.h>
#include <QOpenGLShaderProgram>
@@ -80,8 +81,6 @@
QT_BEGIN_NAMESPACE
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-
namespace {
QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
@@ -188,9 +187,7 @@ void GraphicsContext::initialize()
m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &numTexUnits);
qCDebug(Backend) << "context supports" << numTexUnits << "texture units";
- m_pinnedTextureUnits = QBitArray(numTexUnits);
m_activeTextures.resize(numTexUnits);
- m_textureScopes.resize(numTexUnits);
if (m_gl->format().majorVersion() >= 3) {
m_supportsVAO = true;
@@ -205,6 +202,31 @@ void GraphicsContext::initialize()
qCDebug(Backend) << "VAO support = " << m_supportsVAO;
}
+void GraphicsContext::resolveRenderTargetFormat()
+{
+ const QSurfaceFormat format = m_gl->format();
+ const uint a = format.alphaBufferSize();
+ const uint r = format.redBufferSize();
+ const uint g = format.greenBufferSize();
+ const uint b = format.blueBufferSize();
+
+#define RGBA_BITS(r,g,b,a) (r | (g << 6) | (b << 12) | (a << 18))
+
+ const uint bits = RGBA_BITS(r,g,b,a);
+ switch (bits) {
+ case RGBA_BITS(8,8,8,8):
+ m_renderTargetFormat = QAbstractTexture::RGBA8_UNorm;
+ break;
+ case RGBA_BITS(8,8,8,0):
+ m_renderTargetFormat = QAbstractTexture::RGB8_UNorm;
+ break;
+ case RGBA_BITS(5,6,5,0):
+ m_renderTargetFormat = QAbstractTexture::R5G6B5;
+ break;
+ }
+#undef RGBA_BITS
+}
+
bool GraphicsContext::beginDrawing(QSurface *surface)
{
Q_ASSERT(surface);
@@ -226,6 +248,9 @@ bool GraphicsContext::beginDrawing(QSurface *surface)
if (m_ownCurrent && !makeCurrent(m_surface))
return false;
+ // TODO: cache surface format somewhere rather than doing this every time render surface changes
+ resolveRenderTargetFormat();
+
// Sets or Create the correct m_glHelper
// for the current surface
activateGLHelper();
@@ -252,7 +277,10 @@ bool GraphicsContext::beginDrawing(QSurface *surface)
m_activeShaderDNA = 0;
}
- m_activeTextures.fill(0);
+ // reset active textures
+ for (int u = 0; u < m_activeTextures.size(); ++u)
+ m_activeTextures[u].texture = nullptr;
+
m_boundArrayBuffer = nullptr;
static int callCount = 0;
@@ -393,6 +421,11 @@ bool GraphicsContext::hasValidGLHelper() const
return m_glHelper != nullptr;
}
+bool GraphicsContext::isInitialized() const
+{
+ return m_initialized;
+}
+
bool GraphicsContext::makeCurrent(QSurface *surface)
{
Q_ASSERT(m_gl);
@@ -522,14 +555,20 @@ void GraphicsContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId,
fboId = m_renderTargets.value(renderTargetNodeId);
// We need to check if one of the attachment was resized
- TextureManager *textureManager = m_renderer->nodeManagers()->textureManager();
- bool needsResize = false;
- const auto attachments_ = attachments.attachments();
- for (const Attachment &attachment : attachments_) {
- Texture *rTex = textureManager->lookupResource(attachment.m_textureUuid);
- if (rTex != nullptr)
- needsResize |= rTex->isTextureReset();
+ bool needsResize = !m_renderTargetsSize.contains(fboId); // not even initialized yet?
+ if (!needsResize) {
+ // render target exists, has attachment been resized?
+ GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager();
+ const QSize s = m_renderTargetsSize[fboId];
+ const auto attachments_ = attachments.attachments();
+ for (const Attachment &attachment : attachments_) {
+ GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid);
+ needsResize |= (rTex != nullptr && rTex->size() != s);
+ if (attachment.m_point == QRenderTargetOutput::Color0)
+ m_renderTargetFormat = rTex->properties().format;
+ }
}
+
if (needsResize) {
m_glHelper->bindFrameBufferObject(fboId);
bindFrameBufferAttachmentHelper(fboId, attachments);
@@ -547,19 +586,17 @@ void GraphicsContext::bindFrameBufferAttachmentHelper(GLuint fboId, const Attach
// Set FBO attachments
QSize fboSize;
- TextureManager *textureManager = m_renderer->nodeManagers()->textureManager();
+ GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager();
const auto attachments_ = attachments.attachments();
for (const Attachment &attachment : attachments_) {
- Texture *rTex =textureManager->lookupResource(attachment.m_textureUuid);
- if (rTex != nullptr) {
- QOpenGLTexture *glTex = rTex->getOrCreateGLTexture();
- if (glTex != nullptr) {
- if (fboSize.isEmpty())
- fboSize = QSize(glTex->width(), glTex->height());
- else
- fboSize = QSize(qMin(fboSize.width(), glTex->width()), qMin(fboSize.height(), glTex->height()));
- m_glHelper->bindFrameBufferAttachment(glTex, attachment);
- }
+ GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid);
+ QOpenGLTexture *glTex = rTex ? rTex->getOrCreateGLTexture() : nullptr;
+ if (glTex != nullptr) {
+ if (fboSize.isEmpty())
+ fboSize = QSize(glTex->width(), glTex->height());
+ else
+ fboSize = QSize(qMin(fboSize.width(), glTex->width()), qMin(fboSize.height(), glTex->height()));
+ m_glHelper->bindFrameBufferAttachment(glTex, attachment);
}
}
m_renderTargetsSize.insert(fboId, fboSize);
@@ -591,7 +628,7 @@ void GraphicsContext::setActiveMaterial(Material *rmat)
m_material = rmat;
}
-int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUnit)
+int GraphicsContext::activateTexture(TextureScope scope, GLTexture *tex, int onUnit)
{
// Returns the texture unit to use for the texture
// This always return a valid unit, unless there are more textures than
@@ -604,10 +641,10 @@ int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUni
// actually re-bind if required, the tex->dna on the unit not being the same
// Note: tex->dna() could be 0 if the texture has not been created yet
- if (m_activeTextures[onUnit] != tex->dna() || tex->dna() == 0 || tex->dataUploadRequired()) {
+ if (m_activeTextures[onUnit].texture != tex) {
QOpenGLTexture *glTex = tex->getOrCreateGLTexture();
glTex->bind(onUnit);
- m_activeTextures[onUnit] = tex->dna();
+ m_activeTextures[onUnit].texture = tex;
}
#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
@@ -617,9 +654,9 @@ int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUni
<< tex->textureId() << "on unit" << onUnit;
#endif
- m_textureScores.insert(m_activeTextures[onUnit], 200);
- m_pinnedTextureUnits[onUnit] = true;
- m_textureScopes[onUnit] = scope;
+ m_activeTextures[onUnit].score = 200;
+ m_activeTextures[onUnit].pinned = true;
+ m_activeTextures[onUnit].scope = scope;
return onUnit;
}
@@ -627,12 +664,12 @@ int GraphicsContext::activateTexture(TextureScope scope, Texture *tex, int onUni
void GraphicsContext::deactivateTexturesWithScope(TextureScope ts)
{
for (int u=0; u<m_activeTextures.size(); ++u) {
- if (!m_pinnedTextureUnits[u])
+ if (!m_activeTextures[u].pinned)
continue; // inactive, ignore
- if (m_textureScopes[u] == ts) {
- m_pinnedTextureUnits[u] = false;
- m_textureScores.insert(m_activeTextures[u], m_textureScores.value(m_activeTextures[u], 1) - 1);
+ if (m_activeTextures[u].scope == ts) {
+ m_activeTextures[u].pinned = false;
+ m_activeTextures[u].score = qMax(m_activeTextures[u].score, 1) - 1;
}
} // of units iteration
}
@@ -717,12 +754,12 @@ GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
return glHelper;
}
-void GraphicsContext::deactivateTexture(Texture* tex)
+void GraphicsContext::deactivateTexture(GLTexture* tex)
{
for (int u=0; u<m_activeTextures.size(); ++u) {
- if (m_activeTextures[u] == tex->dna()) {
- Q_ASSERT(m_pinnedTextureUnits[u]);
- m_pinnedTextureUnits[u] = false;
+ if (m_activeTextures[u].texture == tex) {
+ Q_ASSERT(m_activeTextures[u].pinned);
+ m_activeTextures[u].pinned = false;
return;
}
} // of units iteration
@@ -735,7 +772,8 @@ void GraphicsContext::setCurrentStateSet(RenderStateSet *ss)
if (ss == m_stateSet)
return;
- ss->apply(this);
+ if (ss)
+ ss->apply(this);
m_stateSet = ss;
}
@@ -1007,20 +1045,20 @@ void GraphicsContext::setSeamlessCubemap(bool enable)
Tries to use the texture unit with the texture that hasn't been used for the longest time
if the texture happens not to be already pinned on a texture unit.
*/
-GLint GraphicsContext::assignUnitForTexture(Texture *tex)
+GLint GraphicsContext::assignUnitForTexture(GLTexture *tex)
{
int lowestScoredUnit = -1;
int lowestScore = 0xfffffff;
for (int u=0; u<m_activeTextures.size(); ++u) {
- if (m_activeTextures[u] == tex->dna())
+ if (m_activeTextures[u].texture == tex)
return u;
// No texture is currently active on the texture unit
// we save the texture unit with the texture that has been on there
// the longest time while not being used
- if (!m_pinnedTextureUnits[u]) {
- int score = m_textureScores.value(m_activeTextures[u], 0);
+ if (!m_activeTextures[u].pinned) {
+ int score = m_activeTextures[u].score;
if (score < lowestScore) {
lowestScore = score;
lowestScoredUnit = u;
@@ -1036,18 +1074,8 @@ GLint GraphicsContext::assignUnitForTexture(Texture *tex)
void GraphicsContext::decayTextureScores()
{
- QHash<uint, int>::iterator it = m_textureScores.begin();
- const QHash<uint, int>::iterator end = m_textureScores.end();
-
- while (it != end) {
- it.value()--;
- if (it.value() <= 0) {
- qCDebug(Backend) << "removing inactive texture" << it.key();
- it = m_textureScores.erase(it);
- } else {
- ++it;
- }
- }
+ for (int u = 0; u < m_activeTextures.size(); u++)
+ m_activeTextures[u].score = qMax(m_activeTextures[u].score - 1, 0);
}
QOpenGLShaderProgram* GraphicsContext::activeShader() const
@@ -1078,12 +1106,13 @@ void GraphicsContext::setParameters(ShaderParameterPack &parameterPack)
for (int i = 0; i < parameterPack.textures().size(); ++i) {
const ShaderParameterPack::NamedTexture &namedTex = parameterPack.textures().at(i);
- Texture *t = manager->lookupResource<Texture, TextureManager>(namedTex.texId);
- if (t != nullptr) {
- int texUnit = activateTexture(TextureScopeMaterial, t);
- if (uniformValues.contains(namedTex.glslNameId)) {
+ // Given a Texture QNodeId, we retrieve the associated shared GLTexture
+ if (uniformValues.contains(namedTex.glslNameId)) {
+ GLTexture *t = manager->glTextureManager()->lookupResource(namedTex.texId);
+ if (t != nullptr) {
UniformValue &texUniform = uniformValues[namedTex.glslNameId];
Q_ASSERT(texUniform.valueType() == UniformValue::TextureValue);
+ const int texUnit = activateTexture(TextureScopeMaterial, t);
texUniform.data<UniformValue::Texture>()->textureId = texUnit;
}
}
@@ -1176,97 +1205,97 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
switch (type) {
case UniformType::Float:
- applyUniformHelper<UniformType::Float>(description.m_location, v);
+ applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, v);
break;
case UniformType::Vec2:
- applyUniformHelper<UniformType::Vec2>(description.m_location, v);
+ applyUniformHelper<UniformType::Vec2>(description.m_location, description.m_size, v);
break;
case UniformType::Vec3:
- applyUniformHelper<UniformType::Vec3>(description.m_location, v);
+ applyUniformHelper<UniformType::Vec3>(description.m_location, description.m_size, v);
break;
case UniformType::Vec4:
- applyUniformHelper<UniformType::Vec4>(description.m_location, v);
+ applyUniformHelper<UniformType::Vec4>(description.m_location, description.m_size, v);
break;
case UniformType::Double:
- applyUniformHelper<UniformType::Double>(description.m_location, v);
+ applyUniformHelper<UniformType::Double>(description.m_location, description.m_size, v);
break;
case UniformType::DVec2:
- applyUniformHelper<UniformType::DVec2>(description.m_location, v);
+ applyUniformHelper<UniformType::DVec2>(description.m_location, description.m_size, v);
break;
case UniformType::DVec3:
- applyUniformHelper<UniformType::DVec3>(description.m_location, v);
+ applyUniformHelper<UniformType::DVec3>(description.m_location, description.m_size, v);
break;
case UniformType::DVec4:
- applyUniformHelper<UniformType::DVec4>(description.m_location, v);
+ applyUniformHelper<UniformType::DVec4>(description.m_location, description.m_size, v);
break;
case UniformType::Sampler:
case UniformType::Int:
- applyUniformHelper<UniformType::Int>(description.m_location, v);
+ applyUniformHelper<UniformType::Int>(description.m_location, description.m_size, v);
break;
case UniformType::IVec2:
- applyUniformHelper<UniformType::IVec2>(description.m_location, v);
+ applyUniformHelper<UniformType::IVec2>(description.m_location, description.m_size, v);
break;
case UniformType::IVec3:
- applyUniformHelper<UniformType::IVec3>(description.m_location, v);
+ applyUniformHelper<UniformType::IVec3>(description.m_location, description.m_size, v);
break;
case UniformType::IVec4:
- applyUniformHelper<UniformType::IVec4>(description.m_location, v);
+ applyUniformHelper<UniformType::IVec4>(description.m_location, description.m_size, v);
break;
case UniformType::UInt:
- applyUniformHelper<UniformType::Int>(description.m_location, v);
+ applyUniformHelper<UniformType::Int>(description.m_location, description.m_size, v);
break;
case UniformType::UIVec2:
- applyUniformHelper<UniformType::IVec2>(description.m_location, v);
+ applyUniformHelper<UniformType::IVec2>(description.m_location, description.m_size, v);
break;
case UniformType::UIVec3:
- applyUniformHelper<UniformType::IVec3>(description.m_location, v);
+ applyUniformHelper<UniformType::IVec3>(description.m_location, description.m_size, v);
break;
case UniformType::UIVec4:
- applyUniformHelper<UniformType::IVec4>(description.m_location, v);
+ applyUniformHelper<UniformType::IVec4>(description.m_location, description.m_size, v);
break;
case UniformType::Bool:
- applyUniformHelper<UniformType::Bool>(description.m_location, v);
+ applyUniformHelper<UniformType::Bool>(description.m_location, description.m_size, v);
break;
case UniformType::BVec2:
- applyUniformHelper<UniformType::BVec2>(description.m_location, v);
+ applyUniformHelper<UniformType::BVec2>(description.m_location, description.m_size, v);
break;
case UniformType::BVec3:
- applyUniformHelper<UniformType::BVec3>(description.m_location, v);
+ applyUniformHelper<UniformType::BVec3>(description.m_location, description.m_size, v);
break;
case UniformType::BVec4:
- applyUniformHelper<UniformType::BVec4>(description.m_location, v);
+ applyUniformHelper<UniformType::BVec4>(description.m_location, description.m_size, v);
break;
case UniformType::Mat2:
- applyUniformHelper<UniformType::Mat2>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat2>(description.m_location, description.m_size, v);
break;
case UniformType::Mat3:
- applyUniformHelper<UniformType::Mat3>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat3>(description.m_location, description.m_size, v);
break;
case UniformType::Mat4:
- applyUniformHelper<UniformType::Mat4>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat4>(description.m_location, description.m_size, v);
break;
case UniformType::Mat2x3:
- applyUniformHelper<UniformType::Mat2x3>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat2x3>(description.m_location, description.m_size, v);
break;
case UniformType::Mat3x2:
- applyUniformHelper<UniformType::Mat3x2>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat3x2>(description.m_location, description.m_size, v);
break;
case UniformType::Mat2x4:
- applyUniformHelper<UniformType::Mat2x4>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat2x4>(description.m_location, description.m_size, v);
break;
case UniformType::Mat4x2:
- applyUniformHelper<UniformType::Mat4x2>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat4x2>(description.m_location, description.m_size, v);
break;
case UniformType::Mat3x4:
- applyUniformHelper<UniformType::Mat3x4>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat3x4>(description.m_location, description.m_size, v);
break;
case UniformType::Mat4x3:
- applyUniformHelper<UniformType::Mat4x3>(description.m_location, v);
+ applyUniformHelper<UniformType::Mat4x3>(description.m_location, description.m_size, v);
break;
default:
@@ -1305,7 +1334,7 @@ void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffe
VAOVertexAttribute attr;
attr.bufferHandle = glBufferHandle;
attr.bufferType = bufferType;
- attr.location = (location >= 0 ? location + i : location);
+ attr.location = location + i;
attr.dataType = attributeDataType;
attr.byteOffset = attribute->byteOffset() + (i * attrCount * typeSize);
attr.vertexSize = attribute->vertexSize() / attrCount;
@@ -1549,10 +1578,175 @@ GLint GraphicsContext::glDataTypeFromAttributeDataType(QAttribute::VertexBaseTyp
return GL_FLOAT;
}
+static void copyGLFramebufferDataToImage(QImage &img, const uchar *srcData, uint stride, uint width, uint height, QAbstractTexture::TextureFormat format)
+{
+ switch (format) {
+ case QAbstractTexture::RGBA32F:
+ {
+ uchar *srcScanline = (uchar *)srcData + stride * (height - 1);
+ for (uint i = 0; i < height; ++i) {
+ uchar *dstScanline = img.scanLine(i);
+ float *pSrc = (float*)srcScanline;
+ for (uint j = 0; j < width; j++) {
+ *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+2] / (1.0f + pSrc[4*j+2])));
+ *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+1] / (1.0f + pSrc[4*j+1])));
+ *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+0] / (1.0f + pSrc[4*j+0])));
+ *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+3], 1.0f));
+ }
+ srcScanline -= stride;
+ }
+ } break;
+ default:
+ {
+ uchar* srcScanline = (uchar *)srcData + stride * (height - 1);
+ for (uint i = 0; i < height; ++i) {
+ memcpy(img.scanLine(i), srcScanline, stride);
+ srcScanline -= stride;
+ }
+ } break;
+ }
+}
+
QImage GraphicsContext::readFramebuffer(QSize size)
{
- // todo: own implementation
- return qt_gl_read_framebuffer(size, true, true);
+ QImage img;
+ const unsigned int area = size.width() * size.height();
+ unsigned int bytes;
+ GLenum format, type;
+ QImage::Format imageFormat;
+ uint stride;
+
+#ifndef QT_OPENGL_ES_2
+ /* format value should match GL internalFormat */
+ GLenum internalFormat = m_renderTargetFormat;
+#endif
+
+ switch (m_renderTargetFormat) {
+ case QAbstractTexture::RGBAFormat:
+ case QAbstractTexture::RGBA8_SNorm:
+ case QAbstractTexture::RGBA8_UNorm:
+ case QAbstractTexture::RGBA8U:
+ case QAbstractTexture::SRGB8_Alpha8:
+#ifdef QT_OPENGL_ES_2
+ format = GL_RGBA;
+ imageFormat = QImage::Format_RGBA8888_Premultiplied;
+#else
+ format = GL_BGRA;
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ internalFormat = GL_RGBA8;
+#endif
+ type = GL_UNSIGNED_BYTE;
+ bytes = area * 4;
+ stride = size.width() * 4;
+ break;
+ case QAbstractTexture::SRGB8:
+ case QAbstractTexture::RGBFormat:
+ case QAbstractTexture::RGB8U:
+#ifdef QT_OPENGL_ES_2
+ format = GL_RGBA;
+ imageFormat = QImage::Format_RGBX8888;
+#else
+ format = GL_BGRA;
+ imageFormat = QImage::Format_RGB32;
+ internalFormat = GL_RGB8;
+#endif
+ type = GL_UNSIGNED_BYTE;
+ bytes = area * 4;
+ stride = size.width() * 4;
+ break;
+#ifndef QT_OPENGL_ES_2
+ case QAbstractTexture::RG11B10F:
+ bytes = area * 4;
+ format = GL_RGB;
+ type = GL_UNSIGNED_INT_10F_11F_11F_REV;
+ imageFormat = QImage::Format_RGB30;
+ stride = size.width() * 4;
+ break;
+ case QAbstractTexture::RGB10A2:
+ bytes = area * 4;
+ format = GL_RGBA;
+ type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ imageFormat = QImage::Format_A2BGR30_Premultiplied;
+ stride = size.width() * 4;
+ break;
+ case QAbstractTexture::R5G6B5:
+ bytes = area * 2;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT;
+ internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV;
+ imageFormat = QImage::Format_RGB16;
+ stride = size.width() * 2;
+ break;
+ case QAbstractTexture::RGBA16F:
+ case QAbstractTexture::RGBA16U:
+ case QAbstractTexture::RGBA32F:
+ case QAbstractTexture::RGBA32U:
+ bytes = area * 16;
+ format = GL_RGBA;
+ type = GL_FLOAT;
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ stride = size.width() * 16;
+ break;
+#endif
+ default:
+ // unsupported format
+ Q_UNREACHABLE();
+ return img;
+ }
+
+#ifndef QT_OPENGL_ES_2
+ GLint samples = 0;
+ m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples);
+ if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer))
+ return img;
+#endif
+
+ img = QImage(size.width(), size.height(), imageFormat);
+
+ QScopedArrayPointer<uchar> data(new uchar [bytes]);
+
+#ifndef QT_OPENGL_ES_2
+ if (samples > 0) {
+ // resolve multisample-framebuffer to renderbuffer and read pixels from it
+ GLuint fbo, rb;
+ QOpenGLFunctions *gl = m_gl->functions();
+ gl->glGenFramebuffers(1, &fbo);
+ gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+ gl->glGenRenderbuffers(1, &rb);
+ gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
+ gl->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, size.width(), size.height());
+ gl->glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
+
+ const GLenum status = gl->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ gl->glDeleteRenderbuffers(1, &rb);
+ gl->glDeleteFramebuffers(1, &fbo);
+ return img;
+ }
+
+ m_glHelper->blitFramebuffer(0, 0, size.width(), size.height(),
+ 0, 0, size.width(), size.height(),
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ gl->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+ gl->glReadPixels(0,0,size.width(), size.height(), format, type, data.data());
+
+ copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat);
+
+ gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
+ gl->glDeleteRenderbuffers(1, &rb);
+ gl->glBindFramebuffer(GL_FRAMEBUFFER, m_activeFBO);
+ gl->glDeleteFramebuffers(1, &fbo);
+ } else {
+#endif
+ // read pixels directly from framebuffer
+ m_gl->functions()->glReadPixels(0,0,size.width(), size.height(), format, type, data.data());
+ copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat);
+
+#ifndef QT_OPENGL_ES_2
+ }
+#endif
+
+ return img;
}
QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv)
diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h
index 647db9e47..9f7a0f972 100644
--- a/src/render/graphicshelpers/graphicscontext_p.h
+++ b/src/render/graphicshelpers/graphicscontext_p.h
@@ -84,7 +84,7 @@ class Renderer;
class GraphicsHelperInterface;
class RenderStateSet;
class Material;
-class Texture;
+class GLTexture;
class RenderCommand;
class RenderTarget;
class AttachmentPack;
@@ -100,7 +100,7 @@ enum TextureScope
typedef QPair<QString, int> NamedUniformLocation;
-class GraphicsContext
+class Q_AUTOTEST_EXPORT GraphicsContext
{
public:
GraphicsContext();
@@ -126,6 +126,7 @@ public:
void doneCurrent();
void activateGLHelper();
bool hasValidGLHelper() const;
+ bool isInitialized() const;
QOpenGLShaderProgram *createShaderProgram(Shader *shaderNode);
void loadShader(Shader* shader);
@@ -174,9 +175,9 @@ public:
* @param onUnit - option, specify the explicit unit to activate on
* @return - the unit the texture was activated on
*/
- int activateTexture(TextureScope scope, Texture* tex, int onUnit = -1);
+ int activateTexture(TextureScope scope, GLTexture* tex, int onUnit = -1);
- void deactivateTexture(Texture *tex);
+ void deactivateTexture(GLTexture *tex);
void setCurrentStateSet(RenderStateSet* ss);
RenderStateSet *currentStateSet() const;
@@ -237,7 +238,7 @@ private:
void decayTextureScores();
- GLint assignUnitForTexture(Texture* tex);
+ GLint assignUnitForTexture(GLTexture* tex);
void deactivateTexturesWithScope(TextureScope ts);
GraphicsHelperInterface *resolveHighestOpenGLFunctions();
@@ -247,6 +248,7 @@ private:
HGLBuffer createGLBufferFor(Buffer *buffer);
void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false);
bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type);
+ void resolveRenderTargetFormat();
bool m_initialized;
const unsigned int m_id;
@@ -262,23 +264,24 @@ private:
QHash<Qt3DCore::QNodeId, HGLBuffer> m_renderBufferHash;
QHash<Qt3DCore::QNodeId, GLuint> m_renderTargets;
QHash<GLuint, QSize> m_renderTargetsSize;
+ QAbstractTexture::TextureFormat m_renderTargetFormat;
QHash<QSurface *, GraphicsHelperInterface*> m_glHelpers;
// active textures, indexed by texture unit
- QVector<uint> m_activeTextures;
- QBitArray m_pinnedTextureUnits;
- QVector<TextureScope> m_textureScopes;
+ struct ActiveTexture {
+ GLTexture *texture = nullptr;
+ int score = 0;
+ TextureScope scope = TextureScopeMaterial;
+ bool pinned = false;
+ };
+ QVector<ActiveTexture> m_activeTextures;
// cache some current state, to make sure we don't issue unnecessary GL calls
int m_currClearStencilValue;
float m_currClearDepthValue;
QColor m_currClearColorValue;
- // recency score for all render-textures we've seen. Higher scores
- // mean more recently used.
- QHash<uint, int> m_textureScores;
-
Material* m_material;
QRectF m_viewport;
GLuint m_activeFBO;
@@ -319,7 +322,7 @@ private:
void applyUniform(const ShaderUniform &description, const UniformValue &v);
template<UniformType>
- void applyUniformHelper(int, const UniformValue &) const
+ void applyUniformHelper(int, int, const UniformValue &) const
{
Q_ASSERT_X(false, Q_FUNC_INFO, "Uniform: Didn't provide specialized apply() implementation");
}
@@ -327,13 +330,13 @@ private:
#define QT3D_UNIFORM_TYPE_PROTO(UniformTypeEnum, BaseType, Func) \
template<> \
-void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, const UniformValue &value) const;
+void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, int count, const UniformValue &value) const;
#define QT3D_UNIFORM_TYPE_IMPL(UniformTypeEnum, BaseType, Func) \
template<> \
- void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, const UniformValue &value) const \
+ void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, int count, const UniformValue &value) const \
{ \
- m_glHelper->Func(location, 1, value.constData<BaseType>()); \
+ m_glHelper->Func(location, count, value.constData<BaseType>()); \
}
diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp
index 3a268cb5f..1335b250f 100644
--- a/src/render/graphicshelpers/graphicshelperes2.cpp
+++ b/src/render/graphicshelpers/graphicshelperes2.cpp
@@ -334,8 +334,14 @@ void GraphicsHelperES2::bindFrameBufferAttachment(QOpenGLTexture *texture, const
else
qCritical() << "Unsupported FBO attachment OpenGL ES 2.0";
+ const QOpenGLTexture::Target target = texture->target();
+
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) {
+ qWarning() << "OpenGL ES 2.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO";
+ return;
+ }
+
texture->bind();
- QOpenGLTexture::Target target = texture->target();
if (target == QOpenGLTexture::Target2D)
m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel);
else if (target == QOpenGLTexture::TargetCubeMap)
@@ -701,6 +707,21 @@ UniformType GraphicsHelperES2::uniformTypeFromGLType(GLenum type)
}
}
+void GraphicsHelperES2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ Q_UNUSED(srcX0);
+ Q_UNUSED(srcX1);
+ Q_UNUSED(srcY0);
+ Q_UNUSED(srcY1);
+ Q_UNUSED(dstX0);
+ Q_UNUSED(dstX1);
+ Q_UNUSED(dstY0);
+ Q_UNUSED(dstY1);
+ Q_UNUSED(mask);
+ Q_UNUSED(filter);
+ qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)";
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h
index 52d68f691..17249ef23 100644
--- a/src/render/graphicshelpers/graphicshelperes2_p.h
+++ b/src/render/graphicshelpers/graphicshelperes2_p.h
@@ -77,6 +77,7 @@ public:
void blendEquation(GLenum mode) Q_DECL_OVERRIDE;
void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE;
void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE;
GLuint boundFrameBufferObject() Q_DECL_OVERRIDE;
void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE;
bool checkFrameBufferComplete() Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelperes3.cpp b/src/render/graphicshelpers/graphicshelperes3.cpp
index eb492e98d..fcd0a2ad2 100644
--- a/src/render/graphicshelpers/graphicshelperes3.cpp
+++ b/src/render/graphicshelpers/graphicshelperes3.cpp
@@ -119,8 +119,14 @@ void GraphicsHelperES3::bindFrameBufferAttachment(QOpenGLTexture *texture, const
else
qCritical() << "Unsupported FBO attachment OpenGL ES 3.0";
+ const QOpenGLTexture::Target target = texture->target();
+
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) {
+ qWarning() << "OpenGL ES 3.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO";
+ return;
+ }
+
texture->bind();
- QOpenGLTexture::Target target = texture->target();
if (target == QOpenGLTexture::Target2D)
m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel);
else if (target == QOpenGLTexture::TargetCubeMap)
@@ -135,6 +141,7 @@ bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature
switch (feature) {
case RenderBufferDimensionRetrieval:
case MRT:
+ case BlitFramebuffer:
return true;
default:
return false;
@@ -164,6 +171,11 @@ UniformType GraphicsHelperES3::uniformTypeFromGLType(GLenum glType)
}
}
+void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelperes3_p.h b/src/render/graphicshelpers/graphicshelperes3_p.h
index 2844c140d..7520328d4 100644
--- a/src/render/graphicshelpers/graphicshelperes3_p.h
+++ b/src/render/graphicshelpers/graphicshelperes3_p.h
@@ -67,6 +67,7 @@ public:
// QGraphicHelperInterface interface
virtual void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ virtual void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE;
virtual void drawBuffers(GLsizei n, const int *bufs) Q_DECL_OVERRIDE;
virtual void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) Q_DECL_OVERRIDE;
virtual void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp
index 1315b4ab8..8ee0c020b 100644
--- a/src/render/graphicshelpers/graphicshelpergl2.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl2.cpp
@@ -316,8 +316,14 @@ void GraphicsHelperGL2::bindFrameBufferAttachment(QOpenGLTexture *texture, const
else
qCritical() << "DepthStencil Attachment not supported on OpenGL 2.0";
+ const QOpenGLTexture::Target target = texture->target();
+
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) {
+ qWarning() << "OpenGL 2.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO";
+ return;
+ }
+
texture->bind();
- QOpenGLTexture::Target target = texture->target();
if (target == QOpenGLTexture::Target3D)
m_fboFuncs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
else if (target == QOpenGLTexture::TargetCubeMap)
@@ -731,6 +737,21 @@ UniformType GraphicsHelperGL2::uniformTypeFromGLType(GLenum type)
}
}
+void GraphicsHelperGL2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ Q_UNUSED(srcX0);
+ Q_UNUSED(srcX1);
+ Q_UNUSED(srcY0);
+ Q_UNUSED(srcY1);
+ Q_UNUSED(dstX0);
+ Q_UNUSED(dstX1);
+ Q_UNUSED(dstY0);
+ Q_UNUSED(dstY1);
+ Q_UNUSED(mask);
+ Q_UNUSED(filter);
+ qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)";
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelpergl2_p.h b/src/render/graphicshelpers/graphicshelpergl2_p.h
index 0352c77d3..cfd90eab7 100644
--- a/src/render/graphicshelpers/graphicshelpergl2_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl2_p.h
@@ -79,6 +79,7 @@ public:
void blendEquation(GLenum mode) Q_DECL_OVERRIDE;
void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE;
void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE;
GLuint boundFrameBufferObject() Q_DECL_OVERRIDE;
void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE;
bool checkFrameBufferComplete() Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
index 3cb0dd7e5..47e9414ca 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_2.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
@@ -391,6 +391,7 @@ bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature featu
case RenderBufferDimensionRetrieval:
case TextureDimensionRetrieval:
case BindableFragmentOutputs:
+ case BlitFramebuffer:
return true;
case Tessellation:
return !m_tessFuncs.isNull();
@@ -1064,6 +1065,11 @@ UniformType GraphicsHelperGL3_2::uniformTypeFromGLType(GLenum type)
}
}
+void GraphicsHelperGL3_2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
index b6a4b0c35..1ee716a76 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_2_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
@@ -81,6 +81,7 @@ public:
void blendEquation(GLenum mode) Q_DECL_OVERRIDE;
void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE;
void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE;
GLuint boundFrameBufferObject() Q_DECL_OVERRIDE;
void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE;
bool checkFrameBufferComplete() Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp
index 53b89bdef..7f0223af2 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp
@@ -372,7 +372,7 @@ void GraphicsHelperGL3_3::bindFrameBufferAttachment(QOpenGLTexture *texture, con
m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
else if (target == QOpenGLTexture::TargetCubeMapArray)
m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
- else if (target == QOpenGLTexture::TargetCubeMap)
+ else if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces)
m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
else
m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
@@ -388,6 +388,7 @@ bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature featu
case RenderBufferDimensionRetrieval:
case TextureDimensionRetrieval:
case BindableFragmentOutputs:
+ case BlitFramebuffer:
return true;
case Tessellation:
return !m_tessFuncs.isNull();
@@ -1061,6 +1062,11 @@ UniformType GraphicsHelperGL3_3::uniformTypeFromGLType(GLenum type)
}
}
+void GraphicsHelperGL3_3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/graphicshelpers/graphicshelpergl3_3_p.h
index bbea8806a..b2ea8abca 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_3_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_3_p.h
@@ -81,6 +81,7 @@ public:
void blendEquation(GLenum mode) Q_DECL_OVERRIDE;
void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE;
void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE;
GLuint boundFrameBufferObject() Q_DECL_OVERRIDE;
void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE;
bool checkFrameBufferComplete() Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp
index 230b02a63..81a6846e0 100644
--- a/src/render/graphicshelpers/graphicshelpergl4.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl4.cpp
@@ -566,7 +566,7 @@ void GraphicsHelperGL4::bindFrameBufferAttachment(QOpenGLTexture *texture, const
m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
else if (target == QOpenGLTexture::TargetCubeMapArray)
m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
- else if (target == QOpenGLTexture::TargetCubeMap)
+ else if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces)
m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
else
m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
@@ -586,6 +586,7 @@ bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature
case ShaderStorageObject:
case Compute:
case DrawBuffersBlend:
+ case BlitFramebuffer:
return true;
default:
return false;
@@ -1049,6 +1050,11 @@ void GraphicsHelperGL4::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
m_funcs->glDispatchCompute(wx, wy, wz);
}
+void GraphicsHelperGL4::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h
index e596b185c..1f2111419 100644
--- a/src/render/graphicshelpers/graphicshelpergl4_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl4_p.h
@@ -79,6 +79,7 @@ public:
void blendEquation(GLenum mode) Q_DECL_OVERRIDE;
void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) Q_DECL_OVERRIDE;
void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) Q_DECL_OVERRIDE;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) Q_DECL_OVERRIDE;
GLuint boundFrameBufferObject() Q_DECL_OVERRIDE;
void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE;
bool checkFrameBufferComplete() Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelperinterface_p.h b/src/render/graphicshelpers/graphicshelperinterface_p.h
index 1a7199a2c..a22ea0274 100644
--- a/src/render/graphicshelpers/graphicshelperinterface_p.h
+++ b/src/render/graphicshelpers/graphicshelperinterface_p.h
@@ -77,7 +77,8 @@ public:
TextureDimensionRetrieval,
ShaderStorageObject,
Compute,
- DrawBuffersBlend
+ DrawBuffersBlend,
+ BlitFramebuffer
};
virtual ~GraphicsHelperInterface() {}
@@ -91,6 +92,7 @@ public:
virtual void blendEquation(GLenum mode) = 0;
virtual void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) = 0;
virtual void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) = 0;
+ virtual void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) = 0;
virtual GLuint boundFrameBufferObject() = 0;
virtual void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) = 0;
virtual bool checkFrameBufferComplete() = 0;
diff --git a/src/render/io/objloader.cpp b/src/render/io/objloader.cpp
index 3ceab1306..fedb2a0ab 100644
--- a/src/render/io/objloader.cpp
+++ b/src/render/io/objloader.cpp
@@ -60,10 +60,18 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+struct Entry
+{
+ int start;
+ int size;
+};
+QT3D_DECLARE_TYPEINFO(Qt3DRender, Entry, Q_PRIMITIVE_TYPE)
+
/*
* A helper class to split a QByteArray and access its sections without
* additional memory allocations.
*/
+
class ByteArraySplitter
{
public:
@@ -118,17 +126,10 @@ public:
return ByteArraySplitter(m_input + m_entries[index].start, m_input + m_entries[index].start + m_entries[index].size, delimiter, splitBehavior);
}
- struct Entry
- {
- int start;
- int size;
- };
-
private:
QVarLengthArray<Entry, 16> m_entries;
const char *m_input;
};
-QT3D_DECLARE_TYPEINFO(Qt3DRender, ByteArraySplitter::Entry, Q_PRIMITIVE_TYPE)
inline uint qHash(const FaceIndices &faceIndices)
{
diff --git a/src/render/io/qsceneimporter_p.h b/src/render/io/qsceneimporter_p.h
index 6198f65fd..e76eb8780 100644
--- a/src/render/io/qsceneimporter_p.h
+++ b/src/render/io/qsceneimporter_p.h
@@ -80,7 +80,7 @@ public:
Loaded,
Error
};
- Q_ENUM(ParserStatus)
+ Q_ENUM(ParserStatus) // LCOV_EXCL_LINE
QSceneImporter();
virtual ~QSceneImporter();
diff --git a/src/render/io/qsceneloader.h b/src/render/io/qsceneloader.h
index c8eb3c8f6..76f8c4d80 100644
--- a/src/render/io/qsceneloader.h
+++ b/src/render/io/qsceneloader.h
@@ -67,7 +67,7 @@ public:
Ready,
Error
};
- Q_ENUM(Status)
+ Q_ENUM(Status) // LCOV_EXCL_LINE
enum ComponentType {
UnknownComponent = 0,
diff --git a/src/render/jobs/filtercompatibletechniquejob.cpp b/src/render/jobs/filtercompatibletechniquejob.cpp
new file mode 100644
index 000000000..362e4088f
--- /dev/null
+++ b/src/render/jobs/filtercompatibletechniquejob.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "filtercompatibletechniquejob_p.h"
+#include <Qt3DRender/private/techniquemanager_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/graphicscontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+FilterCompatibleTechniqueJob::FilterCompatibleTechniqueJob()
+ : m_manager(nullptr)
+ , m_renderer(nullptr)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::FilterCompatibleTechniques, 0);
+}
+
+void FilterCompatibleTechniqueJob::setManager(TechniqueManager *manager)
+{
+ m_manager = manager;
+}
+
+TechniqueManager *FilterCompatibleTechniqueJob::manager() const
+{
+ return m_manager;
+}
+
+void FilterCompatibleTechniqueJob::setRenderer(Renderer *renderer)
+{
+ m_renderer = renderer;
+}
+
+Renderer *FilterCompatibleTechniqueJob::renderer() const
+{
+ return m_renderer;
+}
+
+void FilterCompatibleTechniqueJob::run()
+{
+ Q_ASSERT(m_manager != nullptr && m_renderer != nullptr);
+
+ if (m_renderer->isRunning() && m_renderer->graphicsContext()->isInitialized()) {
+ const QVector<Qt3DCore::QNodeId> dirtyTechniqueIds = m_manager->takeDirtyTechniques();
+ for (const Qt3DCore::QNodeId techniqueId : dirtyTechniqueIds) {
+ Technique *technique = m_manager->lookupResource(techniqueId);
+ if (Q_LIKELY(technique != nullptr))
+ technique->setCompatibleWithRenderer((*m_renderer->contextInfo() == *technique->graphicsApiFilter()));
+ }
+ }
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/filtercompatibletechniquejob_p.h b/src/render/jobs/filtercompatibletechniquejob_p.h
new file mode 100644
index 000000000..6040149c5
--- /dev/null
+++ b/src/render/jobs/filtercompatibletechniquejob_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_FILTERCOMPATIBLETECHNIQUEJOB_H
+#define QT3DRENDER_RENDER_FILTERCOMPATIBLETECHNIQUEJOB_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
+
+#include <QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class TechniqueManager;
+class Renderer;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT FilterCompatibleTechniqueJob : public Qt3DCore::QAspectJob
+{
+public:
+ FilterCompatibleTechniqueJob();
+
+ void setManager(TechniqueManager *managers);
+ TechniqueManager *manager() const;
+
+ void setRenderer(Renderer *renderer);
+ Renderer *renderer() const;
+
+ void run() Q_DECL_OVERRIDE;
+
+private:
+ TechniqueManager *m_manager;
+ Renderer *m_renderer;
+};
+
+typedef QSharedPointer<FilterCompatibleTechniqueJob> FilterCompatibleTechniqueJobPtr;
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_FILTERCOMPATIBLETECHNIQUEJOB_H
diff --git a/src/render/jobs/filterlayerentityjob_p.h b/src/render/jobs/filterlayerentityjob_p.h
index 26084e44a..50b988ce4 100644
--- a/src/render/jobs/filterlayerentityjob_p.h
+++ b/src/render/jobs/filterlayerentityjob_p.h
@@ -53,6 +53,7 @@
#include <Qt3DCore/qaspectjob.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -63,7 +64,7 @@ namespace Render {
class Entity;
class NodeManagers;
-class Q_AUTOTEST_EXPORT FilterLayerEntityJob : public Qt3DCore::QAspectJob
+class QT3DRENDERSHARED_PRIVATE_EXPORT FilterLayerEntityJob : public Qt3DCore::QAspectJob
{
public:
FilterLayerEntityJob();
@@ -73,6 +74,9 @@ public:
inline void setHasLayerFilter(bool hasLayerFilter) Q_DECL_NOEXCEPT { m_hasLayerFilter = hasLayerFilter; }
inline QVector<Entity *> filteredEntities() const Q_DECL_NOEXCEPT { return m_filteredEntities; }
+ inline bool hasLayerFilter() const Q_DECL_NOTHROW { return m_hasLayerFilter; }
+ inline Qt3DCore::QNodeIdVector layers() const { return m_layerIds; }
+
// QAspectJob interface
void run() Q_DECL_FINAL;
diff --git a/src/render/jobs/framecleanupjob.cpp b/src/render/jobs/framecleanupjob.cpp
index ab3a18223..3105f547c 100644
--- a/src/render/jobs/framecleanupjob.cpp
+++ b/src/render/jobs/framecleanupjob.cpp
@@ -73,10 +73,6 @@ void FrameCleanupJob::run()
// mark each ShaderData clean
ShaderData::cleanup(m_managers);
- // Cleanup texture handles
- TextureDataManager *textureDataManager = m_managers->textureDataManager();
- textureDataManager->cleanup();
-
// Debug bounding volume debug
updateBoundingVolumesDebug(m_root);
}
diff --git a/src/render/jobs/frustumcullingjob_p.h b/src/render/jobs/frustumcullingjob_p.h
index cb4b38b2b..ebd870937 100644
--- a/src/render/jobs/frustumcullingjob_p.h
+++ b/src/render/jobs/frustumcullingjob_p.h
@@ -71,7 +71,9 @@ public:
inline void setRoot(Entity *root) Q_DECL_NOTHROW { m_root = root; }
inline void setActive(bool active) Q_DECL_NOTHROW { m_active = active; }
+ inline bool isActive() const Q_DECL_NOTHROW { return m_active; }
inline void setViewProjection(const QMatrix4x4 &viewProjection) Q_DECL_NOTHROW { m_viewProjection = viewProjection; }
+ inline QMatrix4x4 viewProjection() const Q_DECL_NOTHROW { return m_viewProjection; }
QVector<Entity *> visibleEntities() const Q_DECL_NOTHROW { return m_visibleEntities; }
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index a5a8bb8e2..f45f5639e 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -64,7 +64,7 @@ namespace JobTypes {
enum JobType {
LoadBuffer = 1,
FrameCleanup,
- FramePreparation,
+ UpdateShaderDataTransform,
CalcBoundingVolume,
CalcTriangleVolume,
LoadGeometry,
@@ -92,7 +92,9 @@ namespace JobTypes {
SyncRenderViewInitialization,
SyncRenderViewCommandBuilder,
SyncFrustumCulling,
- ClearBufferDrawIndex
+ ClearBufferDrawIndex,
+ UpdateMeshTriangleList,
+ FilterCompatibleTechniques
};
} // JobTypes
diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri
index 9ad8f9bc0..e8686a28e 100644
--- a/src/render/jobs/jobs.pri
+++ b/src/render/jobs/jobs.pri
@@ -5,7 +5,6 @@ HEADERS += \
$$PWD/renderviewjobutils_p.h \
$$PWD/loadscenejob_p.h \
$$PWD/framecleanupjob_p.h \
- $$PWD/framepreparationjob_p.h \
$$PWD/loadtexturedatajob_p.h \
$$PWD/loadbufferjob_p.h \
$$PWD/loadgeometryjob_p.h \
@@ -23,14 +22,17 @@ HEADERS += \
$$PWD/lightgatherer_p.h \
$$PWD/expandboundingvolumejob_p.h \
$$PWD/updateworldboundingvolumejob_p.h \
- $$PWD/sendrendercapturejob_p.h
+ $$PWD/sendrendercapturejob_p.h \
+ $$PWD/updateshaderdatatransformjob_p.h \
+ $$PWD/updatemeshtrianglelistjob_p.h \
+ $$PWD/pickboundingvolumeutils_p.h \
+ $$PWD/filtercompatibletechniquejob_p.h
SOURCES += \
$$PWD/updateworldtransformjob.cpp \
$$PWD/renderviewjobutils.cpp \
$$PWD/loadscenejob.cpp \
$$PWD/framecleanupjob.cpp \
- $$PWD/framepreparationjob.cpp \
$$PWD/loadtexturedatajob.cpp \
$$PWD/loadbufferjob.cpp \
$$PWD/loadgeometryjob.cpp \
@@ -45,4 +47,8 @@ SOURCES += \
$$PWD/lightgatherer.cpp \
$$PWD/expandboundingvolumejob.cpp \
$$PWD/updateworldboundingvolumejob.cpp \
- $$PWD/sendrendercapturejob.cpp
+ $$PWD/sendrendercapturejob.cpp \
+ $$PWD/updateshaderdatatransformjob.cpp \
+ $$PWD/updatemeshtrianglelistjob.cpp \
+ $$PWD/pickboundingvolumeutils.cpp \
+ $$PWD/filtercompatibletechniquejob.cpp
diff --git a/src/render/jobs/loadgeometryjob_p.h b/src/render/jobs/loadgeometryjob_p.h
index bc9358ad8..2b0331d1c 100644
--- a/src/render/jobs/loadgeometryjob_p.h
+++ b/src/render/jobs/loadgeometryjob_p.h
@@ -63,7 +63,7 @@ namespace Render {
class NodeManagers;
-class LoadGeometryJob : public Qt3DCore::QAspectJob
+class Q_AUTOTEST_EXPORT LoadGeometryJob : public Qt3DCore::QAspectJob
{
public:
explicit LoadGeometryJob(const HGeometryRenderer &handle);
diff --git a/src/render/jobs/loadtexturedatajob.cpp b/src/render/jobs/loadtexturedatajob.cpp
index b8663e4a7..55232d74f 100644
--- a/src/render/jobs/loadtexturedatajob.cpp
+++ b/src/render/jobs/loadtexturedatajob.cpp
@@ -39,12 +39,8 @@
#include "loadtexturedatajob_p.h"
#include <Qt3DRender/private/nodemanagers_p.h>
-#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/texturedatamanager_p.h>
-#include <Qt3DRender/private/qtextureimage_p.h>
#include <Qt3DRender/qtextureimagedata.h>
-#include <Qt3DRender/qtexturedata.h>
-#include <QThread>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/qtextureimagedata_p.h>
@@ -53,87 +49,16 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-namespace {
-
-typedef QPair<HTextureData, QTextureImageData *> HandleDataPair;
-
-HandleDataPair textureDataFromGenerator(TextureDataManager *textureDataManager,
- QTextureImageDataGeneratorPtr generator)
+LoadTextureDataJob::LoadTextureDataJob(const QTextureGeneratorPtr &texGen)
+ : m_texGen(texGen)
+ , m_imgDataGen(nullptr)
{
- HTextureData textureDataHandle;
- QTextureImageData *data = nullptr;
-
- QMutexLocker locker(textureDataManager->mutex());
- // We don't want to take the chance of having two jobs uploading the same functor
- // because of sync issues
-
- textureDataHandle = textureDataManager->textureDataFromFunctor(generator);
-
- // Texture data handle isn't null == there's already a matching TextureData
- if (!textureDataHandle.isNull()) {
- data = textureDataManager->data(textureDataHandle);
- } else {
- // Texture data is null -> we need to generate it
- QTextureImageDataPtr dataPtr = generator->operator ()();
- if (dataPtr.isNull()) {
- qCDebug(Jobs) << Q_FUNC_INFO << "Texture has no raw data";
- } else {
- // Save the QTextureImageDataPtr with it's functor as a key
- textureDataHandle = textureDataManager->acquire();
- data = textureDataManager->data(textureDataHandle);
- *data = *(dataPtr.data());
- textureDataManager->addTextureDataForFunctor(textureDataHandle, generator);
- }
- }
-
- return qMakePair(textureDataHandle, data);
-}
-
-void createTextureFromGenerator(TextureDataManager *textureDataManager,
- Texture *texture)
-{
- QTextureGeneratorPtr generator = texture->dataGenerator();
- const QTextureDataPtr generatedData = generator->operator ()();
-
- // TO DO set the status of the texture based on the status of the functor
-
- // Use the first QTexImageData loaded to determine the target / mipmaps
- // if not specified
-
- if (texture->target() != QAbstractTexture::TargetAutomatic)
- qWarning() << "When a texture provides a generator, it's target is expected to be TargetAutomatic";
-
- texture->setTarget(static_cast<QAbstractTexture::Target>(generatedData->target()));
- texture->setSize(generatedData->width(), generatedData->height(), generatedData->depth());
- texture->setLayers(generatedData->layers());
- texture->setFormat(generatedData->format());
-
- // Note: These texture data handles aren't associated with a QTextureImageDataGenerator
- // and will therefore be destroyed when the Texture element is destroyed or cleaned up
- const QVector<QTextureImageDataPtr> imageData = generatedData->imageData();
-
- if (imageData.size() > 0) {
- QMutexLocker locker(textureDataManager->mutex());
- // We don't want to take the chance of having two jobs uploading the same functor
- // because of sync issues
-
- // Set the mips level based on the first image if autoMipMapGeneration is disabled
- if (!texture->isAutoMipMapGenerationEnabled())
- texture->setMipLevels(imageData.first()->mipLevels());
-
- for (QTextureImageDataPtr dataPtr : imageData) {
- HTextureData textureDataHandle = textureDataManager->acquire();
- QTextureImageData *data = textureDataManager->data(textureDataHandle);
- *data = *(dataPtr.data());
- texture->addTextureDataHandle(textureDataHandle);
- }
- }
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadTextureData, 0);
}
-} // anonymous
-
-LoadTextureDataJob::LoadTextureDataJob(Qt3DCore::QNodeId textureId)
- : m_textureId(textureId)
+LoadTextureDataJob::LoadTextureDataJob(const QTextureImageDataGeneratorPtr &imgDataGen)
+ : m_texGen(nullptr)
+ , m_imgDataGen(imgDataGen)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadTextureData, 0);
}
@@ -144,73 +69,13 @@ LoadTextureDataJob::~LoadTextureDataJob()
void LoadTextureDataJob::run()
{
- qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread();
-
- Texture *txt = m_manager->textureManager()->lookupResource(m_textureId);
- TextureDataManager *textureDataManager = m_manager->manager<QTextureImageData, TextureDataManager>();
-
- if (txt != nullptr) {
- // We need to clear the TextureData handles of the texture in case it was previously
- // loaded with a different functor
- txt->releaseTextureDataHandles();
-
- // If the texture has a functor we used it to generate embedded TextureImages
- if (txt->dataGenerator())
- createTextureFromGenerator(textureDataManager, txt);
-
- // Load update each TextureImage
- const auto texImgHandles = txt->textureImages();
- for (HTextureImage texImgHandle : texImgHandles) {
- TextureImage *texImg = m_manager->textureImageManager()->data(texImgHandle);
- if (texImg != nullptr && texImg->isDirty() && !texImg->dataGenerator().isNull()) {
- QTextureImageDataGeneratorPtr generator = texImg->dataGenerator();
-
- QPair<HTextureData, QTextureImageData *> handleData = textureDataFromGenerator(textureDataManager, generator);
-
- // If using QTextureImage, notify the frontend of the change in status
- const QImageTextureDataFunctor *imageGenerator = functor_cast<QImageTextureDataFunctor>(generator.data());
- if (imageGenerator)
- texImg->setStatus(imageGenerator->status());
-
- HTextureData textureDataHandle = handleData.first;
- QTextureImageData *data = handleData.second;
-
- // XXX released textureDataManager mutex, do we have a race here?
-
- // Update HTextureImage Functor to release TextureData when needed
- TextureDataManager *textureDataManager = m_manager->manager<QTextureImageData, TextureDataManager>();
- textureDataManager->assignFunctorToTextureImage(generator, texImgHandle);
-
- // Set texture size of texture if the first layer / level / face has a valid size
- // otherwise assume the size was set on the texture itself
- if (texImg->layer() == 0 && texImg->mipLevel() == 0 &&
- texImg->face() == QAbstractTexture::CubeMapPositiveX) {
-
- if (data == nullptr) {
- qWarning() << "Texture data is null, texture data failed to load";
- } else {
- // Set the size of the texture based on the layer 0 / level 0
- // if the functor provides something valid. Otherwise we assume the texture
- // already has the correct size
- if (data->width() != -1 && data->height() != -1 && data->depth() != -1) {
- txt->setSize(data->width(), data->height(), data->depth());
- }
- // Set the format of the texture if the texture format is set to Automatic
- if (txt->format() == QAbstractTexture::Automatic) {
- txt->setFormat(static_cast<QAbstractTexture::TextureFormat>(data->format()));
- }
- }
- }
- // Set the textureDataHandle on the texture image
- // Note: this internally updates the DNA of the TextureImage
- texImg->setTextureDataHandle(textureDataHandle);
- if (data)
- texImg->updateDNA(::qHash(QTextureImageDataPrivate::get(data)->m_data));
- }
- }
- // Tell the renderer to reload/upload to GPU the TextureImage for the Texture
- // next frame
- txt->requestTextureDataUpdate();
+ if (m_texGen) {
+ QTextureDataPtr texData = (*m_texGen)();
+ m_manager->textureDataManager()->assignData(m_texGen, texData);
+ }
+ if (m_imgDataGen) {
+ QTextureImageDataPtr imgData = (*m_imgDataGen)();
+ m_manager->textureImageDataManager()->assignData(m_imgDataGen, imgData);
}
}
diff --git a/src/render/jobs/loadtexturedatajob_p.h b/src/render/jobs/loadtexturedatajob_p.h
index db2521354..36fdd950b 100644
--- a/src/render/jobs/loadtexturedatajob_p.h
+++ b/src/render/jobs/loadtexturedatajob_p.h
@@ -53,7 +53,8 @@
#include <Qt3DCore/qnodeid.h>
#include <Qt3DCore/qaspectjob.h>
-#include <Qt3DRender/qtextureimage.h>
+#include <Qt3DRender/qtexturegenerator.h>
+#include <Qt3DRender/qtextureimagedatagenerator.h>
QT_BEGIN_NAMESPACE
@@ -66,15 +67,19 @@ class NodeManagers;
class LoadTextureDataJob : public Qt3DCore::QAspectJob
{
public:
- explicit LoadTextureDataJob(Qt3DCore::QNodeId textureId);
+ LoadTextureDataJob(const QTextureGeneratorPtr &texGen);
+ LoadTextureDataJob(const QTextureImageDataGeneratorPtr &imgDataGen);
~LoadTextureDataJob();
+
inline void setNodeManagers(NodeManagers *manager) { m_manager = manager; }
protected:
void run() Q_DECL_FINAL;
private:
- Qt3DCore::QNodeId m_textureId;
+ QTextureGeneratorPtr m_texGen;
+ QTextureImageDataGeneratorPtr m_imgDataGen;
+
NodeManagers *m_manager;
};
diff --git a/src/render/jobs/materialparametergathererjob_p.h b/src/render/jobs/materialparametergathererjob_p.h
index 63b4d2946..d14e096d8 100644
--- a/src/render/jobs/materialparametergathererjob_p.h
+++ b/src/render/jobs/materialparametergathererjob_p.h
@@ -81,6 +81,9 @@ public:
inline QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> &materialToPassAndParameter() Q_DECL_NOTHROW { return m_parameters; }
inline void setHandles(const QVector<HMaterial> &handles) Q_DECL_NOTHROW { m_handles = handles; }
+ inline TechniqueFilter *techniqueFilter() const Q_DECL_NOTHROW { return m_techniqueFilter; }
+ inline RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_renderPassFilter; }
+
void run() Q_DECL_FINAL;
private:
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 19f1d2b1c..7aa2be759 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -38,28 +38,16 @@
****************************************************************************/
#include "pickboundingvolumejob_p.h"
-#include "qpickevent.h"
#include "qpicktriangleevent.h"
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
-#include <Qt3DRender/private/framegraphnode_p.h>
-#include <Qt3DRender/private/cameralens_p.h>
-#include <Qt3DRender/private/cameraselectornode_p.h>
-#include <Qt3DRender/private/viewportnode_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/objectpicker_p.h>
#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
-#include <Qt3DRender/private/trianglesvisitor_p.h>
-#include <Qt3DRender/private/qraycastingservice_p.h>
-#include <Qt3DRender/private/rendersurfaceselector_p.h>
+
#include <Qt3DRender/private/rendersettings_p.h>
-#include <Qt3DRender/private/rendersurfaceselector_p.h>
-#include <Qt3DRender/private/qray3d_p.h>
#include <Qt3DRender/qgeometryrenderer.h>
-#include <Qt3DCore/private/qservicelocator_p.h>
-#include <QSurface>
#include <Qt3DRender/private/job_common_p.h>
QT_BEGIN_NAMESPACE
@@ -68,335 +56,76 @@ namespace Qt3DRender {
namespace Render {
-struct ViewportCameraAreaTriplet
-{
- Qt3DCore::QNodeId cameraId;
- QRectF viewport;
- QSize area;
-};
-QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, ViewportCameraAreaTriplet, Q_PRIMITIVE_TYPE)
-
namespace {
-class ViewportCameraAreaGatherer
+void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
{
-private:
- QVector<FrameGraphNode *> m_leaves;
-
- void visit(FrameGraphNode *node)
- {
- const auto children = node->children();
- for (Render::FrameGraphNode *n : children)
- visit(n);
- if (node->childrenIds().empty())
- m_leaves.push_back(node);
+ switch (event.button()) {
+ case Qt::LeftButton:
+ eventButton = QPickEvent::LeftButton;
+ break;
+ case Qt::RightButton:
+ eventButton = QPickEvent::RightButton;
+ break;
+ case Qt::MiddleButton:
+ eventButton = QPickEvent::MiddleButton;
+ break;
+ case Qt::BackButton:
+ eventButton = QPickEvent::BackButton;
+ break;
+ default:
+ break;
}
- ViewportCameraAreaTriplet gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const
- {
- ViewportCameraAreaTriplet vca;
- vca.viewport = QRectF(0.0f, 0.0f, 1.0f, 1.0f);
-
- while (node) {
- if (node->isEnabled()) {
- switch (node->nodeType()) {
- case FrameGraphNode::CameraSelector:
- vca.cameraId = static_cast<const CameraSelector *>(node)->cameraUuid();
- break;
- case FrameGraphNode::Viewport:
- vca.viewport = computeViewport(vca.viewport, static_cast<const ViewportNode *>(node));
- break;
- case FrameGraphNode::Surface:
- vca.area = static_cast<const RenderSurfaceSelector *>(node)->renderTargetSize();
- break;
- default:
- break;
- }
- }
- node = node->parent();
- }
- return vca;
- }
-
- bool isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const
- {
- for (const ViewportCameraAreaTriplet &triplet : vcaTriplets) {
- if (vca.cameraId == triplet.cameraId && vca.viewport == triplet.viewport && vca.area == triplet.area)
- return false;
- }
- return true;
- }
-
-public:
- QVector<ViewportCameraAreaTriplet> gather(FrameGraphNode *root)
- {
- // Retrieve all leaves
- visit(root);
- QVector<ViewportCameraAreaTriplet> vcaTriplets;
- vcaTriplets.reserve(m_leaves.count());
-
- // Find all viewport/camera pairs by traversing from leaf to root
- for (Render::FrameGraphNode *leaf : qAsConst(m_leaves)) {
- ViewportCameraAreaTriplet vcaTriplet = gatherUpViewportCameraAreas(leaf);
- if (!vcaTriplet.cameraId.isNull() && isUnique(vcaTriplets, vcaTriplet))
- vcaTriplets.push_back(vcaTriplet);
- }
- return vcaTriplets;
- }
-
-};
-
-static QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities)
-{
- if (entity != nullptr) {
- entities.push_back(entity);
- // Traverse children
- const auto children = entity->children();
- for (Entity *child : children)
- entities = gatherEntities(child, std::move(entities));
- }
- return entities;
+ if (event.buttons() & Qt::LeftButton)
+ eventButtons |= QPickEvent::LeftButton;
+ if (event.buttons() & Qt::RightButton)
+ eventButtons |= QPickEvent::RightButton;
+ if (event.buttons() & Qt::MiddleButton)
+ eventButtons |= QPickEvent::MiddleButton;
+ if (event.buttons() & Qt::BackButton)
+ eventButtons |= QPickEvent::BackButton;
+ if (event.modifiers() & Qt::ShiftModifier)
+ eventModifiers |= QPickEvent::ShiftModifier;
+ if (event.modifiers() & Qt::ControlModifier)
+ eventModifiers |= QPickEvent::ControlModifier;
+ if (event.modifiers() & Qt::AltModifier)
+ eventModifiers |= QPickEvent::AltModifier;
+ if (event.modifiers() & Qt::MetaModifier)
+ eventModifiers |= QPickEvent::MetaModifier;
+ if (event.modifiers() & Qt::KeypadModifier)
+ eventModifiers |= QPickEvent::KeypadModifier;
}
-class EntityGatherer
-{
-public:
- explicit EntityGatherer(Entity *root)
- : m_root(root)
- , m_needsRefresh(true)
- {
- }
-
- QVector<Entity *> entities() const
- {
- if (m_needsRefresh) {
- m_entities.clear();
- m_entities = gatherEntities(m_root, std::move(m_entities));
- m_needsRefresh = false;
- }
- return m_entities;
- }
-
-private:
- Entity *m_root;
- mutable QVector<Entity *> m_entities;
- mutable bool m_needsRefresh;
-};
-
-class CollisionVisitor : public TrianglesVisitor
-{
-public:
- typedef QVector<QCollisionQueryResult::Hit> HitList;
- HitList hits;
-
- CollisionVisitor(NodeManagers* manager, const Entity *root, const QRay3D& ray, QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode) : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_faceOrientationPickingMode(faceOrientationPickingMode), m_triangleIndex(0) { }
-private:
- const Entity *m_root;
- QRay3D m_ray;
- QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode;
- uint m_triangleIndex;
-
- void visit(uint andx, const QVector3D &a,
- uint bndx, const QVector3D &b,
- uint cndx, const QVector3D &c)
- {
- const QMatrix4x4* mat = m_root->worldTransform();
- const QVector3D tA = *mat * a;
- const QVector3D tB = *mat * b;
- const QVector3D tC = *mat * c;
-
- float t = 0.f;
- QVector3D uvw;
- bool intersects = intersectsSegmentTriangle(m_ray, tC, tB, tA, uvw, t);
- if (intersects) {
- QCollisionQueryResult::Hit queryResult;
- queryResult.m_intersection = m_ray.point(t * m_ray.distance());
- queryResult.m_distance = m_ray.projectedDistance(queryResult.m_intersection);
- queryResult.m_entityId = m_root->peerId();
- queryResult.m_vertexIndex[0] = andx;
- queryResult.m_vertexIndex[1] = bndx;
- queryResult.m_vertexIndex[2] = cndx;
- hits.push_back(queryResult);
- }
-
- m_triangleIndex++;
- }
-
- // Note: a, b, c in clockwise order
- // RealTime Collision Detection page 192
- bool intersectsSegmentTriangle(const QRay3D &ray,
- const QVector3D &a,
- const QVector3D &b,
- const QVector3D &c,
- QVector3D &uvw,
- float &t)
- {
- const QVector3D ab = b - a;
- const QVector3D ac = c - a;
- const QVector3D qp = (ray.origin() - ray.point(ray.distance()));
-
- const QVector3D n = QVector3D::crossProduct(ab, ac);
- const float d = QVector3D::dotProduct(qp, n);
-
- if (d <= 0.0f && 0 == (m_faceOrientationPickingMode & QPickingSettings::BackFace))
- return false;
-
- const QVector3D ap = ray.origin() - a;
- t = QVector3D::dotProduct(ap, n);
-
- if (t < 0.0f || t > d)
- return false;
-
- const QVector3D e = QVector3D::crossProduct(qp, ap);
- uvw.setY(QVector3D::dotProduct(ac, e));
-
- if (uvw.y() < 0.0f || uvw.y() > d)
- return false;
-
- uvw.setZ(-QVector3D::dotProduct(ab, e));
-
- if (uvw.z() < 0.0f || uvw.y() + uvw.z() > d)
- return false;
-
- const float ood = 1.0f / d;
- t *= ood;
- uvw.setY(uvw.y() * ood);
- uvw.setZ(uvw.z() * ood);
- uvw.setX(1.0f - uvw.y() - uvw.z());
-
- return true;
- }
-};
-
-struct AbstractCollisionGathererFunctor
-{
- AbstractCollisionGathererFunctor() : m_renderer(0) { }
- virtual ~AbstractCollisionGathererFunctor() { }
-
- Renderer *m_renderer;
- QRay3D m_ray;
-
- typedef CollisionVisitor::HitList result_type;
-
- result_type operator ()(const Entity *entity) const
- {
- result_type result;
-
- HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
-
- // If the Entity which actually received the hit doesn't have
- // an object picker component, we need to check the parent if it has one ...
- while (objectPickerHandle.isNull() && entity != nullptr) {
- entity = entity->parent();
- if (entity != nullptr)
- objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
- }
-
- ObjectPicker *objectPicker = m_renderer->nodeManagers()->objectPickerManager()->data(objectPickerHandle);
- if (objectPicker == nullptr)
- return result_type(); // don't bother picking entities that don't have an object picker
-
- Qt3DRender::QRayCastingService rayCasting;
-
- return pick(&rayCasting, entity);
- }
-
- virtual result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const = 0;
-};
-
-struct EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor
-{
- result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE
- {
- result_type result;
-
- const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
- if (queryResult.m_distance >= 0.f)
- result.push_back(queryResult);
-
- return result;
- }
-};
+} // anonymous
-struct TriangleCollisionGathererFunctor : public AbstractCollisionGathererFunctor
+PickBoundingVolumeJob::PickBoundingVolumeJob()
+ : m_manager(nullptr)
+ , m_node(nullptr)
+ , m_frameGraphRoot(nullptr)
+ , m_renderSettings(nullptr)
{
- TriangleCollisionGathererFunctor() : AbstractCollisionGathererFunctor(), m_pickBackFacingTriangles(QPickingSettings::FrontFace) { }
-
- QPickingSettings::FaceOrientationPickingMode m_pickBackFacingTriangles;
-
- result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE
- {
- result_type result;
-
- GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
- if (!gRenderer)
- return result;
-
- if (rayHitsEntity(rayCasting, entity)) {
- CollisionVisitor visitor(m_renderer->nodeManagers(), entity, m_ray, m_pickBackFacingTriangles);
- visitor.apply(gRenderer, entity->peerId());
- result = visitor.hits;
-
- struct
- {
- bool operator()(const result_type::value_type &a, const result_type::value_type &b)
- {
- return a.m_distance < b.m_distance;
- }
- } compareHitsDistance;
- std::sort(result.begin(), result.end(), compareHitsDistance);
- }
-
- return result;
- }
-
- bool rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
- {
- const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
- return queryResult.m_distance >= 0.f;
- }
-};
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0);
+}
-CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate)
+void PickBoundingVolumeJob::setRoot(Entity *root)
{
- if (!intermediate.empty()) {
- if (result.empty())
- result.push_back(intermediate.front());
- float closest = result.front().m_distance;
- for (const auto &v : intermediate) {
- if (v.m_distance < closest) {
- result.push_front(v);
- closest = v.m_distance;
- }
- }
-
- while (result.size() > 1)
- result.pop_back();
- }
- return result;
+ m_node = root;
}
-// Unordered
-CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate)
+void PickBoundingVolumeJob::setMouseEvents(const QList<QMouseEvent> &pendingEvents)
{
- if (!intermediate.empty())
- results << intermediate;
- return results;
+ m_pendingMouseEvents = pendingEvents;
}
-} // anonymous
-
-PickBoundingVolumeJob::PickBoundingVolumeJob(Renderer *renderer)
- : m_renderer(renderer)
- , m_manager(nullptr)
- , m_node(nullptr)
+void PickBoundingVolumeJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0);
+ m_frameGraphRoot = frameGraphRoot;
}
-void PickBoundingVolumeJob::setRoot(Entity *root)
+void PickBoundingVolumeJob::setRenderSettings(RenderSettings *settings)
{
- m_node = root;
+ m_renderSettings = settings;
}
QRay3D PickBoundingVolumeJob::intersectionRay(const QPoint &pos, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix, const QRect &viewport)
@@ -411,221 +140,238 @@ QRay3D PickBoundingVolumeJob::intersectionRay(const QPoint &pos, const QMatrix4x
(farPos - nearPos).length());
}
-void PickBoundingVolumeJob::setManagers(NodeManagers *manager)
+bool PickBoundingVolumeJob::runHelper()
{
- m_manager = manager;
-}
+ // Move to clear the events so that we don't process them several times
+ // if run is called several times
+ const auto mouseEvents = std::move(m_pendingMouseEvents);
-void PickBoundingVolumeJob::run()
-{
- const auto mouseEvents = m_renderer->pendingPickingEvents();
+ // If we have no events return early
if (mouseEvents.empty())
- return;
+ return false;
- ViewportCameraAreaGatherer vcaGatherer;
- const QVector<ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_renderer->frameGraphRoot());
+ PickingUtils::ViewportCameraAreaGatherer vcaGatherer;
+ // TO DO: We could cache this and only gather when we know the FrameGraph tree has changed
+ const QVector<PickingUtils::ViewportCameraAreaTriplet> vcaTriplets = vcaGatherer.gather(m_frameGraphRoot);
+ // If we have no viewport / camera or area, return early
+ if (vcaTriplets.empty())
+ return false;
- if (!vcaTriplets.empty()) {
- bool hasMoveEvent = false;
- bool hasOtherEvent = false;
+ bool hasMoveEvent = false;
+ bool hasOtherEvent = false;
- for (const QMouseEvent &event : mouseEvents) {
- const bool isMove = (event.type() == QEvent::MouseMove);
- hasMoveEvent |= isMove;
- hasOtherEvent |= !isMove;
- }
+ // Quickly look which types of events we've got
+ for (const QMouseEvent &event : mouseEvents) {
+ const bool isMove = (event.type() == QEvent::MouseMove);
+ hasMoveEvent |= isMove;
+ hasOtherEvent |= !isMove;
+ }
- // We gather when we have a click/release event or a move
- // event and a QObjectPicker enabled to receive it
+ // In the case we have a move event, find if we actually have
+ // an object picker that cares about these
+ if (!hasOtherEvent) {
+ // Retrieve the last used object picker
ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
- // In the case we have a move event, find if we actually have
- // an object picker that cares about these
- if (!hasOtherEvent) {
- // The only way to set lastCurrentPicker is to click
- // so we can return since if we're there it means we
- // have only move events
- if (lastCurrentPicker == nullptr)
- return;
-
- const bool caresAboutMove = (hasMoveEvent && lastCurrentPicker->isDragEnabled());
- // Early return if the current object picker doesn't care about move events
- if (!caresAboutMove)
- return;
- }
+ // The only way to set lastCurrentPicker is to click
+ // so we can return since if we're there it means we
+ // have only move events
+ if (lastCurrentPicker == nullptr)
+ return false;
+
+ const bool caresAboutMove = (hasMoveEvent && lastCurrentPicker->isDragEnabled());
+ // Early return if the current object picker doesn't care about move events
+ if (!caresAboutMove)
+ return false;
+ }
- // Gather the entities for the frame
- EntityGatherer entitiesGatherer(m_node);
-
- for (const QMouseEvent &event : mouseEvents) {
- QPickEvent::Buttons eventButton = QPickEvent::NoButton;
- switch (event.button()) {
- case Qt::LeftButton: eventButton = QPickEvent::LeftButton; break;
- case Qt::RightButton: eventButton = QPickEvent::RightButton; break;
- case Qt::MiddleButton: eventButton = QPickEvent::MiddleButton; break;
- case Qt::BackButton: eventButton = QPickEvent::BackButton; break;
- default: break;
+
+ // TO DO:
+ // If we have move or hover move events that someone cares about, we try to avoid expensive computations
+ // by compressing them into a single one
+
+ // Gather the entities for the frame
+ // TO DO: We could skip doing that every frame and only do it when we know for sure
+ // that the tree structure has changed
+ PickingUtils::EntityGatherer entitiesGatherer(m_node);
+
+ // Store the reducer function which varies depending on the picking settings set on the renderer
+ using ReducerFunction = PickingUtils::CollisionVisitor::HitList (*)(PickingUtils::CollisionVisitor::HitList &results, const PickingUtils::CollisionVisitor::HitList &intermediate);
+
+ const bool trianglePickingRequested = (m_renderSettings->pickMethod() == QPickingSettings::TrianglePicking);
+ const bool allHitsRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks);
+
+ // Select the best reduction function based on the settings
+ const ReducerFunction reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+
+ // For each mouse event
+ for (const QMouseEvent &event : mouseEvents) {
+ m_hoveredPickersToClear = m_hoveredPickers;
+
+ QPickEvent::Buttons eventButton = QPickEvent::NoButton;
+ int eventButtons = 0;
+ int eventModifiers = QPickEvent::NoModifier;
+
+ setEventButtonAndModifiers(event, eventButton, eventButtons, eventModifiers);
+
+ // For each triplet of Viewport / Camera and Area
+ for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) {
+ typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList;
+ HitList sphereHits;
+ QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId);
+ if (trianglePickingRequested) {
+ PickingUtils::TriangleCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp);
+ } else {
+ PickingUtils::EntityCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp);
}
- int eventButtons = 0;
- if (event.buttons() & Qt::LeftButton)
- eventButtons |= QPickEvent::LeftButton;
- if (event.buttons() & Qt::RightButton)
- eventButtons |= QPickEvent::RightButton;
- if (event.buttons() & Qt::MiddleButton)
- eventButtons |= QPickEvent::MiddleButton;
- if (event.buttons() & Qt::BackButton)
- eventButtons |= QPickEvent::BackButton;
- int eventModifiers = QPickEvent::NoModifier;
- if (event.modifiers() & Qt::ShiftModifier)
- eventModifiers |= QPickEvent::ShiftModifier;
- if (event.modifiers() & Qt::ControlModifier)
- eventModifiers |= QPickEvent::ControlModifier;
- if (event.modifiers() & Qt::AltModifier)
- eventModifiers |= QPickEvent::AltModifier;
- if (event.modifiers() & Qt::MetaModifier)
- eventModifiers |= QPickEvent::MetaModifier;
- if (event.modifiers() & Qt::KeypadModifier)
- eventModifiers |= QPickEvent::KeypadModifier;
-
- m_hoveredPickersToClear = m_hoveredPickers;
- lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
- for (const ViewportCameraAreaTriplet &vca : vcaTriplets) {
- typedef AbstractCollisionGathererFunctor::result_type HitList;
- HitList sphereHits;
- QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId);
- auto reducerOp = m_renderer->settings() && m_renderer->settings()->pickResultMode() == QPickingSettings::AllPicks ? reduceToAllHits : reduceToFirstHit;
- if (m_renderer->settings() && m_renderer->settings()->pickMethod() == QPickingSettings::TrianglePicking) {
- TriangleCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_renderer = m_renderer;
- gathererFunctor.m_ray = ray;
- gathererFunctor.m_pickBackFacingTriangles = m_renderer->settings()->faceOrientationPickingMode();
- sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp);
- } else {
- EntityCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_renderer = m_renderer;
- gathererFunctor.m_ray = ray;
- sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp);
- }
+ // Dispatch events based on hit results
+ dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers);
+ }
+ }
+
+ // Clear Hovered elements that needs to be cleared
+ // Send exit event to object pickers on which we
+ // had set the hovered flag for a previous frame
+ // and that aren't being hovered any longer
+ clearPreviouslyHoveredPickers();
+ return true;
+}
- // If we have hits
- if (!sphereHits.isEmpty()) {
- // Note: how can we control that we want the first/last/all elements along the ray to be picked
+void PickBoundingVolumeJob::setManagers(NodeManagers *manager)
+{
+ m_manager = manager;
+}
+
+void PickBoundingVolumeJob::run()
+{
+ Q_ASSERT(m_frameGraphRoot && m_renderSettings && m_node && m_manager);
+ runHelper();
+}
- // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having
- // an ObjectPicker component when it comes
+void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
+ const PickingUtils::CollisionVisitor::HitList &sphereHits,
+ QPickEvent::Buttons eventButton,
+ int eventButtons,
+ int eventModifiers)
+{
+ ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
+ // If we have hits
+ if (!sphereHits.isEmpty()) {
- // We want to gather hits against triangles
- // build a triangle based bounding volume
+ const bool trianglePickingRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks);
+ // Note: how can we control that we want the first/last/all elements along the ray to be picked
- for (const QCollisionQueryResult::Hit &hit : qAsConst(sphereHits)) {
- Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId);
- HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+ // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having
+ // an ObjectPicker component when it comes
- // If the Entity which actually received the hit doesn't have
- // an object picker component, we need to check the parent if it has one ...
- while (objectPickerHandle.isNull() && entity != nullptr) {
- entity = entity->parent();
- if (entity != nullptr)
- objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
- }
+ // We want to gather hits against triangles
+ // build a triangle based bounding volume
- ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle);
-
- if (objectPicker != nullptr) {
- // Send the corresponding event
- QVector3D localIntersection = hit.m_intersection;
- if (entity && entity->worldTransform())
- localIntersection = hit.m_intersection * entity->worldTransform()->inverted();
- QPickEventPtr pickEvent;
- if (m_renderer->settings() && m_renderer->settings()->pickMethod() == QPickingSettings::TrianglePicking) {
- pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
- hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2],
- eventButton, eventButtons, eventModifiers));
- } else {
- pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
- eventButton, eventButtons, eventModifiers));
- }
-
- switch (event.type()) {
- case QEvent::MouseButtonPress: {
- // Store pressed object handle
- m_currentPicker = objectPickerHandle;
- // Send pressed event to m_currentPicker
- objectPicker->onPressed(pickEvent);
- break;
- }
-
- case QEvent::MouseButtonRelease: {
- if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle)
- m_currentPicker = HObjectPicker();
- // Only send the release event if it was pressed
- if (objectPicker->isPressed()) {
- objectPicker->onClicked(pickEvent);
- objectPicker->onReleased(pickEvent);
- }
- break;
- }
-
- case Qt::TapGesture: {
- objectPicker->onClicked(pickEvent);
- break;
- }
-
- case QEvent::MouseMove: {
- if (objectPicker->isPressed() && objectPicker->isDragEnabled()) {
- objectPicker->onMoved(pickEvent);
- }
- // fallthrough
- }
- case QEvent::HoverMove: {
- if (!m_hoveredPickers.contains(objectPickerHandle)) {
- if (objectPicker->isHoverEnabled()) {
- // Send entered event to objectPicker
- objectPicker->onEntered();
- // and save it in the hoveredPickers
- m_hoveredPickers.push_back(objectPickerHandle);
- }
- }
- break;
- }
-
- default:
- break;
- }
- }
+ for (const QCollisionQueryResult::Hit &hit : qAsConst(sphereHits)) {
+ Entity *entity = m_manager->renderNodesManager()->lookupResource(hit.m_entityId);
+ HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
- // The ObjectPicker was hit -> it is still being hovered
- m_hoveredPickersToClear.removeAll(objectPickerHandle);
+ // If the Entity which actually received the hit doesn't have
+ // an object picker component, we need to check the parent if it has one ...
+ while (objectPickerHandle.isNull() && entity != nullptr) {
+ entity = entity->parent();
+ if (entity != nullptr)
+ objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+ }
+ ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle);
+
+ if (objectPicker != nullptr) {
+ // Send the corresponding event
+ QVector3D localIntersection = hit.m_intersection;
+ if (entity && entity->worldTransform())
+ localIntersection = hit.m_intersection * entity->worldTransform()->inverted();
+
+ QPickEventPtr pickEvent;
+ if (trianglePickingRequested)
+ pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
+ hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2],
+ eventButton, eventButtons, eventModifiers));
+ else
+ pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
+ eventButton, eventButtons, eventModifiers));
+
+ switch (event.type()) {
+ case QEvent::MouseButtonPress: {
+ // Store pressed object handle
+ m_currentPicker = objectPickerHandle;
+ // Send pressed event to m_currentPicker
+ objectPicker->onPressed(pickEvent);
+ break;
+ }
- lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
+ case QEvent::MouseButtonRelease: {
+ if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle)
+ m_currentPicker = HObjectPicker();
+ // Only send the release event if it was pressed
+ if (objectPicker->isPressed()) {
+ objectPicker->onClicked(pickEvent);
+ objectPicker->onReleased(pickEvent);
}
+ break;
+ }
- // Otherwise no hits
- } else {
- switch (event.type()) {
- case QEvent::MouseButtonRelease: {
- // Send release event to m_currentPicker
- if (lastCurrentPicker != nullptr) {
- m_currentPicker = HObjectPicker();
- QPickEventPtr pickEvent(new QPickEvent);
- lastCurrentPicker->onReleased(pickEvent);
- }
- break;
+ case Qt::TapGesture: {
+ objectPicker->onClicked(pickEvent);
+ break;
+ }
+
+ case QEvent::MouseMove: {
+ if (objectPicker->isPressed() && objectPicker->isDragEnabled()) {
+ objectPicker->onMoved(pickEvent);
}
- default:
- break;
+ // fallthrough
+ }
+ case QEvent::HoverMove: {
+ if (!m_hoveredPickers.contains(objectPickerHandle)) {
+ if (objectPicker->isHoverEnabled()) {
+ // Send entered event to objectPicker
+ objectPicker->onEntered();
+ // and save it in the hoveredPickers
+ m_hoveredPickers.push_back(objectPickerHandle);
+ }
}
+ break;
+ }
+
+ default:
+ break;
}
}
+
+ // The ObjectPicker was hit -> it is still being hovered
+ m_hoveredPickersToClear.removeAll(objectPickerHandle);
+
+ lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
}
- // Clear Hovered elements that needs to be cleared
- // Send exit event to object pickers on which we
- // had set the hovered flag for a previous frame
- // and that aren't being hovered any longer
- clearPreviouslyHoveredPickers();
+ // Otherwise no hits
+ } else {
+ switch (event.type()) {
+ case QEvent::MouseButtonRelease: {
+ // Send release event to m_currentPicker
+ if (lastCurrentPicker != nullptr) {
+ m_currentPicker = HObjectPicker();
+ QPickEventPtr pickEvent(new QPickEvent);
+ lastCurrentPicker->onReleased(pickEvent);
+ }
+ break;
+ }
+ default:
+ break;
+ }
}
}
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index 1baa67fee..e0a759d6c 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -56,6 +56,8 @@
#include <Qt3DRender/private/handle_types_p.h>
#include <Qt3DRender/private/qboundingvolumeprovider_p.h>
#include <Qt3DRender/private/qcollisionqueryresult_p.h>
+#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
+#include <Qt3DRender/qpickevent.h>
#include <QMouseEvent>
#include <QSharedPointer>
@@ -74,26 +76,42 @@ namespace Render {
class Entity;
class Renderer;
class NodeManagers;
+class RenderSettings;
class Q_AUTOTEST_EXPORT PickBoundingVolumeJob : public Qt3DCore::QAspectJob
{
public:
- PickBoundingVolumeJob(Renderer *renderer);
+ PickBoundingVolumeJob();
void setRoot(Entity *root);
+ void setMouseEvents(const QList<QMouseEvent> &pendingEvents);
+ void setFrameGraphRoot(FrameGraphNode *frameGraphRoot);
+ void setRenderSettings(RenderSettings *settings);
+ void setManagers(NodeManagers *manager);
static QRay3D intersectionRay(const QPoint &pos,
const QMatrix4x4 &viewMatrix,
const QMatrix4x4 &projectionMatrix,
const QRect &viewport);
- void setManagers(NodeManagers *manager);
+
+ // For unit tests
+ inline HObjectPicker currentPicker() const { return m_currentPicker; }
+ inline QVector<HObjectPicker> hoveredPickers() const { return m_hoveredPickers; }
+ bool runHelper();
+
protected:
void run() Q_DECL_FINAL;
+ void dispatchPickEvents(const QMouseEvent &event, const PickingUtils::CollisionVisitor::HitList &sphereHits,
+ QPickEvent::Buttons eventButton,
+ int eventButtons,
+ int eventModifiers);
private:
- Renderer *m_renderer;
NodeManagers *m_manager;
Entity *m_node;
+ FrameGraphNode *m_frameGraphRoot;
+ RenderSettings *m_renderSettings;
+ QList<QMouseEvent> m_pendingMouseEvents;
void viewMatrixForCamera(Qt3DCore::QNodeId cameraId,
QMatrix4x4 &viewMatrix,
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
new file mode 100644
index 000000000..fd4eded27
--- /dev/null
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pickboundingvolumeutils_p.h"
+#include <Qt3DRender/private/framegraphnode_p.h>
+#include <Qt3DRender/private/cameralens_p.h>
+#include <Qt3DRender/private/cameraselectornode_p.h>
+#include <Qt3DRender/private/viewportnode_p.h>
+#include <Qt3DRender/private/rendersurfaceselector_p.h>
+#include <Qt3DRender/private/triangleboundingvolume_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/entity_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace PickingUtils {
+
+void ViewportCameraAreaGatherer::visit(FrameGraphNode *node)
+{
+ const auto children = node->children();
+ for (Render::FrameGraphNode *n : children)
+ visit(n);
+ if (node->childrenIds().empty())
+ m_leaves.push_back(node);
+}
+
+ViewportCameraAreaTriplet ViewportCameraAreaGatherer::gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const
+{
+ ViewportCameraAreaTriplet vca;
+ vca.viewport = QRectF(0.0f, 0.0f, 1.0f, 1.0f);
+
+ while (node) {
+ if (node->isEnabled()) {
+ switch (node->nodeType()) {
+ case FrameGraphNode::CameraSelector:
+ vca.cameraId = static_cast<const CameraSelector *>(node)->cameraUuid();
+ break;
+ case FrameGraphNode::Viewport:
+ vca.viewport = computeViewport(vca.viewport, static_cast<const ViewportNode *>(node));
+ break;
+ case FrameGraphNode::Surface:
+ vca.area = static_cast<const RenderSurfaceSelector *>(node)->renderTargetSize();
+ break;
+ default:
+ break;
+ }
+ }
+ node = node->parent();
+ }
+ return vca;
+}
+
+QVector<ViewportCameraAreaTriplet> ViewportCameraAreaGatherer::gather(FrameGraphNode *root)
+{
+ // Retrieve all leaves
+ visit(root);
+ QVector<ViewportCameraAreaTriplet> vcaTriplets;
+ vcaTriplets.reserve(m_leaves.count());
+
+ // Find all viewport/camera pairs by traversing from leaf to root
+ for (Render::FrameGraphNode *leaf : qAsConst(m_leaves)) {
+ ViewportCameraAreaTriplet vcaTriplet = gatherUpViewportCameraAreas(leaf);
+ if (!vcaTriplet.cameraId.isNull() && isUnique(vcaTriplets, vcaTriplet))
+ vcaTriplets.push_back(vcaTriplet);
+ }
+ return vcaTriplets;
+}
+
+bool PickingUtils::ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const
+{
+ for (const ViewportCameraAreaTriplet &triplet : vcaTriplets) {
+ if (vca.cameraId == triplet.cameraId && vca.viewport == triplet.viewport && vca.area == triplet.area)
+ return false;
+ }
+ return true;
+}
+
+QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities)
+{
+ if (entity != nullptr) {
+ entities.push_back(entity);
+ // Traverse children
+ const auto children = entity->children();
+ for (Entity *child : children)
+ entities = gatherEntities(child, std::move(entities));
+ }
+ return entities;
+}
+
+EntityGatherer::EntityGatherer(Entity *root)
+ : m_root(root)
+ , m_needsRefresh(true)
+{
+}
+
+QVector<Entity *> EntityGatherer::entities() const
+{
+ if (m_needsRefresh) {
+ m_entities.clear();
+ m_entities = gatherEntities(m_root, std::move(m_entities));
+ m_needsRefresh = false;
+ }
+ return m_entities;
+}
+
+void CollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c)
+{
+ TriangleBoundingVolume volume(m_root->peerId(), a, b, c);
+ volume = volume.transform(*m_root->worldTransform());
+
+ QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, &volume);
+ if (queryResult.m_distance > 0.) {
+ queryResult.m_triangleIndex = m_triangleIndex;
+ queryResult.m_vertexIndex[0] = andx;
+ queryResult.m_vertexIndex[1] = bndx;
+ queryResult.m_vertexIndex[2] = cndx;
+ hits.push_back(queryResult);
+ }
+
+ m_triangleIndex++;
+}
+
+AbstractCollisionGathererFunctor::AbstractCollisionGathererFunctor()
+ : m_manager(nullptr)
+{ }
+
+AbstractCollisionGathererFunctor::~AbstractCollisionGathererFunctor()
+{ }
+
+AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor::operator ()(const Entity *entity) const
+{
+ HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
+
+ // If the Entity which actually received the hit doesn't have
+ // an object picker component, we need to check the parent if it has one ...
+ auto parentEntity = entity;
+ while (objectPickerHandle.isNull() && parentEntity != nullptr) {
+ parentEntity = parentEntity->parent();
+ if (parentEntity != nullptr)
+ objectPickerHandle = parentEntity->componentHandle<ObjectPicker, 16>();
+ }
+
+ ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle);
+ if (objectPicker == nullptr)
+ return result_type(); // don't bother picking entities that don't have an object picker
+
+ Qt3DRender::QRayCastingService rayCasting;
+
+ return pick(&rayCasting, entity);
+}
+
+AbstractCollisionGathererFunctor::result_type EntityCollisionGathererFunctor::pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
+{
+ result_type result;
+
+ const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
+ if (queryResult.m_distance >= 0.f)
+ result.push_back(queryResult);
+
+ return result;
+}
+
+AbstractCollisionGathererFunctor::result_type TriangleCollisionGathererFunctor::pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
+{
+ result_type result;
+
+ GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
+ if (!gRenderer)
+ return result;
+
+ if (rayHitsEntity(rayCasting, entity)) {
+ CollisionVisitor visitor(m_manager, entity, m_ray);
+ visitor.apply(gRenderer, entity->peerId());
+ result = visitor.hits;
+
+ struct
+ {
+ bool operator()(const result_type::value_type &a, const result_type::value_type &b)
+ {
+ return a.m_distance < b.m_distance;
+ }
+ } compareHitsDistance;
+ std::sort(result.begin(), result.end(), compareHitsDistance);
+ }
+
+ return result;
+}
+
+bool TriangleCollisionGathererFunctor::rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
+{
+ const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
+ return queryResult.m_distance >= 0.f;
+}
+
+CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate)
+{
+ if (!intermediate.empty()) {
+ if (result.empty())
+ result.push_back(intermediate.front());
+ float closest = result.front().m_distance;
+ for (const auto &v : intermediate) {
+ if (v.m_distance < closest) {
+ result.push_front(v);
+ closest = v.m_distance;
+ }
+ }
+
+ while (result.size() > 1)
+ result.pop_back();
+ }
+ return result;
+}
+
+CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate)
+{
+ if (!intermediate.empty())
+ results << intermediate;
+ return results;
+}
+
+} // PickingUtils
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
new file mode 100644
index 000000000..5bc94a13b
--- /dev/null
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_PICKBOUNDINGVOLUMEUTILS_H
+#define QT3DRENDER_RENDER_PICKBOUNDINGVOLUMEUTILS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/private/qray3d_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/qraycastingservice_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractCollisionQueryService;
+
+namespace Render {
+
+class Entity;
+class Renderer;
+class FrameGraphNode;
+
+namespace PickingUtils {
+
+struct Q_AUTOTEST_EXPORT ViewportCameraAreaTriplet
+{
+ Qt3DCore::QNodeId cameraId;
+ QRectF viewport;
+ QSize area;
+};
+QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaTriplet, Q_PRIMITIVE_TYPE)
+
+class Q_AUTOTEST_EXPORT ViewportCameraAreaGatherer
+{
+public:
+ QVector<ViewportCameraAreaTriplet> gather(FrameGraphNode *root);
+
+private:
+ QVector<FrameGraphNode *> m_leaves;
+
+ void visit(FrameGraphNode *node);
+ ViewportCameraAreaTriplet gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const;
+ bool isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const;
+};
+
+class Q_AUTOTEST_EXPORT EntityGatherer
+{
+public:
+ explicit EntityGatherer(Entity *root);
+
+ QVector<Entity *> entities() const;
+
+private:
+ Entity *m_root;
+ mutable QVector<Entity *> m_entities;
+ mutable bool m_needsRefresh;
+};
+
+class Q_AUTOTEST_EXPORT CollisionVisitor : public TrianglesVisitor
+{
+public:
+ typedef QVector<QCollisionQueryResult::Hit> HitList;
+ HitList hits;
+
+ CollisionVisitor(NodeManagers* manager, const Entity *root, const QRay3D& ray) : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0) { }
+private:
+ const Entity *m_root;
+ QRay3D m_ray;
+ Qt3DRender::QRayCastingService rayCasting;
+ uint m_triangleIndex;
+
+ void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b,
+ uint cndx, const QVector3D &c);
+};
+
+struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
+{
+ AbstractCollisionGathererFunctor();
+ virtual ~AbstractCollisionGathererFunctor();
+
+ NodeManagers *m_manager;
+ QRay3D m_ray;
+
+ // This define is required to work with QtConcurrent
+ typedef CollisionVisitor::HitList result_type;
+ result_type operator ()(const Entity *entity) const;
+ virtual result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const = 0;
+};
+
+struct Q_AUTOTEST_EXPORT EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor
+{
+ result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE;
+};
+
+struct Q_AUTOTEST_EXPORT TriangleCollisionGathererFunctor : public AbstractCollisionGathererFunctor
+{
+ result_type pick(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE;
+
+ bool rayHitsEntity(QAbstractCollisionQueryService *rayCasting, const Entity *entity) const;
+};
+
+Q_AUTOTEST_EXPORT QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities);
+
+Q_AUTOTEST_EXPORT CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate);
+
+// Unordered
+Q_AUTOTEST_EXPORT CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate);
+
+} // PickingUtils
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_PICKBOUNDINGVOLUMEUTILS_H
diff --git a/src/render/jobs/renderviewinitializerjob_p.h b/src/render/jobs/renderviewinitializerjob_p.h
index 81091183b..0ee017df9 100644
--- a/src/render/jobs/renderviewinitializerjob_p.h
+++ b/src/render/jobs/renderviewinitializerjob_p.h
@@ -86,8 +86,8 @@ public:
// a shadow map texture is submitted before the RenderView that
// contains commands making use of the shadow map
inline void setSubmitOrderIndex(int index) { m_index = index; }
+ inline int submitOrderIndex() const { return m_index; }
-protected:
void run() Q_DECL_OVERRIDE;
private:
diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp
index 3face7197..3d98ac2a2 100644
--- a/src/render/jobs/renderviewjobutils.cpp
+++ b/src/render/jobs/renderviewjobutils.cpp
@@ -64,6 +64,7 @@
#include <Qt3DRender/private/rendersurfaceselector_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
+#include <Qt3DRender/private/techniquemanager_p.h>
QT_BEGIN_NAMESPACE
@@ -92,6 +93,9 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
FrameGraphNode::FrameGraphNodeType type = node->nodeType();
if (node->isEnabled())
switch (type) {
+ case FrameGraphNode::InvalidNodeType:
+ // A base FrameGraphNode, can be used for grouping purposes
+ break;
case FrameGraphNode::CameraSelector:
// Can be set only once and we take camera nearest to the leaf node
if (!rv->renderCameraLens()) {
@@ -260,8 +264,8 @@ Technique *findTechniqueForEffect(Renderer *renderer,
for (const QNodeId techniqueId : techniqueIds) {
Technique *technique = manager->techniqueManager()->lookupResource(techniqueId);
- if (!technique)
- continue;
+ // Should be valid, if not there likely a problem with node addition/destruction changes
+ Q_ASSERT(technique);
// We need to be sure the renderer is still running <=> still has a GraphicsContext
if (renderer->isRunning() && *renderer->contextInfo() == *technique->graphicsApiFilter()) {
diff --git a/src/render/jobs/renderviewjobutils_p.h b/src/render/jobs/renderviewjobutils_p.h
index ad86685a9..bc042a582 100644
--- a/src/render/jobs/renderviewjobutils_p.h
+++ b/src/render/jobs/renderviewjobutils_p.h
@@ -140,8 +140,7 @@ void parametersFromParametersProvider(ParameterInfoList *infoList,
ParameterManager *manager,
T *provider)
{
- if (provider != nullptr)
- addParametersForIds(infoList, manager, provider->parameters());
+ addParametersForIds(infoList, manager, provider->parameters());
}
Q_AUTOTEST_EXPORT ParameterInfoList::const_iterator findParamInfo(ParameterInfoList *infoList,
diff --git a/src/render/jobs/sendrendercapturejob_p.h b/src/render/jobs/sendrendercapturejob_p.h
index f1e6b65f2..a6a7f7e79 100644
--- a/src/render/jobs/sendrendercapturejob_p.h
+++ b/src/render/jobs/sendrendercapturejob_p.h
@@ -71,7 +71,6 @@ public:
void setManagers(NodeManagers *managers);
-protected:
void run() Q_DECL_FINAL;
private:
diff --git a/src/render/jobs/updatemeshtrianglelistjob.cpp b/src/render/jobs/updatemeshtrianglelistjob.cpp
new file mode 100644
index 000000000..dd3934948
--- /dev/null
+++ b/src/render/jobs/updatemeshtrianglelistjob.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "updatemeshtrianglelistjob_p.h"
+#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/light_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+UpdateMeshTriangleListJob::UpdateMeshTriangleListJob()
+ : m_manager(nullptr)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateMeshTriangleList, 0);
+}
+
+UpdateMeshTriangleListJob::~UpdateMeshTriangleListJob()
+{
+}
+
+void UpdateMeshTriangleListJob::setManagers(NodeManagers *manager)
+{
+ m_manager = manager;
+}
+
+void UpdateMeshTriangleListJob::run()
+{
+ GeometryRendererManager *geomRenderermanager = m_manager->geometryRendererManager();
+ GeometryManager *geomManager = m_manager->geometryManager();
+ BufferManager *bufferManager = m_manager->bufferManager();
+ AttributeManager *attributeManager = m_manager->attributeManager();
+
+ const QVector<HGeometryRenderer> handles = geomRenderermanager->activeHandles();
+
+ for (const HGeometryRenderer handle : handles) {
+ // Look if for the GeometryRender/Geometry the attributes and or buffers are dirty
+ // in which case we need to recompute the triangle list
+ const GeometryRenderer *geomRenderer = geomRenderermanager->data(handle);
+ if (geomRenderer != nullptr) {
+ const Geometry *geom = geomManager->lookupResource(geomRenderer->geometryId());
+ if (geom != nullptr) {
+ const Qt3DCore::QNodeId geomRendererId = geomRenderer->peerId();
+ if (!geomRenderermanager->isGeometryRendererScheduledForTriangleDataRefresh(geomRendererId)) {
+ // Check if the attributes or buffers are dirty
+ bool dirty = geomRenderer->isDirty();
+ const auto attrIds = geom->attributes();
+ for (const Qt3DCore::QNodeId attrId : attrIds) {
+ const Attribute *attr = attributeManager->lookupResource(attrId);
+ if (attr != nullptr) {
+ dirty |= attr->isDirty();
+ if (!dirty) {
+ const Buffer *buffer = bufferManager->lookupResource(attr->bufferId());
+ if (buffer != nullptr)
+ dirty = buffer->isDirty();
+ }
+ if (dirty)
+ break;
+ }
+ }
+ if (dirty)
+ m_manager->geometryRendererManager()->requestTriangleDataRefreshForGeometryRenderer(geomRendererId);
+ }
+ }
+ }
+ }
+}
+
+NodeManagers *UpdateMeshTriangleListJob::managers() const
+{
+ return m_manager;
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/updatemeshtrianglelistjob_p.h b/src/render/jobs/updatemeshtrianglelistjob_p.h
new file mode 100644
index 000000000..9c0383739
--- /dev/null
+++ b/src/render/jobs/updatemeshtrianglelistjob_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_UPDATEMESHTRIANGLELISTJOB_H
+#define QT3DRENDER_RENDER_UPDATEMESHTRIANGLELISTJOB_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class NodeManagers;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT UpdateMeshTriangleListJob : public Qt3DCore::QAspectJob
+{
+public:
+ UpdateMeshTriangleListJob();
+ ~UpdateMeshTriangleListJob();
+
+ void setManagers(NodeManagers *manager);
+ void run() Q_DECL_FINAL;
+
+ NodeManagers *managers() const;
+
+private:
+ NodeManagers *m_manager;
+};
+
+typedef QSharedPointer<UpdateMeshTriangleListJob> UpdateMeshTriangleListJobPtr;
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_UPDATEMESHTRIANGLELISTJOB_H
diff --git a/src/render/jobs/framepreparationjob.cpp b/src/render/jobs/updateshaderdatatransformjob.cpp
index ef5b4bdb4..243edb4f7 100644
--- a/src/render/jobs/framepreparationjob.cpp
+++ b/src/render/jobs/updateshaderdatatransformjob.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "framepreparationjob_p.h"
+#include "updateshaderdatatransformjob_p.h"
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/shaderdata_p.h>
@@ -58,71 +58,38 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-FramePreparationJob::FramePreparationJob()
- : m_root(nullptr)
- , m_manager(nullptr)
+UpdateShaderDataTransformJob::UpdateShaderDataTransformJob()
+ : m_manager(nullptr)
{
- SET_JOB_RUN_STAT_TYPE(this, JobTypes::FramePreparation, 0);
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateShaderDataTransform, 0);
}
-FramePreparationJob::~FramePreparationJob()
+UpdateShaderDataTransformJob::~UpdateShaderDataTransformJob()
{
}
-void FramePreparationJob::setRoot(Entity *root)
-{
- m_root = root;
-}
-
-void FramePreparationJob::setManagers(NodeManagers *manager)
+void UpdateShaderDataTransformJob::setManagers(NodeManagers *manager)
{
m_manager = manager;
}
-void FramePreparationJob::run()
+NodeManagers *UpdateShaderDataTransformJob::managers() const
{
- parseNodeTree(m_root);
+ return m_manager;
}
-void FramePreparationJob::parseNodeTree(Entity *node)
+void UpdateShaderDataTransformJob::run()
{
- // Update transform properties in ShaderDatas and Lights
- const QVector<ShaderData *> shaderDatas = node->renderComponents<ShaderData>();
- for (ShaderData *r : shaderDatas)
- r->updateWorldTransform(*node->worldTransform());
+ EntityManager *manager = m_manager->renderNodesManager();
+ const QVector<HEntity> handles = manager->activeHandles();
- // Look if for the GeometryRender/Geometry the attributes and or buffers are dirty
- // in which case we need to recompute the triangle list
- GeometryRenderer *geomRenderer = node->renderComponent<GeometryRenderer>();
- const Qt3DCore::QNodeId geomRendererId = node->componentUuid<GeometryRenderer>();
- Geometry *geom = nullptr;
- if (geomRenderer &&
- (geom = m_manager->lookupResource<Geometry, GeometryManager>(geomRenderer->geometryId())) != nullptr) {
- if (!m_manager->geometryRendererManager()->isGeometryRendererScheduledForTriangleDataRefresh(geomRendererId)) {
- // Check if the attributes or buffers are dirty
- bool dirty = geomRenderer->isDirty();
- Attribute *attr = nullptr;
- const auto attrIds = geom->attributes();
- for (const Qt3DCore::QNodeId attrId : attrIds) {
- if ((attr = m_manager->attributeManager()->lookupResource(attrId)) != nullptr) {
- dirty |= attr->isDirty();
- if (!dirty) {
- Buffer *buffer = nullptr;
- if ((buffer = m_manager->bufferManager()->lookupResource(attr->bufferId())) != nullptr)
- dirty = buffer->isDirty();
- }
- if (dirty)
- break;
- }
- }
- if (dirty)
- m_manager->geometryRendererManager()->requestTriangleDataRefreshForGeometryRenderer(geomRendererId);
- }
+ for (const HEntity handle : handles) {
+ Entity *node = manager->data(handle);
+ // Update transform properties in ShaderDatas and Lights
+ const QVector<ShaderData *> shaderDatas = node->renderComponents<ShaderData>();
+ for (ShaderData *r : shaderDatas)
+ r->updateWorldTransform(*node->worldTransform());
}
-
- const QVector<Entity *> children = node->children();
- for (Entity *c : children)
- parseNodeTree(c);
}
} // namespace Render
diff --git a/src/render/jobs/framepreparationjob_p.h b/src/render/jobs/updateshaderdatatransformjob_p.h
index 35db5862d..6fe365b6b 100644
--- a/src/render/jobs/framepreparationjob_p.h
+++ b/src/render/jobs/updateshaderdatatransformjob_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_RENDER_FRAMEPREPARATIONJOB_H
-#define QT3DRENDER_RENDER_FRAMEPREPARATIONJOB_H
+#ifndef QT3DRENDER_RENDER_UPDATESHADERDATATRANSFORMJOB_H
+#define QT3DRENDER_RENDER_UPDATESHADERDATATRANSFORMJOB_H
//
// W A R N I N G
@@ -61,28 +61,23 @@ namespace Qt3DRender {
namespace Render {
class NodeManagers;
-class Entity;
-class QT3DRENDERSHARED_PRIVATE_EXPORT FramePreparationJob : public Qt3DCore::QAspectJob
+class QT3DRENDERSHARED_PRIVATE_EXPORT UpdateShaderDataTransformJob : public Qt3DCore::QAspectJob
{
public:
- FramePreparationJob();
- ~FramePreparationJob();
+ UpdateShaderDataTransformJob();
+ ~UpdateShaderDataTransformJob();
- void setRoot(Entity *root);
void setManagers(NodeManagers *manager);
+ NodeManagers *managers() const;
-protected:
void run() Q_DECL_FINAL;
private:
- void parseNodeTree(Entity *node);
-
- Entity *m_root;
NodeManagers *m_manager;
};
-typedef QSharedPointer<FramePreparationJob> FramePreparationJobPtr;
+typedef QSharedPointer<UpdateShaderDataTransformJob> UpdateShaderDataTransformJobPtr;
} // namespace Render
@@ -90,4 +85,4 @@ typedef QSharedPointer<FramePreparationJob> FramePreparationJobPtr;
QT_END_NAMESPACE
-#endif // QT3DRENDER_RENDER_FRAMEPREPARATIONJOB_H
+#endif // QT3DRENDER_RENDER_UPDATESHADERDATATRANSFORMJOB_H
diff --git a/src/render/lights/light_p.h b/src/render/lights/light_p.h
index 31901bf11..19deb1bcc 100644
--- a/src/render/lights/light_p.h
+++ b/src/render/lights/light_p.h
@@ -92,6 +92,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::Light*)
+Q_DECLARE_METATYPE(Qt3DRender::Render::Light*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_LIGHT_P_H
diff --git a/src/render/lights/qabstractlight.h b/src/render/lights/qabstractlight.h
index 7cc98b57b..33a88b215 100644
--- a/src/render/lights/qabstractlight.h
+++ b/src/render/lights/qabstractlight.h
@@ -67,7 +67,7 @@ public:
DirectionalLight,
SpotLight
};
- Q_ENUM(Type)
+ Q_ENUM(Type) // LCOV_EXCL_LINE
Type type() const;
QColor color() const;
diff --git a/src/render/materialsystem/effect.cpp b/src/render/materialsystem/effect.cpp
index 8e25e74fc..29d05ed01 100644
--- a/src/render/materialsystem/effect.cpp
+++ b/src/render/materialsystem/effect.cpp
@@ -69,6 +69,8 @@ Effect::~Effect()
void Effect::cleanup()
{
QBackendNode::setEnabled(false);
+ m_parameterPack.clear();
+ m_techniques.clear();
}
void Effect::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
diff --git a/src/render/materialsystem/effect_p.h b/src/render/materialsystem/effect_p.h
index 50d470d8e..62435b582 100644
--- a/src/render/materialsystem/effect_p.h
+++ b/src/render/materialsystem/effect_p.h
@@ -63,7 +63,7 @@ class QTechnique;
namespace Render {
-class Effect : public BackendNode
+class Q_AUTOTEST_EXPORT Effect : public BackendNode
{
public:
Effect();
diff --git a/src/render/materialsystem/filterkey.cpp b/src/render/materialsystem/filterkey.cpp
index db139f1fe..fd911c419 100644
--- a/src/render/materialsystem/filterkey.cpp
+++ b/src/render/materialsystem/filterkey.cpp
@@ -60,6 +60,9 @@ FilterKey::~FilterKey()
void FilterKey::cleanup()
{
+ QBackendNode::setEnabled(false);
+ m_name.clear();
+ m_value.clear();
}
void FilterKey::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -70,12 +73,12 @@ void FilterKey::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &ch
m_value = data.value;
}
-QVariant FilterKey::criterionValue() const
+QVariant FilterKey::value() const
{
return m_value;
}
-QString FilterKey::criterionName() const
+QString FilterKey::name() const
{
return m_name;
}
@@ -103,8 +106,8 @@ bool FilterKey::operator ==(const FilterKey &other)
{
if (&other == this)
return true;
- return ((other.criterionName() == criterionName()) &&
- (other.criterionValue() == criterionValue()));
+ return ((other.name() == name()) &&
+ (other.value() == value()));
}
bool FilterKey::operator !=(const FilterKey &other)
diff --git a/src/render/materialsystem/filterkey_p.h b/src/render/materialsystem/filterkey_p.h
index 8291e32f0..4aea3d78a 100644
--- a/src/render/materialsystem/filterkey_p.h
+++ b/src/render/materialsystem/filterkey_p.h
@@ -62,15 +62,15 @@ class QFilterKey;
namespace Render {
-class FilterKey : public BackendNode
+class Q_AUTOTEST_EXPORT FilterKey : public BackendNode
{
public:
FilterKey();
~FilterKey();
void cleanup();
- QVariant criterionValue() const;
- QString criterionName() const;
+ QVariant value() const;
+ QString name() const;
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
bool operator ==(const FilterKey &other);
bool operator !=(const FilterKey &other);
diff --git a/src/render/materialsystem/materialsystem.pri b/src/render/materialsystem/materialsystem.pri
index 7b893982b..b6e9ead03 100644
--- a/src/render/materialsystem/materialsystem.pri
+++ b/src/render/materialsystem/materialsystem.pri
@@ -27,7 +27,8 @@ HEADERS += \
$$PWD/technique_p.h \
$$PWD/qgraphicsapifilter.h \
$$PWD/qgraphicsapifilter_p.h \
- $$PWD/shadercache_p.h
+ $$PWD/shadercache_p.h \
+ $$PWD/techniquemanager_p.h
SOURCES += \
$$PWD/filterkey.cpp \
@@ -47,4 +48,5 @@ SOURCES += \
$$PWD/shaderdata.cpp \
$$PWD/technique.cpp \
$$PWD/qgraphicsapifilter.cpp \
- $$PWD/shadercache.cpp
+ $$PWD/shadercache.cpp \
+ $$PWD/techniquemanager.cpp
diff --git a/src/render/materialsystem/parameter.cpp b/src/render/materialsystem/parameter.cpp
index 2cd026422..9c40c199a 100644
--- a/src/render/materialsystem/parameter.cpp
+++ b/src/render/materialsystem/parameter.cpp
@@ -62,6 +62,14 @@ Parameter::Parameter()
{
}
+void Parameter::cleanup()
+{
+ QBackendNode::setEnabled(false);
+ m_nameId = -1;
+ m_name.clear();
+ m_uniformValue = UniformValue();
+}
+
void Parameter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QParameterData>>(change);
diff --git a/src/render/materialsystem/parameter_p.h b/src/render/materialsystem/parameter_p.h
index c6861ca36..6830ef07d 100644
--- a/src/render/materialsystem/parameter_p.h
+++ b/src/render/materialsystem/parameter_p.h
@@ -63,13 +63,14 @@ namespace Render {
class ParameterManager;
class ShaderDataManager;
-class TextureManager;
-class Parameter : public BackendNode
+class Q_AUTOTEST_EXPORT Parameter : public BackendNode
{
public:
Parameter();
+ void cleanup();
+
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
QString name() const;
diff --git a/src/render/materialsystem/qgraphicsapifilter.h b/src/render/materialsystem/qgraphicsapifilter.h
index c618358dd..488d8bd4b 100644
--- a/src/render/materialsystem/qgraphicsapifilter.h
+++ b/src/render/materialsystem/qgraphicsapifilter.h
@@ -67,14 +67,14 @@ public:
OpenGLES = QSurfaceFormat::OpenGLES,
OpenGL = QSurfaceFormat::OpenGL
};
- Q_ENUM(Api)
+ Q_ENUM(Api) // LCOV_EXCL_LINE
enum OpenGLProfile {
NoProfile = QSurfaceFormat::NoProfile,
CoreProfile = QSurfaceFormat::CoreProfile,
CompatibilityProfile = QSurfaceFormat::CompatibilityProfile
};
- Q_ENUM(OpenGLProfile)
+ Q_ENUM(OpenGLProfile) // LCOV_EXCL_LINE
explicit QGraphicsApiFilter(QObject *parent = nullptr);
~QGraphicsApiFilter();
diff --git a/src/render/materialsystem/qgraphicsapifilter_p.h b/src/render/materialsystem/qgraphicsapifilter_p.h
index fed9df2ab..723eb14c2 100644
--- a/src/render/materialsystem/qgraphicsapifilter_p.h
+++ b/src/render/materialsystem/qgraphicsapifilter_p.h
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-struct GraphicsApiFilterData
+struct Q_AUTOTEST_EXPORT GraphicsApiFilterData
{
GraphicsApiFilterData();
@@ -74,7 +74,7 @@ struct GraphicsApiFilterData
bool operator <(const GraphicsApiFilterData &other) const;
};
-class QGraphicsApiFilterPrivate : public QObjectPrivate
+class Q_AUTOTEST_EXPORT QGraphicsApiFilterPrivate : public QObjectPrivate
{
public:
QGraphicsApiFilterPrivate()
@@ -92,6 +92,6 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::GraphicsApiFilterData);
+Q_DECLARE_METATYPE(Qt3DRender::GraphicsApiFilterData); // LCOV_EXCL_LINE
#endif // QT3DRENDER_QGRAPHICSAPIFILTER_P_H
diff --git a/src/render/materialsystem/qparameter.cpp b/src/render/materialsystem/qparameter.cpp
index 10af1d24c..8f83fd02e 100644
--- a/src/render/materialsystem/qparameter.cpp
+++ b/src/render/materialsystem/qparameter.cpp
@@ -53,6 +53,7 @@
/*!
* \class Qt3DRender::QParameter
+ * \inheaderfile Qt3DRender/QParameter
* \inmodule Qt3DRender
*
* \brief Provides storage for a name and value pair.
diff --git a/src/render/materialsystem/qshaderdata.cpp b/src/render/materialsystem/qshaderdata.cpp
index 066a6c55f..a636bc1a8 100644
--- a/src/render/materialsystem/qshaderdata.cpp
+++ b/src/render/materialsystem/qshaderdata.cpp
@@ -62,6 +62,7 @@ QShaderDataPrivate::QShaderDataPrivate(PropertyReaderInterfacePtr reader)
/*!
* \class Qt3DRender::QShaderData
+ * \inheaderfile Qt3DRender/QShaderData
* \inmodule Qt3DRender
*
* \brief Provides a way of specifying values of a Uniform Block or a shader
diff --git a/src/render/materialsystem/qshaderdata.h b/src/render/materialsystem/qshaderdata.h
index 767f4043f..e695d1eb0 100644
--- a/src/render/materialsystem/qshaderdata.h
+++ b/src/render/materialsystem/qshaderdata.h
@@ -82,7 +82,7 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QShaderData*)
-Q_DECLARE_METATYPE(QVector<Qt3DRender::QShaderData*>)
+Q_DECLARE_METATYPE(Qt3DRender::QShaderData*) // LCOV_EXCL_LINE
+Q_DECLARE_METATYPE(QVector<Qt3DRender::QShaderData*>) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QSHADERDATA_H
diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h
index f5a577de5..442a25b2e 100644
--- a/src/render/materialsystem/qshaderprogram.h
+++ b/src/render/materialsystem/qshaderprogram.h
@@ -71,7 +71,7 @@ public:
Geometry,
Compute
};
- Q_ENUM(ShaderType)
+ Q_ENUM(ShaderType) // LCOV_EXCL_LINE
// Source code in-line
QByteArray vertexShaderCode() const;
diff --git a/src/render/materialsystem/renderpass.cpp b/src/render/materialsystem/renderpass.cpp
index c589b3df6..e0fadddd9 100644
--- a/src/render/materialsystem/renderpass.cpp
+++ b/src/render/materialsystem/renderpass.cpp
@@ -70,6 +70,7 @@ RenderPass::~RenderPass()
void RenderPass::cleanup()
{
+ QBackendNode::setEnabled(false);
m_renderStates.clear();
m_filterKeyList.clear();
m_parameterPack.clear();
diff --git a/src/render/materialsystem/shaderdata_p.h b/src/render/materialsystem/shaderdata_p.h
index 6ce0c734c..987687eab 100644
--- a/src/render/materialsystem/shaderdata_p.h
+++ b/src/render/materialsystem/shaderdata_p.h
@@ -145,6 +145,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::ShaderData*)
+Q_DECLARE_METATYPE(Qt3DRender::Render::ShaderData*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_SHADERDATA_P_H
diff --git a/src/render/materialsystem/technique.cpp b/src/render/materialsystem/technique.cpp
index a3a650f7a..4fd1555e1 100644
--- a/src/render/materialsystem/technique.cpp
+++ b/src/render/materialsystem/technique.cpp
@@ -51,6 +51,9 @@
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qpropertynodeaddedchange.h>
#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/techniquemanager_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
#include <QDebug>
@@ -63,6 +66,8 @@ namespace Render {
Technique::Technique()
: BackendNode()
+ , m_isCompatibleWithRenderer(false)
+ , m_nodeManager(nullptr)
{
}
@@ -77,6 +82,7 @@ void Technique::cleanup()
m_parameterPack.clear();
m_renderPasses.clear();
m_filterKeyList.clear();
+ m_isCompatibleWithRenderer = false;
}
void Technique::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -88,6 +94,7 @@ void Technique::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &ch
m_filterKeyList = data.filterKeyIds;
m_parameterPack.setParameters(data.parameterIds);
m_renderPasses = data.renderPassIds;
+ m_nodeManager->techniqueManager()->addDirtyTechnique(peerId());
}
void Technique::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -98,6 +105,10 @@ void Technique::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (change->propertyName() == QByteArrayLiteral("graphicsApiFilterData")) {
GraphicsApiFilterData filterData = change->value().value<GraphicsApiFilterData>();
m_graphicsApiFilterData = filterData;
+ // Notify the manager that our graphicsApiFilterData has changed
+ // and that we therefore need to be check for compatibility again
+ m_isCompatibleWithRenderer = false;
+ m_nodeManager->techniqueManager()->addDirtyTechnique(peerId());
}
break;
}
@@ -162,6 +173,55 @@ const GraphicsApiFilterData *Technique::graphicsApiFilter() const
return &m_graphicsApiFilterData;
}
+bool Technique::isCompatibleWithRenderer() const
+{
+ return m_isCompatibleWithRenderer;
+}
+
+void Technique::setCompatibleWithRenderer(bool compatible)
+{
+ m_isCompatibleWithRenderer = compatible;
+}
+
+bool Technique::isCompatibleWithFilters(const QNodeIdVector &filterKeyIds)
+{
+ // There is a technique filter so we need to check for a technique with suitable criteria.
+ // Check for early bail out if the technique doesn't have sufficient number of criteria and
+ // can therefore never satisfy the filter
+ if (m_filterKeyList.size() < filterKeyIds.size())
+ return false;
+
+ // Iterate through the filter criteria and for each one search for a criteria on the
+ // technique that satisfies it
+ for (const QNodeId filterKeyId : filterKeyIds) {
+ FilterKey *filterKey = m_nodeManager->filterKeyManager()->lookupResource(filterKeyId);
+
+ bool foundMatch = false;
+
+ for (const QNodeId techniqueFilterKeyId : qAsConst(m_filterKeyList)) {
+ FilterKey *techniqueFilterKey = m_nodeManager->filterKeyManager()->lookupResource(techniqueFilterKeyId);
+ if ((foundMatch = (*techniqueFilterKey == *filterKey)))
+ break;
+ }
+
+ // No match for TechniqueFilter criterion in any of the technique's criteria.
+ // So no way this can match. Don't bother checking the rest of the criteria.
+ if (!foundMatch)
+ return false;
+ }
+ return true;
+}
+
+void Technique::setNodeManager(NodeManagers *nodeManager)
+{
+ m_nodeManager = nodeManager;
+}
+
+NodeManagers *Technique::nodeManager() const
+{
+ return m_nodeManager;
+}
+
void Technique::appendFilterKey(Qt3DCore::QNodeId criterionId)
{
if (!m_filterKeyList.contains(criterionId))
@@ -173,6 +233,31 @@ void Technique::removeFilterKey(Qt3DCore::QNodeId criterionId)
m_filterKeyList.removeOne(criterionId);
}
+TechniqueFunctor::TechniqueFunctor(AbstractRenderer *renderer, NodeManagers *manager)
+ : m_manager(manager)
+ , m_renderer(renderer)
+{
+}
+
+QBackendNode *TechniqueFunctor::create(const QNodeCreatedChangeBasePtr &change) const
+{
+ Technique *technique = m_manager->techniqueManager()->getOrCreateResource(change->subjectId());
+ technique->setNodeManager(m_manager);
+ technique->setRenderer(m_renderer);
+ return technique;
+}
+
+QBackendNode *TechniqueFunctor::get(QNodeId id) const
+{
+ return m_manager->techniqueManager()->lookupResource(id);
+}
+
+void TechniqueFunctor::destroy(QNodeId id) const
+{
+ m_manager->techniqueManager()->releaseResource(id);
+
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/materialsystem/technique_p.h b/src/render/materialsystem/technique_p.h
index 541076a0b..85fa09c02 100644
--- a/src/render/materialsystem/technique_p.h
+++ b/src/render/materialsystem/technique_p.h
@@ -73,7 +73,7 @@ namespace Render {
class TechniqueManager;
-class Technique : public BackendNode
+class Q_AUTOTEST_EXPORT Technique : public BackendNode
{
public:
Technique();
@@ -93,6 +93,14 @@ public:
QVector<Qt3DCore::QNodeId> renderPasses() const;
const GraphicsApiFilterData *graphicsApiFilter() const;
+ bool isCompatibleWithRenderer() const;
+ void setCompatibleWithRenderer(bool compatible);
+
+ bool isCompatibleWithFilters(const Qt3DCore::QNodeIdVector &filterKeyIds);
+
+ void setNodeManager(NodeManagers *nodeManager);
+ NodeManagers *nodeManager() const;
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -100,6 +108,20 @@ private:
ParameterPack m_parameterPack;
QVector<Qt3DCore::QNodeId> m_filterKeyList;
QVector<Qt3DCore::QNodeId> m_renderPasses;
+ bool m_isCompatibleWithRenderer;
+ NodeManagers *m_nodeManager;
+};
+
+class TechniqueFunctor : public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit TechniqueFunctor(AbstractRenderer *renderer, NodeManagers *manager);
+ Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_OVERRIDE;
+ Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE;
+ void destroy(Qt3DCore::QNodeId id) const Q_DECL_OVERRIDE;
+private:
+ NodeManagers *m_manager;
+ AbstractRenderer *m_renderer;
};
} // namespace Render
diff --git a/src/render/materialsystem/techniquemanager.cpp b/src/render/materialsystem/techniquemanager.cpp
new file mode 100644
index 000000000..a59810ea1
--- /dev/null
+++ b/src/render/materialsystem/techniquemanager.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "techniquemanager_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+TechniqueManager::TechniqueManager()
+{
+}
+
+// AspectThread
+void TechniqueManager::addDirtyTechnique(Qt3DCore::QNodeId techniqueId)
+{
+ if (!m_dirtyTechniques.contains(techniqueId))
+ m_dirtyTechniques.push_back(techniqueId);
+}
+
+// AspectThread
+QVector<Qt3DCore::QNodeId> TechniqueManager::takeDirtyTechniques()
+{
+ return std::move(m_dirtyTechniques);
+}
+
+} // Render
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/materialsystem/techniquemanager_p.h b/src/render/materialsystem/techniquemanager_p.h
new file mode 100644
index 000000000..5c86741c3
--- /dev/null
+++ b/src/render/materialsystem/techniquemanager_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_TECHNIQUEMANAGER_H
+#define QT3DRENDER_RENDER_TECHNIQUEMANAGER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/private/qresourcemanager_p.h>
+#include <Qt3DRender/private/technique_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT TechniqueManager : public Qt3DCore::QResourceManager<
+ Technique,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ TechniqueManager();
+
+ void addDirtyTechnique(Qt3DCore::QNodeId techniqueId);
+ QVector<Qt3DCore::QNodeId> takeDirtyTechniques();
+
+private:
+ QVector<Qt3DCore::QNodeId> m_dirtyTechniques;
+};
+
+} // Render
+} // Qt3DRender
+
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Technique, Q_REQUIRES_CLEANUP)
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_TECHNIQUEMANAGER_H
diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp
index c29c13cff..c7abf639c 100644
--- a/src/render/picking/qpickevent.cpp
+++ b/src/render/picking/qpickevent.cpp
@@ -89,8 +89,7 @@ QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersecti
}
/*!
- \fn Qt3DRender::QPickEvent::QPickEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance)
- Constructs a new QPickEvent with the given parameters: \a position, \a intersection, \a localIntersection, \a distance, \a button, \a buttons and \a modifiers
+ Constructs a new QPickEvent with the given parameters: \a position, \a worldIntersection, \a localIntersection, \a distance, \a button, \a buttons and \a modifiers
*/
QPickEvent::QPickEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, QPickEvent::Buttons button, int buttons, int modifiers)
: QObject(*new QPickEventPrivate())
diff --git a/src/render/picking/qpickevent.h b/src/render/picking/qpickevent.h
index cd925f7ea..3fbee0d30 100644
--- a/src/render/picking/qpickevent.h
+++ b/src/render/picking/qpickevent.h
@@ -73,7 +73,7 @@ public:
BackButton = Qt::BackButton,
NoButton = Qt::NoButton
};
- Q_ENUM(Buttons)
+ Q_ENUM(Buttons) // LCOV_EXCL_LINE
enum Modifiers {
NoModifier = Qt::NoModifier,
@@ -83,7 +83,7 @@ public:
MetaModifier = Qt::MetaModifier,
KeypadModifier = Qt::KeypadModifier
};
- Q_ENUM(Modifiers)
+ Q_ENUM(Modifiers) // LCOV_EXCL_LINE
QPickEvent();
QPickEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance);
@@ -118,6 +118,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QPickEvent*)
+Q_DECLARE_METATYPE(Qt3DRender::QPickEvent*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QPICKEVENT_H
diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp
index 50cafb8d9..ae96d5d2b 100644
--- a/src/render/picking/qpicktriangleevent.cpp
+++ b/src/render/picking/qpicktriangleevent.cpp
@@ -69,7 +69,7 @@ public:
\brief The QPickTriangleEvent class holds information when a triangle is picked
- \sa QPickEvent, QPickSettings
+ \sa QPickEvent
\since 5.7
*/
@@ -78,7 +78,7 @@ public:
* \instantiates Qt3DRender::QPickTriangleEvent
* \inqmlmodule Qt3D.Render
* \brief PickTriangleEvent holds information when a triangle is picked.
- * \sa ObjectPicker, PickSettings
+ * \sa ObjectPicker
*/
@@ -94,7 +94,7 @@ QPickTriangleEvent::QPickTriangleEvent()
/*!
* \brief QPickTriangleEvent::QPickTriangleEvent Constructs a new QPickEvent with the given parameters
* \a position,
- * \a intersection,
+ * \a worldIntersection,
* \a localIntersection,
* \a distance,
* \a triangleIndex,
@@ -150,7 +150,7 @@ QPickTriangleEvent::~QPickTriangleEvent()
*/
/*!
* \brief QPickTriangleEvent::triangleIndex
- * \return the index of the picked triangle
+ * Returns the index of the picked triangle
*/
uint QPickTriangleEvent::triangleIndex() const
{
@@ -168,7 +168,7 @@ uint QPickTriangleEvent::triangleIndex() const
*/
/*!
* \brief QPickTriangleEvent::vertex1Index
- * \returns index of first point of picked triangle
+ * Returns the index of the first point of the picked triangle
*/
uint QPickTriangleEvent::vertex1Index() const
{
@@ -186,7 +186,7 @@ uint QPickTriangleEvent::vertex1Index() const
*/
/*!
* \brief QPickTriangleEvent::vertex2Index
- * \returns index of second point of picked triangle
+ * Returns the index of the second point of the picked triangle
*/
uint QPickTriangleEvent::vertex2Index() const
{
diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h
index a2bb7873b..d26eacb98 100644
--- a/src/render/raycasting/qabstractcollisionqueryservice_p.h
+++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h
@@ -105,6 +105,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QAbstractCollisionQueryService::QueryMode)
+Q_DECLARE_METATYPE(Qt3DRender::QAbstractCollisionQueryService::QueryMode) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QABSTRACTCOLLISIONQUERYSERVICE_P_H
diff --git a/src/render/raycasting/qboundingvolume_p.h b/src/render/raycasting/qboundingvolume_p.h
index 87f7e45f5..a69530246 100644
--- a/src/render/raycasting/qboundingvolume_p.h
+++ b/src/render/raycasting/qboundingvolume_p.h
@@ -79,6 +79,6 @@ public:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QBoundingVolume*)
+Q_DECLARE_METATYPE(Qt3DRender::QBoundingVolume*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QBOUNDINGVOLUME_P_H
diff --git a/src/render/raycasting/qray3d_p.h b/src/render/raycasting/qray3d_p.h
index 3e454e7c8..d1fce726d 100644
--- a/src/render/raycasting/qray3d_p.h
+++ b/src/render/raycasting/qray3d_p.h
@@ -118,6 +118,6 @@ inline bool qFuzzyCompare(const Qt3DRender::QRay3D &ray1, const Qt3DRender::QRay
qFuzzyCompare(ray1.direction(), ray2.direction());
}
-Q_DECLARE_METATYPE(Qt3DRender::QRay3D)
+Q_DECLARE_METATYPE(Qt3DRender::QRay3D) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QRAY3D_H
diff --git a/src/render/render.pro b/src/render/render.pro
index 267664220..bcfcadd97 100644
--- a/src/render/render.pro
+++ b/src/render/render.pro
@@ -24,7 +24,6 @@ include (texture/texture.pri)
DEFINES += QT_NO_FOREACH
gcov {
- CONFIG += static
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage
}
diff --git a/src/render/renderstates/qalphacoverage.cpp b/src/render/renderstates/qalphacoverage.cpp
index 17251955d..428454040 100644
--- a/src/render/renderstates/qalphacoverage.cpp
+++ b/src/render/renderstates/qalphacoverage.cpp
@@ -46,13 +46,41 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QAlphaCoverage
- * \brief A QAlphaCoverage class
- * \since 5.7
- * \ingroup renderstates
+ \class Qt3DRender::QAlphaCoverage
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+ \brief Enable alpha-to-coverage multisampling mode
+
+ A Qt3DRender::QAlphaCoverage class enables alpha-to-coverage multisampling mode.
+ When enabled, the fragment alpha value is used as a coverage for the sample
+ and combined with fragment coverage value. Qt3DRender::QAlphaCoverage does
+ nothing if multisampling is disabled. Alpha-to-coverage is most useful when
+ order independent blending is required, for example when rendering leaves,
+ grass and other rich vegetation.
+
+ \sa Qt3DRender::QMultiSampleAntiAliasing
+ */
+
+/*!
+ \qmltype AlphaCoverage
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QAlphaCoverage
+ \inherits RenderState
+ \brief Enable alpha-to-coverage multisampling mode
+
+ An AlphaCoverage type enables alpha-to-coverage multisampling mode.
+ When enabled, the fragment alpha value is used as a coverage for the sample
+ and combined with fragment coverage value. AlphaCoverage does nothing if
+ multisampling is disabled. Alpha-to-coverage is most useful when
+ order independent blending is required, for example when rendering leaves,
+ grass and other rich vegetation.
+
+ \sa MultiSampleAntiAliasing
*/
-/*! \internal */
class QAlphaCoveragePrivate : public QRenderStatePrivate
{
public :
@@ -64,8 +92,8 @@ public :
};
/*!
- * The constructor creates a new QAlphaCoverage::QAlphaCoverage instance
- * with the specified \a parent.
+ The constructor creates a new QAlphaCoverage::QAlphaCoverage instance
+ with the specified \a parent.
*/
QAlphaCoverage::QAlphaCoverage(QNode *parent)
: QRenderState(*new QAlphaCoveragePrivate, parent)
diff --git a/src/render/renderstates/qalphatest.cpp b/src/render/renderstates/qalphatest.cpp
index 2341c1039..81227d499 100644
--- a/src/render/renderstates/qalphatest.cpp
+++ b/src/render/renderstates/qalphatest.cpp
@@ -38,17 +38,6 @@
**
****************************************************************************/
-/*!
- * \class QAlphaTest
- * \brief The QAlphaTest class is an OpenGL helper.
- * \since 5.7
- * \ingroup renderstates
- *
- * As the OpenGL documentation explains; The alpha test discards a fragment
- * conditional on the outcome of a comparison between the incoming fragment's
- * alpha value and a constant value.
- */
-
#include "qalphatest.h"
#include "qalphatest_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -57,6 +46,80 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
+/*!
+ \class Qt3DRender::QAlphaTest
+ \brief The QAlphaTest class specify alpha reference test
+ \since 5.7
+ \inmodule Qt3DRender
+ \ingroup renderstates
+
+ As the OpenGL documentation explains; The alpha test discards a fragment
+ conditional on the outcome of a comparison between the incoming fragment's
+ alpha value and a constant reference value.
+ */
+
+/*!
+ \qmltype AlphaTest
+ \brief The AlphaTest class specify alpha reference test
+ \since 5.7
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QAlphaTest
+ \ingroup renderstates
+
+ As the OpenGL documentation explains; The alpha test discards a fragment
+ conditional on the outcome of a comparison between the incoming fragment's
+ alpha value and a constant reference value.
+ */
+
+/*!
+ \enum Qt3DRender::QAlphaTest::AlphaFunction
+
+ Enumeration for the alpha function values
+ \value Never Never pass alpha test
+ \value Always Always pass alpha test
+ \value Less Pass alpha test if fragment alpha is less than reference value
+ \value LessOrEqual Pass alpha test if fragment alpha is less than or equal to reference value
+ \value Equal Pass alpha test if fragment alpha is equal to reference value
+ \value GreaterOrEqual Pass alpha test if fragment alpha is greater than or equal to reference value
+ \value Greater Pass alpha test if fragment alpha is greater than reference value
+ \value NotEqual Pass alpha test if fragment alpha is not equal to reference value
+*/
+
+/*!
+ \qmlproperty enumeration AlphaTest::alphaFunction
+ Holds the alpha function used by the alpha test. Default is AlphaTest.Never.
+ \list
+ \li AlphaTest.Never
+ \li AlphaTest.Always
+ \li AlphaTest.Less
+ \li AlphaTest.LessOrEqual
+ \li AlphaTest.Equal
+ \li AlphaTest.GreaterOrEqual
+ \li AlphaTest.Greater
+ \li AlphaTest.NotEqual
+ \endlist
+ \sa Qt3DRender::QAlphaTest::AlphaFunction
+*/
+
+/*!
+ \qmlproperty real AlphaTest::referenceValue
+ Holds the reference value used by the alpha test. Default is 0.0.
+ When set, the value is clamped between 0 and 1.
+*/
+
+/*!
+ \property QAlphaTest::alphaFunction
+ Holds the alpha function used by the alpha test. Default is Never.
+*/
+
+/*!
+ \property QAlphaTest::referenceValue
+ Holds the reference value used by the alpha test. Default is 0.0.
+ When set, the value is clamped between 0 and 1.
+*/
+
+
QAlphaTest::QAlphaTest(QNode *parent)
: QRenderState(*new QAlphaTestPrivate, parent)
{
@@ -67,19 +130,12 @@ QAlphaTest::~QAlphaTest()
{
}
-/*!
- * \return the current alpha test function.
- */
QAlphaTest::AlphaFunction QAlphaTest::alphaFunction() const
{
Q_D(const QAlphaTest);
return d->m_alphaFunction;
}
-/*!
- * Sets the alpha test function to \a alphaFunction.
- * \param alphaFunction
- */
void QAlphaTest::setAlphaFunction(QAlphaTest::AlphaFunction alphaFunction)
{
Q_D(QAlphaTest);
@@ -89,18 +145,12 @@ void QAlphaTest::setAlphaFunction(QAlphaTest::AlphaFunction alphaFunction)
}
}
-/*!
- * \return a float value between 0 and 1.
- */
float QAlphaTest::referenceValue() const
{
Q_D(const QAlphaTest);
return d->m_referenceValue;
}
-/*!
- * Sets the reference value which is clamped between 0 and 1 to \a referenceValue.
- */
void QAlphaTest::setReferenceValue(float referenceValue)
{
Q_D(QAlphaTest);
diff --git a/src/render/renderstates/qalphatest.h b/src/render/renderstates/qalphatest.h
index 49a5fac43..67106ade5 100644
--- a/src/render/renderstates/qalphatest.h
+++ b/src/render/renderstates/qalphatest.h
@@ -66,7 +66,7 @@ public:
Greater = 0x0204,
NotEqual = 0x0205
};
- Q_ENUM(AlphaFunction)
+ Q_ENUM(AlphaFunction) // LCOV_EXCL_LINE
explicit QAlphaTest(Qt3DCore::QNode *parent = nullptr);
~QAlphaTest();
diff --git a/src/render/renderstates/qblendequation.cpp b/src/render/renderstates/qblendequation.cpp
index e48e83883..220116626 100644
--- a/src/render/renderstates/qblendequation.cpp
+++ b/src/render/renderstates/qblendequation.cpp
@@ -40,6 +40,7 @@
/*!
* \class Qt3DRender::QBlendEquation
+ * \inheaderfile Qt3DRender/QBlendEquation
* \brief The QBlendEquation class specifies the equation used for both the RGB
* blend equation and the Alpha blend equation
* \inmodule Qt3DRender
diff --git a/src/render/renderstates/qblendequation.h b/src/render/renderstates/qblendequation.h
index 6810cf96e..8bdfe4907 100644
--- a/src/render/renderstates/qblendequation.h
+++ b/src/render/renderstates/qblendequation.h
@@ -63,7 +63,7 @@ public:
Min = 0x8007,
Max = 0x8008
};
- Q_ENUM(BlendFunction)
+ Q_ENUM(BlendFunction) // LCOV_EXCL_LINE
explicit QBlendEquation(Qt3DCore::QNode *parent = nullptr);
~QBlendEquation();
diff --git a/src/render/renderstates/qblendequationarguments.cpp b/src/render/renderstates/qblendequationarguments.cpp
index 58c048138..7ea020083 100644
--- a/src/render/renderstates/qblendequationarguments.cpp
+++ b/src/render/renderstates/qblendequationarguments.cpp
@@ -121,7 +121,8 @@ QBlendEquationArguments::QBlendEquationArguments(QBlendEquationArgumentsPrivate
\value OneMinusConstantColor GL_ONE_MINUS_CONSTANT_COLOR
\value OneMinusConstantAlpha GL_ONE_MINUS_CONSTANT_ALPHA
\value OneMinusSource1Alpha GL_ONE_MINUS_SRC1_ALPHA
- \value OneMinusSource1Color0 GL_ONE_MINUS_SRC1_COLOR
+ \value OneMinusSource1Color GL_ONE_MINUS_SRC1_COLOR
+ \value OneMinusSource1Color0 GL_ONE_MINUS_SRC1_COLOR (deprecated)
*/
/*!
diff --git a/src/render/renderstates/qblendequationarguments.h b/src/render/renderstates/qblendequationarguments.h
index 2f844b8cf..5f613770a 100644
--- a/src/render/renderstates/qblendequationarguments.h
+++ b/src/render/renderstates/qblendequationarguments.h
@@ -80,9 +80,10 @@ public:
OneMinusConstantColor = 0x8002,
OneMinusConstantAlpha = 0x8004,
OneMinusSource1Alpha,
- OneMinusSource1Color0
+ OneMinusSource1Color,
+ OneMinusSource1Color0 = OneMinusSource1Color // ### Qt 6: Remove
};
- Q_ENUM(Blending)
+ Q_ENUM(Blending) // LCOV_EXCL_LINE
explicit QBlendEquationArguments(Qt3DCore::QNode *parent = nullptr);
~QBlendEquationArguments();
diff --git a/src/render/renderstates/qclipplane.cpp b/src/render/renderstates/qclipplane.cpp
index f117d040a..19053c147 100644
--- a/src/render/renderstates/qclipplane.cpp
+++ b/src/render/renderstates/qclipplane.cpp
@@ -55,7 +55,8 @@ namespace Qt3DRender {
By default, OpenGL supports up to 8 additional clipping planes.
Qt3DCore::QClipPlane allows to enable one of these additional planes. These
planes can then be manipulated in the shaders using gl_ClipDistance[i]
- where i varies between 0 and 8.
+ where i varies between 0 and 7. The underlying implementation may support more
+ than 8 clip planes, but it is not guaranteed.
*/
/*!
@@ -70,9 +71,44 @@ namespace Qt3DRender {
By default, OpenGL supports up to 8 additional clipping planes. ClipPlane
allows to enable one of these additional planes. These planes can then be
manipulated in the shaders using gl_ClipDistance[i] where i varies between
- 0 and 8.
+ 0 and 7. The underlying implementation may support more than 8 clip planes,
+ but it is not guaranteed.
*/
+/*!
+ \qmlproperty int ClipPlane::planeIndex
+ Holds the index of the plane.
+ \note Usually between 0-7.
+*/
+
+/*!
+ \qmlproperty vector3d ClipPlane::normal
+ Holds the normal of the plane.
+*/
+
+/*!
+ \qmlproperty real ClipPlane::distance
+ Holds the distance of the plane from the world origin.
+*/
+
+
+/*!
+ \property QClipPlane::planeIndex
+ Holds the index of the plane.
+ \note Usually between 0-7.
+*/
+
+/*!
+ \property QClipPlane::normal
+ Holds the normal of the plane.
+*/
+
+/*!
+ \property QClipPlane::distance
+ Holds the distance of the plane from the world origin.
+*/
+
+
QClipPlane::QClipPlane(QNode *parent)
: QRenderState(*new QClipPlanePrivate(), parent)
{
@@ -83,10 +119,6 @@ QClipPlane::~QClipPlane()
{
}
-/*!
- * Returns the index of the clip plane.
- * \note usually between 0-7
- */
int QClipPlane::planeIndex() const
{
Q_D(const QClipPlane);
@@ -105,10 +137,6 @@ float QClipPlane::distance() const
return d->m_distance;
}
-/*!
- * Sets the index of the clip plane to \a plane.
- * \note above 7, support is not garanteed
- */
void QClipPlane::setPlaneIndex(int planeIndex)
{
Q_D(QClipPlane);
diff --git a/src/render/renderstates/qcolormask.cpp b/src/render/renderstates/qcolormask.cpp
index 71819db94..fde09d7b0 100644
--- a/src/render/renderstates/qcolormask.cpp
+++ b/src/render/renderstates/qcolormask.cpp
@@ -48,7 +48,22 @@ namespace Qt3DRender {
/*!
\class Qt3DRender::QColorMask
\inmodule Qt3DRender
+ \since 5.7
+ \brief Allows specifying which color components should be written to the
+ currently bound frame buffer.
+ By default, the property for each color component (red, green, blue, alpha)
+ is set to \c true which means they will be written to the frame buffer.
+ Setting any of the color component to \c false will prevent it from being
+ written into the frame buffer.
+ */
+
+/*!
+ \qmltype ColorMask
+ \inqmlmodule Qt3D.Render
+ \since 5.7
+ \inherits RenderState
+ \instantiates Qt3DRender::QColorMask
\brief Allows specifying which color components should be written to the
currently bound frame buffer.
@@ -58,6 +73,26 @@ namespace Qt3DRender {
written into the frame buffer.
*/
+/*!
+ \qmlproperty bool ColorMask::redMasked
+ Holds whether red color component should be written to the frame buffer.
+*/
+
+/*!
+ \qmlproperty bool ColorMask::greenMasked
+ Holds whether green color component should be written to the frame buffer.
+*/
+
+/*!
+ \qmlproperty bool ColorMask::blueMasked
+ Holds whether blue color component should be written to the frame buffer.
+*/
+
+/*!
+ \qmlproperty bool ColorMask::alphaMasked
+ Holds whether alpha component should be written to the frame buffer.
+*/
+
/*!
Constructs a new Qt3DCore::QColorMask instance with \a parent as parent.
@@ -97,7 +132,7 @@ bool QColorMask::isAlphaMasked() const
}
/*!
- \property Qt3DRender::QColorMask::red
+ \property QColorMask::redMasked
Holds whether the red color component should be written to the frame buffer.
*/
void QColorMask::setRedMasked(bool redMasked)
@@ -110,7 +145,7 @@ void QColorMask::setRedMasked(bool redMasked)
}
/*!
- \property Qt3DRender::QColorMask::green
+ \property QColorMask::greenMasked
Holds whether the green color component should be written to the frame buffer.
*/
void QColorMask::setGreenMasked(bool greenMasked)
@@ -123,7 +158,7 @@ void QColorMask::setGreenMasked(bool greenMasked)
}
/*!
- \property Qt3DRender::QColorMask::blue
+ \property QColorMask::blueMasked
Holds whether the blue color component should be written to the frame buffer.
*/
void QColorMask::setBlueMasked(bool blueMasked)
@@ -136,7 +171,7 @@ void QColorMask::setBlueMasked(bool blueMasked)
}
/*!
- \property Qt3DRender::QColorMask::alphaMasked
+ \property QColorMask::alphaMasked
Holds whether the alphaMasked component should be written to the frame buffer.
*/
void QColorMask::setAlphaMasked(bool alphaMasked)
diff --git a/src/render/renderstates/qcullface.cpp b/src/render/renderstates/qcullface.cpp
index 2b8a7f8e0..e96346287 100644
--- a/src/render/renderstates/qcullface.cpp
+++ b/src/render/renderstates/qcullface.cpp
@@ -38,18 +38,7 @@
**
****************************************************************************/
-/*!
- * \class QCullFace
- * \brief The QCullFace class specifies whether front or back face culling
- * are enabled
- * \since 5.7
- * \ingroup renderstates
- *
- * QCullFace sets whether the front or back facets are culled.
- * Facets include triangles, quadrilaterals, polygons and rectangles.
- *
- * \sa QFrontFace
- */
+
#include "qcullface.h"
#include "qcullface_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -59,7 +48,57 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * Constructs a new QCullFace::QCullFace instance with \a parent as parent.
+ \class Qt3DRender::QCullFace
+ \brief The QCullFace class specifies whether front or back face culling
+ are enabled
+ \since 5.7
+ \inmodule Qt3DRender
+ \ingroup renderstates
+
+ QCullFace sets whether the front or back facets are culled.
+ Facets include triangles, quadrilaterals, polygons and rectangles.
+
+ \sa QFrontFace
+ */
+
+/*!
+ \qmltype CullFace
+ \brief The CullFace type specifies whether front or back face culling
+ are enabled
+ \since 5.7
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QCullFace
+ \inherits RenderState
+ \ingroup renderstates
+
+ CullFace sets whether the front or back facets are culled.
+ Facets include triangles, quadrilaterals, polygons and rectangles.
+
+ \sa FrontFace
+ */
+
+/*!
+ \enum Qt3DRender::QCullFace::CullingMode
+
+ This enumeration specifies values for the culling mode.
+ \value NoCulling culling is disabled
+ \value Front Culling is enabled for front facing polygons
+ \value Back Culling is enabled for back facing polygons
+ \value FrontAndBack Culling is enabled for all polygons, points and lines are drawn.
+*/
+
+/*!
+ \qmlproperty enumeration CullFace::mode
+ Holds the culling mode used by CullFace. Default is set to QCullFace.Back.
+*/
+
+/*!
+ \property QCullFace::mode
+ Holds the culling mode used by QCullFace. Default is set to QCullFace.Back.
+*/
+
+/*!
+ Constructs a new QCullFace::QCullFace instance with \a parent as parent.
*/
QCullFace::QCullFace(QNode *parent)
: QRenderState(*new QCullFacePrivate, parent)
@@ -71,19 +110,12 @@ QCullFace::~QCullFace()
{
}
-/*!
- * \return which culling mode is currently enabled.
- */
QCullFace::CullingMode QCullFace::mode() const
{
Q_D(const QCullFace);
return d->m_mode;
}
-/*!
- * Sets which faces to cull to \a mode. Default is set to back.
- * \param mode
- */
void QCullFace::setMode(QCullFace::CullingMode mode)
{
Q_D(QCullFace);
diff --git a/src/render/renderstates/qcullface.h b/src/render/renderstates/qcullface.h
index 3474fe009..8598d3b88 100644
--- a/src/render/renderstates/qcullface.h
+++ b/src/render/renderstates/qcullface.h
@@ -64,7 +64,7 @@ public:
Back = 0x0405,
FrontAndBack = 0x0408
};
- Q_ENUM(CullingMode)
+ Q_ENUM(CullingMode) // LCOV_EXCL_LINE
explicit QCullFace(Qt3DCore::QNode *parent = nullptr);
~QCullFace();
diff --git a/src/render/renderstates/qdepthtest.cpp b/src/render/renderstates/qdepthtest.cpp
index c2299f810..7e67ba5ba 100644
--- a/src/render/renderstates/qdepthtest.cpp
+++ b/src/render/renderstates/qdepthtest.cpp
@@ -38,14 +38,6 @@
**
****************************************************************************/
-/*!
- * \class QDepthTest
- * \brief The QDepthTest class tests the fragment shader's depth value against
- * the depth of a sample being written to.
- * \since 5.7
- * \ingroup renderstates
- *
- */
#include "qdepthtest.h"
#include "qdepthtest_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -55,7 +47,79 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QDepthTest::QDepthTest instance with the specified \a parent.
+ \class Qt3DRender::QDepthTest
+ \brief The QDepthTest class tests the fragment shader's depth value against
+ the depth of a sample being written to.
+ \since 5.7
+ \inmodule Qt3DRender
+ \ingroup renderstates
+
+ A QDepthTest class is used to enable depth testing with a given depth test function.
+ The depth test enables writing fragment color values when the depth test passes, and
+ reject fragments which fail the test. The depth test uses the depth function to
+ test the fragments depth value to the value against z-buffer. If the underlying surface
+ does not have z-buffer, then QDepthTest does nothing.
+
+ \sa QAlphaTest, QStencilTest
+ */
+
+/*!
+ \qmltype DepthTest
+ \brief The DepthTest type tests the fragment shader's depth value against
+ the depth of a sample being written to.
+ \since 5.7
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QDepthTest
+ \ingroup renderstates
+
+ A DepthTest type is used to enable depth testing with a given depth test function.
+ The depth test enables writing fragment color values when the depth test passes, and
+ reject fragments which fail the test. The depth test uses the depth function to
+ test the fragments depth value to the value against z-buffer. If the underlying surface
+ does not have z-buffer, the DepthTest does nothing.
+
+ \sa AlphaTest, StencilTest
+ */
+
+/*!
+ \enum Qt3DRender::QDepthTest::DepthFunction
+
+ Enumeration for the depth function values
+ \value Never Never pass depth test
+ \value Always Always pass depth test
+ \value Less Pass depth test if fragment depth is less than z-buffer value
+ \value LessOrEqual Pass depth test if fragment depth is less than or equal to z-buffer value
+ \value Equal Pass depth test if fragment depth is equal to z-buffer value
+ \value GreaterOrEqual Pass depth test if fragment depth is greater than or equal to z-buffer value
+ \value Greater Pass depth test if fragment depth is greater than z-buffer value
+ \value NotEqual Pass depth test if fragment depth is not equal to z-buffer value
+*/
+
+/*!
+ \qmlproperty enumeration DepthTest::depthFunction
+ Holds the current function used by depth test. The default is DepthTest.Never.
+ \list
+ \li DepthTest.Never
+ \li DepthTest.Always
+ \li DepthTest.Less
+ \li DepthTest.LessOrEqual
+ \li DepthTest.Equal
+ \li DepthTest.GreaterOrEqual
+ \li DepthTest.Greater
+ \li DepthTest.NotEqual
+ \endlist
+ \sa Qt3DRender::QDepthTest::DepthFunction
+*/
+
+/*!
+ \property QDepthTest::depthFunction
+ Holds the current function used by depth test. The default is Never.
+*/
+
+
+/*!
+ The constructor creates a new QDepthTest::QDepthTest instance with the specified \a parent.
*/
QDepthTest::QDepthTest(QNode *parent)
: QRenderState(*new QDepthTestPrivate, parent)
@@ -67,19 +131,12 @@ QDepthTest::~QDepthTest()
{
}
-/*!
- * \return the current enabled depth function.
- */
QDepthTest::DepthFunction QDepthTest::depthFunction() const
{
Q_D(const QDepthTest);
return d->m_depthFunction;
}
-/*!
- * Sets the depth function being enabled to \a depthFunction
- * \param depthFunction
- */
void QDepthTest::setDepthFunction(QDepthTest::DepthFunction depthFunction)
{
Q_D(QDepthTest);
diff --git a/src/render/renderstates/qdepthtest.h b/src/render/renderstates/qdepthtest.h
index 16b4a5b85..9482ef9a5 100644
--- a/src/render/renderstates/qdepthtest.h
+++ b/src/render/renderstates/qdepthtest.h
@@ -65,7 +65,7 @@ public:
Greater = 0x0204,
NotEqual = 0x0205
};
- Q_ENUM(DepthFunction)
+ Q_ENUM(DepthFunction) // LCOV_EXCL_LINE
explicit QDepthTest(Qt3DCore::QNode *parent = nullptr);
~QDepthTest();
diff --git a/src/render/renderstates/qdithering.cpp b/src/render/renderstates/qdithering.cpp
index 7b98ed7ae..102cfa0ff 100644
--- a/src/render/renderstates/qdithering.cpp
+++ b/src/render/renderstates/qdithering.cpp
@@ -48,13 +48,31 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QDithering
- * \brief The QDithering class
- * \since 5.7
- * \ingroup
+ \class Qt3DRender::QDithering
+ \since 5.7
+ \inmodule Qt3DRender
+ \brief Enable dithering
+
+ A Qt3DRender::QDithering class enables dithering. Dithering adds noise to the
+ color values to randomize quantization error in order to prevent large scale
+ patterns in the final image, such as banding. Dithering is most useful when
+ rendering to a surface with low color bit depth, such as RGB565 or RGBA4444.
+ */
+
+/*!
+ \qmltype Dithering
+ \since 5.7
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QDithering
+ \brief Enable dithering
+
+ A Dithering type enables dithering. Dithering adds noise to the
+ color values to randomize quantization error in order to prevent large scale
+ patterns in the final image, such as banding. Dithering is most useful when
+ rendering to a surface with low color bit depth, such as RGB565 or RGBA4444.
*/
-/*! \internal */
class QDitheringPrivate : public QRenderStatePrivate
{
public:
@@ -66,8 +84,8 @@ public:
};
/*!
- * The constructor creates a new QDithering::QDithering instance with
- * the specified \a parent.
+ The constructor creates a new QDithering::QDithering instance with
+ the specified \a parent.
*/
QDithering::QDithering(QNode *parent)
: QRenderState(*new QDitheringPrivate, parent)
diff --git a/src/render/renderstates/qfrontface.cpp b/src/render/renderstates/qfrontface.cpp
index 016f27370..a814be82f 100644
--- a/src/render/renderstates/qfrontface.cpp
+++ b/src/render/renderstates/qfrontface.cpp
@@ -38,13 +38,6 @@
**
****************************************************************************/
-/*!
- * \class QFrontFace
- * \brief The QFrontFace class defines front and back facing polygons.
- * \since 5.7
- * \ingroup renderstates
- *
- */
#include "qfrontface.h"
#include "qfrontface_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -54,8 +47,52 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QFrontFace::QFrontFace instance with the
- * specified \a parent
+ \class Qt3DRender::QFrontFace
+ \brief The QFrontFace class defines front and back facing polygons.
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QFrontFace sets the winding direction of the front facing polygons.
+
+ \sa QCullFace
+ */
+
+/*!
+ \qmltype FrontFace
+ \brief The FrontFace type defines front and back facing polygons.
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QFrontFace
+
+ A FrontFace sets the winding direction of the front facing polygons.
+
+ \sa CullFace
+ */
+
+/*!
+ \enum QFrontFace::WindingDirection
+
+ This enumeration specifies the winding direction values.
+ \value ClockWise Clockwise polygons are front facing.
+ \value CounterClockWise Counter clockwise polygons are front facing.
+*/
+
+/*!
+ \qmlproperty enumeration FrontFace::direction
+ Holds the winding direction of the front facing polygons. Default is FrontFace.Clockwise.
+*/
+
+/*!
+ \property QFrontFace::direction
+ Holds the winding direction of the front facing polygons. Default is Clockwise.
+*/
+
+/*!
+ The constructor creates a new QFrontFace::QFrontFace instance with the
+ specified \a parent
*/
QFrontFace::QFrontFace(QNode *parent)
: QRenderState(*new QFrontFacePrivate, parent)
@@ -67,19 +104,12 @@ QFrontFace::~QFrontFace()
{
}
-/*!
- * \return the current winding direction
- */
QFrontFace::WindingDirection QFrontFace::direction() const
{
Q_D(const QFrontFace);
return d->m_direction;
}
-/*!
- * Sets the winding direction to \a direction
- * \param direction
- */
void QFrontFace::setDirection(QFrontFace::WindingDirection direction)
{
Q_D(QFrontFace);
diff --git a/src/render/renderstates/qfrontface.h b/src/render/renderstates/qfrontface.h
index dd8a7f5fe..0f1061280 100644
--- a/src/render/renderstates/qfrontface.h
+++ b/src/render/renderstates/qfrontface.h
@@ -60,7 +60,7 @@ public:
ClockWise = 0x0900,
CounterClockWise = 0x0901
};
- Q_ENUM(WindingDirection)
+ Q_ENUM(WindingDirection) // LCOV_EXCL_LINE
explicit QFrontFace(Qt3DCore::QNode *parent = nullptr);
~QFrontFace();
diff --git a/src/render/renderstates/qmultisampleantialiasing.cpp b/src/render/renderstates/qmultisampleantialiasing.cpp
index ae398cd0d..923fc435e 100644
--- a/src/render/renderstates/qmultisampleantialiasing.cpp
+++ b/src/render/renderstates/qmultisampleantialiasing.cpp
@@ -47,13 +47,29 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class QMultiSampleAntiAliasing
- * \brief The QMultiSampleAntiAliasing class
- * \since 5.7
- * \ingroup renderstates
+ \class Qt3DRender::QMultiSampleAntiAliasing
+ \brief Enable multisample antialiasing
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QMultiSampleAntiAliasing class enables multisample antialiasing.
+ The render target must have been allocated with multisampling enabled.
+ */
+
+/*!
+ \qmltype MultiSampleAntiAliasing
+ \brief Enable multisample antialiasing
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QMultiSampleAntiAliasing
+
+ A MultiSampleAntiAliasing type enables multisample antialiasing.
+ The render target must have been allocated with multisampling enabled.
*/
-/*! \internal */
class QMultiSampleAntiAliasingPrivate : public QRenderStatePrivate
{
public:
@@ -66,8 +82,8 @@ public:
};
/*!
- * The constructor creates a new QMultiSampleAntiAliasing::QMultiSampleAntiAliasing
- * instance with the specified \a parent.
+ The constructor creates a new QMultiSampleAntiAliasing::QMultiSampleAntiAliasing
+ instance with the specified \a parent.
*/
QMultiSampleAntiAliasing::QMultiSampleAntiAliasing(QNode *parent)
: QRenderState(*new QMultiSampleAntiAliasingPrivate, parent)
diff --git a/src/render/renderstates/qnodepthmask.cpp b/src/render/renderstates/qnodepthmask.cpp
index b508f60b3..f0376cfb6 100644
--- a/src/render/renderstates/qnodepthmask.cpp
+++ b/src/render/renderstates/qnodepthmask.cpp
@@ -48,13 +48,31 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class QNoDepthMask
- * \brief The QNoDepthMask class
- * \since 5.7
- * \ingroup renderstates
+ \class Qt3DRender::QNoDepthMask
+ \brief Disable depth write
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QNoDepthMask class disables fragment depth write to depth buffer.
+
+ \sa Qt3DRender::QDepthTest
+ */
+
+/*!
+ \qmltype NoDepthMask
+ \brief Disable depth write
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QNoDepthMask
+
+ A NoDepthMask type disables fragment depth write to depth buffer.
+
+ \sa Qt3DRender::QDepthTest
*/
-/*! \internal */
class QNoDepthMaskPrivate : public QRenderStatePrivate
{
public:
@@ -67,8 +85,8 @@ public:
};
/*!
- * the constructor creates a new QNoDepthMask::QNoDepthMask instance with
- * the specified \a parent.
+ The constructor creates a new QNoDepthMask::QNoDepthMask instance with
+ the specified \a parent.
*/
QNoDepthMask::QNoDepthMask(QNode *parent)
: QRenderState(*new QNoDepthMaskPrivate, parent)
diff --git a/src/render/renderstates/qpointsize.cpp b/src/render/renderstates/qpointsize.cpp
index 03c37bc4b..10687f8f2 100644
--- a/src/render/renderstates/qpointsize.cpp
+++ b/src/render/renderstates/qpointsize.cpp
@@ -48,6 +48,7 @@ namespace Qt3DRender {
/*!
\class Qt3DRender::QPointSize
\inmodule Qt3DRender
+ \since 5.7
\brief Specifies the size of rasterized points. May either be set statically
or by shader programs.
@@ -59,6 +60,8 @@ namespace Qt3DRender {
/*!
\qmltype PointSize
+ \since 5.7
+ \inherits RenderState
\instantiates Qt3DRender::QPointSize
\inqmlmodule Qt3D.Render
@@ -72,12 +75,29 @@ namespace Qt3DRender {
*/
/*!
- \qmlproperty float Qt3D.Render::QPointSize::value
+ \enum Qt3DRender::QPointSize::SizeMode
+
+ This enumeration specifies values for the size mode.
+ \value Fixed The point size is by the QPointSize::value.
+ \value Programmable The point size value must be set in shader
+*/
+/*!
+ \qmlproperty real PointSize::value
+ Specifies the point size value to be used.
+*/
+
+/*!
+ \qmlproperty enumeration PointSize::sizeMode
+ Specifies the sizeMode to be used.
+*/
+
+/*!
+ \property QPointSize::value
Specifies the point size value to be used.
*/
/*!
- \qmlproperty QPointSize::SizeMode Qt3D.Render::QPointSize::sizeMode
+ \property QPointSize::sizeMode
Specifies the sizeMode to be used.
*/
diff --git a/src/render/renderstates/qpointsize.h b/src/render/renderstates/qpointsize.h
index fdfa54a9c..621d983b8 100644
--- a/src/render/renderstates/qpointsize.h
+++ b/src/render/renderstates/qpointsize.h
@@ -58,7 +58,7 @@ public:
Fixed = 0,
Programmable = 1
};
- Q_ENUM(SizeMode)
+ Q_ENUM(SizeMode) // LCOV_EXCL_LINE
explicit QPointSize(Qt3DCore::QNode *parent = nullptr);
~QPointSize();
diff --git a/src/render/renderstates/qpolygonoffset.cpp b/src/render/renderstates/qpolygonoffset.cpp
index d9703ab4b..0d397f159 100644
--- a/src/render/renderstates/qpolygonoffset.cpp
+++ b/src/render/renderstates/qpolygonoffset.cpp
@@ -37,14 +37,6 @@
**
****************************************************************************/
-/*!
- * \class QPolygonOffset
- * \brief The QPolygonOffset class sets the scale and steps to calculate depth
- * values for polygon offsets.
- * \since 5.7
- * \ingroup renderstates
- *
- */
#include "qpolygonoffset.h"
#include "qpolygonoffset_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -54,8 +46,58 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QPolygonOffset::QPolygonOffset instance
- * with the specified \a parent
+ \class Qt3DRender::QPolygonOffset
+ \brief The QPolygonOffset class sets the scale and steps to calculate depth
+ values for polygon offsets.
+ \since 5.7
+ \inmodule Qt3DRender
+ \ingroup renderstates
+
+ A QPolygonOffset class adds an offset to the fragment depth value prior to
+ depth test and depth write. The offset can be used to avoid z-fighting when
+ rendering polygons with very close depth values such as decals.
+ */
+
+/*!
+ \qmltype PolygonOffset
+ \brief The PolygonOffset type sets the scale and steps to calculate depth
+ values for polygon offsets.
+ \since 5.7
+ \inqmlmodule Qt3D.Render
+ \ingroup renderstates
+ \inherits RenderState
+ \instantiates Qt3DRender::QPolygonOffset
+
+ A PolygonOffset type adds an offset to the fragment depth value prior to
+ depth test and depth write. The offset can be used to avoid z-fighting when
+ rendering polygons with very close depth values such as decals.
+ */
+
+/*!
+ \qmlproperty real PolygonOffset::scaleFactor
+ Holds the scale factor used to create a variable depth offset for
+ each polygon. Default value is 0.
+*/
+
+/*!
+ \qmlproperty real PolygonOffset::depthSteps
+ Holds the units that create constant depth offsets. Default value is 0.
+*/
+
+/*!
+ \property QPolygonOffset::scaleFactor
+ Holds the scale factor used to create a variable depth offset for
+ each polygon. Default value is 0.
+*/
+
+/*!
+ \property QPolygonOffset::depthSteps
+ Holds the units that create constant depth offsets. Default value is 0.
+*/
+
+/*!
+ The constructor creates a new QPolygonOffset::QPolygonOffset instance
+ with the specified \a parent
*/
QPolygonOffset::QPolygonOffset(QNode *parent)
: QRenderState(*new QPolygonOffsetPrivate, parent)
@@ -67,20 +109,12 @@ QPolygonOffset::~QPolygonOffset()
{
}
-/*!
- * \return the current scale factor.
- */
float QPolygonOffset::scaleFactor() const
{
Q_D(const QPolygonOffset);
return d->m_scaleFactor;
}
-/*!
- * Sets the scale factor used to create a variable depth offset for
- * each polygon, to \a scaleFactor. Default value is 0.
- * \param scaleFactor
- */
void QPolygonOffset::setScaleFactor(float scaleFactor)
{
Q_D(QPolygonOffset);
@@ -90,19 +124,12 @@ void QPolygonOffset::setScaleFactor(float scaleFactor)
}
}
-/*!
- * \return the current depth steps.
- */
float QPolygonOffset::depthSteps() const
{
Q_D(const QPolygonOffset);
return d->m_depthSteps;
}
-/*!
- * Sets the units that create constant depth offsets, to depthSteps.
- * \param depthSteps
- */
void QPolygonOffset::setDepthSteps(float depthSteps)
{
Q_D(QPolygonOffset);
diff --git a/src/render/renderstates/qrenderstate.cpp b/src/render/renderstates/qrenderstate.cpp
index 974d8f602..e49292dbd 100644
--- a/src/render/renderstates/qrenderstate.cpp
+++ b/src/render/renderstates/qrenderstate.cpp
@@ -47,10 +47,26 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class QRenderState
- * \brief The QRenderState class
- * \since 5.7
- * \ingroup renderstates
+ \class Qt3DRender::QRenderState
+ \brief An abstract base class for all render states
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QRenderState class is abstract base class for all render states.
+ One can not instantiate QRenderState directly, but through its subclasses.
+ */
+
+/*!
+ \qmltype RenderState
+ \brief An abstract base type for all render states
+ \since 5.7
+ \inherits Node
+ \instantiates Qt3DRender::QRenderState
+ \ingroup renderstates
+
+ A RenderState type is abstract base class for all render states.
+ One can not instantiate RenderState directly, but through its subclasses.
*/
/*! \internal */
diff --git a/src/render/renderstates/qrenderstatecreatedchange.cpp b/src/render/renderstates/qrenderstatecreatedchange.cpp
index 4842ae303..5e0713552 100644
--- a/src/render/renderstates/qrenderstatecreatedchange.cpp
+++ b/src/render/renderstates/qrenderstatecreatedchange.cpp
@@ -43,8 +43,10 @@ namespace Qt3DRender {
/*!
* \class Qt3DRender::QRenderStateCreatedChange
+ * \inheaderfile Qt3DRender/QRenderStateCreatedChange
* \brief The QRenderStateCreatedChange class
* \since 5.7
+ * \inmodule Qt3DRender
* \ingroup renderstates
*/
diff --git a/src/render/renderstates/qscissortest.cpp b/src/render/renderstates/qscissortest.cpp
index e363ba54d..718978b7a 100644
--- a/src/render/renderstates/qscissortest.cpp
+++ b/src/render/renderstates/qscissortest.cpp
@@ -38,15 +38,6 @@
**
****************************************************************************/
-/*!
- * \class QScissorTest
- * \brief The QScissorTest class discards fragments that fall outside of a
- * certain rectangular portion of the screen.
- * \since 5.7
- * \ingroup renderstates
- *
- */
-
#include "qscissortest.h"
#include "qscissortest_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -56,8 +47,76 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QScissorTest::QScissorTest instance with the
- * specified \a parent
+ \class Qt3DRender::QScissorTest
+ \brief The QScissorTest class discards fragments that fall outside of a
+ certain rectangular portion of the screen.
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A QScissorTest class enables scissor test, which discards fragments outside
+ the rectangular area of the screen specified by the left, bottom, width and
+ height properties.
+ */
+
+/*!
+ \qmltype ScissorTest
+ \brief The ScissorTest type discards fragments that fall outside of a
+ certain rectangular portion of the screen.
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QScissorTest
+ \inherits RenderState
+
+ A ScissorTest type enables scissor test, which discards fragments outside
+ the rectangular area of the screen specified by the left, bottom, width and
+ height properties.
+ */
+
+/*!
+ \qmlproperty int ScissorTest::left
+ Holds the left coordinate of the scissor box.
+*/
+
+/*!
+ \qmlproperty int ScissorTest::bottom
+ Holds the bottom coordinate of the scissor box.
+*/
+
+/*!
+ \qmlproperty int ScissorTest::width
+ Holds the width of the scissor box.
+*/
+
+/*!
+ \qmlproperty int ScissorTest::height
+ Holds the height of the scissor box.
+*/
+
+/*!
+ \property QScissorTest::left
+ Holds the left coordinate of the scissor box.
+*/
+
+/*!
+ \property QScissorTest::bottom
+ Holds the bottom coordinate of the scissor box.
+*/
+
+/*!
+ \property QScissorTest::width
+ Holds the width of the scissor box.
+*/
+
+/*!
+ \property QScissorTest::height
+ Holds the height of the scissor box.
+*/
+
+/*!
+ The constructor creates a new QScissorTest::QScissorTest instance with the
+ specified \a parent
*/
QScissorTest::QScissorTest(QNode *parent)
: QRenderState(*new QScissorTestPrivate, parent)
@@ -69,19 +128,12 @@ QScissorTest::~QScissorTest()
{
}
-/*!
- * \return the left of the scissor box
- */
int QScissorTest::left() const
{
Q_D(const QScissorTest);
return d->m_left;
}
-/*!
- * Sets the left of the scissor box to \a setLeft
- * \param left
- */
void QScissorTest::setLeft(int left)
{
Q_D(QScissorTest);
@@ -91,19 +143,12 @@ void QScissorTest::setLeft(int left)
}
}
-/*!
- * \return the bottom of the scrissor box
- */
int QScissorTest::bottom() const
{
Q_D(const QScissorTest);
return d->m_bottom;
}
-/*!
- * Sets the bottom of the scissor box to \a bottom
- * \param bottom
- */
void QScissorTest::setBottom(int bottom)
{
Q_D(QScissorTest);
@@ -113,19 +158,12 @@ void QScissorTest::setBottom(int bottom)
}
}
-/*!
- * \return the width of the scissor box
- */
int QScissorTest::width() const
{
Q_D(const QScissorTest);
return d->m_width;
}
-/*!
- * Sets the width of the scissor box to \a width
- * \param width
- */
void QScissorTest::setWidth(int width)
{
Q_D(QScissorTest);
@@ -135,19 +173,12 @@ void QScissorTest::setWidth(int width)
}
}
-/*!
- * \return the height of the scissor box
- */
int QScissorTest::height() const
{
Q_D(const QScissorTest);
return d->m_height;
}
-/*!
- * Sets the height of the scissor box to \a height
- * \param height
- */
void QScissorTest::setHeight(int height)
{
Q_D(QScissorTest);
diff --git a/src/render/renderstates/qseamlesscubemap.cpp b/src/render/renderstates/qseamlesscubemap.cpp
index 6cf97743b..860b36450 100644
--- a/src/render/renderstates/qseamlesscubemap.cpp
+++ b/src/render/renderstates/qseamlesscubemap.cpp
@@ -47,15 +47,28 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QSeamlessCubemap
- * \brief Enables seamless cubemap texture filtering.
- * When present in a state set, enables the seamless cubemap texture filtering
- * as provided by the GL_ARB_seamless_cubemap extension (if available).
- * \since 5.7
- * \ingroup
+ \class Qt3DRender::QSeamlessCubemap
+ \brief Enables seamless cubemap texture filtering.
+ \since 5.7
+ \inmodule Qt3DRender
+
+ When present in a state set, enables the seamless cubemap texture filtering
+ as provided by the GL_ARB_seamless_cubemap extension (if available).
*/
-/*! \internal */
+/*!
+ \qmltype SeamlessCubemap
+ \brief Enables seamless cubemap texture filtering.
+ \since 5.7
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QSeamlessCubemap
+ \inherits RenderState
+
+ When present in a state set, enables the seamless cubemap texture filtering
+ as provided by the GL_ARB_seamless_cubemap extension (if available).
+ */
+
+
class QSeamlessCubemapPrivate : public QRenderStatePrivate
{
public:
@@ -68,8 +81,8 @@ public:
};
/*!
- * The constructor creates a new QSeamlessCubemap::QSeamlessCubemap instance
- * with the specified \a parent.
+ The constructor creates a new QSeamlessCubemap::QSeamlessCubemap instance
+ with the specified \a parent.
*/
QSeamlessCubemap::QSeamlessCubemap(QNode *parent)
: QRenderState(*new QSeamlessCubemapPrivate, parent)
diff --git a/src/render/renderstates/qstencilmask.cpp b/src/render/renderstates/qstencilmask.cpp
index 64cffbe8a..1b9b2cd10 100644
--- a/src/render/renderstates/qstencilmask.cpp
+++ b/src/render/renderstates/qstencilmask.cpp
@@ -37,15 +37,6 @@
**
****************************************************************************/
-/*!
- * \class QStencilMask
- * \brief The QStencilMask class controls the front and back writing of
- * individual bits in the stencil planes.
- * \since 5.7
- * \ingroup renderstates
- *
- */
-
#include "qstencilmask.h"
#include "qstencilmask_p.h"
#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
@@ -55,8 +46,61 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QStencilMask::QStencilMask instance with the
- * specified \a parent.
+ \class Qt3DRender::QStencilMask
+ \brief The QStencilMask class controls the front and back writing of
+ individual bits in the stencil planes.
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QStencilMask class specifies a write mask for the stencil values
+ after the stencil test. Mask can be specified separately for the front-facing
+ and back-facing polygons. The fragment stencil value is and'd with the mask
+ before it is written to the stencil buffer.
+
+ \sa Qt3DRender::QStencilTest
+ */
+
+/*!
+ \qmltype StencilMask
+ \brief The StencilMask type controls the front and back writing of
+ individual bits in the stencil planes.
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QStencilMask
+ \inherits RenderState
+
+ A StencilMask type specifies the mask for the stencil test. Mask can be specified
+ separately for the front-facing and back-facing polygons. The stencil test reference
+ value and stencil buffer value gets and'd with the mask prior to applying stencil function.
+
+ \sa StencilTest
+ */
+
+/*!
+ \qmlproperty int StencilMask::frontOutputMask
+ Holds the write mask for the fragment stencil values for front-facing polygons.
+*/
+
+/*!
+ \qmlproperty int StencilMask::backOutputMask
+ Holds the write mask for the fragment stencil values for back-facing polygons.
+*/
+
+/*!
+ \property QStencilMask::frontOutputMask
+ Holds the write mask for the fragment stencil values for front-facing polygons.
+*/
+
+/*!
+ \property QStencilMask::backOutputMask
+ Holds the write mask for the fragment stencil values for back-facing polygons.
+*/
+
+/*!
+ The constructor creates a new QStencilMask::QStencilMask instance with the
+ specified \a parent.
*/
QStencilMask::QStencilMask(QNode *parent)
: QRenderState(*new QStencilMaskPrivate(), parent)
@@ -68,10 +112,6 @@ QStencilMask::~QStencilMask()
{
}
-/*!
- * Sets the front output mask to \a mask.
- * \param mask
- */
void QStencilMask::setFrontOutputMask(uint mask)
{
Q_D(QStencilMask);
@@ -81,10 +121,6 @@ void QStencilMask::setFrontOutputMask(uint mask)
}
}
-/*!
- * Sets the back output mask to \a mask.
- * \param mask
- */
void QStencilMask::setBackOutputMask(uint mask)
{
Q_D(QStencilMask);
@@ -94,18 +130,12 @@ void QStencilMask::setBackOutputMask(uint mask)
}
}
-/*!
- * \return the front output mask.
- */
uint QStencilMask::frontOutputMask() const
{
Q_D(const QStencilMask);
return d->m_frontOutputMask;
}
-/*!
- * \return the back output mask.
- */
uint QStencilMask::backOutputMask() const
{
Q_D(const QStencilMask);
diff --git a/src/render/renderstates/qstenciloperation.cpp b/src/render/renderstates/qstenciloperation.cpp
index 0b3842c53..7a5b113d8 100644
--- a/src/render/renderstates/qstenciloperation.cpp
+++ b/src/render/renderstates/qstenciloperation.cpp
@@ -37,14 +37,6 @@
**
****************************************************************************/
-/*!
- * \class QStencilOperation
- * \brief The QStencilOperation class allows the selection of either the front
- * or back sides.
- * \since 5.7
- * \ingroup renderstates
- */
-
#include "qstenciloperation.h"
#include "qstenciloperation_p.h"
#include "qstenciloperationarguments.h"
@@ -55,8 +47,58 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QStencilOperation::QStencilOperation instance with
- * the specified \a parent.
+ \class Qt3DRender::QStencilOperation
+ \brief The QStencilOperation class specifies stencil operation
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ A Qt3DRender::QStencilOperation class specifies the stencil operations
+ for the front- and back-facing polygons. The stencil operation control
+ what is done to fragment when the stencil and depth test pass or fail.
+
+ \sa Qt3DRender::QStencilTest
+ */
+
+/*!
+ \qmltype StencilOperation
+ \brief The StencilOperation type specifies stencil operation
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \inherits RenderState
+ \instantiates Qt3DRender::QStencilOperation
+
+ A StencilOperation type specifies the stencil operations
+ for the front- and back-facing polygons. The stencil operation control
+ what is done to fragment when the stencil and depth test pass or fail.
+
+ \sa StencilTest
+ */
+
+/*!
+ \qmlproperty StencilOperationArguments StencilOperation::front
+ Holds the stencil operation arguments for front-facing polygons.
+*/
+
+/*!
+ \qmlproperty StencilOperationArguments StencilOperation::back
+ Holds the stencil operation arguments for back-facing polygons.
+*/
+
+/*!
+ \property QStencilOperation::front
+ Holds the stencil operation arguments for front-facing polygons.
+*/
+
+/*!
+ \property QStencilOperation::back
+ Holds the stencil operation arguments for back-facing polygons.
+*/
+
+/*!
+ The constructor creates a new QStencilOperation::QStencilOperation instance with
+ the specified \a parent.
*/
QStencilOperation::QStencilOperation(QNode *parent)
: QRenderState(*new QStencilOperationPrivate(), parent)
@@ -68,18 +110,12 @@ QStencilOperation::~QStencilOperation()
{
}
-/*!
- * \return the front fragments.
- */
QStencilOperationArguments *QStencilOperation::front() const
{
Q_D(const QStencilOperation);
return d->m_front;
}
-/*!
- * \return the back fragments.
- */
QStencilOperationArguments *QStencilOperation::back() const
{
Q_D(const QStencilOperation);
diff --git a/src/render/renderstates/qstenciloperationarguments.cpp b/src/render/renderstates/qstenciloperationarguments.cpp
index a7b1192be..f5d0c1f4f 100644
--- a/src/render/renderstates/qstenciloperationarguments.cpp
+++ b/src/render/renderstates/qstenciloperationarguments.cpp
@@ -37,15 +37,6 @@
**
****************************************************************************/
-/*!
- * \class QStencilOperationArguments
- * \brief The QStencilOperationArguments class sets the actions to be taken
- * when stencil and depth tests fail.
- * \since 5.7
- * \ingroup renderstates
- *
- */
-
#include "qstenciloperationarguments.h"
#include "qstenciloperationarguments_p.h"
@@ -54,8 +45,123 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * The constructor creates a new QStencilOperationArguments::QStencilOperationArguments
- * instance with the specified \a mode and \a parent.
+ \class Qt3DRender::QStencilOperationArguments
+ \brief The QStencilOperationArguments class sets the actions to be taken
+ when stencil and depth tests fail.
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ The Qt3DRender::QStencilOperationArguments class specifies the arguments for
+ the stencil operations.
+
+ \sa Qt3DRender::QStencilOperation
+ */
+
+/*!
+ \qmltype StencilOperationArguments
+ \brief The StencilOperationArguments type sets the actions to be taken
+ when stencil and depth tests fail.
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QStencilOperationArguments
+ \inherits QtObject
+
+ The StencilOperationArguments type specifies the arguments for the stencil operations.
+
+ \sa StencilOperation
+ */
+
+/*!
+ \enum Qt3DRender::QStencilOperationArguments::FaceMode
+ This enumeration holds the values for stencil operation argument face modes
+ \value Front Arguments are applied to front-facing polygons.
+ \value Back Arguments are applied to back-facing polygons.
+ \value FrontAndBack Arguments are applied to both front- and back-facing polygons.
+*/
+
+/*!
+ \enum Qt3DRender::QStencilOperationArguments::Operation
+ This enumeration holds the values for stencil operation.
+ \value Zero Set stencil value to zero.
+ \value Keep Keep current stencil value.
+ \value Replace Replace with the masked fragment stencil value.
+ \value Increment Increment current value with saturation.
+ \value Decrement Decrement current value with saturation.
+ \value IncrementWrap Increment current value with wrap.
+ \value DecrementWrap Decrement current value with wrap.
+ \value Invert Invert the current value.
+*/
+
+/*!
+ \qmlproperty enumeration StencilOperationArguments::faceMode
+ Holds the faces the arguments are applied to.
+ \list
+ \li StencilOperationArguments.Front
+ \li StencilOperationArguments.Back
+ \li StencilOperationArguments.FrontAndBack
+ \endlist
+ \sa Qt3DRender::QStencilOperationArguments::FaceMode
+ \readonly
+*/
+
+/*!
+ \qmlproperty enumeration StencilOperationArguments::stencilTestFailureOperation
+ Holds the stencil test operation for when the stencil test fails.
+ Default is StencilOperationArguments.Keep.
+ \list
+ \li StencilOperationArguments.Zero
+ \li StencilOperationArguments.Keep
+ \li StencilOperationArguments.Replace
+ \li StencilOperationArguments.Increment
+ \li StencilOperationArguments.Decrement
+ \li StencilOperationArguments.IncrementWrap
+ \li StencilOperationArguments.DecrementWrap
+ \li StencilOperationArguments.Inverter
+ \endlist
+ \sa Qt3DRender::QStencilOperationArguments::Operation
+*/
+
+/*!
+ \qmlproperty enumeration StencilOperationArguments::depthTestFailureOperation
+ Holds the stencil test operation for when the stencil test passes, but
+ depth test fails. Default is StencilOperationArguments.Keep.
+ \sa StencilOperationArguments::stencilTestFailureOperation, Qt3DRender::QStencilOperationArguments::Operation
+*/
+
+/*!
+ \qmlproperty enumeration StencilOperationArguments::allTestsPassOperation
+ Holds the stencil test operation for when depth and stencil test pass. Default is StencilOperationArguments.Keep.
+ \sa StencilOperationArguments::stencilTestFailureOperation, Qt3DRender::QStencilOperationArguments::Operation
+*/
+
+/*!
+ \property QStencilOperationArguments::faceMode
+ Holds the faces the arguments are applied to.
+ \readonly
+*/
+
+/*!
+ \property QStencilOperationArguments::stencilTestFailureOperation
+ Holds the stencil test operation for when the stencil test fails.
+ Default is StencilOperationArguments.Keep.
+*/
+
+/*!
+ \property QStencilOperationArguments::depthTestFailureOperation
+ Holds the stencil test operation for when the stencil test passes, but
+ depth test fails. Default is StencilOperationArguments.Keep.
+*/
+
+/*!
+ \property QStencilOperationArguments::allTestsPassOperation
+ Holds the stencil test operation for when depth and stencil test pass. Default is StencilOperationArguments.Keep.
+*/
+
+/*!
+ The constructor creates a new QStencilOperationArguments::QStencilOperationArguments
+ instance with the specified \a mode and \a parent.
*/
QStencilOperationArguments::QStencilOperationArguments(FaceMode mode, QObject *parent)
: QObject(*new QStencilOperationArgumentsPrivate(mode), parent)
@@ -67,19 +173,12 @@ QStencilOperationArguments::~QStencilOperationArguments()
{
}
-/*!
- * \return the current face mode.
- */
QStencilOperationArguments::FaceMode QStencilOperationArguments::faceMode() const
{
Q_D(const QStencilOperationArguments);
return d->m_face;
}
-/*!
- * Sets the stencil action when a test fails, to operation.
- * \param operation
- */
void QStencilOperationArguments::setStencilTestFailureOperation(QStencilOperationArguments::Operation operation)
{
Q_D(QStencilOperationArguments);
@@ -89,19 +188,12 @@ void QStencilOperationArguments::setStencilTestFailureOperation(QStencilOperatio
}
}
-/*!
- * \return the current stencil test failure operation.
- */
QStencilOperationArguments::Operation QStencilOperationArguments::stencilTestFailureOperation() const
{
Q_D(const QStencilOperationArguments);
return d->m_stencilTestFailureOperation;
}
-/*!
- * Sets the action when the depth test fails, to operation.
- * \param operation
- */
void QStencilOperationArguments::setDepthTestFailureOperation(QStencilOperationArguments::Operation operation)
{
Q_D(QStencilOperationArguments);
@@ -111,19 +203,12 @@ void QStencilOperationArguments::setDepthTestFailureOperation(QStencilOperationA
}
}
-/*!
- * \return the current depth test failure operation.
- */
QStencilOperationArguments::Operation QStencilOperationArguments::depthTestFailureOperation() const
{
Q_D(const QStencilOperationArguments);
return d->m_depthTestFailureOperation;
}
-/*!
- * Sets the action when both the depth and stencil tests fail, to operation.
- * \param operation
- */
void QStencilOperationArguments::setAllTestsPassOperation(QStencilOperationArguments::Operation operation)
{
Q_D(QStencilOperationArguments);
@@ -133,9 +218,6 @@ void QStencilOperationArguments::setAllTestsPassOperation(QStencilOperationArgum
}
}
-/*!
- * \return the current failure operation for when both tests fail.
- */
QStencilOperationArguments::Operation QStencilOperationArguments::allTestsPassOperation() const
{
Q_D(const QStencilOperationArguments);
diff --git a/src/render/renderstates/qstenciloperationarguments.h b/src/render/renderstates/qstenciloperationarguments.h
index 31d32f4d5..db80ecc19 100644
--- a/src/render/renderstates/qstenciloperationarguments.h
+++ b/src/render/renderstates/qstenciloperationarguments.h
@@ -65,7 +65,7 @@ public:
Back = 0x0405,
FrontAndBack = 0x0408
};
- Q_ENUM(FaceMode)
+ Q_ENUM(FaceMode) // LCOV_EXCL_LINE
enum Operation
{
@@ -78,7 +78,7 @@ public:
DecrementWrap = 0x8508,
Invert = 0x150A
};
- Q_ENUM(Operation)
+ Q_ENUM(Operation) // LCOV_EXCL_LINE
~QStencilOperationArguments();
diff --git a/src/render/renderstates/qstenciltest.cpp b/src/render/renderstates/qstenciltest.cpp
index 2341a3b7d..f1e42f1e3 100644
--- a/src/render/renderstates/qstenciltest.cpp
+++ b/src/render/renderstates/qstenciltest.cpp
@@ -48,15 +48,60 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class Qt3DRender::QStencilTest
- * \brief The QStencilTest class
- * \since 5.7
- * \ingroup renderstates
+ \class Qt3DRender::QStencilTest
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+ \brief The QStencilTest class specifies arguments for the stecil test
+
+ A Qt3DRender::QStencilTest class specifies argument for the stencil test.
+ The stencil test comprises of three arguments: stencil test function,
+ stencil test mask and stencil reference value. QStencilTest allows these
+ arguments to be set for both front- and back-facing polygons separately.
+
+ \sa Qt3DRender::QStencilMask, Qt3DRender::QStencilOperation
*/
/*!
- * The constructor creates a new QStencilTest::QStencilTest instance with
- * the specified \a parent.
+ \qmltype StencilTest
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \brief The StencilTest type specifies arguments for the stecil test
+ \inherits RenderState
+ \instantiates Qt3DRender::QStencilTest
+
+ A StencilTest type specifies argument for the stencil test.
+ The stencil test comprises of three arguments: stencil test function,
+ stencil test mask and stencil reference value. StencilTest allows these
+ arguments to be set for both front- and back-facing polygons separately.
+
+ \sa StencilMask, StencilOperation
+ */
+
+/*!
+ \qmlproperty StencilTestArguments StencilTest::front
+ Holds the stencil test arguments for front-facing polygons.
+*/
+
+/*!
+ \qmlproperty StencilTestArguments StencilTest::back
+ Holds the stencil test arguments for back-facing polygons.
+*/
+
+/*!
+ \property QStencilTest::front
+ Holds the stencil test arguments for front-facing polygons.
+*/
+
+/*!
+ \property QStencilTest::back
+ Holds the stencil test arguments for back-facing polygons.
+*/
+
+/*!
+ The constructor creates a new QStencilTest::QStencilTest instance with
+ the specified \a parent.
*/
QStencilTest::QStencilTest(QNode *parent)
: QRenderState(*new QStencilTestPrivate, parent)
@@ -68,18 +113,12 @@ QStencilTest::~QStencilTest()
{
}
-/*!
- * \return the stencil test for the front
- */
QStencilTestArguments *QStencilTest::front() const
{
Q_D(const QStencilTest);
return d->m_front;
}
-/*!
- * \return the stencil test for the back
- */
QStencilTestArguments *QStencilTest::back() const
{
Q_D(const QStencilTest);
diff --git a/src/render/renderstates/qstenciltestarguments.cpp b/src/render/renderstates/qstenciltestarguments.cpp
index 1e618e372..ae1fd1111 100644
--- a/src/render/renderstates/qstenciltestarguments.cpp
+++ b/src/render/renderstates/qstenciltestarguments.cpp
@@ -45,15 +45,113 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
/*!
- * \class QStencilTestArguments
- * \brief The QStencilTestArguments class
- * \since 5.7
- * \ingroup renderstates
+ \class Qt3DRender::QStencilTestArguments
+ \brief The QStencilTestArguments class specifies arguments for stencil test
+ \since 5.7
+ \ingroup renderstates
+ \inmodule Qt3DRender
+
+ The Qt3DRender::QStencilTestArguments class specifies the arguments for
+ the stencil test.
+ */
+
+/*!
+ \qmltype StencilTestArguments
+ \brief The StencilTestArguments type specifies arguments for stencil test
+ \since 5.7
+ \ingroup renderstates
+ \inqmlmodule Qt3D.Render
+ \instantiates Qt3DRender::QStencilTestArguments
+ \inherits QtObject
+
+ The StencilTestArguments type specifies the arguments for
+ the stencil test.
*/
/*!
- * The constructor creates a new QStencilTestArguments::QStencilTestArguments
- * instance with the specified \a face and \a parent.
+ \enum Qt3DRender::QStencilTestArguments::StencilFaceMode
+ This enumeration holds the values for stencil test arguments face modes
+ \value Front Arguments are applied to front-facing polygons.
+ \value Back Arguments are applied to back-facing polygons.
+ \value FrontAndBack Arguments are applied to both front- and back-facing polygons.
+*/
+
+/*!
+ \enum Qt3DRender::QStencilTestArguments::StencilFunction
+
+ Enumeration for the stencil function values
+ \value Never Never pass stencil test
+ \value Always Always pass stencil test
+ \value Less Pass stencil test if fragment stencil is less than reference value
+ \value LessOrEqual Pass stencil test if fragment stencil is less than or equal to reference value
+ \value Equal Pass stencil test if fragment stencil is equal to reference value
+ \value GreaterOrEqual Pass stencil test if fragment stencil is greater than or equal to reference value
+ \value Greater Pass stencil test if fragment stencil is greater than reference value
+ \value NotEqual Pass stencil test if fragment stencil is not equal to reference value
+*/
+
+/*!
+ \qmlproperty enumeration StencilTestArguments::faceMode
+ Holds the faces the arguments are applied to.
+ \list
+ \li StencilTestArguments.Front
+ \li StencilTestArguments.Back
+ \li StencilTestArguments.FrontAndBack
+ \endlist
+ \sa Qt3DRender::QStencilTestArguments::StencilFaceMode
+ \readonly
+*/
+
+/*!
+ \qmlproperty int StencilTestArguments::comparisonMask
+ Holds the stencil test comparison mask. Default is all zeroes.
+*/
+
+/*!
+ \qmlproperty int StencilTestArguments::referenceValue
+ Holds the stencil test reference value. Default is zero.
+*/
+
+/*!
+ \qmlproperty enumeration StencilTestArguments::stencilFunction
+ Holds the stencil test function. Default is StencilTestArguments.Never.
+ \list
+ \li StencilTestArguments.Never
+ \li StencilTestArguments.Always
+ \li StencilTestArguments.Less
+ \li StencilTestArguments.LessOrEqual
+ \li StencilTestArguments.Equal
+ \li StencilTestArguments.GreaterOrEqual
+ \li StencilTestArguments.Greater
+ \li StencilTestArguments.NotEqual
+ \endlist
+*/
+
+/*!
+ \property QStencilTestArguments::faceMode
+ Holds the faces the arguments are applied to.
+ \readonly
+*/
+
+/*!
+ \property QStencilTestArguments::comparisonMask
+ Holds the stencil test comparison mask. Default is all zeroes.
+*/
+
+/*!
+ \property QStencilTestArguments::referenceValue
+ Holds the stencil test reference value. Default is zero.
+*/
+
+/*!
+ \property QStencilTestArguments::stencilFunction
+ Holds the stencil test function. Default is Never.
+ \sa Qt3DRender::QStencilTestArguments::StencilFunction
+*/
+
+/*!
+ The constructor creates a new QStencilTestArguments::QStencilTestArguments
+ instance with the specified \a face and \a parent.
*/
QStencilTestArguments::QStencilTestArguments(QStencilTestArguments::StencilFaceMode face, QObject *parent)
: QObject(*new QStencilTestArgumentsPrivate(face), parent)
@@ -65,19 +163,12 @@ QStencilTestArguments::~QStencilTestArguments()
{
}
-/*!
- * \return the current comparison mask.
- */
uint QStencilTestArguments::comparisonMask() const
{
Q_D(const QStencilTestArguments);
return d->m_comparisonMask;
}
-/*!
- * Sets the comparison mask.
- * \param comparisonMask
- */
void QStencilTestArguments::setComparisonMask(uint comparisonMask)
{
Q_D(QStencilTestArguments);
@@ -87,19 +178,12 @@ void QStencilTestArguments::setComparisonMask(uint comparisonMask)
}
}
-/*!
- * \return the current reference value.
- */
int QStencilTestArguments::referenceValue() const
{
Q_D(const QStencilTestArguments);
return d->m_referenceValue;
}
-/*!
- * Sets the reference value.
- * \param referenceValue
- */
void QStencilTestArguments::setReferenceValue(int referenceValue)
{
Q_D(QStencilTestArguments);
@@ -109,19 +193,12 @@ void QStencilTestArguments::setReferenceValue(int referenceValue)
}
}
-/*!
- * \return the current stencil function.
- */
QStencilTestArguments::StencilFunction QStencilTestArguments::stencilFunction() const
{
Q_D(const QStencilTestArguments);
return d->m_stencilFunction;
}
-/*!
- * Sets the stencil function.
- * \param stencilFunction
- */
void QStencilTestArguments::setStencilFunction(QStencilTestArguments::StencilFunction stencilFunction)
{
Q_D(QStencilTestArguments);
@@ -131,9 +208,6 @@ void QStencilTestArguments::setStencilFunction(QStencilTestArguments::StencilFun
}
}
-/*!
- * \return the current face mode.
- */
QStencilTestArguments::StencilFaceMode QStencilTestArguments::faceMode() const
{
Q_D(const QStencilTestArguments);
diff --git a/src/render/renderstates/qstenciltestarguments.h b/src/render/renderstates/qstenciltestarguments.h
index 17d9fa21e..f20885d03 100644
--- a/src/render/renderstates/qstenciltestarguments.h
+++ b/src/render/renderstates/qstenciltestarguments.h
@@ -65,7 +65,7 @@ public:
Back = 0x0405,
FrontAndBack = 0x0408
};
- Q_ENUM(StencilFaceMode)
+ Q_ENUM(StencilFaceMode) // LCOV_EXCL_LINE
enum StencilFunction
{
@@ -78,7 +78,7 @@ public:
Greater = 0x0204,
NotEqual = 0x0205
};
- Q_ENUM(StencilFunction)
+ Q_ENUM(StencilFunction) // LCOV_EXCL_LINE
~QStencilTestArguments();
diff --git a/src/render/renderstates/statevariant_p.h b/src/render/renderstates/statevariant_p.h
index f2a631d2e..e13599e75 100644
--- a/src/render/renderstates/statevariant_p.h
+++ b/src/render/renderstates/statevariant_p.h
@@ -87,17 +87,17 @@ struct StateVariant
u_Data()
{
// Assumes the above types don't need to have their ctor called
- memset(this, 0, sizeof(u_Data));
+ memset(static_cast<void *>(this), 0, sizeof(u_Data));
}
u_Data(const u_Data &other)
{
- memcpy(this, &other, sizeof(u_Data));
+ memcpy(static_cast<void *>(this), static_cast<const void *>(&other), sizeof(u_Data));
}
u_Data& operator=(const u_Data &other)
{
- memcpy(this, &other, sizeof(u_Data));
+ memcpy(static_cast<void *>(this), static_cast<const void *>(&other), sizeof(u_Data));
return *this;
}
@@ -121,7 +121,7 @@ struct StateVariant
#if !defined(_MSC_VER) || (_MSC_VER > 1800)
// all union members start at the same memory address
// so we can just write into whichever we want
- memcpy(&(v.data), &state, sizeof(state));
+ memcpy(static_cast<void *>(&v.data), static_cast<const void *>(&state), sizeof(state));
#else
v.m_impl.reset(new GenericState(state));
#endif
diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h
new file mode 100644
index 000000000..1be5a1af8
--- /dev/null
+++ b/src/render/texture/apitexturemanager_p.h
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_APITEXTUREMANAGER_P_H
+#define QT3DRENDER_RENDER_APITEXTUREMANAGER_P_H
+
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/texturedatamanager_p.h>
+#include <Qt3DRender/private/textureimage_p.h>
+#include <Qt3DRender/private/texture_p.h>
+#include <Qt3DRender/qtexturegenerator.h>
+#include <Qt3DRender/qtextureimagedatagenerator.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+// Manages instances of APITexture. This includes sharing between multiple
+// Texture nodes, updating APITextures and deleting abandoned instances.
+template <class APITexture, class APITextureImage>
+class APITextureManager
+{
+public:
+
+ explicit APITextureManager(TextureImageManager *textureImageManager,
+ TextureDataManager *textureDataManager,
+ TextureImageDataManager *textureImageDataManager)
+ : m_textureImageManager(textureImageManager)
+ , m_textureDataManager(textureDataManager)
+ , m_textureImageDataManager(textureImageDataManager)
+ {
+ }
+
+ ~APITextureManager()
+ {
+ qDeleteAll(activeResources());
+ m_nodeIdToGLTexture.clear();
+ m_sharedTextures.clear();
+ m_updatedTextures.clear();
+ }
+
+ // Used to retrieve all resources that needs to be destroyed on the GPU
+ QVector<APITexture *> activeResources() const
+ {
+ // Active Resources are
+ // all shared textures
+ // all unique textures
+ // all textures that haven't yet been destroyed
+ // Note: updatedTextures only referenced textures in one of these 3 vectors
+ return m_sharedTextures.keys().toVector() + m_uniqueTextures + m_abandonedTextures;
+ }
+
+ APITexture *lookupResource(Qt3DCore::QNodeId textureId)
+ {
+ return m_nodeIdToGLTexture.value(textureId);
+ }
+
+ // Returns a APITexture that matches the given QTexture node. Will make sure
+ // that texture data generator jobs are launched, if necessary. The APITexture
+ // may be shared between multiple texture backend nodes
+ APITexture *getOrCreateShared(const Texture *node)
+ {
+ Q_ASSERT(node);
+
+ APITexture *shared = findMatchingShared(node);
+
+ // no matching shared texture was found; create a new one:
+ if (shared == nullptr)
+ shared = createTexture(node, false);
+
+ // store texture node to shared texture relationship
+ adoptShared(shared, node);
+
+ return shared;
+ }
+
+ // Store that the shared texture references node
+ void adoptShared(APITexture *sharedApiTexture, const Texture *node)
+ {
+ if (!m_sharedTextures[sharedApiTexture].contains(node->peerId())) {
+ m_sharedTextures[sharedApiTexture].push_back(node->peerId());
+ m_nodeIdToGLTexture.insert(node->peerId(), sharedApiTexture);
+ }
+ }
+
+ // If there is already a shared texture with the properties of the given
+ // texture node, return this instance, else NULL.
+ // Note: the reference to the texture node is added if the shared texture
+ // wasn't referencing it already
+ APITexture *findMatchingShared(const Texture *node)
+ {
+ Q_ASSERT(node);
+
+ // search for existing texture
+ const auto end = m_sharedTextures.end();
+ for (auto it = m_sharedTextures.begin(); it != end; ++it)
+ if (isSameTexture(it.key(), node))
+ return it.key();
+ return nullptr;
+ }
+
+ // Returns a APITexture that matches the given QTexture node. Will make sure
+ // that texture data generator jobs are launched, if necessary.
+ APITexture *createUnique(const Texture *node)
+ {
+ Q_ASSERT(node);
+ APITexture *uniqueTex = createTexture(node, true);
+ m_uniqueTextures.push_back(uniqueTex);
+ m_nodeIdToGLTexture.insert(node->peerId(), uniqueTex);
+ return uniqueTex;
+ }
+
+ // De-associate the given APITexture from the backend node. If the texture
+ // is no longer referenced by any other node, it will be deleted.
+ void abandon(APITexture *tex, const Texture *node)
+ {
+ APITexture *apiTexture = m_nodeIdToGLTexture.take(node->peerId());
+ Q_ASSERT(tex == apiTexture);
+
+ if (Q_UNLIKELY(!apiTexture)) {
+ qWarning() << "[Qt3DRender::TextureManager] abandon: could not find Texture";
+ return;
+ }
+
+ if (tex->isUnique()) {
+ m_uniqueTextures.removeAll(apiTexture);
+ m_abandonedTextures.push_back(apiTexture);
+ } else {
+ QVector<Qt3DCore::QNodeId> &referencedTextureNodes = m_sharedTextures[apiTexture];
+ referencedTextureNodes.removeAll(node->peerId());
+
+ // If no texture nodes is referencing the shared APITexture, remove it
+ if (referencedTextureNodes.empty()) {
+ m_abandonedTextures.push_back(apiTexture);
+ m_sharedTextures.remove(apiTexture);
+ }
+ }
+ }
+
+ // Change the properties of the given texture, if it is a non-shared texture
+ // Returns true, if it was changed successfully, false otherwise
+ bool setProperties(APITexture *tex, const TextureProperties &props)
+ {
+ Q_ASSERT(tex);
+
+ if (isShared(tex))
+ return false;
+
+ tex->setProperties(props);
+ m_updatedTextures.push_back(tex);
+
+ return true;
+ }
+
+ // Change the parameters of the given texture, if it is a non-shared texture
+ // Returns true, if it was changed successfully, false otherwise
+ bool setParameters(APITexture *tex, const TextureParameters &params)
+ {
+ Q_ASSERT(tex);
+
+ if (isShared(tex))
+ return false;
+
+ tex->setParameters(params);
+ m_updatedTextures.push_back(tex);
+
+ return true;
+ }
+
+ // Change the texture images of the given texture, if it is a non-shared texture
+ // Return true, if it was changed successfully, false otherwise
+ bool setImages(APITexture *tex, const QVector<HTextureImage> &images)
+ {
+ Q_ASSERT(tex);
+
+ if (isShared(tex))
+ return false;
+
+ // create Image structs
+ QVector<APITextureImage> texImgs = texImgsFromNodes(images);
+ if (texImgs.size() != images.size())
+ return false;
+
+ tex->setImages(texImgs);
+ m_updatedTextures.push_back(tex);
+
+ return true;
+ }
+
+ // Retrieves abandoned textures. This should be regularly called from the OpenGL thread
+ // to make sure needed GL resources are de-allocated.
+ QVector<APITexture*> takeAbandonedTextures()
+ {
+ return std::move(m_abandonedTextures);
+ }
+
+ // Retrieves textures that have been modified
+ QVector<APITexture*> takeUpdatedTextures()
+ {
+ return std::move(m_updatedTextures);
+ }
+
+ // Returns whether the given APITexture is shared between multiple TextureNodes
+ bool isShared(APITexture *impl)
+ {
+ Q_ASSERT(impl);
+
+ if (impl->isUnique())
+ return false;
+
+ auto it = m_sharedTextures.find(impl);
+ if (it == m_sharedTextures.cend())
+ return false;
+
+ return it.value().size() > 1;
+ }
+
+private:
+
+ // Check if the given APITexture matches the TextureNode
+ bool isSameTexture(const APITexture *tex, const Texture *texNode)
+ {
+ // make sure there either are no texture generators, or the two are the same
+ if (tex->textureGenerator().isNull() != texNode->dataGenerator().isNull())
+ return false;
+ if (!tex->textureGenerator().isNull() && !(*tex->textureGenerator() == *texNode->dataGenerator()))
+ return false;
+
+ // make sure the image generators are the same
+ const QVector<APITextureImage> texImgGens = tex->images();
+ const QVector<HTextureImage> texImgs = texNode->textureImages();
+ if (texImgGens.size() != texImgs.size())
+ return false;
+ for (int i = 0; i < texImgGens.size(); ++i) {
+ const TextureImage *img = m_textureImageManager->data(texImgs[i]);
+ Q_ASSERT(img != nullptr);
+ if (!(*img->dataGenerator() == *texImgGens[i].generator)
+ || img->layer() != texImgGens[i].layer
+ || img->face() != texImgGens[i].face
+ || img->mipLevel() != texImgGens[i].mipLevel)
+ return false;
+ }
+
+ // if the texture has a texture generator, this generator will mostly determine
+ // the properties of the texture.
+ if (!tex->textureGenerator().isNull())
+ return (tex->properties().generateMipMaps == texNode->properties().generateMipMaps
+ && tex->parameters() == texNode->parameters());
+
+ // if it doesn't have a texture generator, but texture image generators,
+ // few more properties will influence the texture type
+ if (!texImgGens.empty())
+ return (tex->properties().target == texNode->properties().target
+ && tex->properties().format == texNode->properties().format
+ && tex->properties().generateMipMaps == texNode->properties().generateMipMaps
+ && tex->parameters() == texNode->parameters());
+
+ // texture without images
+ return tex->properties() == texNode->properties()
+ && tex->parameters() == texNode->parameters();
+ }
+
+ // Create APITexture from given TextureNode. Also make sure the generators
+ // will be executed by jobs soon.
+ APITexture *createTexture(const Texture *node, bool unique)
+ {
+ // create Image structs
+ const QVector<APITextureImage> texImgs = texImgsFromNodes(node->textureImages());
+ if (texImgs.empty() && !node->textureImages().empty())
+ return nullptr;
+
+ // no matching shared texture was found, create a new one
+ APITexture *newTex = new APITexture(m_textureDataManager, m_textureImageDataManager, node->dataGenerator(), unique);
+ newTex->setProperties(node->properties());
+ newTex->setParameters(node->parameters());
+ newTex->setImages(texImgs);
+
+ m_updatedTextures.push_back(newTex);
+
+ return newTex;
+ }
+
+ QVector<APITextureImage> texImgsFromNodes(const QVector<HTextureImage> &images) const
+ {
+ QVector<APITextureImage> ret;
+ ret.resize(images.size());
+
+ for (int i = 0; i < images.size(); ++i) {
+ const TextureImage *img = m_textureImageManager->data(images[i]);
+ if (!img) {
+ qWarning() << "[Qt3DRender::TextureManager] invalid TextureImage handle";
+ return QVector<APITextureImage>();
+ }
+
+ ret[i].generator = img->dataGenerator();
+ ret[i].face = img->face();
+ ret[i].layer = img->layer();
+ ret[i].mipLevel = img->mipLevel();
+ }
+
+ return ret;
+ }
+
+ TextureImageManager *m_textureImageManager;
+ TextureDataManager *m_textureDataManager;
+ TextureImageDataManager *m_textureImageDataManager;
+
+ /* each non-unique texture is associated with a number of Texture nodes referencing it */
+ QHash<APITexture*, QVector<Qt3DCore::QNodeId>> m_sharedTextures;
+
+ // Texture id -> APITexture (both shared and unique ones)
+ QHash<Qt3DCore::QNodeId, APITexture *> m_nodeIdToGLTexture;
+
+ QVector<APITexture*> m_uniqueTextures;
+ QVector<APITexture*> m_abandonedTextures;
+ QVector<APITexture*> m_updatedTextures;
+};
+
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_APITEXTUREMANAGER_P_H
diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp
new file mode 100644
index 000000000..7916e390d
--- /dev/null
+++ b/src/render/texture/gltexture.cpp
@@ -0,0 +1,413 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qhash.h>
+#include "gltexture_p.h"
+
+#include <QDebug>
+#include <QOpenGLFunctions>
+#include <QOpenGLTexture>
+#include <QOpenGLPixelTransferOptions>
+#include <Qt3DRender/qtexture.h>
+#include <Qt3DRender/qtexturedata.h>
+#include <Qt3DRender/qtextureimagedata.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/texturedatamanager_p.h>
+#include <Qt3DRender/private/qabstracttexture_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+GLTexture::GLTexture(TextureDataManager *texDataMgr,
+ TextureImageDataManager *texImgDataMgr,
+ const QTextureGeneratorPtr &texGen,
+ bool unique)
+ : m_unique(unique)
+ , m_gl(nullptr)
+ , m_textureDataManager(texDataMgr)
+ , m_textureImageDataManager(texImgDataMgr)
+ , m_dataFunctor(texGen)
+{
+ // make sure texture generator is executed
+ if (!texGen.isNull())
+ m_textureDataManager->requestData(texGen, this);
+}
+
+GLTexture::~GLTexture()
+{
+ if (m_gl) {
+ qWarning() << "[Qt3DRender::GLTexture] Destructor called without properly deleting texture";
+ delete m_gl;
+ }
+
+ // release texture data
+ for (const Image &img : qAsConst(m_images))
+ m_textureImageDataManager->releaseData(img.generator, this);
+
+ if (m_dataFunctor)
+ m_textureDataManager->releaseData(m_dataFunctor, this);
+}
+
+void GLTexture::destroyGLTexture()
+{
+ delete m_gl;
+ m_gl = nullptr;
+ m_dirty = 0;
+}
+
+QOpenGLTexture* GLTexture::getOrCreateGLTexture()
+{
+ bool needUpload = false;
+ bool texturedDataInvalid = false;
+
+ // on the first invocation in the render thread, make sure to
+ // evaluate the texture data generator output
+ // (this might change some property values)
+ if (m_dataFunctor && !m_textureData) {
+ m_textureData = m_textureDataManager->getData(m_dataFunctor);
+
+ // if there is a texture generator, most properties will be defined by it
+ if (m_textureData) {
+ if (m_properties.target != QAbstractTexture::TargetAutomatic)
+ qWarning() << "[Qt3DRender::GLTexture] When a texture provides a generator, it's target is expected to be TargetAutomatic";
+
+ m_properties.target = m_textureData->target();
+ m_properties.width = m_textureData->width();
+ m_properties.height = m_textureData->height();
+ m_properties.depth = m_textureData->depth();
+ m_properties.layers = m_textureData->layers();
+ m_properties.format = m_textureData->format();
+
+ const QVector<QTextureImageDataPtr> imageData = m_textureData->imageData();
+
+ if (imageData.size() > 0) {
+ // Set the mips level based on the first image if autoMipMapGeneration is disabled
+ if (!m_properties.generateMipMaps)
+ m_properties.mipLevels = imageData.first()->mipLevels();
+ }
+
+ m_dirty |= Properties;
+ needUpload = true;
+ } else {
+ qWarning() << "[Qt3DRender::GLTexture] No QTextureData generated from Texture Generator";
+ texturedDataInvalid = true;
+ }
+ }
+
+ // additional texture images may be defined through image data generators
+ if (m_dirty.testFlag(TextureData)) {
+ m_imageData.clear();
+ needUpload = true;
+
+ for (const Image &img : qAsConst(m_images)) {
+ const QTextureImageDataPtr imgData = m_textureImageDataManager->getData(img.generator);
+
+ if (imgData) {
+ m_imageData << imgData;
+
+ // If the texture doesn't have a texture generator, we will
+ // derive some properties from the first TextureImage (layer=0, miplvl=0, face=0)
+ if (!m_textureData && img.layer == 0 && img.mipLevel == 0 && img.face == QAbstractTexture::CubeMapPositiveX) {
+ if (imgData->width() != -1 && imgData->height() != -1 && imgData->depth() != -1) {
+ m_properties.width = imgData->width();
+ m_properties.height = imgData->height();
+ m_properties.depth = imgData->depth();
+ }
+
+ // Set the format of the texture if the texture format is set to Automatic
+ if (m_properties.format == QAbstractTexture::Automatic) {
+ m_properties.format = static_cast<QAbstractTexture::TextureFormat>(imgData->format());
+ }
+
+ m_dirty |= Properties;
+ }
+ } else {
+ qWarning() << "[Qt3DRender::GLTexture] No QTextureImageData generated from functor";
+ texturedDataInvalid = true;
+ }
+ }
+ }
+
+
+ // if the properties changed, we need to re-allocate the texture
+ if (m_dirty.testFlag(Properties)) {
+ delete m_gl;
+ m_gl = nullptr;
+ }
+
+ if (!m_gl) {
+ m_gl = buildGLTexture();
+ m_gl->allocateStorage();
+ if (!m_gl->isStorageAllocated()) {
+ qWarning() << Q_FUNC_INFO << "texture storage allocation failed";
+ return nullptr;
+ }
+ }
+
+ // need to (re-)upload texture data?
+ if (needUpload && !texturedDataInvalid) {
+ uploadGLTextureData();
+ }
+
+ // need to set texture parameters?
+ if (m_dirty.testFlag(Properties) || m_dirty.testFlag(Parameters)) {
+ updateGLTextureParameters();
+ }
+
+ m_dirty = 0;
+
+ return m_gl;
+}
+
+void GLTexture::setParameters(const TextureParameters &params)
+{
+ if (m_parameters != params) {
+ m_parameters = params;
+ m_dirty |= Parameters;
+ }
+}
+
+void GLTexture::setProperties(const TextureProperties &props)
+{
+ if (m_properties != props) {
+ m_properties = props;
+ m_dirty |= Properties;
+ }
+}
+
+void GLTexture::setImages(const QVector<Image> &images)
+{
+ // check if something has changed at all
+ bool same = (images.size() == m_images.size());
+ if (same) {
+ for (int i = 0; i < images.size(); i++) {
+ if (images[i] != m_images[i])
+ same = false;
+ }
+ }
+
+ // de-reference all old texture image generators that will no longer be used.
+ // we need to check all generators against each other to make sure we don't
+ // de-ref a texture that would still be in use, thus maybe causing it to
+ // be deleted
+ if (!same) {
+ for (const Image &oldImg : qAsConst(m_images)) {
+ bool stillHaveThatImage = false;
+
+ for (const Image &newImg : images) {
+ if (oldImg.generator == newImg.generator) {
+ stillHaveThatImage = true;
+ break;
+ }
+ }
+
+ if (!stillHaveThatImage)
+ m_textureImageDataManager->releaseData(oldImg.generator, this);
+ }
+
+ m_images = images;
+ m_dirty |= TextureData;
+
+ // make sure the generators are executed
+ for (const Image& img : qAsConst(images)) {
+ m_textureImageDataManager->requestData(img.generator, this);
+ }
+ }
+}
+
+QOpenGLTexture *GLTexture::buildGLTexture()
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx) {
+ qWarning() << Q_FUNC_INFO << "requires an OpenGL context";
+ return nullptr;
+ }
+
+ if (m_properties.target == QAbstractTexture::TargetAutomatic) {
+ qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point";
+ return nullptr;
+ }
+
+ QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_properties.target));
+
+ // m_format may not be ES2 compatible. Now it's time to convert it, if necessary.
+ QAbstractTexture::TextureFormat format = m_properties.format;
+ if (ctx->isOpenGLES() && ctx->format().majorVersion() < 3) {
+ switch (m_properties.format) {
+ case QOpenGLTexture::RGBA8_UNorm:
+ case QOpenGLTexture::RGBAFormat:
+ format = QAbstractTexture::RGBAFormat;
+ break;
+ case QOpenGLTexture::RGB8_UNorm:
+ case QOpenGLTexture::RGBFormat:
+ format = QAbstractTexture::RGBFormat;
+ break;
+ case QOpenGLTexture::DepthFormat:
+ format = QAbstractTexture::DepthFormat;
+ break;
+ default:
+ qWarning() << Q_FUNC_INFO << "could not find a matching OpenGL ES 2.0 unsized texture format";
+ break;
+ }
+ }
+
+ // Map ETC1 to ETC2 when supported. This allows using features like
+ // immutable storage as ETC2 is standard in GLES 3.0, while the ETC1 extension
+ // is written against GLES 1.0.
+ if (m_properties.format == QAbstractTexture::RGB8_ETC1) {
+ if ((ctx->isOpenGLES() && ctx->format().majorVersion() >= 3)
+ || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture"))
+ || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility")))
+ format = m_properties.format = QAbstractTexture::RGB8_ETC2;
+ }
+
+ glTex->setFormat(m_properties.format == QAbstractTexture::Automatic ?
+ QOpenGLTexture::NoFormat :
+ static_cast<QOpenGLTexture::TextureFormat>(format));
+ glTex->setSize(m_properties.width, m_properties.height, m_properties.depth);
+ // Set layers count if texture array
+ if (m_properties.target == QAbstractTexture::Target1DArray ||
+ m_properties.target == QAbstractTexture::Target2DArray ||
+ m_properties.target == QAbstractTexture::Target3D ||
+ m_properties.target == QAbstractTexture::Target2DMultisampleArray ||
+ m_properties.target == QAbstractTexture::TargetCubeMapArray) {
+ glTex->setLayers(m_properties.layers);
+ }
+
+ if (m_properties.target == QAbstractTexture::Target2DMultisample ||
+ m_properties.target == QAbstractTexture::Target2DMultisampleArray) {
+ // Set samples count if multisampled texture
+ // (multisampled textures don't have mipmaps)
+ glTex->setSamples(m_properties.samples);
+ } else if (m_properties.generateMipMaps) {
+ glTex->setMipLevels(glTex->maximumMipLevels());
+ } else {
+ glTex->setAutoMipMapGenerationEnabled(false);
+ glTex->setMipBaseLevel(0);
+ glTex->setMipMaxLevel(m_properties.mipLevels - 1);
+ glTex->setMipLevels(m_properties.mipLevels);
+ }
+
+ if (!glTex->create()) {
+ qWarning() << Q_FUNC_INFO << "creating QOpenGLTexture failed";
+ return nullptr;
+ }
+
+ return glTex;
+}
+
+static void uploadGLData(QOpenGLTexture *glTex,
+ int level, int layer, QOpenGLTexture::CubeMapFace face,
+ const QByteArray &bytes, const QTextureImageDataPtr &data)
+{
+ if (data->isCompressed()) {
+ glTex->setCompressedData(level, layer, face, bytes.size(), bytes.constData());
+ } else {
+ QOpenGLPixelTransferOptions uploadOptions;
+ uploadOptions.setAlignment(1);
+ glTex->setData(level, layer, face, data->pixelFormat(), data->pixelType(), bytes.constData(), &uploadOptions);
+ }
+}
+
+void GLTexture::uploadGLTextureData()
+{
+ // Upload all QTexImageData set by the QTextureGenerator
+ if (m_textureData) {
+ const QVector<QTextureImageDataPtr> imgData = m_textureData->imageData();
+
+ for (const QTextureImageDataPtr &data : imgData) {
+ const int mipLevels = m_properties.generateMipMaps ? 1 : data->mipLevels();
+
+ for (int layer = 0; layer < data->layers(); layer++) {
+ for (int face = 0; face < data->faces(); face++) {
+ for (int level = 0; level < mipLevels; level++) {
+ // ensure we don't accidently cause a detach / copy of the raw bytes
+ const QByteArray bytes(data->data(layer, face, level));
+ uploadGLData(m_gl, level, layer,
+ static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face),
+ bytes, data);
+ }
+ }
+ }
+ }
+ }
+
+ // Upload all QTexImageData references by the TextureImages
+ for (int i = 0; i < m_images.size(); i++) {
+ const QTextureImageDataPtr &imgData = m_imageData.at(i);
+
+ // ensure we don't accidently cause a detach / copy of the raw bytes
+ const QByteArray bytes(imgData->data());
+ uploadGLData(m_gl, m_images[i].mipLevel, m_images[i].layer,
+ static_cast<QOpenGLTexture::CubeMapFace>(m_images[i].face),
+ bytes, imgData);
+ }
+}
+
+void GLTexture::updateGLTextureParameters()
+{
+ m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeX));
+ if (m_properties.target != QAbstractTexture::Target1D &&
+ m_properties.target != QAbstractTexture::Target1DArray &&
+ m_properties.target != QAbstractTexture::TargetBuffer)
+ m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeY));
+ if (m_properties.target == QAbstractTexture::Target3D)
+ m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeZ));
+ m_gl->setMinMagFilters(static_cast<QOpenGLTexture::Filter>(m_parameters.minificationFilter),
+ static_cast<QOpenGLTexture::Filter>(m_parameters.magnificationFilter));
+ if (m_gl->hasFeature(QOpenGLTexture::AnisotropicFiltering))
+ m_gl->setMaximumAnisotropy(m_parameters.maximumAnisotropy);
+ if (m_gl->hasFeature(QOpenGLTexture::TextureComparisonOperators)) {
+ m_gl->setComparisonFunction(static_cast<QOpenGLTexture::ComparisonFunction>(m_parameters.comparisonFunction));
+ m_gl->setComparisonMode(static_cast<QOpenGLTexture::ComparisonMode>(m_parameters.comparisonMode));
+ }
+}
+
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h
new file mode 100644
index 000000000..f911262be
--- /dev/null
+++ b/src/render/texture/gltexture_p.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GLTEXTURE_H
+#define QT3DRENDER_RENDER_GLTEXTURE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/qtexture.h>
+#include <Qt3DRender/qtextureimagedata.h>
+#include <Qt3DRender/qtexturegenerator.h>
+#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DRender/private/handle_types_p.h>
+#include <Qt3DRender/private/texture_p.h>
+#include <QOpenGLContext>
+#include <QFlags>
+#include <QMutex>
+#include <QSize>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLTexture;
+
+namespace Qt3DRender {
+namespace Render {
+
+class TextureImageManager;
+class TextureDataManager;
+class TextureImageDataManager;
+
+/**
+ * @brief
+ * Actual implementation of the OpenGL texture object. Makes sure the
+ * QOpenGLTexture is up-to-date with the generators, properties and parameters
+ * that were set for this GLTexture.
+ *
+ * Can be shared among multiple QTexture backend nodes through the
+ * GLTextureManager, which will make sure that there are no two GLTextures
+ * sharing the same texture data.
+ *
+ * A GLTexture can be unique though. In that case, it will not be shared
+ * between QTextures, but private to one QTexture only.
+ */
+class Q_AUTOTEST_EXPORT GLTexture
+{
+public:
+ GLTexture(TextureDataManager *texDataMgr,
+ TextureImageDataManager *texImgDataMgr,
+ const QTextureGeneratorPtr &texGen,
+ bool unique);
+
+ ~GLTexture();
+
+ /**
+ * Helper class to hold the defining properties of TextureImages
+ */
+ struct Image {
+ QTextureImageDataGeneratorPtr generator;
+ int layer;
+ int mipLevel;
+ QAbstractTexture::CubeMapFace face;
+
+ inline bool operator==(const Image &o) const {
+ bool sameGenerators = (generator == o.generator)
+ || (!generator.isNull() && !o.generator.isNull() && *generator == *o.generator);
+ return sameGenerators && layer == o.layer && mipLevel == o.mipLevel && face == o.face;
+ }
+ inline bool operator!=(const Image &o) const { return !(*this == o); }
+ };
+
+ inline bool isUnique() const { return m_unique; }
+
+ inline TextureProperties properties() const { return m_properties; }
+ inline TextureParameters parameters() const { return m_parameters; }
+ inline QTextureGeneratorPtr textureGenerator() const { return m_dataFunctor; }
+ inline QVector<Image> images() const { return m_images; }
+
+ inline QSize size() const { return QSize(m_properties.width, m_properties.height); }
+ inline QOpenGLTexture *getGLTexture() const { return m_gl; }
+
+ /**
+ * @brief
+ * Returns the QOpenGLTexture for this GLTexture. If necessary,
+ * the GL texture will be created from the TextureImageDatas associated
+ * with the texture and image functors. If no functors are provided,
+ * the texture will be created without images.
+ *
+ * If the texture properties or parameters have changed, these changes
+ * will be applied to the resulting OpenGL texture.
+ */
+ QOpenGLTexture* getOrCreateGLTexture();
+
+ /**
+ * @brief Make sure to call this before calling the dtor
+ */
+ void destroyGLTexture();
+
+protected:
+
+ template<class APITexture, class APITextureImage>
+ friend class APITextureManager;
+
+ /*
+ * These methods are to be accessed from the GLTextureManager.
+ * The renderer and the texture backend nodes can only modify Textures
+ * through the GLTextureManager.
+ *
+ * The methods should only be called for unique textures, or textures
+ * that are not shared between multiple nodes.
+ */
+ void setParameters(const TextureParameters &params);
+ void setProperties(const TextureProperties &props);
+ void setImages(const QVector<Image> &images);
+
+private:
+
+ enum DirtyFlag {
+ TextureData = 0x1, // one or more generators need to be executed
+ Properties = 0x2, // texture needs to be (re-)created
+ Parameters = 0x4 // texture parameters need to be (re-)set
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+
+ QOpenGLTexture *buildGLTexture();
+ void uploadGLTextureData();
+ void updateGLTextureParameters();
+
+ bool m_unique;
+ DirtyFlags m_dirty;
+ QOpenGLTexture *m_gl;
+
+ TextureDataManager *m_textureDataManager;
+ TextureImageDataManager *m_textureImageDataManager;
+
+ TextureProperties m_properties;
+ TextureParameters m_parameters;
+
+ QTextureGeneratorPtr m_dataFunctor;
+ QVector<Image> m_images;
+
+ // cache actual image data generated by the functors
+ QTextureDataPtr m_textureData;
+ QVector<QTextureImageDataPtr> m_imageData;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GLTEXTURE_H
diff --git a/src/render/texture/gltexturemanager_p.h b/src/render/texture/gltexturemanager_p.h
new file mode 100644
index 000000000..1c8b49911
--- /dev/null
+++ b/src/render/texture/gltexturemanager_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GLTEXTUREMANAGER_H
+#define QT3DRENDER_RENDER_GLTEXTUREMANAGER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/private/apitexturemanager_p.h>
+#include <Qt3DRender/private/gltexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT GLTextureManager : public APITextureManager<GLTexture, GLTexture::Image>
+{
+public:
+ explicit GLTextureManager(TextureImageManager *textureImageManager,
+ TextureDataManager *textureDataManager,
+ TextureImageDataManager *textureImageDataManager)
+ : APITextureManager<GLTexture, GLTexture::Image>(textureImageManager,
+ textureDataManager,
+ textureImageDataManager)
+ {}
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GLTEXTUREMANAGER_H
diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp
index 8d151e0eb..7703933a4 100644
--- a/src/render/texture/qabstracttexture.cpp
+++ b/src/render/texture/qabstracttexture.cpp
@@ -69,6 +69,17 @@ QAbstractTexturePrivate::QAbstractTexturePrivate()
{
}
+void QAbstractTexturePrivate::setDataFunctor(const QTextureGeneratorPtr &generator)
+{
+ if (generator != m_dataFunctor) {
+ m_dataFunctor = generator;
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(m_id);
+ change->setPropertyName("generator");
+ change->setValue(QVariant::fromValue(generator));
+ notifyObservers(change);
+ }
+}
+
/*!
\class Qt3DRender::QAbstractTexture
\inmodule Qt3DRender
diff --git a/src/render/texture/qabstracttexture.h b/src/render/texture/qabstracttexture.h
index 0f1dc5dfe..53868b319 100644
--- a/src/render/texture/qabstracttexture.h
+++ b/src/render/texture/qabstracttexture.h
@@ -82,7 +82,7 @@ public:
Ready,
Error
};
- Q_ENUM(Status)
+ Q_ENUM(Status) // LCOV_EXCL_LINE
enum Target {
TargetAutomatic = 0, // Target will be determined by the Qt3D engine
@@ -98,7 +98,7 @@ public:
TargetRectangle = 0x84F5, // GL_TEXTURE_RECTANGLE
TargetBuffer = 0x8C2A // GL_TEXTURE_BUFFER
};
- Q_ENUM(Target)
+ Q_ENUM(Target) // LCOV_EXCL_LINE
enum TextureFormat {
NoFormat = 0, // GL_NONE
@@ -227,7 +227,7 @@ public:
LuminanceFormat = 0x1909, // GL_LUMINANCE
LuminanceAlphaFormat = 0x190A
};
- Q_ENUM(TextureFormat)
+ Q_ENUM(TextureFormat) // LCOV_EXCL_LINE
enum Filter {
Nearest = 0x2600, // GL_NEAREST
@@ -237,7 +237,7 @@ public:
LinearMipMapNearest = 0x2701, // GL_LINEAR_MIPMAP_NEAREST
LinearMipMapLinear = 0x2703 // GL_LINEAR_MIPMAP_LINEAR
};
- Q_ENUM(Filter)
+ Q_ENUM(Filter) // LCOV_EXCL_LINE
enum CubeMapFace {
CubeMapPositiveX = 0x8515, // GL_TEXTURE_CUBE_MAP_POSITIVE_X
@@ -248,7 +248,7 @@ public:
CubeMapNegativeZ = 0x851A, // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
AllFaces
};
- Q_ENUM(CubeMapFace)
+ Q_ENUM(CubeMapFace) // LCOV_EXCL_LINE
enum ComparisonFunction {
CompareLessEqual = 0x0203, // GL_LEQUAL
@@ -260,13 +260,13 @@ public:
CompareAlways = 0x0207, // GL_ALWAYS
CompareNever = 0x0200 // GL_NEVER
};
- Q_ENUM(ComparisonFunction)
+ Q_ENUM(ComparisonFunction) // LCOV_EXCL_LINE
enum ComparisonMode {
CompareRefToTexture = 0x884E, // GL_COMPARE_REF_TO_TEXTURE
CompareNone = 0x0000 // GL_NONE
};
- Q_ENUM(ComparisonMode)
+ Q_ENUM(ComparisonMode) // LCOV_EXCL_LINE
~QAbstractTexture();
@@ -344,6 +344,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QAbstractTexture *)
+Q_DECLARE_METATYPE(Qt3DRender::QAbstractTexture *) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QABSTRACTTEXTURE_H
diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h
index 80e939bf9..7f5a32c94 100644
--- a/src/render/texture/qabstracttexture_p.h
+++ b/src/render/texture/qabstracttexture_p.h
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QAbstractTexturePrivate : public Qt3DCore::QNodePrivate
+class Q_AUTOTEST_EXPORT QAbstractTexturePrivate : public Qt3DCore::QNodePrivate
{
public :
QAbstractTexturePrivate();
@@ -86,6 +86,9 @@ public :
int m_layers;
int m_samples;
+ void setDataFunctor(const QTextureGeneratorPtr &generator);
+
+private:
QTextureGeneratorPtr m_dataFunctor;
};
diff --git a/src/render/texture/qabstracttextureimage.cpp b/src/render/texture/qabstracttextureimage.cpp
index 42e78ced6..2f91539ff 100644
--- a/src/render/texture/qabstracttextureimage.cpp
+++ b/src/render/texture/qabstracttextureimage.cpp
@@ -78,7 +78,7 @@ namespace Qt3DRender {
\fn bool QTextureImageDataGenerator::operator ==(const QTextureImageDataGenerator &other) const
Implement the method to compare this texture data generator to \a other.
- The operator is used to check if the \l QAbstractTextureImage needs to reload
+ Returns a boolean that indicates whether the \l QAbstractTextureImage needs to reload
the \l QTextureImageData.
*/
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index af7f35d48..a566ecc36 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -938,8 +938,10 @@ void QTextureLoader::setSource(const QUrl& source)
Q_D(QTextureLoader);
if (source != d->m_source) {
d->m_source = source;
- d->m_dataFunctor.reset(new QTextureFromSourceGenerator(source, d->m_mirrored));
+ d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored));
+ const bool blocked = blockNotifications(true);
emit sourceChanged(source);
+ blockNotifications(blocked);
}
}
@@ -984,8 +986,10 @@ void QTextureLoader::setMirrored(bool mirrored)
Q_D(QTextureLoader);
if (mirrored != d->m_mirrored) {
d->m_mirrored = mirrored;
- d->m_dataFunctor.reset(new QTextureFromSourceGenerator(d->m_source, d->m_mirrored));
+ d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored));
+ const bool blocked = blockNotifications(true);
emit mirroredChanged(mirrored);
+ blockNotifications(blocked);
}
}
@@ -1001,6 +1005,16 @@ bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) co
otherFunctor->m_mirrored == m_mirrored);
}
+QUrl QTextureFromSourceGenerator::url() const
+{
+ return m_url;
+}
+
+bool QTextureFromSourceGenerator::isMirrored() const
+{
+ return m_mirrored;
+}
+
/*!
* Constructs a new QTextureFromSourceGenerator::QTextureFromSourceGenerator
* instance with \a url.
diff --git a/src/render/texture/qtexture_p.h b/src/render/texture/qtexture_p.h
index 21fe93e2b..a0ea71a58 100644
--- a/src/render/texture/qtexture_p.h
+++ b/src/render/texture/qtexture_p.h
@@ -67,7 +67,7 @@ public:
bool m_mirrored;
};
-class QTextureFromSourceGenerator : public QTextureGenerator
+class Q_AUTOTEST_EXPORT QTextureFromSourceGenerator : public QTextureGenerator
{
public:
explicit QTextureFromSourceGenerator(const QUrl &url, bool mirrored);
@@ -77,11 +77,15 @@ public:
QT3D_FUNCTOR(QTextureFromSourceGenerator)
+ QUrl url() const;
+ bool isMirrored() const;
+
private:
QUrl m_url;
QAbstractTexture::Status m_status;
bool m_mirrored;
};
+typedef QSharedPointer<QTextureFromSourceGenerator> QTextureFromSourceGeneratorPtr;
class Q_AUTOTEST_EXPORT TextureLoadingHelper
{
diff --git a/src/render/texture/qtexturedata.cpp b/src/render/texture/qtexturedata.cpp
index 061c93198..b7bb75242 100644
--- a/src/render/texture/qtexturedata.cpp
+++ b/src/render/texture/qtexturedata.cpp
@@ -46,6 +46,7 @@ namespace Qt3DRender {
/*!
* \class Qt3DRender::QTextureData
+ * \inheaderfile Qt3DRender/QTextureData
* \brief The QTextureData class stores texture information such as
* the target, height, width, depth, layers, wrap, and if mipmaps are enabled.
* \since 5.7
diff --git a/src/render/texture/qtexturegenerator.h b/src/render/texture/qtexturegenerator.h
index 59bebde8c..faa9e1c7b 100644
--- a/src/render/texture/qtexturegenerator.h
+++ b/src/render/texture/qtexturegenerator.h
@@ -66,6 +66,6 @@ typedef QSharedPointer<QTextureGenerator> QTextureGeneratorPtr;
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QTextureGeneratorPtr)
+Q_DECLARE_METATYPE(Qt3DRender::QTextureGeneratorPtr) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QTEXTUREGENERATOR_H
diff --git a/src/render/texture/qtextureimage.cpp b/src/render/texture/qtextureimage.cpp
index 73459bdf6..9834a4e0a 100644
--- a/src/render/texture/qtextureimage.cpp
+++ b/src/render/texture/qtextureimage.cpp
@@ -82,13 +82,6 @@ namespace Qt3DRender {
*/
/*!
- \qmlproperty url TextureImage::source
-
- This property holds the source url from which data for the texture
- image will be loaded.
-*/
-
-/*!
\qmlproperty enumeration TextureImage::status
This property holds the status of the texture image loading.
@@ -103,7 +96,7 @@ namespace Qt3DRender {
*/
/*!
- \property QTextureImage::source
+ \property Qt3DRender::QTextureImage::source
This property holds the source url from which data for the texture
image will be loaded.
@@ -137,7 +130,7 @@ QTextureImage::~QTextureImage()
}
/*!
- \return the source url from which data for the texture image will be loaded.
+ Returns the source url from which data for the texture image will be loaded.
*/
QUrl QTextureImage::source() const
{
@@ -146,7 +139,7 @@ QUrl QTextureImage::source() const
}
/*!
- \return the current status.
+ Returns the current status.
*/
QTextureImage::Status QTextureImage::status() const
{
@@ -155,7 +148,7 @@ QTextureImage::Status QTextureImage::status() const
}
/*!
- * \return whether mirroring is enabled or not.
+ * Returns whether mirroring is enabled or not.
*/
bool QTextureImage::isMirrored() const
{
@@ -164,13 +157,6 @@ bool QTextureImage::isMirrored() const
}
/*!
- \property Qt3DRender::QTextureImage::source
-
- This property holds the source url from which data for the texture
- image will be loaded.
-*/
-
-/*!
\qmlproperty url Qt3D.Render::TextureImage::source
This property holds the source url from which data for the texture
@@ -186,7 +172,9 @@ void QTextureImage::setSource(const QUrl &source)
Q_D(QTextureImage);
if (source != d->m_source) {
d->m_source = source;
+ const bool blocked = blockNotifications(true);
emit sourceChanged(source);
+ blockNotifications(blocked);
notifyDataGeneratorChanged();
}
}
@@ -232,7 +220,9 @@ void QTextureImage::setMirrored(bool mirrored)
Q_D(QTextureImage);
if (mirrored != d->m_mirrored) {
d->m_mirrored = mirrored;
+ const bool blocked = blockNotifications(true);
emit mirroredChanged(mirrored);
+ blockNotifications(blocked);
notifyDataGeneratorChanged();
}
}
@@ -251,7 +241,7 @@ void QTextureImage::setStatus(Status status)
}
/*!
- \return the Qt3DRender::QTextureImageDataGeneratorPtr functor to be used by the
+ Returns the Qt3DRender::QTextureImageDataGeneratorPtr functor to be used by the
backend to load the texture image data into an OpenGL texture object.
*/
QTextureImageDataGeneratorPtr QTextureImage::dataGenerator() const
@@ -306,6 +296,16 @@ bool QImageTextureDataFunctor::operator ==(const QTextureImageDataGenerator &oth
otherFunctor->m_mirrored == m_mirrored);
}
+QUrl QImageTextureDataFunctor::url() const
+{
+ return m_url;
+}
+
+bool QImageTextureDataFunctor::isMirrored() const
+{
+ return m_mirrored;
+}
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/texture/qtextureimage.h b/src/render/texture/qtextureimage.h
index c8d0121f8..e2ab54a1b 100644
--- a/src/render/texture/qtextureimage.h
+++ b/src/render/texture/qtextureimage.h
@@ -66,7 +66,7 @@ public:
Ready,
Error
};
- Q_ENUM(Status)
+ Q_ENUM(Status) // LCOV_EXCL_LINE
QUrl source() const;
Status status() const;
diff --git a/src/render/texture/qtextureimage_p.h b/src/render/texture/qtextureimage_p.h
index cebd9a951..323742781 100644
--- a/src/render/texture/qtextureimage_p.h
+++ b/src/render/texture/qtextureimage_p.h
@@ -67,7 +67,7 @@ class QTextureImagePrivate : public QAbstractTextureImagePrivate
public:
QTextureImagePrivate()
: QAbstractTextureImagePrivate()
- , m_status(QTextureImage::Loading)
+ , m_status(QTextureImage::None)
, m_mirrored(true)
{
}
@@ -79,7 +79,7 @@ public:
bool m_mirrored;
};
-class QImageTextureDataFunctor : public QTextureImageDataGenerator
+class Q_AUTOTEST_EXPORT QImageTextureDataFunctor : public QTextureImageDataGenerator
{
public:
explicit QImageTextureDataFunctor(const QUrl &url, bool mirrored);
@@ -89,6 +89,9 @@ public:
inline QTextureImage::Status status() const { return m_status; }
QT3D_FUNCTOR(QImageTextureDataFunctor)
+ QUrl url() const;
+ bool isMirrored() const;
+
private:
QUrl m_url;
QDateTime m_lastModified;
@@ -96,6 +99,8 @@ private:
bool m_mirrored;
};
+typedef QSharedPointer<QImageTextureDataFunctor> QImageTextureDataFunctorPtr;
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/texture/qtextureimagedatagenerator.h b/src/render/texture/qtextureimagedatagenerator.h
index eee7a8149..5213f3929 100644
--- a/src/render/texture/qtextureimagedatagenerator.h
+++ b/src/render/texture/qtextureimagedatagenerator.h
@@ -69,6 +69,6 @@ typedef QSharedPointer<QTextureImageDataGenerator> QTextureImageDataGeneratorPtr
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QTextureImageDataGeneratorPtr)
+Q_DECLARE_METATYPE(Qt3DRender::QTextureImageDataGeneratorPtr) // LCOV_EXCL_LINE
#endif // QT3DRENDER_QTEXTUREIMAGEDATAGENERATOR_H
diff --git a/src/render/texture/qtexturewrapmode.h b/src/render/texture/qtexturewrapmode.h
index bb27acf4a..7349e654c 100644
--- a/src/render/texture/qtexturewrapmode.h
+++ b/src/render/texture/qtexturewrapmode.h
@@ -63,7 +63,7 @@ public:
ClampToEdge = 0x812F, // GL_CLAMP_TO_EDGE
ClampToBorder = 0x812D // GL_CLAMP_TO_BORDER
};
- Q_ENUM(WrapMode)
+ Q_ENUM(WrapMode) // LCOV_EXCL_LINE
explicit QTextureWrapMode(WrapMode wrapMode = ClampToEdge, QObject *parent = nullptr);
explicit QTextureWrapMode(WrapMode x, WrapMode y, WrapMode z, QObject *parent = nullptr);
diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp
index d44ac151c..233dc364a 100644
--- a/src/render/texture/texture.cpp
+++ b/src/render/texture/texture.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,22 +37,20 @@
**
****************************************************************************/
-#include <QtCore/qhash.h>
#include "texture_p.h"
#include <QDebug>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
-#include <QOpenGLPixelTransferOptions>
-#include <Qt3DRender/qtexture.h>
-#include <Qt3DRender/qtextureimagedata.h>
-#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/texturedatamanager_p.h>
-#include <Qt3DRender/private/qabstracttexture_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qpropertynodeaddedchange.h>
#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DRender/private/texture_p.h>
+#include <Qt3DRender/private/qabstracttexture_p.h>
+#include <Qt3DRender/private/gltexturemanager_p.h>
+#include <Qt3DRender/private/managers_p.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt3DCore;
@@ -60,584 +58,156 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
-/* A Texture can get its data in two complementary ways
- * - Usually when a texture is created it is associated with a various number of
- * QTextureImages <-> TextureImage which will internally contain a set of QTexImageData
- * - A QTexture can also provide a QTextureGenerator functor which might also
- * return a vector of QTexImageData
- * So internally a Texture has a vector of HTextureImage which allow to retrieve a TextureImage and HTextureData
- * but also a vector of HTextureData filled by the QTextureGenerator if present.
- * From a memory management point of view, the texture needs to make sure it releases the HTextureData
- * that were generated from the QTextureGenerator as these are not shared and belong to the Texture object.
- * The HTextureData associated to a HTextureImage are managed by the TextureImage.
- */
-
Texture::Texture()
- : BackendNode()
- , m_gl(nullptr)
- , m_width(1)
- , m_height(1)
- , m_depth(1)
- , m_layers(1)
- , m_samples(1)
- , m_mipLevels(1)
- , m_generateMipMaps(false)
- , m_target(QAbstractTexture::Target2D)
- , m_format(QAbstractTexture::RGBA8_UNorm)
- , m_magnificationFilter(QAbstractTexture::Nearest)
- , m_minificationFilter(QAbstractTexture::Nearest)
- , m_wrapModeX(QTextureWrapMode::ClampToEdge)
- , m_wrapModeY(QTextureWrapMode::ClampToEdge)
- , m_wrapModeZ(QTextureWrapMode::ClampToEdge)
- , m_maximumAnisotropy(1.0f)
- , m_comparisonFunction(QAbstractTexture::CompareLessEqual)
- , m_comparisonMode(QAbstractTexture::CompareNone)
- , m_isDirty(false)
- , m_filtersAndWrapUpdated(false)
- , m_dataUploadRequired(false)
- , m_textureDNA(0)
- , m_textureManager(nullptr)
+ // We need backend -> frontend notifications to update the status of the texture
+ : BackendNode(ReadWrite)
+ , m_dirty(DirtyGenerators|DirtyProperties|DirtyParameters)
, m_textureImageManager(nullptr)
- , m_textureDataManager(nullptr)
{
- // We need backend -> frontend notifications to update the status of the texture
}
Texture::~Texture()
{
- // Release the texture data handles that may have been loaded
- // by a QTextureGenerator functor
- releaseTextureDataHandles();
-}
-
-void Texture::cleanup()
-{
- // Release the texture data handles that may have been loaded
- // by a QTextureGenerator functor
- releaseTextureDataHandles();
-
- QBackendNode::setEnabled(false);
- m_gl = nullptr;
- m_width = 1;
- m_height = 1;
- m_depth = 1;
- m_layers = 1;
- m_samples = 1;
- m_mipLevels = 1;
- m_generateMipMaps = false;
- m_target = QAbstractTexture::Target2D;
- m_format = QAbstractTexture::RGBA8_UNorm;
- m_magnificationFilter = QAbstractTexture::Nearest;
- m_minificationFilter = QAbstractTexture::Nearest;
- m_wrapModeX = QTextureWrapMode::ClampToEdge;
- m_wrapModeY = QTextureWrapMode::ClampToEdge;
- m_wrapModeZ = QTextureWrapMode::ClampToEdge;
- m_maximumAnisotropy = 1.0f;
- m_comparisonFunction = QAbstractTexture::CompareLessEqual;
- m_comparisonMode = QAbstractTexture::CompareNone;
- m_isDirty = false;
- m_filtersAndWrapUpdated = false;
- m_dataUploadRequired = false;
- m_textureDNA = 0;
- m_textureImages.clear();
- m_textureManager = nullptr;
- m_textureImageManager = nullptr;
- m_textureDataManager = nullptr;
- m_dataFunctor.clear();
-}
-
-// AspectThread
-void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
-{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractTextureData>>(change);
- const auto &data = typedChange->data;
-
- QMutexLocker lock(&m_lock);
- m_target = data.target;
- m_format = data.format;
- m_width = data.width;
- m_height = data.height;
- m_depth = data.depth;
- m_generateMipMaps = data.autoMipMap;
- m_minificationFilter = data.minFilter;
- m_magnificationFilter = data.magFilter;
- m_wrapModeX = data.wrapModeX;
- m_wrapModeY = data.wrapModeY;
- m_wrapModeZ = data.wrapModeZ;
- m_maximumAnisotropy = data.maximumAnisotropy;
- m_comparisonFunction = data.comparisonFunction;
- m_comparisonMode = data.comparisonMode;
- m_layers = data.layers;
- m_samples = data.samples;
- m_dataFunctor = data.dataFunctor;
- if (m_dataFunctor)
- addToPendingTextureJobs();
-
- // TODO: Handle texture image ids better. At the moment we rely upon the assumption
- // in the TextureImage that its parent is a Texture. Better to set the ids from here
- // I think, and do it consistently with other types that refer to other nodes.
- //data.textureImageIds
-
- m_isDirty = true;
+ // We do not abandon the api texture
+ // because if the dtor is called that means
+ // the manager was destroyed otherwise cleanup
+ // would have been called
}
-// RenderTread
-QOpenGLTexture *Texture::getOrCreateGLTexture()
-{
- // m_gl HAS to be destroyed in the OpenGL Thread
- // Will be recreated with updated values the next time
- // buildGLTexture is called
-
-
- // getOrCreateGLTexture is called by the OpenGL Render Thread
- // sceneChangeEvent is called by the QAspectThread
- // only the OpenGL Render Thread can set isDirty to false
- // only a sceneChangeEvent in QAspectThread can set isDirty to true
- // We need the lock to make sure there are no races when the OpenGL
- // thread tries to read isDirty or one of the texture properties in case
- // we are receiving a sceneChangeEvent that modifies isDirty or one of the properties
- // at the same time
-
- QMutexLocker lock(&m_lock);
- if (m_isDirty) {
- delete m_gl;
- m_gl = nullptr;
- m_isDirty = false;
- }
-
- // If the texture exists, we just update it and return
- if (m_gl != nullptr) {
-
- bool refreshDNA = m_filtersAndWrapUpdated || m_dataUploadRequired;
-
- if (m_filtersAndWrapUpdated) {
- updateWrapAndFilters();
- m_filtersAndWrapUpdated = false;
- }
- if (m_dataUploadRequired)
- updateAndLoadTextureImage();
-
- if (refreshDNA)
- updateDNA();
-
- return m_gl;
- }
-
- // Builds a new Texture, the texture was never created or it was destroyed
- // because it was dirty
- m_gl = buildGLTexture();
-
- m_gl->allocateStorage();
- if (!m_gl->isStorageAllocated()) {
- qWarning() << Q_FUNC_INFO << "texture storage allocation failed";
- return nullptr;
- }
-
- // Filters and WrapMode are set
- updateWrapAndFilters();
- m_filtersAndWrapUpdated = false;
-
- // Upload textures data the first time
- updateAndLoadTextureImage();
-
- // Update DNA
- updateDNA();
-
- // Ideally we might want to abstract that and use the GraphicsContext as a wrapper
- // around that.
-#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
- if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) {
- int err = ctx->functions()->glGetError();
- if (err)
- qWarning() << Q_FUNC_INFO << "GL error after generating mip-maps" << QString::number(err, 16);
- }
-#endif
-
- return m_gl;
-}
-
-// RenderThread
-QOpenGLTexture *Texture::buildGLTexture()
+void Texture::setTextureImageManager(TextureImageManager *manager)
{
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (!ctx) {
- qWarning() << Q_FUNC_INFO << "requires an OpenGL context";
- return nullptr;
- }
-
- if (m_target == QAbstractTexture::TargetAutomatic) {
- qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point";
- return nullptr;
- }
-
- QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_target));
-
- // m_format may not be ES2 compatible. Now it's time to convert it, if necessary.
- QAbstractTexture::TextureFormat format = m_format;
- if (ctx->isOpenGLES() && ctx->format().majorVersion() < 3) {
- switch (m_format) {
- case QOpenGLTexture::RGBA8_UNorm:
- case QOpenGLTexture::RGBAFormat:
- format = QAbstractTexture::RGBAFormat;
- break;
- case QOpenGLTexture::RGB8_UNorm:
- case QOpenGLTexture::RGBFormat:
- format = QAbstractTexture::RGBFormat;
- break;
- case QOpenGLTexture::DepthFormat:
- format = QAbstractTexture::DepthFormat;
- break;
- default:
- qWarning() << Q_FUNC_INFO << "could not find a matching OpenGL ES 2.0 unsized texture format";
- break;
- }
- }
-
- // Map ETC1 to ETC2 when supported. This allows using features like
- // immutable storage as ETC2 is standard in GLES 3.0, while the ETC1 extension
- // is written against GLES 1.0.
- if (m_format == QAbstractTexture::RGB8_ETC1) {
- if ((ctx->isOpenGLES() && ctx->format().majorVersion() >= 3)
- || ctx->hasExtension(QByteArrayLiteral("GL_OES_compressed_ETC2_RGB8_texture"))
- || ctx->hasExtension(QByteArrayLiteral("GL_ARB_ES3_compatibility")))
- format = m_format = QAbstractTexture::RGB8_ETC2;
- }
-
- glTex->setFormat(format == QAbstractTexture::Automatic ?
- QOpenGLTexture::NoFormat :
- static_cast<QOpenGLTexture::TextureFormat>(format));
- glTex->setSize(m_width, m_height, m_depth);
- // Set layers count if texture array
- if (m_target == QAbstractTexture::Target1DArray ||
- m_target == QAbstractTexture::Target2DArray ||
- m_target == QAbstractTexture::Target3D ||
- m_target == QAbstractTexture::Target2DMultisampleArray ||
- m_target == QAbstractTexture::TargetCubeMapArray) {
- glTex->setLayers(m_layers);
- }
-
- if (m_target == QAbstractTexture::Target2DMultisample ||
- m_target == QAbstractTexture::Target2DMultisampleArray) {
- // Set samples count if multisampled texture
- // (multisampled textures don't have mipmaps)
- glTex->setSamples(m_samples);
- } else if (m_generateMipMaps) {
- glTex->setMipLevels(glTex->maximumMipLevels());
- } else {
- glTex->setAutoMipMapGenerationEnabled(false);
- glTex->setMipBaseLevel(0);
- glTex->setMipMaxLevel(m_mipLevels - 1);
- glTex->setMipLevels(m_mipLevels);
- }
-
- if (!glTex->create()) {
- qWarning() << Q_FUNC_INFO << "creating QOpenGLTexture failed";
- return nullptr;
- }
-
- // FIXME : make this conditional on Qt version
- // work-around issue in QOpenGLTexture DSA emulaation which rasies
- // an Invalid Enum error
-#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
- int err = ctx->functions()->glGetError();
- if (err)
- qWarning() << Q_FUNC_INFO << err;
-#endif
-
- return glTex;
+ m_textureImageManager = manager;
}
-// RenderThread
-void Texture::setToGLTexture(QTextureImageData *imgData)
+void Texture::addDirtyFlag(DirtyFlags flags)
{
- Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated());
-
- const int layers = imgData->layers();
- const int faces = imgData->faces();
- const int mipLevels = m_generateMipMaps ? 1 : imgData->mipLevels();
-
- for (int layer = 0; layer < layers; layer++) {
- for (int face = 0; face < faces; face++) {
- for (int level = 0; level < mipLevels; level++) {
- // ensure we don't accidently cause a detach / copy of the raw bytes
- const QByteArray &bytes(imgData->data(layer, face, level));
-
- if (imgData->isCompressed()) {
- m_gl->setCompressedData(level,
- layer,
- static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face),
- bytes.size(),
- bytes.constData());
- } else {
- QOpenGLPixelTransferOptions uploadOptions;
- uploadOptions.setAlignment(1);
- m_gl->setData(level,
- layer,
- static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face),
- imgData->pixelFormat(),
- imgData->pixelType(),
- bytes.constData(),
- &uploadOptions);
- }
- }
- }
- }
-
- // FIXME : make this conditional on Qt version
- // work-around issue in QOpenGLTexture DSA emulation which rasies
- // an Invalid Enum error
-#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
- if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) {
- int err = ctx->functions()->glGetError();
- if (err)
- qWarning() << Q_FUNC_INFO << err;
- }
-#endif
+ m_dirty |= flags;
}
-// RenderThread
-void Texture::setToGLTexture(TextureImage *rImg, QTextureImageData *imgData)
+void Texture::unsetDirty()
{
- Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated());
- // ensure we don't accidently cause a detach / copy of the raw bytes
- const QByteArray &bytes(imgData->data());
- if (imgData->isCompressed()) {
- m_gl->setCompressedData(rImg->mipLevel(),
- rImg->layer(),
- static_cast<QOpenGLTexture::CubeMapFace>(rImg->face()),
- bytes.size(),
- bytes.constData());
- } else {
- QOpenGLPixelTransferOptions uploadOptions;
- uploadOptions.setAlignment(1);
- m_gl->setData(rImg->mipLevel(),
- rImg->layer(),
- static_cast<QOpenGLTexture::CubeMapFace>(rImg->face()),
- imgData->pixelFormat(),
- imgData->pixelType(),
- bytes.constData(),
- &uploadOptions);
- }
-
- // FIXME : make this conditional on Qt version
- // work-around issue in QOpenGLTexture DSA emulaation which rasies
- // an Invalid Enum error
-#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
- if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) {
- int err = ctx->functions()->glGetError();
- if (err)
- qWarning() << Q_FUNC_INFO << err;
- }
-#endif
+ m_dirty = Texture::NotDirty;
}
-// RenderThread
-void Texture::updateWrapAndFilters()
+void Texture::addTextureImage(Qt3DCore::QNodeId id)
{
- // multisample texture targets don't support sampler state
- if (m_target == QAbstractTexture::Target2DMultisample ||
- m_target == QAbstractTexture::Target2DMultisampleArray) {
+ if (!m_textureImageManager) {
+ qWarning() << "[Qt3DRender::TextureNode] addTextureImage: invalid TextureImageManager";
return;
}
- m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_wrapModeX));
- if (m_target != QAbstractTexture::Target1D &&
- m_target != QAbstractTexture::Target1DArray &&
- m_target != QAbstractTexture::TargetBuffer)
- m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_wrapModeY));
- if (m_target == QAbstractTexture::Target3D)
- m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_wrapModeZ));
- m_gl->setMinMagFilters(static_cast<QOpenGLTexture::Filter>(m_minificationFilter),
- static_cast<QOpenGLTexture::Filter>(m_magnificationFilter));
- if (m_gl->hasFeature(QOpenGLTexture::AnisotropicFiltering))
- m_gl->setMaximumAnisotropy(m_maximumAnisotropy);
- if (m_gl->hasFeature(QOpenGLTexture::TextureComparisonOperators)) {
- m_gl->setComparisonFunction(static_cast<QOpenGLTexture::ComparisonFunction>(m_comparisonFunction));
- m_gl->setComparisonMode(static_cast<QOpenGLTexture::ComparisonMode>(m_comparisonMode));
+ const HTextureImage handle = m_textureImageManager->lookupHandle(id);
+ if (handle.isNull()) {
+ qWarning() << "[Qt3DRender::TextureNode] addTextureImage: image handle is NULL";
+ } else if (!m_textureImages.contains(handle)) {
+ m_textureImages << handle;
+ addDirtyFlag(DirtyGenerators);
}
}
-void Texture::updateDNA()
+void Texture::removeTextureImage(Qt3DCore::QNodeId id)
{
- const int key = m_width + m_height + m_depth + m_layers + m_mipLevels +
- (m_generateMipMaps ? 1 : 0) +
- static_cast<int>(m_target) +
- static_cast<int>(m_format) +
- static_cast<int>(m_magnificationFilter) +
- static_cast<int>(m_minificationFilter) +
- static_cast<int>(m_wrapModeX) +
- static_cast<int>(m_wrapModeY) +
- static_cast<int>(m_wrapModeZ) +
- static_cast<int>(m_comparisonFunction) +
- static_cast<int>(m_comparisonMode);
- m_textureDNA = ::qHash(key) + ::qHash(m_maximumAnisotropy);
-
- // apply non-unique hashes from texture images or texture data
- for (HTextureImage imgHandle : qAsConst(m_textureImages)) {
- TextureImage *img = m_textureImageManager->data(imgHandle);
- if (img)
- m_textureDNA += img->dna();
- }
- for (const HTextureData textureDataHandle : qAsConst(m_textureDataHandles))
- m_textureDNA += ::qHash(textureDataHandle.index());
-
- // if texture contains no potentially shared image data: texture is unique
- if (m_textureImages.empty() && m_textureDataHandles.isEmpty()) // Ensures uniqueness by adding unique QNode id to the dna
- m_textureDNA += qHash(peerId());
-}
-
-// RenderThread
-GLint Texture::textureId()
-{
- return getOrCreateGLTexture()->textureId();
-}
-
-// Any Thread
-bool Texture::isTextureReset() const
-{
- QMutexLocker lock(&m_lock);
- return m_isDirty;
-}
-
-void Texture::setTarget(QAbstractTexture::Target target)
-{
- if (target != m_target) {
- m_target = target;
- m_isDirty = true;
- }
-}
-
-void Texture::setSize(int width, int height, int depth)
-{
- if (width != m_width) {
- m_width = width;
- m_isDirty |= true;
- }
- if (height != m_height) {
- m_height = height;
- m_isDirty |= true;
- }
- if (depth != m_depth) {
- m_depth = depth;
- m_isDirty |= true;
- }
-}
-
-void Texture::setFormat(QAbstractTexture::TextureFormat format)
-{
- if (format != m_format) {
- m_format = format;
- m_isDirty |= true;
- }
-}
-
-void Texture::setMipLevels(int mipLevels)
-{
- if (mipLevels != m_mipLevels) {
- m_mipLevels = mipLevels;
- m_isDirty = true;
+ if (!m_textureImageManager) {
+ qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: invalid TextureImageManager";
+ return;
}
-}
-void Texture::setLayers(int layers)
-{
- if (layers != m_layers) {
- m_layers = layers;
- m_isDirty = true;
+ const HTextureImage handle = m_textureImageManager->lookupHandle(id);
+ if (handle.isNull()) {
+ qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: image handle is NULL";
+ } else {
+ m_textureImages.removeAll(handle);
+ addDirtyFlag(DirtyGenerators);
}
}
-int Texture::width() const
-{
- return m_width;
-}
-
-int Texture::height() const
-{
- return m_height;
-}
-
-int Texture::depth() const
-{
- return m_depth;
-}
-
-int Texture::layers() const
+void Texture::cleanup()
{
- return m_layers;
-}
+ // Whoever calls this must make sure to also check if this
+ // texture is being referenced by a shared API specific texture (GLTexture)
+ m_dataFunctor.reset();
+ m_textureImages.clear();
-int Texture::samples() const
-{
- return m_samples;
+ // set default values
+ m_properties.width = 1;
+ m_properties.height = 1;
+ m_properties.depth = 1;
+ m_properties.layers = 1;
+ m_properties.mipLevels = 1;
+ m_properties.samples = 1;
+ m_properties.generateMipMaps = false;
+ m_properties.format = QAbstractTexture::RGBA8_UNorm;
+ m_properties.target = QAbstractTexture::Target2D;
+
+ m_parameters.magnificationFilter = QAbstractTexture::Nearest;
+ m_parameters.minificationFilter = QAbstractTexture::Nearest;
+ m_parameters.wrapModeX = QTextureWrapMode::ClampToEdge;
+ m_parameters.wrapModeY = QTextureWrapMode::ClampToEdge;
+ m_parameters.wrapModeZ = QTextureWrapMode::ClampToEdge;
+ m_parameters.maximumAnisotropy = 1.0f;
+ m_parameters.comparisonFunction = QAbstractTexture::CompareLessEqual;
+ m_parameters.comparisonMode = QAbstractTexture::CompareNone;
}
// ChangeArbiter/Aspect Thread
void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
- // The QOpenGLTexture has to be manipulated from the RenderThread only
- QMutexLocker lock(&m_lock);
- // We lock here so that we're sure the texture cannot be rebuilt while we are
- // modifying one of its properties
+ DirtyFlags dirty;
+
switch (e->type()) {
case PropertyUpdated: {
QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("width")) {
- setSize(propertyChange->value().toInt(), m_height, m_depth);
+ m_properties.width = propertyChange->value().toInt();
+ dirty = DirtyProperties;
} else if (propertyChange->propertyName() == QByteArrayLiteral("height")) {
- setSize(m_width, propertyChange->value().toInt(), m_depth);
+ m_properties.height = propertyChange->value().toInt();
+ dirty = DirtyProperties;
} else if (propertyChange->propertyName() == QByteArrayLiteral("depth")) {
- setSize(m_width, m_height, propertyChange->value().toInt());
+ m_properties.depth = propertyChange->value().toInt();
+ dirty = DirtyProperties;
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("maximumLayers")) {
+ m_properties.layers = propertyChange->value().toInt();
+ dirty = DirtyProperties;
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("format")) {
+ m_properties.format = static_cast<QAbstractTexture::TextureFormat>(propertyChange->value().toInt());
+ dirty = DirtyProperties;
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("target")) {
+ m_properties.target = static_cast<QAbstractTexture::Target>(propertyChange->value().toInt());
+ dirty = DirtyProperties;
} else if (propertyChange->propertyName() == QByteArrayLiteral("mipmaps")) {
- const bool oldMipMaps = m_generateMipMaps;
- m_generateMipMaps = propertyChange->value().toBool();
- m_isDirty |= (oldMipMaps != m_generateMipMaps);
+ m_properties.generateMipMaps = propertyChange->value().toBool();
+ dirty = DirtyProperties;
} else if (propertyChange->propertyName() == QByteArrayLiteral("minificationFilter")) {
- QAbstractTexture::Filter oldMinFilter = m_minificationFilter;
- m_minificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt());
- m_filtersAndWrapUpdated |= (oldMinFilter != m_minificationFilter);
+ m_parameters.minificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt());
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("magnificationFilter")) {
- QAbstractTexture::Filter oldMagFilter = m_magnificationFilter;
- m_magnificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt());
- m_filtersAndWrapUpdated |= (oldMagFilter != m_magnificationFilter);
+ m_parameters.magnificationFilter = static_cast<QAbstractTexture::Filter>(propertyChange->value().toInt());
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeX")) {
- QTextureWrapMode::WrapMode oldWrapModeX = m_wrapModeX;
- m_wrapModeX = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
- m_filtersAndWrapUpdated |= (oldWrapModeX != m_wrapModeX);
+ m_parameters.wrapModeX = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeY")) {
- QTextureWrapMode::WrapMode oldWrapModeY = m_wrapModeY;
- m_wrapModeY = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
- m_filtersAndWrapUpdated |= (oldWrapModeY != m_wrapModeY);
+ m_parameters.wrapModeY = static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("wrapModeZ")) {
- QTextureWrapMode::WrapMode oldWrapModeZ = m_wrapModeZ;
- m_wrapModeZ =static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
- m_filtersAndWrapUpdated |= (oldWrapModeZ != m_wrapModeZ);
- } else if (propertyChange->propertyName() == QByteArrayLiteral("format")) {
- setFormat(static_cast<QAbstractTexture::TextureFormat>(propertyChange->value().toInt()));
- } else if (propertyChange->propertyName() == QByteArrayLiteral("target")) {
- QAbstractTexture::Target oldTarget = m_target;
- m_target = static_cast<QAbstractTexture::Target>(propertyChange->value().toInt());
- m_isDirty |= (oldTarget != m_target);
+ m_parameters.wrapModeZ =static_cast<QTextureWrapMode::WrapMode>(propertyChange->value().toInt());
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("maximumAnisotropy")) {
- float oldMaximumAnisotropy = m_maximumAnisotropy;
- m_maximumAnisotropy = propertyChange->value().toFloat();
- m_filtersAndWrapUpdated |= !qFuzzyCompare(oldMaximumAnisotropy, m_maximumAnisotropy);
+ m_parameters.maximumAnisotropy = propertyChange->value().toFloat();
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonFunction")) {
- QAbstractTexture::ComparisonFunction oldComparisonFunction = m_comparisonFunction;
- m_comparisonFunction = propertyChange->value().value<QAbstractTexture::ComparisonFunction>();
- m_filtersAndWrapUpdated |= (oldComparisonFunction != m_comparisonFunction);
+ m_parameters.comparisonFunction = propertyChange->value().value<QAbstractTexture::ComparisonFunction>();
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("comparisonMode")) {
- QAbstractTexture::ComparisonMode oldComparisonMode = m_comparisonMode;
- m_comparisonMode = propertyChange->value().value<QAbstractTexture::ComparisonMode>();
- m_filtersAndWrapUpdated |= (oldComparisonMode != m_comparisonMode);
+ m_parameters.comparisonMode = propertyChange->value().value<QAbstractTexture::ComparisonMode>();
+ dirty = DirtyParameters;
} else if (propertyChange->propertyName() == QByteArrayLiteral("layers")) {
- const int oldLayers = m_layers;
- m_layers = propertyChange->value().toInt();
- m_isDirty |= (oldLayers != m_layers);
+ m_properties.layers = propertyChange->value().toInt();
+ dirty = DirtyProperties;
} else if (propertyChange->propertyName() == QByteArrayLiteral("samples")) {
- const int oldSamples = m_samples;
- m_samples = propertyChange->value().toInt();
- m_isDirty |= (oldSamples != m_samples);
+ m_properties.samples = propertyChange->value().toInt();
+ dirty = DirtyProperties;
}
// TO DO: Handle the textureGenerator change
@@ -647,7 +217,7 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
case PropertyValueAdded: {
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("textureImage")) {
- m_textureImages.append(m_textureImageManager->lookupHandle(change->addedNodeId()));
+ addTextureImage(change->addedNodeId());
}
}
break;
@@ -655,8 +225,7 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
case PropertyValueRemoved: {
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (change->propertyName() == QByteArrayLiteral("textureImage")) {
- m_textureImages.removeOne(m_textureImageManager->lookupHandle(change->removedNodeId()));
- // If a TextureImage is removed from a Texture, the texture image data remains on GPU
+ removeTextureImage(change->removedNodeId());
}
}
break;
@@ -665,136 +234,67 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
break;
}
- markDirty(AbstractRenderer::AllDirty);
- BackendNode::sceneChangeEvent(e);
-}
-
-TextureDNA Texture::dna() const
-{
- return m_textureDNA;
-}
-
-// AspectThread
-void Texture::setTextureManager(TextureManager *manager)
-{
- m_textureManager = manager;
-}
-
-// AspectThread
-void Texture::setTextureImageManager(TextureImageManager *manager)
-{
- m_textureImageManager = manager;
-}
-
-void Texture::setTextureDataManager(TextureDataManager *manager)
-{
- m_textureDataManager = manager;
-}
-
-// RenderThread
-void Texture::updateAndLoadTextureImage()
-{
- // Upload all QTexImageData set by the QTextureGenerator
- for (const HTextureData textureDataHandle : qAsConst(m_textureDataHandles)) {
- QTextureImageData *data = m_textureDataManager->data(textureDataHandle);
- if (data != Q_NULLPTR)
- setToGLTexture(data);
- }
- // Upload all QTexImageData references by the TextureImages
- QVector<TextureImageDNA> dnas;
- for (const HTextureImage t : qAsConst(m_textureImages)) {
- TextureImage *img = m_textureImageManager->data(t);
- if (img != nullptr && img->isDirty()) {
- if (dnas.contains(img->dna())) {
- img->unsetDirty();
- continue;
- }
- QTextureImageData *data = m_textureDataManager->data(img->textureDataHandle());
- if (data != nullptr) {
- setToGLTexture(img, data);
- dnas.append(img->dna());
- img->unsetDirty();
- }
- }
- }
+ addDirtyFlag(dirty);
- m_dataUploadRequired = false;
+ markDirty(AbstractRenderer::AllDirty);
+ BackendNode::sceneChangeEvent(e);
}
-void Texture::addTextureImageData(HTextureImage handle)
+void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
- m_textureImages.append(handle);
-}
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractTextureData>>(change);
+ const auto &data = typedChange->data;
-void Texture::removeTextureImageData(HTextureImage handle)
-{
- m_textureImages.removeOne(handle);
-}
+ m_properties.target = data.target;
+ m_properties.format = data.format;
+ m_properties.width = data.width;
+ m_properties.height = data.height;
+ m_properties.depth = data.depth;
+ m_properties.generateMipMaps = data.autoMipMap;
+ m_properties.layers = data.layers;
+ m_properties.samples = data.samples;
+ m_parameters.minificationFilter = data.minFilter;
+ m_parameters.magnificationFilter = data.magFilter;
+ m_parameters.wrapModeX = data.wrapModeX;
+ m_parameters.wrapModeY = data.wrapModeY;
+ m_parameters.wrapModeZ = data.wrapModeZ;
+ m_parameters.maximumAnisotropy = data.maximumAnisotropy;
+ m_parameters.comparisonFunction = data.comparisonFunction;
+ m_parameters.comparisonMode = data.comparisonMode;
+ m_dataFunctor = data.dataFunctor;
-void Texture::requestTextureDataUpdate()
-{
- m_dataUploadRequired = true;
+ addDirtyFlag(DirtyFlags(DirtyGenerators|DirtyProperties|DirtyParameters));
}
-// Will request a new jobs, if one of the texture data has changed
-// after the job was executed, requestTextureDataUpdate will be called
-// Called by RenderTextureImages
-void Texture::addToPendingTextureJobs()
-{
- m_textureDataManager->addToPendingTextures(peerId());
-}
TextureFunctor::TextureFunctor(AbstractRenderer *renderer,
- TextureManager *textureManager,
- TextureImageManager *textureImageManager,
- TextureDataManager *textureDataManager)
+ TextureManager *textureNodeManager,
+ TextureImageManager *textureImageManager)
: m_renderer(renderer)
- , m_textureManager(textureManager)
+ , m_textureNodeManager(textureNodeManager)
, m_textureImageManager(textureImageManager)
- , m_textureDataManager(textureDataManager)
{
}
Qt3DCore::QBackendNode *TextureFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
{
- Texture *backend = m_textureManager->getOrCreateResource(change->subjectId());
- backend->setTextureManager(m_textureManager);
+ Texture *backend = m_textureNodeManager->getOrCreateResource(change->subjectId());
backend->setTextureImageManager(m_textureImageManager);
- backend->setTextureDataManager(m_textureDataManager);
backend->setRenderer(m_renderer);
return backend;
}
Qt3DCore::QBackendNode *TextureFunctor::get(Qt3DCore::QNodeId id) const
{
- return m_textureManager->lookupResource(id);
+ return m_textureNodeManager->lookupResource(id);
}
void TextureFunctor::destroy(Qt3DCore::QNodeId id) const
{
- m_textureManager->releaseResource(id);
+ m_textureNodeManager->releaseResource(id);
}
-void Texture::addTextureDataHandle(HTextureData handle)
-{
- m_textureDataHandles.push_back(handle);
- // Request a new upload to the GPU
- requestTextureDataUpdate();
-}
-
-void Texture::releaseTextureDataHandles()
-{
- if (m_textureDataHandles.size() > 0) {
- m_isDirty = true;
- Q_ASSERT(m_textureDataManager);
- for (HTextureData textureData : qAsConst(m_textureDataHandles))
- m_textureDataManager->release(textureData);
- m_textureDataHandles.clear();
- // Request a new upload to the GPU
- requestTextureDataUpdate();
- }
-}
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/texture/texture.pri b/src/render/texture/texture.pri
index 762811003..bd5c34e72 100644
--- a/src/render/texture/texture.pri
+++ b/src/render/texture/texture.pri
@@ -20,18 +20,21 @@ HEADERS += \
$$PWD/qtexturegenerator.h \
$$PWD/qtexture_p.h \
$$PWD/qpaintedtextureimage.h \
- $$PWD/qpaintedtextureimage_p.h
+ $$PWD/qpaintedtextureimage_p.h \
+ $$PWD/gltexture_p.h \
+ $$PWD/gltexturemanager_p.h \
+ $$PWD/apitexturemanager_p.h
SOURCES += \
$$PWD/qabstracttextureimage.cpp \
$$PWD/qtextureimage.cpp \
$$PWD/qtexturewrapmode.cpp \
$$PWD/texture.cpp \
- $$PWD/texturedatamanager.cpp \
$$PWD/textureimage.cpp \
$$PWD/qabstracttexture.cpp \
$$PWD/qtexture.cpp \
$$PWD/qtextureimagedata.cpp \
$$PWD/qtexturedata.cpp \
$$PWD/qtexturegenerator.cpp \
- $$PWD/qpaintedtextureimage.cpp
+ $$PWD/qpaintedtextureimage.cpp \
+ $$PWD/gltexture.cpp
diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h
index 4f0f25564..07e3791e9 100644
--- a/src/render/texture/texture_p.h
+++ b/src/render/texture/texture_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -71,122 +71,118 @@ namespace Render {
class TextureManager;
class TextureImageManager;
-class TextureDataManager;
-typedef quint64 TextureDNA;
+/**
+ * General, constant properties of a texture
+ */
+struct TextureProperties
+{
+ int width = 1;
+ int height = 1;
+ int depth = 1;
+ int layers = 1;
+ int mipLevels = 1;
+ int samples = 1;
+ QAbstractTexture::Target target = QAbstractTexture::Target2D;
+ QAbstractTexture::TextureFormat format = QAbstractTexture::RGBA8_UNorm;
+ bool generateMipMaps = false;
+
+ bool operator==(const TextureProperties &o) const {
+ return (width == o.width) && (height == o.height) && (depth == o.depth)
+ && (layers == o.layers) && (mipLevels == o.mipLevels) && (target == o.target)
+ && (format == o.format) && (generateMipMaps == o.generateMipMaps)
+ && (samples == o.samples);
+ }
+ inline bool operator!=(const TextureProperties &o) const { return !(*this == o); }
+};
+
+/**
+ * Texture parameters that are independent of texture data and that may
+ * change without the re-uploading the texture
+ */
+struct TextureParameters
+{
+ QAbstractTexture::Filter magnificationFilter = QAbstractTexture::Nearest;
+ QAbstractTexture::Filter minificationFilter = QAbstractTexture::Nearest;
+ QTextureWrapMode::WrapMode wrapModeX = QTextureWrapMode::ClampToEdge;
+ QTextureWrapMode::WrapMode wrapModeY = QTextureWrapMode::ClampToEdge;
+ QTextureWrapMode::WrapMode wrapModeZ = QTextureWrapMode::ClampToEdge;
+ float maximumAnisotropy = 1.0f;
+ QAbstractTexture::ComparisonFunction comparisonFunction = QAbstractTexture::CompareLessEqual;
+ QAbstractTexture::ComparisonMode comparisonMode = QAbstractTexture::CompareNone;
+
+ bool operator==(const TextureParameters &o) const {
+ return (magnificationFilter == o.magnificationFilter) && (minificationFilter == o.minificationFilter)
+ && (wrapModeX == o.wrapModeX) && (wrapModeY == o.wrapModeY) && (wrapModeZ == o.wrapModeZ)
+ && (maximumAnisotropy == o.maximumAnisotropy)
+ && (comparisonFunction == o.comparisonFunction) && (comparisonMode == o.comparisonMode);
+ }
+ inline bool operator!=(const TextureParameters &o) const { return !(*this == o); }
+};
+/**
+ * Backend object for QAbstractTexture. Just holds texture properties and parameters.
+ * Will query the TextureImplManager for an instance of TextureImpl that matches it's
+ * properties.
+ */
class Q_AUTOTEST_EXPORT Texture : public BackendNode
{
public:
Texture();
~Texture();
- void cleanup();
- QOpenGLTexture *getOrCreateGLTexture();
+ enum DirtyFlag {
+ NotDirty = 0,
+ DirtyProperties = 0x1,
+ DirtyParameters = 0x2,
+ DirtyGenerators = 0x4
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
- GLint textureId();
+ void setTextureImageManager(TextureImageManager *manager);
+
+ void addDirtyFlag(DirtyFlags flags);
+ inline DirtyFlags dirtyFlags() const { return m_dirty; }
+ void unsetDirty();
- bool isTextureReset() const;
+ void addTextureImage(Qt3DCore::QNodeId id);
+ void removeTextureImage(Qt3DCore::QNodeId id);
+ void cleanup();
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
- TextureDNA dna() const;
- void setTextureManager(TextureManager *manager);
- void setTextureImageManager(TextureImageManager *manager);
- void setTextureDataManager(TextureDataManager *manager);
-
- void updateAndLoadTextureImage();
- void addTextureImageData(HTextureImage handle);
- void removeTextureImageData(HTextureImage handle);
-
- void requestTextureDataUpdate();
- void addToPendingTextureJobs();
- void setTarget(QAbstractTexture::Target target);
- void setSize(int width, int height, int depth);
- void setFormat(QAbstractTexture::TextureFormat format);
- void setMipLevels(int mipmapLevels);
- void setLayers(int layers);
-
- int width() const;
- int height() const;
- int depth() const;
- int layers() const;
- int samples() const;
-
- inline QVector<HTextureImage> textureImages() const { return m_textureImages; }
- inline QAbstractTexture::TextureFormat format() const { return m_format; }
- inline QAbstractTexture::Target target() const { return m_target; }
- inline bool isAutoMipMapGenerationEnabled() const { return m_generateMipMaps; }
-
- inline QTextureGeneratorPtr dataGenerator() const { return m_dataFunctor; }
- void addTextureDataHandle(HTextureData handle);
- inline QVector<HTextureData> textureDataHandles() const { return m_textureDataHandles; }
- void releaseTextureDataHandles();
-
- inline bool dataUploadRequired() const { return m_dataUploadRequired; }
- inline bool isDirty() const { return m_isDirty; }
+ inline const TextureProperties& properties() const { return m_properties; }
+ inline const TextureParameters& parameters() const { return m_parameters; }
+ inline const QVector<HTextureImage>& textureImages() const { return m_textureImages; }
+ inline const QTextureGeneratorPtr& dataGenerator() const { return m_dataFunctor; }
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
- QOpenGLTexture *m_gl;
-
- QOpenGLTexture *buildGLTexture();
- void setToGLTexture(QTextureImageData *imgData);
- void setToGLTexture(TextureImage *rImg, QTextureImageData *imgData);
- void updateWrapAndFilters();
-
- int m_width;
- int m_height;
- int m_depth;
- int m_layers;
- int m_samples;
- int m_mipLevels;
- bool m_generateMipMaps;
- QAbstractTexture::Target m_target;
- QAbstractTexture::TextureFormat m_format;
- QAbstractTexture::Filter m_magnificationFilter;
- QAbstractTexture::Filter m_minificationFilter;
- QTextureWrapMode::WrapMode m_wrapModeX;
- QTextureWrapMode::WrapMode m_wrapModeY;
- QTextureWrapMode::WrapMode m_wrapModeZ;
- float m_maximumAnisotropy;
- QAbstractTexture::ComparisonFunction m_comparisonFunction;
- QAbstractTexture::ComparisonMode m_comparisonMode;
+ DirtyFlags m_dirty;
+ TextureProperties m_properties;
+ TextureParameters m_parameters;
QTextureGeneratorPtr m_dataFunctor;
- QVector<HTextureData> m_textureDataHandles;
QVector<HTextureImage> m_textureImages;
- bool m_isDirty;
- bool m_filtersAndWrapUpdated;
- bool m_dataUploadRequired;
-
- mutable QMutex m_lock;
- TextureDNA m_textureDNA;
- TextureManager *m_textureManager;
TextureImageManager *m_textureImageManager;
- TextureDataManager *m_textureDataManager;
-
- void updateDNA();
};
class TextureFunctor : public Qt3DCore::QBackendNodeMapper
{
public:
explicit TextureFunctor(AbstractRenderer *renderer,
- TextureManager *textureManager,
- TextureImageManager *textureImageManager,
- TextureDataManager *textureDataManager);
+ TextureManager *textureNodeManager,
+ TextureImageManager *textureImageManager);
Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL;
Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL;
void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL;
private:
AbstractRenderer *m_renderer;
- TextureManager *m_textureManager;
+ TextureManager *m_textureNodeManager;
TextureImageManager *m_textureImageManager;
- TextureDataManager *m_textureDataManager;
};
} // namespace Render
@@ -194,6 +190,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::Render::Texture*)
+Q_DECLARE_METATYPE(Qt3DRender::Render::Texture*) // LCOV_EXCL_LINE
#endif // QT3DRENDER_RENDER_TEXTURE_H
diff --git a/src/render/texture/texturedatamanager.cpp b/src/render/texture/texturedatamanager.cpp
deleted file mode 100644
index abd536116..000000000
--- a/src/render/texture/texturedatamanager.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** 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-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "texturedatamanager_p.h"
-#include <Qt3DRender/qtextureimagedatagenerator.h>
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DRender {
-
-namespace Render {
-
-
-TextureDataManager::TextureDataManager()
- : m_mutex(QMutex::Recursive)
-{}
-
-// Called from AspectThread sync
-void TextureDataManager::addToPendingTextures(Qt3DCore::QNodeId textureId)
-{
- // This simple check ensures that we won't be having n jobs
- // for one mesh, in case n Materials are referencing the said
- // texture
- if (!m_texturesPending.contains(textureId))
- m_texturesPending.append(textureId);
-}
-
-// Called from AspectThread prepare jobs
-// Caller will often use std::move on this to clear it
-QVector<Qt3DCore::QNodeId> &TextureDataManager::texturesPending()
-{
- return m_texturesPending;
-}
-
-// Called from LoadTextureDataJob threads
-HTextureData TextureDataManager::textureDataFromFunctor(const QTextureImageDataGeneratorPtr &functor) const
-{
- QMutexLocker lock(&m_mutex);
- for (int i = 0, m = m_textureDataFunctors.size(); i < m; ++i) {
- if (*functor == *(m_textureDataFunctors[i].first))
- return m_textureDataFunctors[i].second;
- }
- return HTextureData();
-}
-
-// Called from LoadTextureDataJob threads
-void TextureDataManager::addTextureDataForFunctor(HTextureData textureDataHandle, const QTextureImageDataGeneratorPtr &functor)
-{
- QMutexLocker lock(&m_mutex);
- m_textureDataFunctors.push_back(qMakePair(functor, textureDataHandle));
-}
-
-// Called from LoadTextureDataJob threads
-void TextureDataManager::removeTextureDataFunctor(const QTextureImageDataGeneratorPtr &functor)
-{
- QMutexLocker lock(&m_mutex);
- for (int i = 0, m = m_textureDataFunctors.size(); i < m; ++i) {
- if (*functor == *(m_textureDataFunctors[i].first)) {
- m_textureDataFunctors.remove(i);
- break;
- }
- }
-}
-
-// Called from LoadTextureDataJob threads
-void TextureDataManager::assignFunctorToTextureImage(const QTextureImageDataGeneratorPtr &newFunctor, HTextureImage imageHandle)
-{
- QMutexLocker lock(&m_mutex);
- QVector<QPair<QTextureImageDataGeneratorPtr, QVector<HTextureImage> > >::iterator it = m_texturesImagesPerFunctor.begin();
-
- bool newFunctorAlreadyExists = false;
- bool oldFunctorWasRemoved = false;
- while (it != m_texturesImagesPerFunctor.end()) {
- QPair<QTextureImageDataGeneratorPtr, QVector<HTextureImage> > &entry = *it;
- QTextureImageDataGeneratorPtr functor = entry.first;
- QVector<HTextureImage> &imageHandles = entry.second;
- const bool functorMatchesNewFunctor = (*functor == *newFunctor);
- bool removed = false;
-
- if (functorMatchesNewFunctor) {
- // New Functor already exist, just need to append
- imageHandles.push_back(imageHandle);
- newFunctorAlreadyExists = true;
- } else if (imageHandles.contains(imageHandle)) {
- // functor in array != New Functor and contains
- // <=> functor was the previous functor of imageHandle
- // the image handle, we need to remove the handle
- imageHandles.removeAll(imageHandle);
-
- // If no texture image is referencing the functor anymore
- // get rid of the functor
- if (imageHandles.isEmpty()) {
- // We need to release the texture image data
- HTextureData textureDataHandle = textureDataFromFunctor(functor);
- if (!m_textureHandlesToRelease.contains(textureDataHandle))
- m_textureHandlesToRelease.push_back(textureDataHandle);
- // Remove functor
- removeTextureDataFunctor(functor);
- // Remove the entry
- it = m_texturesImagesPerFunctor.erase(it);
- removed = true;
- oldFunctorWasRemoved = true;
- }
- }
-
- // Early exit if we can
- if (oldFunctorWasRemoved && newFunctorAlreadyExists)
- break;
-
- if (!removed)
- ++it;
- }
-
- // Insert new imageHandle with new functor
- if (!newFunctorAlreadyExists)
- m_texturesImagesPerFunctor.push_back(qMakePair(newFunctor, QVector<HTextureImage>() << imageHandle));
-}
-
-QMutex *TextureDataManager::mutex() const
-{
- return &m_mutex;
-}
-
-// Called by cleanup job
-// No need to lock
-void TextureDataManager::cleanup()
-{
- for (int i = 0, m = m_textureHandlesToRelease.size(); i < m; ++i)
- release(m_textureHandlesToRelease[i]);
- m_textureHandlesToRelease.clear();
-}
-
-} // namespace Render
-
-} // namespace Qt3DRender
-
-QT_END_NAMESPACE
diff --git a/src/render/texture/texturedatamanager_p.h b/src/render/texture/texturedatamanager_p.h
index a420460e9..a93bace52 100644
--- a/src/render/texture/texturedatamanager_p.h
+++ b/src/render/texture/texturedatamanager_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -51,57 +51,168 @@
// We mean it.
//
-#include <Qt3DCore/private/qresourcemanager_p.h>
+#include <QMutex>
+#include <QMutexLocker>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qtextureimagedata.h>
-#include <Qt3DRender/private/handle_types_p.h>
-
-#include <QPair>
-#include <Qt3DCore/qnodeid.h>
+#include <Qt3DRender/qtexturegenerator.h>
+#include <Qt3DRender/qtextureimagedatagenerator.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-
namespace Render {
-typedef QPair<QTextureImageDataGeneratorPtr, QVector<HTextureImage> > FunctorImageHandlesPair;
-typedef QPair<QTextureImageDataGeneratorPtr, HTextureData> FunctorTextureDataPair;
-
-class TextureDataManager : public Qt3DCore::QResourceManager<QTextureImageData,
- Qt3DCore::QNodeId,
- 16,
- Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>
+/**
+ * The texture data managers associates each texture data generator
+ * with the data objects generated by them. That is, either
+ *
+ * QTextureImageDataGenerator -> QTextureImageData, or
+ * QTextureGenerator -> QTextureData
+ *
+ * This way, texture classes only need to refer to the texture functors used.
+ * Aspect jobs will make sure that at the start of each frame, all generators
+ * registered with the GeneratorDataManagers have been executed.
+ *
+ * This guarantees that no texture data generator is executed twice.
+ *
+ * Each Generator is associated with a number of textures that reference it.
+ * If the last texture disassociates from a generator, the QTextureData will
+ * be deleted.
+ */
+template <class GeneratorPtr, class DataPtr, class APITexture>
+class GeneratorDataManager
{
public:
- TextureDataManager();
- void addToPendingTextures(Qt3DCore::QNodeId textureId);
+ GeneratorDataManager() {}
+
+ /*!
+ * If no data for the given generator exists, make sure that the
+ * generators are executed the next frame. Reference generator by
+ * given texture
+ */
+ void requestData(const GeneratorPtr &generator, const APITexture *tex)
+ {
+ QMutexLocker lock(&m_mutex);
+
+ Entry *entry = findEntry(generator);
+ if (entry == nullptr)
+ entry = createEntry(generator);
+ Q_ASSERT(entry);
+ if (!entry->referencingTextures.contains(tex))
+ entry->referencingTextures.push_back(tex);
+ }
+
+ /*!
+ * Dereference given generator from texture. If no other textures still reference
+ * the generator, the associated data will be deleted
+ */
+ void releaseData(const GeneratorPtr &generator, const APITexture *tex)
+ {
+ QMutexLocker lock(&m_mutex);
+
+ const auto end = m_data.end();
+ for (auto it = m_data.begin(); it != end; ++it) {
+ Entry &entry = *it;
+ if (*entry.generator == *generator) {
+ entry.referencingTextures.removeAll(tex);
+ // delete, if that was the last reference
+ if (entry.referencingTextures.empty()) {
+ m_data.erase(it);
+ return;
+ }
+ }
+ }
+ }
+
+ /*!
+ * Return data associated with given generator, if existent
+ */
+ DataPtr getData(const GeneratorPtr &generator)
+ {
+ QMutexLocker lock(&m_mutex);
+
+ const Entry *entry = findEntry(generator);
+ return entry ? entry->data : DataPtr();
+ }
+
+ /*!
+ * Returns all generators that were not yet executed
+ */
+ QVector<GeneratorPtr> pendingGenerators()
+ {
+ QMutexLocker lock(&m_mutex);
+
+ QVector<GeneratorPtr> ret;
+ for (const Entry &entry : m_data)
+ if (!entry.data && !ret.contains(entry.generator))
+ ret.push_back(entry.generator);
+ return ret;
+ }
+
+ /*!
+ * Assigns a piece of data to the generator that was used to
+ * create it.
+ */
+ void assignData(const GeneratorPtr &generator, const DataPtr &data)
+ {
+ QMutexLocker lock(&m_mutex);
+
+ Entry *entry = findEntry(generator);
+ if (!entry)
+ qWarning() << "[TextureDataManager] assignData() called with non-existent generator";
+ else
+ entry->data = data;
+ }
- QVector<Qt3DCore::QNodeId> &texturesPending();
+private:
- HTextureData textureDataFromFunctor(const QTextureImageDataGeneratorPtr &functor) const;
- void addTextureDataForFunctor(HTextureData textureDataHandle, const QTextureImageDataGeneratorPtr &functor);
- void removeTextureDataFunctor(const QTextureImageDataGeneratorPtr &functor);
+ struct Entry {
+ GeneratorPtr generator;
+ QVector<const APITexture*> referencingTextures;
+ DataPtr data;
+ };
+
+ /*!
+ * Helper function: return entry for given generator if it exists, nullptr
+ * otherwise.
+ */
+ Entry* findEntry(const GeneratorPtr &generator)
+ {
+ for (int i = 0, sz = m_data.size(); i < sz; ++i)
+ if (*m_data[i].generator == *generator)
+ return &m_data[i];
+ return nullptr;
+ }
+
+ Entry *createEntry(const GeneratorPtr &generator)
+ {
+ Entry newEntry;
+ newEntry.generator = generator;
+
+ m_data.push_back(newEntry);
+ return &m_data.back();
+ }
+
+ QMutex m_mutex;
+ QVector<Entry> m_data;
+};
- void assignFunctorToTextureImage(const QTextureImageDataGeneratorPtr &functor, HTextureImage imageHandle);
+class GLTexture;
- QMutex *mutex() const;
- void cleanup();
+class Q_AUTOTEST_EXPORT TextureDataManager
+ : public GeneratorDataManager<QTextureGeneratorPtr, QTextureDataPtr, GLTexture>
+{
+};
-private:
- QVector<Qt3DCore::QNodeId> m_texturesPending;
- QVector<FunctorTextureDataPair> m_textureDataFunctors;
- QVector<FunctorImageHandlesPair> m_texturesImagesPerFunctor;
- mutable QMutex m_mutex;
- QVector<HTextureData> m_textureHandlesToRelease;
+class Q_AUTOTEST_EXPORT TextureImageDataManager
+ : public GeneratorDataManager<QTextureImageDataGeneratorPtr, QTextureImageDataPtr, GLTexture>
+{
};
} // namespace Render
} // namespace Qt3DRender
-Q_DECLARE_RESOURCE_INFO(Qt3DRender::QTextureImageData, Q_REQUIRES_CLEANUP)
-
QT_END_NAMESPACE
#endif // TEXTUREDATAMANAGER_H
diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp
index 7e2ac6277..f44a82649 100644
--- a/src/render/texture/textureimage.cpp
+++ b/src/render/texture/textureimage.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -39,9 +39,8 @@
#include "textureimage_p.h"
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DRender/qtextureimagedatagenerator.h>
+#include <Qt3DRender/qtextureimage.h>
#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/qabstracttextureimage_p.h>
QT_BEGIN_NAMESPACE
@@ -56,27 +55,16 @@ TextureImage::TextureImage()
, m_layer(0)
, m_mipLevel(0)
, m_face(QAbstractTexture::CubeMapPositiveX)
- , m_dirty(true)
, m_textureManager(nullptr)
- , m_textureImageManager(nullptr)
- , m_textureDataManager(nullptr)
- , m_dna(0)
+{
+}
+
+TextureImage::~TextureImage()
{
}
void TextureImage::cleanup()
{
- QBackendNode::setEnabled(false);
- m_layer = 0;
- m_mipLevel = 0;
- m_dirty = true;
- m_face = QAbstractTexture::CubeMapPositiveX;
- m_generator.reset();
- m_textureManager = nullptr;
- m_textureImageManager = nullptr;
- m_textureDataManager = nullptr;
- m_referencedTextures.clear();
- m_dna = 0;
}
void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -89,15 +77,14 @@ void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr
m_generator = data.generator;
if (!change->parentId()) {
- qWarning() << "No QAbstractTextureProvider parent found";
+ qWarning() << "No QAbstractTexture parent found";
} else {
- m_textureProviderId = change->parentId();
- m_textureProvider = m_textureManager->lookupHandle(m_textureProviderId);
+ const QNodeId id = change->parentId();
+ m_textureProvider = m_textureManager->lookupHandle(id);
Texture *texture = m_textureManager->data(m_textureProvider);
Q_ASSERT(texture);
// Notify the Texture that it has a new TextureImage and needs an update
- texture->addTextureImageData(m_textureImageManager->lookupHandle(peerId()));
- texture->addToPendingTextureJobs();
+ texture->addTextureImage(peerId());
}
}
@@ -105,27 +92,23 @@ void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- const bool wasDirty = m_dirty;
if (e->type() == PropertyUpdated) {
if (propertyChange->propertyName() == QByteArrayLiteral("layer")) {
m_layer = propertyChange->value().toInt();
- m_dirty = true;
} else if (propertyChange->propertyName() == QByteArrayLiteral("mipLevel")) {
m_mipLevel = propertyChange->value().toInt();
- m_dirty = true;
} else if (propertyChange->propertyName() == QByteArrayLiteral("face")) {
m_face = static_cast<QAbstractTexture::CubeMapFace>(propertyChange->value().toInt());
- m_dirty = true;
} else if (propertyChange->propertyName() == QByteArrayLiteral("dataGenerator")) {
m_generator = propertyChange->value().value<QTextureImageDataGeneratorPtr>();
- m_dirty = true;
}
- }
- if (!wasDirty && wasDirty != m_dirty) { // Notify the Texture that we were updated and request it to schedule an update job
+
+ // Notify the Texture that we were updated and request it to schedule an update job
Texture *txt = m_textureManager->data(m_textureProvider);
if (txt != nullptr)
- txt->addToPendingTextureJobs();
+ txt->addDirtyFlag(Texture::DirtyGenerators);
}
+
markDirty(AbstractRenderer::AllDirty);
BackendNode::sceneChangeEvent(e);
}
@@ -135,64 +118,12 @@ void TextureImage::setTextureManager(TextureManager *manager)
m_textureManager = manager;
}
-void TextureImage::setTextureImageManager(TextureImageManager *manager)
-{
- m_textureImageManager = manager;
-}
-
-void TextureImage::setTextureDataManager(TextureDataManager *manager)
-{
- m_textureDataManager = manager;
-}
-
-void TextureImage::unsetDirty()
-{
- m_dirty = false;
-}
-
-// Called by LoadDataTextureJob when the texture data has been successfully load
-void TextureImage::setTextureDataHandle(HTextureData handle)
-{
- m_textureDataHandle = handle;
-}
-
-void TextureImage::setStatus(QTextureImage::Status status)
-{
- // Notify the frontend
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName("status");
- e->setValue(status);
- notifyObservers(e);
-}
-
-union DNABuilder {
- quint64 dna;
- quint32 dataHash;
- quint16 layer;
- quint8 face;
- quint8 mipLevel;
-};
-
-void TextureImage::updateDNA(quint32 dataHash)
-{
- // 64 bits [ 32 bits data ] [ 16 bits layer ] [ 8 bits mip level ] [ 8 bits face ]
- DNABuilder builder;
- builder.dataHash = dataHash;
- builder.layer = m_layer;
- builder.face = m_face;
- builder.mipLevel = m_mipLevel;
-
- m_dna = builder.dna;
-}
-
-TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer, TextureManager *textureManager,
- TextureImageManager *textureImageManager,
- TextureDataManager *textureDataManager)
- : m_textureManager(textureManager)
+TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer,
+ TextureManager *textureManager,
+ TextureImageManager *textureImageManager)
+ : m_renderer(renderer)
+ , m_textureManager(textureManager)
, m_textureImageManager(textureImageManager)
- , m_textureDataManager(textureDataManager)
- , m_renderer(renderer)
{
}
@@ -200,8 +131,6 @@ Qt3DCore::QBackendNode *TextureImageFunctor::create(const Qt3DCore::QNodeCreated
{
TextureImage *backend = m_textureImageManager->getOrCreateResource(change->subjectId());
backend->setTextureManager(m_textureManager);
- backend->setTextureImageManager(m_textureImageManager);
- backend->setTextureDataManager(m_textureDataManager);
backend->setRenderer(m_renderer);
return backend;
}
diff --git a/src/render/texture/textureimage_p.h b/src/render/texture/textureimage_p.h
index 8a5f7d0ba..131114f7e 100644
--- a/src/render/texture/textureimage_p.h
+++ b/src/render/texture/textureimage_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -54,9 +54,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/handle_types_p.h>
#include <Qt3DRender/qabstracttexture.h>
-#include <Qt3DRender/qtextureimage.h>
-#include <Qt3DRender/qabstracttextureimage.h>
-#include <qglobal.h>
+#include <Qt3DRender/qtextureimagedatagenerator.h>
QT_BEGIN_NAMESPACE
@@ -68,51 +66,37 @@ class TextureManager;
class TextureImageManager;
class TextureDataManager;
-typedef quint64 TextureImageDNA;
-
-class TextureImage : public BackendNode
+/**
+ * Backend class for QAbstractTextureImage.
+ * Will only hold the generator and some info values.
+ */
+class Q_AUTOTEST_EXPORT TextureImage : public BackendNode
{
public:
TextureImage();
+ ~TextureImage();
+
void cleanup();
- void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
- int m_layer;
- int m_mipLevel;
- QAbstractTexture::CubeMapFace m_face;
- bool m_dirty;
- inline TextureImageDNA dna() const { return m_dna; }
+ void setTextureManager(TextureManager *manager);
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
inline int layer() const { return m_layer; }
inline int mipLevel() const { return m_mipLevel; }
inline QAbstractTexture::CubeMapFace face() const { return m_face; }
-
- void setTextureManager(TextureManager *manager);
- void setTextureImageManager(TextureImageManager *manager);
- void setTextureDataManager(TextureDataManager *manager);
- void setStatus(QTextureImage::Status status);
- void unsetDirty();
-
- inline bool isDirty() const { return m_dirty; }
- void setTextureDataHandle(HTextureData handle);
-
- inline HTextureData textureDataHandle() const { return m_textureDataHandle; }
inline QTextureImageDataGeneratorPtr dataGenerator() const { return m_generator; }
- void updateDNA(quint32 dataHash);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
-
+ int m_layer;
+ int m_mipLevel;
+ QAbstractTexture::CubeMapFace m_face;
QTextureImageDataGeneratorPtr m_generator;
- HTextureData m_textureDataHandle;
+
TextureManager *m_textureManager;
- TextureImageManager *m_textureImageManager;
- TextureDataManager *m_textureDataManager;
- QVector<Qt3DCore::QNodeId> m_referencedTextures;
HTexture m_textureProvider;
- Qt3DCore::QNodeId m_textureProviderId;
- TextureImageDNA m_dna;
};
class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper
@@ -120,18 +104,16 @@ class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper
public:
explicit TextureImageFunctor(AbstractRenderer *renderer,
TextureManager *textureManager,
- TextureImageManager *textureImageManager,
- TextureDataManager *textureDataManager);
+ TextureImageManager *textureImageManager);
Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const Q_DECL_FINAL;
Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const Q_DECL_FINAL;
void destroy(Qt3DCore::QNodeId id) const Q_DECL_FINAL;
private:
+ AbstractRenderer *m_renderer;
TextureManager *m_textureManager;
TextureImageManager *m_textureImageManager;
- TextureDataManager *m_textureDataManager;
- AbstractRenderer *m_renderer;
};
diff --git a/sync.profile b/sync.profile
index 3c23a8b8d..ec14bbc37 100644
--- a/sync.profile
+++ b/sync.profile
@@ -14,16 +14,3 @@
# Force generation of camel case headers for classes inside Qt3D* namespaces
$publicclassregexp = "Qt3D.*::.+";
-
-# Module dependencies.
-# Every module that is required to build this module should have one entry.
-# Each of the module version specifiers can take one of the following values:
-# - A specific Git revision.
-# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch)
-#
-%dependencies = (
- "qtbase" => "",
- "qtxmlpatterns" => "",
- "qtdeclarative" => "",
- "qtimageformats" => "",
-);
diff --git a/tests/auto/core/common/common.pri b/tests/auto/core/common/common.pri
index cdfcae337..bb5dee86b 100644
--- a/tests/auto/core/common/common.pri
+++ b/tests/auto/core/common/common.pri
@@ -1,8 +1,10 @@
SOURCES += \
- $$PWD/qbackendnodetester.cpp
+ $$PWD/qbackendnodetester.cpp \
+ $$PWD/testpostmanarbiter.cpp
HEADERS += \
- $$PWD/qbackendnodetester.h
+ $$PWD/qbackendnodetester.h \
+ $$PWD/testpostmanarbiter.h
INCLUDEPATH += $$PWD
diff --git a/tests/auto/render/commons/testpostmanarbiter.cpp b/tests/auto/core/common/testpostmanarbiter.cpp
index 6c3ca025b..6c3ca025b 100644
--- a/tests/auto/render/commons/testpostmanarbiter.cpp
+++ b/tests/auto/core/common/testpostmanarbiter.cpp
diff --git a/tests/auto/render/commons/testpostmanarbiter.h b/tests/auto/core/common/testpostmanarbiter.h
index cb2b87afd..cb2b87afd 100644
--- a/tests/auto/render/commons/testpostmanarbiter.h
+++ b/tests/auto/core/common/testpostmanarbiter.h
diff --git a/tests/auto/core/qtransform/qtransform.pro b/tests/auto/core/qtransform/qtransform.pro
index 88d30932c..190eab5c5 100644
--- a/tests/auto/core/qtransform/qtransform.pro
+++ b/tests/auto/core/qtransform/qtransform.pro
@@ -6,4 +6,4 @@ SOURCES += tst_qtransform.cpp
QT += testlib 3dcore
-include(../../render/commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/extras/extras.pro b/tests/auto/extras/extras.pro
index 381924d7b..bbdf118b3 100644
--- a/tests/auto/extras/extras.pro
+++ b/tests/auto/extras/extras.pro
@@ -1,5 +1,10 @@
TEMPLATE = subdirs
-SUBDIRS = \
- qcuboidgeometry \
- qtorusgeometry
+contains(QT_CONFIG, private_tests) {
+ SUBDIRS += \
+ qcuboidgeometry \
+ qtorusgeometry \
+ qforwardrenderer \
+ qfirstpersoncameracontroller \
+ qorbitcameracontroller
+}
diff --git a/tests/auto/extras/qfirstpersoncameracontroller/qfirstpersoncameracontroller.pro b/tests/auto/extras/qfirstpersoncameracontroller/qfirstpersoncameracontroller.pro
new file mode 100644
index 000000000..4952cc07d
--- /dev/null
+++ b/tests/auto/extras/qfirstpersoncameracontroller/qfirstpersoncameracontroller.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+
+TARGET = tst_qfirstpersoncameracontroller
+
+QT += 3dcore 3dcore-private 3drender 3drender-private 3dextras testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qfirstpersoncameracontroller.cpp
diff --git a/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp b/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp
new file mode 100644
index 000000000..22046051b
--- /dev/null
+++ b/tests/auto/extras/qfirstpersoncameracontroller/tst_qfirstpersoncameracontroller.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DExtras/qfirstpersoncameracontroller.h>
+#include <Qt3DRender/qcamera.h>
+#include <QObject>
+#include <QSignalSpy>
+
+class tst_QFirstPersonCameraController : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DExtras::QFirstPersonCameraController firstPersonCameraController;
+
+ // THEN
+ QVERIFY(firstPersonCameraController.camera() == nullptr);
+ QCOMPARE(firstPersonCameraController.linearSpeed(), 10.0f);
+ QCOMPARE(firstPersonCameraController.lookSpeed(), 180.0f);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DExtras::QFirstPersonCameraController firstPersonCameraController;
+
+ {
+ // WHEN
+ QSignalSpy spy(&firstPersonCameraController, SIGNAL(cameraChanged()));
+ Qt3DRender::QCamera *newValue = new Qt3DRender::QCamera(&firstPersonCameraController);
+ firstPersonCameraController.setCamera(newValue);
+
+ // THEN
+ QCOMPARE(firstPersonCameraController.camera(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ firstPersonCameraController.setCamera(newValue);
+
+ // THEN
+ QCOMPARE(firstPersonCameraController.camera(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ // WHEN
+ spy.clear();
+ // Check node bookeeping
+ delete newValue;
+
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(firstPersonCameraController.camera() == nullptr);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&firstPersonCameraController, SIGNAL(linearSpeedChanged()));
+ const float newValue = 300.0f;
+ firstPersonCameraController.setLinearSpeed(newValue);
+
+ // THEN
+ QCOMPARE(firstPersonCameraController.linearSpeed(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ firstPersonCameraController.setLinearSpeed(newValue);
+
+ // THEN
+ QCOMPARE(firstPersonCameraController.linearSpeed(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&firstPersonCameraController, SIGNAL(lookSpeedChanged()));
+ const float newValue = 0.001f;
+ firstPersonCameraController.setLookSpeed(newValue);
+
+ // THEN
+ QCOMPARE(firstPersonCameraController.lookSpeed(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ firstPersonCameraController.setLookSpeed(newValue);
+
+ // THEN
+ QCOMPARE(firstPersonCameraController.lookSpeed(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ }
+
+};
+
+QTEST_APPLESS_MAIN(tst_QFirstPersonCameraController)
+
+#include "tst_qfirstpersoncameracontroller.moc"
diff --git a/tests/auto/extras/qforwardrenderer/qforwardrenderer.pro b/tests/auto/extras/qforwardrenderer/qforwardrenderer.pro
new file mode 100644
index 000000000..6dc853f5a
--- /dev/null
+++ b/tests/auto/extras/qforwardrenderer/qforwardrenderer.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+
+TARGET = tst_qforwardrenderer
+
+QT += 3dcore 3dcore-private 3drender 3drender-private 3dextras testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qforwardrenderer.cpp
diff --git a/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp b/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp
new file mode 100644
index 000000000..122aed520
--- /dev/null
+++ b/tests/auto/extras/qforwardrenderer/tst_qforwardrenderer.cpp
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DExtras/qforwardrenderer.h>
+#include <Qt3DCore/qentity.h>
+#include <QObject>
+#include <QSignalSpy>
+
+class tst_QForwardRenderer : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DCore::QEntity*>();
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DExtras::QForwardRenderer forwardRenderer;
+
+ // THEN
+ QVERIFY(forwardRenderer.surface() == nullptr);
+ QCOMPARE(forwardRenderer.viewportRect(), QRectF(0.0f, 0.0f, 1.0f, 1.0f));
+ QCOMPARE(forwardRenderer.clearColor(), QColor(Qt::white));
+ QVERIFY(forwardRenderer.camera() == nullptr);
+ QCOMPARE(forwardRenderer.externalRenderTargetSize(), QSize());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DExtras::QForwardRenderer forwardRenderer;
+
+ {
+ // WHEN
+ QSignalSpy spy(&forwardRenderer, SIGNAL(surfaceChanged(QObject *)));
+ QWindow newValue;
+ forwardRenderer.setSurface(&newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.surface(), &newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ forwardRenderer.setSurface(&newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.surface(), &newValue);
+ QCOMPARE(spy.count(), 0);
+
+ // WHEN
+ forwardRenderer.setSurface(nullptr);
+
+ // THEN
+ QVERIFY(forwardRenderer.surface() == nullptr);
+ QCOMPARE(spy.count(), 1);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&forwardRenderer, SIGNAL(viewportRectChanged(QRectF)));
+ const QRectF newValue = QRectF(0.5, 0.5, 0.5, 0.5);
+ forwardRenderer.setViewportRect(newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.viewportRect(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ forwardRenderer.setViewportRect(newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.viewportRect(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&forwardRenderer, SIGNAL(clearColorChanged(QColor)));
+ const QColor newValue = QColor(Qt::red);
+ forwardRenderer.setClearColor(newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.clearColor(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ forwardRenderer.setClearColor(newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.clearColor(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&forwardRenderer, SIGNAL(cameraChanged(Qt3DCore::QEntity *)));
+ Qt3DCore::QEntity newValue;
+ forwardRenderer.setCamera(&newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.camera(), &newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ forwardRenderer.setCamera(&newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.camera(), &newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&forwardRenderer, SIGNAL(externalRenderTargetSizeChanged(QSize)));
+ const QSize newValue = QSize(454, 427);
+ forwardRenderer.setExternalRenderTargetSize(newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.externalRenderTargetSize(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ forwardRenderer.setExternalRenderTargetSize(newValue);
+
+ // THEN
+ QCOMPARE(forwardRenderer.externalRenderTargetSize(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_QForwardRenderer)
+
+#include "tst_qforwardrenderer.moc"
diff --git a/tests/auto/extras/qorbitcameracontroller/qorbitcameracontroller.pro b/tests/auto/extras/qorbitcameracontroller/qorbitcameracontroller.pro
new file mode 100644
index 000000000..5a6b68503
--- /dev/null
+++ b/tests/auto/extras/qorbitcameracontroller/qorbitcameracontroller.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+
+TARGET = tst_qorbitcameracontroller
+
+QT += 3dcore 3dcore-private 3drender 3drender-private 3dextras testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qorbitcameracontroller.cpp
+
diff --git a/tests/auto/extras/qorbitcameracontroller/tst_qorbitcameracontroller.cpp b/tests/auto/extras/qorbitcameracontroller/tst_qorbitcameracontroller.cpp
new file mode 100644
index 000000000..04f92b6ac
--- /dev/null
+++ b/tests/auto/extras/qorbitcameracontroller/tst_qorbitcameracontroller.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DExtras/qorbitcameracontroller.h>
+#include <Qt3DRender/qcamera.h>
+#include <QObject>
+#include <QSignalSpy>
+
+class tst_QOrbitCameraController : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DExtras::QOrbitCameraController orbitCameraController;
+
+ // THEN
+ QVERIFY(orbitCameraController.camera() == nullptr);
+ QCOMPARE(orbitCameraController.linearSpeed(), 10.0f);
+ QCOMPARE(orbitCameraController.lookSpeed(), 180.0f);
+ QCOMPARE(orbitCameraController.zoomInLimit(), 2.0f);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DExtras::QOrbitCameraController orbitCameraController;
+
+ {
+ // WHEN
+ QSignalSpy spy(&orbitCameraController, SIGNAL(cameraChanged()));
+ Qt3DRender::QCamera *newValue = new Qt3DRender::QCamera(&orbitCameraController);
+ orbitCameraController.setCamera(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.camera(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ orbitCameraController.setCamera(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.camera(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ // WHEN
+ spy.clear();
+ // Check node bookeeping
+ delete newValue;
+
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(orbitCameraController.camera() == nullptr);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&orbitCameraController, SIGNAL(linearSpeedChanged()));
+ const float newValue = 0.0f;
+ orbitCameraController.setLinearSpeed(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.linearSpeed(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ orbitCameraController.setLinearSpeed(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.linearSpeed(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&orbitCameraController, SIGNAL(lookSpeedChanged()));
+ const float newValue = 100.0f;
+ orbitCameraController.setLookSpeed(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.lookSpeed(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ orbitCameraController.setLookSpeed(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.lookSpeed(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&orbitCameraController, SIGNAL(zoomInLimitChanged()));
+ const float newValue = 1.0f;
+ orbitCameraController.setZoomInLimit(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.zoomInLimit(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ orbitCameraController.setZoomInLimit(newValue);
+
+ // THEN
+ QCOMPARE(orbitCameraController.zoomInLimit(), newValue);
+ QCOMPARE(spy.count(), 0);
+
+ }
+ }
+
+};
+
+QTEST_APPLESS_MAIN(tst_QOrbitCameraController)
+
+#include "tst_qorbitcameracontroller.moc"
diff --git a/tests/auto/input/abstractaxisinput/tst_abstractaxisinput.cpp b/tests/auto/input/abstractaxisinput/tst_abstractaxisinput.cpp
index 26f255d74..0e80b2478 100644
--- a/tests/auto/input/abstractaxisinput/tst_abstractaxisinput.cpp
+++ b/tests/auto/input/abstractaxisinput/tst_abstractaxisinput.cpp
@@ -63,6 +63,13 @@ public:
: AbstractAxisInput()
{
}
+
+ float process(Qt3DInput::Input::InputHandler *inputHandler, qint64 currentTime) Q_DECL_OVERRIDE
+ {
+ Q_UNUSED(inputHandler);
+ Q_UNUSED(currentTime);
+ return 0.0f;
+ }
};
diff --git a/tests/auto/input/action/action.pro b/tests/auto/input/action/action.pro
index 826ec5fea..9896c95aa 100644
--- a/tests/auto/input/action/action.pro
+++ b/tests/auto/input/action/action.pro
@@ -9,4 +9,3 @@ CONFIG += testcase
SOURCES += tst_action.cpp
include(../../core/common/common.pri)
-include(../../render/commons/commons.pri)
diff --git a/tests/auto/input/action/tst_action.cpp b/tests/auto/input/action/tst_action.cpp
index cb2192d1e..ab191be22 100644
--- a/tests/auto/input/action/tst_action.cpp
+++ b/tests/auto/input/action/tst_action.cpp
@@ -146,6 +146,7 @@ private Q_SLOTS:
// GIVEN
TestArbiter arbiter;
Qt3DInput::Input::Action backendAction;
+ backendAction.setEnabled(true);
Qt3DCore::QBackendNodePrivate::get(&backendAction)->setArbiter(&arbiter);
const bool currentActionTriggeredValue = backendAction.actionTriggered();
@@ -170,6 +171,22 @@ private Q_SLOTS:
arbiter.events.clear();
}
+
+ void shouldNotActivateWhenDisabled()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DInput::Input::Action backendAction;
+ backendAction.setEnabled(false);
+ Qt3DCore::QBackendNodePrivate::get(&backendAction)->setArbiter(&arbiter);
+
+ // WHEN
+ backendAction.setActionTriggered(true);
+
+ // THEN
+ QVERIFY(!backendAction.actionTriggered());
+ QCOMPARE(arbiter.events.count(), 0);
+ }
};
QTEST_APPLESS_MAIN(tst_Action)
diff --git a/tests/auto/input/actioninput/tst_actioninput.cpp b/tests/auto/input/actioninput/tst_actioninput.cpp
index 2db4cf760..fd87606a7 100644
--- a/tests/auto/input/actioninput/tst_actioninput.cpp
+++ b/tests/auto/input/actioninput/tst_actioninput.cpp
@@ -132,6 +132,7 @@ private Q_SLOTS:
Qt3DInput::Input::ActionInput backendActionInput;
Qt3DInput::QActionInput actionInput;
+ actionInput.setEnabled(true);
actionInput.setButtons(QVector<int>() << Qt::Key_Space << Qt::Key_Return);
actionInput.setSourceDevice(device);
simulateInitialization(&actionInput, &backendActionInput);
@@ -172,6 +173,29 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendActionInput.process(&handler, 1000000000), false);
}
+
+ void shouldNotProcessWhenDisabled()
+ {
+ // GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
+ Qt3DInput::Input::ActionInput backendActionInput;
+ Qt3DInput::QActionInput actionInput;
+ actionInput.setEnabled(false);
+ actionInput.setButtons(QVector<int>() << Qt::Key_Space << Qt::Key_Return);
+ actionInput.setSourceDevice(device);
+ simulateInitialization(&actionInput, &backendActionInput);
+
+ // WHEN
+ deviceBackend->setButtonPressed(Qt::Key_Space, true);
+
+ // THEN
+ QCOMPARE(backendActionInput.process(&handler, 1000000000), false);
+ }
};
QTEST_APPLESS_MAIN(tst_ActionInput)
diff --git a/tests/auto/input/analogaxisinput/tst_analogaxisinput.cpp b/tests/auto/input/analogaxisinput/tst_analogaxisinput.cpp
index 7e8a25de4..faa7385bc 100644
--- a/tests/auto/input/analogaxisinput/tst_analogaxisinput.cpp
+++ b/tests/auto/input/analogaxisinput/tst_analogaxisinput.cpp
@@ -28,13 +28,15 @@
#include <QtTest/QTest>
#include <qbackendnodetester.h>
+#include "testdevice.h"
+
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DInput/private/analogaxisinput_p.h>
+#include <Qt3DInput/private/inputhandler_p.h>
#include <Qt3DInput/QAnalogAxisInput>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include "testdevice.h"
class tst_AnalogAxisInput: public Qt3DCore::QBackendNodeTester
{
@@ -123,6 +125,74 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendAxisInput.sourceDevice(), device.id());
}
+
+ void shouldProcessAxisValue()
+ {
+ const qint64 s = 1000000000;
+
+ // GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
+ Qt3DInput::Input::AnalogAxisInput backendAxisInput;
+ Qt3DInput::QAnalogAxisInput axisInput;
+ axisInput.setEnabled(true);
+ axisInput.setAxis(2);
+ axisInput.setSourceDevice(device);
+ simulateInitialization(&axisInput, &backendAxisInput);
+ QCOMPARE(backendAxisInput.axis(), 2);
+
+ // WHEN
+ deviceBackend->setAxisValue(2, 0.1f);
+
+ // THEN
+ QCOMPARE(backendAxisInput.process(&handler, 30 * s), 0.1f);
+ QCOMPARE(backendAxisInput.process(&handler, 31 * s), 0.1f);
+
+ // WHEN
+ deviceBackend->setAxisValue(2, 0.2f);
+
+ // THEN
+ QCOMPARE(backendAxisInput.process(&handler, 32 * s), 0.2f);
+ QCOMPARE(backendAxisInput.process(&handler, 33 * s), 0.2f);
+ }
+
+ void shouldNotProcessAxisValueWhenDisabled()
+ {
+ const qint64 s = 1000000000;
+
+ // GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
+ Qt3DInput::Input::AnalogAxisInput backendAxisInput;
+ Qt3DInput::QAnalogAxisInput axisInput;
+ axisInput.setEnabled(false);
+ axisInput.setAxis(2);
+ axisInput.setSourceDevice(device);
+ simulateInitialization(&axisInput, &backendAxisInput);
+ QCOMPARE(backendAxisInput.axis(), 2);
+
+ // WHEN
+ deviceBackend->setAxisValue(2, 0.1f);
+
+ // THEN
+ QCOMPARE(backendAxisInput.process(&handler, 30 * s), 0.0f);
+ QCOMPARE(backendAxisInput.process(&handler, 31 * s), 0.0f);
+
+ // WHEN
+ deviceBackend->setAxisValue(2, 0.2f);
+
+ // THEN
+ QCOMPARE(backendAxisInput.process(&handler, 32 * s), 0.0f);
+ QCOMPARE(backendAxisInput.process(&handler, 33 * s), 0.0f);
+ }
};
QTEST_APPLESS_MAIN(tst_AnalogAxisInput)
diff --git a/tests/auto/input/axis/axis.pro b/tests/auto/input/axis/axis.pro
index 6f1345eae..f2c1dec1d 100644
--- a/tests/auto/input/axis/axis.pro
+++ b/tests/auto/input/axis/axis.pro
@@ -9,4 +9,3 @@ CONFIG += testcase
SOURCES += tst_axis.cpp
include(../../core/common/common.pri)
-include(../../render/commons/commons.pri)
diff --git a/tests/auto/input/axis/tst_axis.cpp b/tests/auto/input/axis/tst_axis.cpp
index a074996e6..dc8b225ba 100644
--- a/tests/auto/input/axis/tst_axis.cpp
+++ b/tests/auto/input/axis/tst_axis.cpp
@@ -147,6 +147,7 @@ private Q_SLOTS:
// GIVEN
TestArbiter arbiter;
Qt3DInput::Input::Axis backendAxis;
+ backendAxis.setEnabled(true);
Qt3DCore::QBackendNodePrivate::get(&backendAxis)->setArbiter(&arbiter);
// WHEN
@@ -171,6 +172,22 @@ private Q_SLOTS:
arbiter.events.clear();
}
+
+ void shouldNotChangeValueWhenDisabled()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DInput::Input::Axis backendAxis;
+ Qt3DCore::QBackendNodePrivate::get(&backendAxis)->setArbiter(&arbiter);
+ backendAxis.setEnabled(false);
+
+ // WHEN
+ backendAxis.setAxisValue(454.0f);
+
+ // THEN
+ QCOMPARE(backendAxis.axisValue(), 0.0f);
+ QCOMPARE(arbiter.events.count(), 0);
+ }
};
QTEST_APPLESS_MAIN(tst_Axis)
diff --git a/tests/auto/input/buttonaxisinput/tst_buttonaxisinput.cpp b/tests/auto/input/buttonaxisinput/tst_buttonaxisinput.cpp
index d4f3702e6..90867a747 100644
--- a/tests/auto/input/buttonaxisinput/tst_buttonaxisinput.cpp
+++ b/tests/auto/input/buttonaxisinput/tst_buttonaxisinput.cpp
@@ -28,13 +28,15 @@
#include <QtTest/QTest>
#include <qbackendnodetester.h>
+#include "testdevice.h"
+
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DInput/private/buttonaxisinput_p.h>
+#include <Qt3DInput/private/inputhandler_p.h>
#include <Qt3DInput/QButtonAxisInput>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include "testdevice.h"
class tst_ButtonAxisInput: public Qt3DCore::QBackendNodeTester
{
@@ -189,84 +191,142 @@ private Q_SLOTS:
QVERIFY(qIsInf(backendAxisInput.deceleration()));
}
- void shouldUpdateSpeedRatioOverTime()
+ void shouldProcessAndUpdateSpeedRatioOverTime()
{
const qint64 s = 1000000000;
// GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
Qt3DInput::Input::ButtonAxisInput backendAxisInput;
Qt3DInput::QButtonAxisInput axisInput;
+ axisInput.setEnabled(true);
+ axisInput.setButtons(QVector<int>() << Qt::Key_Space);
+ axisInput.setScale(-1.0f);
axisInput.setAcceleration(0.15f);
axisInput.setDeceleration(0.3f);
+ axisInput.setSourceDevice(device);
simulateInitialization(&axisInput, &backendAxisInput);
QCOMPARE(backendAxisInput.speedRatio(), 0.0f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 0);
+ // WHEN (accelerate)
+ deviceBackend->setButtonPressed(Qt::Key_Space, true);
+
// WHEN
- backendAxisInput.updateSpeedRatio(30 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 30 * s), 0.0f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.0f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 30 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(31 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 31 * s), -0.15f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.15f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 31 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(32 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 32 * s), -0.3f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.3f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 32 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(35 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 35 * s), -0.75f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.75f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 35 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(37 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 37 * s), -1.0f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 1.0f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 37 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(38 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 38 * s), -1.0f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 1.0f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 38 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(42 * s, Qt3DInput::Input::ButtonAxisInput::Accelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 42 * s), -1.0f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 1.0f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 42 * s);
+
+ // WHEN (decelerate)
+ deviceBackend->setButtonPressed(Qt::Key_Space, false);
+
// WHEN
- backendAxisInput.updateSpeedRatio(43 * s, Qt3DInput::Input::ButtonAxisInput::Decelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 43 * s), -0.7f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.7f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 43 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(45 * s, Qt3DInput::Input::ButtonAxisInput::Decelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 45 * s), -0.1f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.1f);
QCOMPARE(backendAxisInput.lastUpdateTime(), 45 * s);
// WHEN
- backendAxisInput.updateSpeedRatio(46 * s, Qt3DInput::Input::ButtonAxisInput::Decelerate);
+ QCOMPARE(backendAxisInput.process(&handler, 46 * s), 0.0f);
+
+ // THEN
+ QCOMPARE(backendAxisInput.speedRatio(), 0.0f);
+ QCOMPARE(backendAxisInput.lastUpdateTime(), 0);
+ }
+
+ void shouldNotProcessWhenDisabled()
+ {
+ const qint64 s = 1000000000;
+
+ // GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
+ Qt3DInput::Input::ButtonAxisInput backendAxisInput;
+ Qt3DInput::QButtonAxisInput axisInput;
+ axisInput.setEnabled(false);
+ axisInput.setButtons(QVector<int>() << Qt::Key_Space);
+ axisInput.setScale(-1.0f);
+ axisInput.setAcceleration(0.15f);
+ axisInput.setDeceleration(0.3f);
+ axisInput.setSourceDevice(device);
+ simulateInitialization(&axisInput, &backendAxisInput);
+ QCOMPARE(backendAxisInput.speedRatio(), 0.0f);
+ QCOMPARE(backendAxisInput.lastUpdateTime(), 0);
+
+ // WHEN (accelerate)
+ deviceBackend->setButtonPressed(Qt::Key_Space, true);
+
+ // WHEN
+ QCOMPARE(backendAxisInput.process(&handler, 30 * s), 0.0f);
+
+ // THEN
+ QCOMPARE(backendAxisInput.speedRatio(), 0.0f);
+ QCOMPARE(backendAxisInput.lastUpdateTime(), 0);
+
+ // WHEN
+ QCOMPARE(backendAxisInput.process(&handler, 31 * s), 0.0f);
// THEN
QCOMPARE(backendAxisInput.speedRatio(), 0.0f);
diff --git a/tests/auto/input/commons/commons.pri b/tests/auto/input/commons/commons.pri
index ccc14075b..4913f5bbb 100644
--- a/tests/auto/input/commons/commons.pri
+++ b/tests/auto/input/commons/commons.pri
@@ -1,4 +1,5 @@
-HEADERS += $$PWD/testdevice.h
+HEADERS += $$PWD/testdevice.h \
+ $$PWD/testdeviceproxy.h
INCLUDEPATH += $$PWD
diff --git a/tests/auto/input/commons/testdevice.h b/tests/auto/input/commons/testdevice.h
index c6fc4995b..52750029e 100644
--- a/tests/auto/input/commons/testdevice.h
+++ b/tests/auto/input/commons/testdevice.h
@@ -26,6 +26,9 @@
**
****************************************************************************/
+#ifndef TESTDEVICE_H
+#define TESTDEVICE_H
+
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DInput/QAbstractPhysicalDevice>
#include <Qt3DInput/private/qabstractphysicaldevicebackendnode_p.h>
@@ -151,3 +154,5 @@ private:
QVector<TestDevice*> m_devices;
QVector<TestDeviceBackendNode*> m_deviceBackendNodes;
};
+
+#endif // TESTDEVICE_H
diff --git a/tests/auto/input/commons/testdeviceproxy.h b/tests/auto/input/commons/testdeviceproxy.h
new file mode 100644
index 000000000..366f40958
--- /dev/null
+++ b/tests/auto/input/commons/testdeviceproxy.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef TESTDEVICEPROXY_H
+#define TESTDEVICEPROXY_H
+
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h>
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p_p.h>
+
+class TestPhysicalDevice : public Qt3DInput::QAbstractPhysicalDevice
+{
+ Q_OBJECT
+public:
+ explicit TestPhysicalDevice(Qt3DCore::QNode *parent = nullptr)
+ : Qt3DInput::QAbstractPhysicalDevice(parent)
+ {}
+
+ ~TestPhysicalDevice()
+ {
+ }
+
+ enum AxisValues {
+ X = 0,
+ Y,
+ Z
+ };
+
+ enum ButtonValues {
+ Left = 0,
+ Right
+ };
+
+ int axisCount() const Q_DECL_FINAL { return 3; }
+ int buttonCount() const Q_DECL_FINAL { return 2; }
+ QStringList axisNames() const Q_DECL_FINAL { return QStringList() << QStringLiteral("x") << QStringLiteral("y") << QStringLiteral("z"); }
+ QStringList buttonNames() const Q_DECL_FINAL { return QStringList() << QStringLiteral("Left") << QStringLiteral("Right"); }
+
+ int axisIdentifier(const QString &name) const Q_DECL_FINAL
+ {
+ if (name == QLatin1String("x"))
+ return TestPhysicalDevice::X;
+ if (name == QLatin1String("y"))
+ return TestPhysicalDevice::Y;
+ if (name == QLatin1String("z"))
+ return TestPhysicalDevice::Z;
+ return -1;
+ }
+ int buttonIdentifier(const QString &name) const Q_DECL_FINAL
+ {
+ if (name == QLatin1String("Left"))
+ return TestPhysicalDevice::Left;
+ if (name == QLatin1String("Right"))
+ return TestPhysicalDevice::Right;
+ return -1;
+ }
+};
+
+class TestProxyPrivate : public Qt3DInput::QAbstractPhysicalDeviceProxyPrivate
+{
+public:
+ explicit TestProxyPrivate(const QString &name)
+ : Qt3DInput::QAbstractPhysicalDeviceProxyPrivate(name)
+ {}
+};
+
+class TestProxy : public Qt3DInput::QAbstractPhysicalDeviceProxy
+{
+ Q_OBJECT
+public:
+ explicit TestProxy(const QString &name = QStringLiteral("TestProxy"))
+ : Qt3DInput::QAbstractPhysicalDeviceProxy(*new TestProxyPrivate(name))
+ {}
+
+ Qt3DInput::QAbstractPhysicalDevice *device() const
+ {
+ Q_D(const TestProxy);
+ return d->m_device;
+ }
+
+ void simulateSceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+ {
+ Qt3DInput::QAbstractPhysicalDeviceProxy::sceneChangeEvent(change);
+ }
+
+private:
+ Q_DECLARE_PRIVATE(TestProxy)
+};
+
+#endif // TESTDEVICEPROXY_H
diff --git a/tests/auto/input/input.pro b/tests/auto/input/input.pro
index cf0af12cb..f469d07ac 100644
--- a/tests/auto/input/input.pro
+++ b/tests/auto/input/input.pro
@@ -20,5 +20,12 @@ qtConfig(private_tests) {
qaxisaccumulator \
inputsequence \
inputchord \
- qabstractphysicaldevicebackendnode
+ qabstractphysicaldevicebackendnode \
+ logicaldevice \
+ qabstractphysicaldeviceproxy \
+ physicaldeviceproxy \
+ loadproxydevicejob \
+ qmousedevice \
+ mousedevice \
+ utils
}
diff --git a/tests/auto/input/inputchord/tst_inputchord.cpp b/tests/auto/input/inputchord/tst_inputchord.cpp
index a840d7dee..d3ad1c84a 100644
--- a/tests/auto/input/inputchord/tst_inputchord.cpp
+++ b/tests/auto/input/inputchord/tst_inputchord.cpp
@@ -164,6 +164,7 @@ private Q_SLOTS:
Qt3DInput::Input::InputChord backendInputChord;
Qt3DInput::QInputChord inputChord;
+ inputChord.setEnabled(true);
inputChord.setTimeout(300);
inputChord.addChord(firstInput);
inputChord.addChord(secondInput);
@@ -251,6 +252,7 @@ private Q_SLOTS:
Qt3DInput::Input::InputChord backendInputChord;
Qt3DInput::QInputChord inputChord;
+ inputChord.setEnabled(true);
inputChord.setTimeout(300);
inputChord.addChord(firstInput);
inputChord.addChord(secondInput);
@@ -274,6 +276,43 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendInputChord.process(&handler, 1800000000), false);
}
+
+ void shouldNotProcessWhenDisabled()
+ {
+ // GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
+ auto firstInput = new Qt3DInput::QActionInput;
+ firstInput->setButtons(QVector<int>() << Qt::Key_Q);
+ firstInput->setSourceDevice(device);
+ auto backendFirstInput = handler.actionInputManager()->getOrCreateResource(firstInput->id());
+ simulateInitialization(firstInput, backendFirstInput);
+
+ auto secondInput = new Qt3DInput::QActionInput;
+ secondInput->setButtons(QVector<int>() << Qt::Key_W);
+ secondInput->setSourceDevice(device);
+ auto backendSecondInput = handler.actionInputManager()->getOrCreateResource(secondInput->id());
+ simulateInitialization(secondInput, backendSecondInput);
+
+ Qt3DInput::Input::InputChord backendInputChord;
+ Qt3DInput::QInputChord inputChord;
+ inputChord.setEnabled(false);
+ inputChord.setTimeout(300);
+ inputChord.addChord(firstInput);
+ inputChord.addChord(secondInput);
+ simulateInitialization(&inputChord, &backendInputChord);
+
+ // WHEN
+ deviceBackend->setButtonPressed(Qt::Key_Q, true);
+ deviceBackend->setButtonPressed(Qt::Key_W, true);
+
+ // THEN
+ QCOMPARE(backendInputChord.process(&handler, 1000000000), false);
+ }
};
QTEST_APPLESS_MAIN(tst_InputChord)
diff --git a/tests/auto/input/inputsequence/tst_inputsequence.cpp b/tests/auto/input/inputsequence/tst_inputsequence.cpp
index 6b4a39b68..a73572553 100644
--- a/tests/auto/input/inputsequence/tst_inputsequence.cpp
+++ b/tests/auto/input/inputsequence/tst_inputsequence.cpp
@@ -184,6 +184,7 @@ private Q_SLOTS:
Qt3DInput::Input::InputSequence backendInputSequence;
Qt3DInput::QInputSequence inputSequence;
+ inputSequence.setEnabled(true);
inputSequence.setButtonInterval(150);
inputSequence.setTimeout(450);
inputSequence.addSequence(firstInput);
@@ -309,6 +310,7 @@ private Q_SLOTS:
Qt3DInput::Input::InputSequence backendInputSequence;
Qt3DInput::QInputSequence inputSequence;
+ inputSequence.setEnabled(true);
inputSequence.setButtonInterval(250);
inputSequence.setTimeout(450);
inputSequence.addSequence(firstInput);
@@ -366,6 +368,7 @@ private Q_SLOTS:
Qt3DInput::Input::InputSequence backendInputSequence;
Qt3DInput::QInputSequence inputSequence;
+ inputSequence.setEnabled(true);
inputSequence.setButtonInterval(100);
inputSequence.setTimeout(450);
inputSequence.addSequence(firstInput);
@@ -393,6 +396,50 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendInputSequence.process(&handler, 1300000000), false);
}
+
+ void shouldNotProcessWhenDisabled()
+ {
+ // GIVEN
+ TestDeviceIntegration deviceIntegration;
+ TestDevice *device = deviceIntegration.createPhysicalDevice("keyboard");
+ TestDeviceBackendNode *deviceBackend = deviceIntegration.physicalDevice(device->id());
+ Qt3DInput::Input::InputHandler handler;
+ handler.addInputDeviceIntegration(&deviceIntegration);
+
+ auto firstInput = new Qt3DInput::QActionInput;
+ firstInput->setButtons(QVector<int>() << Qt::Key_Q);
+ firstInput->setSourceDevice(device);
+ auto backendFirstInput = handler.actionInputManager()->getOrCreateResource(firstInput->id());
+ simulateInitialization(firstInput, backendFirstInput);
+
+ auto secondInput = new Qt3DInput::QActionInput;
+ secondInput->setButtons(QVector<int>() << Qt::Key_S);
+ secondInput->setSourceDevice(device);
+ auto backendSecondInput = handler.actionInputManager()->getOrCreateResource(secondInput->id());
+ simulateInitialization(secondInput, backendSecondInput);
+
+ Qt3DInput::Input::InputSequence backendInputSequence;
+ Qt3DInput::QInputSequence inputSequence;
+ inputSequence.setEnabled(false);
+ inputSequence.setButtonInterval(150);
+ inputSequence.setTimeout(450);
+ inputSequence.addSequence(firstInput);
+ inputSequence.addSequence(secondInput);
+ simulateInitialization(&inputSequence, &backendInputSequence);
+
+ // WHEN
+ deviceBackend->setButtonPressed(Qt::Key_Q, true);
+
+ // THEN
+ QCOMPARE(backendInputSequence.process(&handler, 1000000000), false);
+
+ // WHEN
+ deviceBackend->setButtonPressed(Qt::Key_Q, false);
+ deviceBackend->setButtonPressed(Qt::Key_S, true);
+
+ // THEN
+ QCOMPARE(backendInputSequence.process(&handler, 1100000000), false);
+ }
};
QTEST_APPLESS_MAIN(tst_InputSequence)
diff --git a/tests/auto/input/loadproxydevicejob/loadproxydevicejob.pro b/tests/auto/input/loadproxydevicejob/loadproxydevicejob.pro
new file mode 100644
index 000000000..b52ba81f0
--- /dev/null
+++ b/tests/auto/input/loadproxydevicejob/loadproxydevicejob.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_loadproxydevicejob
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_loadproxydevicejob.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/input/loadproxydevicejob/tst_loadproxydevicejob.cpp b/tests/auto/input/loadproxydevicejob/tst_loadproxydevicejob.cpp
new file mode 100644
index 000000000..d3745b8cb
--- /dev/null
+++ b/tests/auto/input/loadproxydevicejob/tst_loadproxydevicejob.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/private/loadproxydevicejob_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DInput/private/inputhandler_p.h>
+#include <Qt3DInput/private/physicaldeviceproxy_p.h>
+#include <Qt3DInput/private/qinputdeviceintegration_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include "qbackendnodetester.h"
+#include "testdeviceproxy.h"
+#include "testpostmanarbiter.h"
+
+class FakeInputDeviceIntegration : public Qt3DInput::QInputDeviceIntegration
+{
+public:
+ explicit FakeInputDeviceIntegration(const QString &name)
+ : Qt3DInput::QInputDeviceIntegration()
+ , m_name(name)
+ {}
+
+ QVector<Qt3DCore::QAspectJobPtr> jobsToExecute(qint64) Q_DECL_OVERRIDE
+ {
+ return QVector<Qt3DCore::QAspectJobPtr>();
+ }
+
+ Qt3DInput::QAbstractPhysicalDevice *createPhysicalDevice(const QString &name) Q_DECL_OVERRIDE
+ {
+ if (name == m_name)
+ return new TestPhysicalDevice();
+ return nullptr;
+ }
+
+ Qt3DInput::QAbstractPhysicalDeviceBackendNode *physicalDevice(Qt3DCore::QNodeId) const Q_DECL_OVERRIDE
+ {
+ return nullptr;
+ }
+
+ QVector<Qt3DCore::QNodeId> physicalDevices() const Q_DECL_OVERRIDE
+ {
+ return QVector<Qt3DCore::QNodeId>();
+ }
+
+ QStringList deviceNames() const Q_DECL_OVERRIDE
+ {
+ return QStringList() << m_name;
+ }
+
+private:
+ void onInitialize() Q_DECL_OVERRIDE {}
+ QString m_name;
+};
+
+class tst_LoadProxyDeviceJob : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DInput::Input::LoadProxyDeviceJob backendLoadProxyDeviceJob;
+
+ // THEN
+ QVERIFY(backendLoadProxyDeviceJob.inputHandler() == nullptr);
+ QVERIFY(backendLoadProxyDeviceJob.proxies().empty());
+ }
+
+ void checkJobCreatesDeviceWhenValid()
+ {
+ // GIVEN
+ Qt3DInput::Input::InputHandler inputHandler;
+ Qt3DInput::Input::PhysicalDeviceProxyManager *manager = inputHandler.physicalDeviceProxyManager();
+
+ FakeInputDeviceIntegration inputIntegration(QStringLiteral("TestProxy"));
+ inputHandler.addInputDeviceIntegration(&inputIntegration);
+
+ // THEN
+ QCOMPARE(inputHandler.inputDeviceIntegrations().size(), 1);
+ QCOMPARE(inputHandler.inputDeviceIntegrations().first(), &inputIntegration);
+
+ // WHEN -> valid device name
+ {
+ // WHEN
+ TestProxy proxy;
+ TestArbiter arbiter;
+ Qt3DInput::Input::PhysicalDeviceProxy *backendProxy = manager->getOrCreateResource(proxy.id());
+
+ {
+ backendProxy->setManager(manager);
+ Qt3DCore::QBackendNodeTester backendNodeCreator;
+ backendNodeCreator.simulateInitialization(&proxy, backendProxy);
+ Qt3DCore::QBackendNodePrivate::get(backendProxy)->setArbiter(&arbiter);
+ }
+
+ // THEN
+ QCOMPARE(manager->lookupResource(proxy.id()), backendProxy);
+ QCOMPARE(backendProxy->deviceName(), QStringLiteral("TestProxy"));
+
+ const QVector<Qt3DCore::QNodeId> pendingProxies = manager->takePendingProxiesToLoad();
+ QCOMPARE(pendingProxies.size(), 1);
+ QCOMPARE(pendingProxies.first(), backendProxy->peerId());
+
+ // WHEN
+ Qt3DInput::Input::LoadProxyDeviceJob job;
+ job.setInputHandler(&inputHandler);
+ job.setProxiesToLoad(std::move(pendingProxies));
+
+ job.run();
+
+ // THEN -> PhysicalDeviceWrapper::setDevice should have been called
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "device");
+ QVERIFY(change->value().value<Qt3DInput::QAbstractPhysicalDevice *>() != nullptr);
+ QCOMPARE(change->subjectId(), proxy.id());
+ }
+
+ // WHEN -> invalid name
+ {
+ // WHEN
+ TestProxy proxy(QStringLiteral("NonExisting"));
+ TestArbiter arbiter;
+ Qt3DInput::Input::PhysicalDeviceProxy *backendProxy = manager->getOrCreateResource(proxy.id());
+
+ {
+ backendProxy->setManager(manager);
+ Qt3DCore::QBackendNodeTester backendNodeCreator;
+ backendNodeCreator.simulateInitialization(&proxy, backendProxy);
+ Qt3DCore::QBackendNodePrivate::get(backendProxy)->setArbiter(&arbiter);
+ }
+
+ // THEN
+ QCOMPARE(manager->lookupResource(proxy.id()), backendProxy);
+ QCOMPARE(backendProxy->deviceName(), QStringLiteral("NonExisting"));
+
+ const QVector<Qt3DCore::QNodeId> pendingProxies = manager->takePendingProxiesToLoad();
+ QCOMPARE(pendingProxies.size(), 1);
+ QCOMPARE(pendingProxies.first(), backendProxy->peerId());
+
+ // WHEN
+ Qt3DInput::Input::LoadProxyDeviceJob job;
+ job.setInputHandler(&inputHandler);
+ job.setProxiesToLoad(std::move(pendingProxies));
+
+ job.run();
+
+ // THEN -> PhysicalDeviceWrapper::setDevice should not have been called
+ QCOMPARE(arbiter.events.count(), 0);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_LoadProxyDeviceJob)
+
+#include "tst_loadproxydevicejob.moc"
diff --git a/tests/auto/input/logicaldevice/logicaldevice.pro b/tests/auto/input/logicaldevice/logicaldevice.pro
new file mode 100644
index 000000000..a832fe172
--- /dev/null
+++ b/tests/auto/input/logicaldevice/logicaldevice.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_logicaldevice
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_logicaldevice.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/input/logicaldevice/tst_logicaldevice.cpp b/tests/auto/input/logicaldevice/tst_logicaldevice.cpp
new file mode 100644
index 000000000..58c8c7fcb
--- /dev/null
+++ b/tests/auto/input/logicaldevice/tst_logicaldevice.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/qlogicaldevice.h>
+#include <Qt3DInput/qaction.h>
+#include <Qt3DInput/qaxis.h>
+#include <Qt3DInput/private/qlogicaldevice_p.h>
+#include <Qt3DInput/private/logicaldevice_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include "qbackendnodetester.h"
+
+class tst_LogicalDevice : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DInput::Input::LogicalDevice backendLogicalDevice;
+
+ // THEN
+ QVERIFY(backendLogicalDevice.peerId().isNull());
+ QCOMPARE(backendLogicalDevice.isEnabled(), false);
+ QVERIFY(backendLogicalDevice.axes().empty());
+ QVERIFY(backendLogicalDevice.actions().empty());
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DInput::Input::LogicalDevice backendLogicalDevice;
+
+ // WHEN
+ backendLogicalDevice.setEnabled(true);
+
+ // WHEN
+ {
+ Qt3DInput::QAxis newValue;
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &newValue);
+ change->setPropertyName("axis");
+ backendLogicalDevice.sceneChangeEvent(change);
+ }
+ {
+ Qt3DInput::QAction newValue;
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &newValue);
+ change->setPropertyName("action");
+ backendLogicalDevice.sceneChangeEvent(change);
+ }
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.axes().size(), 1);
+ QCOMPARE(backendLogicalDevice.actions().size(), 1);
+
+ // WHEN
+ backendLogicalDevice.cleanup();
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.isEnabled(), false);
+ QCOMPARE(backendLogicalDevice.axes().size(), 0);
+ QCOMPARE(backendLogicalDevice.actions().size(), 0);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DInput::QLogicalDevice logicalDevice;
+
+ Qt3DInput::QAction *action = new Qt3DInput::QAction(&logicalDevice);
+ Qt3DInput::QAxis *axis = new Qt3DInput::QAxis(&logicalDevice);
+ logicalDevice.addAction(action);
+ logicalDevice.addAxis(axis);
+
+ {
+ // WHEN
+ Qt3DInput::Input::LogicalDevice backendLogicalDevice;
+ simulateInitialization(&logicalDevice, &backendLogicalDevice);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.isEnabled(), true);
+ QCOMPARE(backendLogicalDevice.axes().size(), 1);
+ QCOMPARE(backendLogicalDevice.axes().first(), axis->id());
+ QCOMPARE(backendLogicalDevice.actions().size(), 1);
+ QCOMPARE(backendLogicalDevice.actions().first(), action->id());
+ QCOMPARE(backendLogicalDevice.peerId(), logicalDevice.id());
+ }
+ {
+ // WHEN
+ Qt3DInput::Input::LogicalDevice backendLogicalDevice;
+ logicalDevice.setEnabled(false);
+ simulateInitialization(&logicalDevice, &backendLogicalDevice);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DInput::Input::LogicalDevice backendLogicalDevice;
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendLogicalDevice.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ Qt3DInput::QAxis newValue;
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &newValue);
+ change->setPropertyName("axis");
+ backendLogicalDevice.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.axes().size(), 1);
+ QCOMPARE(backendLogicalDevice.axes().first(), newValue.id());
+
+ // WHEN
+ const auto change2 = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &newValue);
+ change2->setPropertyName("axis");
+ backendLogicalDevice.sceneChangeEvent(change2);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.axes().size(), 0);
+ }
+ {
+ // WHEN
+ Qt3DInput::QAction newValue;
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &newValue);
+ change->setPropertyName("action");
+ backendLogicalDevice.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.actions().size(), 1);
+ QCOMPARE(backendLogicalDevice.actions().first(), newValue.id());
+
+ // WHEN
+ const auto change2 = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &newValue);
+ change2->setPropertyName("action");
+ backendLogicalDevice.sceneChangeEvent(change2);
+
+ // THEN
+ QCOMPARE(backendLogicalDevice.actions().size(), 0);
+ }
+ }
+
+};
+
+QTEST_APPLESS_MAIN(tst_LogicalDevice)
+
+#include "tst_logicaldevice.moc"
diff --git a/tests/auto/input/mousedevice/mousedevice.pro b/tests/auto/input/mousedevice/mousedevice.pro
new file mode 100644
index 000000000..8129a8dee
--- /dev/null
+++ b/tests/auto/input/mousedevice/mousedevice.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_mousedevice
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_mousedevice.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/input/mousedevice/tst_mousedevice.cpp b/tests/auto/input/mousedevice/tst_mousedevice.cpp
new file mode 100644
index 000000000..64447d0de
--- /dev/null
+++ b/tests/auto/input/mousedevice/tst_mousedevice.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/qmousedevice.h>
+#include <Qt3DInput/private/qmousedevice_p.h>
+#include <Qt3DInput/private/mousedevice_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+
+class tst_MouseDevice : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DInput::Input::MouseDevice backendMouseDevice;
+
+ // THEN
+ QCOMPARE(backendMouseDevice.isEnabled(), false);
+ QVERIFY(backendMouseDevice.peerId().isNull());
+ QVERIFY(backendMouseDevice.inputHandler() == nullptr);
+ QCOMPARE(backendMouseDevice.mouseState().xAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().yAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().leftPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().rightPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().centerPressed, false);
+ QCOMPARE(backendMouseDevice.previousPos(), QPointF());
+ QCOMPARE(backendMouseDevice.wasPressed(), false);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DInput::QMouseDevice mouseDevice;
+ mouseDevice.setSensitivity(0.8f);
+
+ {
+ // WHEN
+ Qt3DInput::Input::MouseDevice backendMouseDevice;
+ simulateInitialization(&mouseDevice, &backendMouseDevice);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.isEnabled(), true);
+ QCOMPARE(backendMouseDevice.peerId(), mouseDevice.id());
+ QVERIFY(backendMouseDevice.inputHandler() == nullptr);
+ QCOMPARE(backendMouseDevice.mouseState().xAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().yAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().leftPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().rightPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().centerPressed, false);
+ QCOMPARE(backendMouseDevice.previousPos(), QPointF());
+ QCOMPARE(backendMouseDevice.wasPressed(), false);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.8f);
+ }
+ {
+ // WHEN
+ Qt3DInput::Input::MouseDevice backendMouseDevice;
+ mouseDevice.setEnabled(false);
+ simulateInitialization(&mouseDevice, &backendMouseDevice);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.peerId(), mouseDevice.id());
+ QCOMPARE(backendMouseDevice.isEnabled(), false);
+ }
+ }
+
+ void checkMouseMoveStatesUpdates()
+ {
+ // GIVEN
+ Qt3DInput::Input::MouseDevice backendMouseDevice;
+
+ // WHEN
+ auto eventList = QList<QT_PREPEND_NAMESPACE(QMouseEvent)>() << QT_PREPEND_NAMESPACE(QMouseEvent)(QMouseEvent::MouseButtonPress,
+ QPointF(400.0f, 400.0f),
+ QPointF(400.0f, 400.0f),
+ QPointF(400.0f, 400.0f),
+ Qt::LeftButton,
+ Qt::LeftButton,
+ Qt::NoModifier);
+ backendMouseDevice.updateMouseEvents(eventList);
+
+ // THEN
+ // Note: axis are only modified when moving (> 1 event)
+ QCOMPARE(backendMouseDevice.mouseState().xAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().yAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().leftPressed, true);
+ QCOMPARE(backendMouseDevice.mouseState().rightPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().centerPressed, false);
+ QCOMPARE(backendMouseDevice.previousPos(), QPointF(400.0f, 400.0f));
+ QCOMPARE(backendMouseDevice.wasPressed(), true);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+
+ // WHEN
+ eventList = QList<QT_PREPEND_NAMESPACE(QMouseEvent)>() << QT_PREPEND_NAMESPACE(QMouseEvent)(QMouseEvent::MouseMove,
+ QPointF(600.0f, 600.0f),
+ QPointF(600.0f, 600.0f),
+ QPointF(600.0f, 600.0f),
+ Qt::LeftButton,
+ Qt::LeftButton,
+ Qt::NoModifier);
+ backendMouseDevice.updateMouseEvents(eventList);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.mouseState().xAxis, (600.0f - 400.0f) * 0.1f);
+ QCOMPARE(backendMouseDevice.mouseState().yAxis, (400.0f - 600.0f) * 0.1f);
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().leftPressed, true);
+ QCOMPARE(backendMouseDevice.mouseState().rightPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().centerPressed, false);
+ QCOMPARE(backendMouseDevice.previousPos(), QPointF(600.0f, 600.0f));
+ QCOMPARE(backendMouseDevice.wasPressed(), true);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+
+ // WHEN
+ eventList = QList<QT_PREPEND_NAMESPACE(QMouseEvent)>() << QT_PREPEND_NAMESPACE(QMouseEvent)(QMouseEvent::MouseButtonRelease,
+ QPointF(600.0f, 600.0f),
+ QPointF(600.0f, 600.0f),
+ QPointF(600.0f, 600.0f),
+ Qt::LeftButton,
+ Qt::NoButton,
+ Qt::NoModifier);
+ backendMouseDevice.updateMouseEvents(eventList);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.mouseState().xAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().yAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().leftPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().rightPressed, false);
+ QCOMPARE(backendMouseDevice.mouseState().centerPressed, false);
+ QCOMPARE(backendMouseDevice.previousPos(), QPointF(600.0f, 600.0f));
+ QCOMPARE(backendMouseDevice.wasPressed(), false);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+ }
+
+ void checkMouseWheelState()
+ {
+ // GIVEN
+ Qt3DInput::Input::MouseDevice backendMouseDevice;
+
+ // WHEN
+ auto eventList = QList<QT_PREPEND_NAMESPACE(QWheelEvent)>() << QT_PREPEND_NAMESPACE(QWheelEvent)(QPointF(500.0f, 500.0f),
+ 120,
+ Qt::NoButton,
+ Qt::NoModifier,
+ Qt::Vertical);
+ backendMouseDevice.updateWheelEvents(eventList);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.1f * 120);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+
+ // WHEN
+ eventList = QList<QT_PREPEND_NAMESPACE(QWheelEvent)>() << QT_PREPEND_NAMESPACE(QWheelEvent)(QPointF(500.0f, 500.0f),
+ 120,
+ Qt::NoButton,
+ Qt::NoModifier,
+ Qt::Horizontal);
+ backendMouseDevice.updateWheelEvents(eventList);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.1f * 120);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+
+ // WHEN
+ eventList = QList<QT_PREPEND_NAMESPACE(QWheelEvent)>() << QT_PREPEND_NAMESPACE(QWheelEvent)(QPointF(500.0f, 500.0f),
+ 0,
+ Qt::NoButton,
+ Qt::NoModifier,
+ Qt::Horizontal);
+ backendMouseDevice.updateWheelEvents(eventList);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.mouseState().wXAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.mouseState().wYAxis, 0.0f);
+ QCOMPARE(backendMouseDevice.sensitivity(), 0.1f);
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DInput::Input::MouseDevice backendMouseDevice;
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendMouseDevice.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const float newValue = 99.0f;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("sensitivity");
+ change->setValue(QVariant::fromValue(newValue));
+ backendMouseDevice.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendMouseDevice.sensitivity(), newValue);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_MouseDevice)
+
+#include "tst_mousedevice.moc"
diff --git a/tests/auto/input/physicaldeviceproxy/physicaldeviceproxy.pro b/tests/auto/input/physicaldeviceproxy/physicaldeviceproxy.pro
new file mode 100644
index 000000000..f5656b211
--- /dev/null
+++ b/tests/auto/input/physicaldeviceproxy/physicaldeviceproxy.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_physicaldeviceproxy
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_physicaldeviceproxy.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp b/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp
new file mode 100644
index 000000000..e4d384dba
--- /dev/null
+++ b/tests/auto/input/physicaldeviceproxy/tst_physicaldeviceproxy.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h>
+#include <Qt3DInput/private/qabstractphysicaldeviceproxy_p_p.h>
+#include <Qt3DInput/private/physicaldeviceproxy_p.h>
+#include <Qt3DInput/private/inputmanagers_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include "qbackendnodetester.h"
+#include "testdeviceproxy.h"
+#include "testpostmanarbiter.h"
+
+class tst_PhysicalDeviceProxy : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DInput::Input::PhysicalDeviceProxy backendPhysicalDeviceProxy;
+
+ // THEN
+ QCOMPARE(backendPhysicalDeviceProxy.isEnabled(), false);
+ QVERIFY(backendPhysicalDeviceProxy.peerId().isNull());
+ QCOMPARE(backendPhysicalDeviceProxy.deviceName(), QString());
+ QVERIFY(backendPhysicalDeviceProxy.manager() == nullptr);
+ QVERIFY(backendPhysicalDeviceProxy.physicalDeviceId().isNull());
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ TestProxy PhysicalDeviceProxy;
+ Qt3DInput::Input::PhysicalDeviceProxyManager manager;
+
+ {
+ // WHEN
+ Qt3DInput::Input::PhysicalDeviceProxy backendPhysicalDeviceProxy;
+ backendPhysicalDeviceProxy.setManager(&manager);
+ simulateInitialization(&PhysicalDeviceProxy, &backendPhysicalDeviceProxy);
+
+ // THEN
+ QCOMPARE(backendPhysicalDeviceProxy.isEnabled(), true);
+ QCOMPARE(backendPhysicalDeviceProxy.peerId(), PhysicalDeviceProxy.id());
+ QCOMPARE(backendPhysicalDeviceProxy.deviceName(), QStringLiteral("TestProxy"));
+ QVERIFY(backendPhysicalDeviceProxy.manager() == &manager);
+ QVERIFY(backendPhysicalDeviceProxy.physicalDeviceId().isNull());
+ }
+ {
+ // WHEN
+ Qt3DInput::Input::PhysicalDeviceProxy backendPhysicalDeviceProxy;
+ backendPhysicalDeviceProxy.setManager(&manager);
+ PhysicalDeviceProxy.setEnabled(false);
+ simulateInitialization(&PhysicalDeviceProxy, &backendPhysicalDeviceProxy);
+
+ // THEN
+ QCOMPARE(backendPhysicalDeviceProxy.peerId(), PhysicalDeviceProxy.id());
+ QCOMPARE(backendPhysicalDeviceProxy.isEnabled(), false);
+ }
+ }
+
+ void checkLoadingRequested()
+ {
+ // GIVEN
+ Qt3DInput::Input::PhysicalDeviceProxyManager manager;
+ Qt3DInput::Input::PhysicalDeviceProxy backendPhysicalDeviceProxy;
+ TestProxy deviceProxy;
+
+ // WHEN
+ backendPhysicalDeviceProxy.setManager(&manager);
+ simulateInitialization(&deviceProxy, &backendPhysicalDeviceProxy);
+
+ // THEN
+ QCOMPARE(backendPhysicalDeviceProxy.deviceName(), QStringLiteral("TestProxy"));
+ const QVector<Qt3DCore::QNodeId> pendingWrappers = manager.takePendingProxiesToLoad();
+ QCOMPARE(pendingWrappers.size(), 1);
+ QCOMPARE(pendingWrappers.first(), deviceProxy.id());
+ }
+
+ void checkDeviceLoadedNotification()
+ {
+ // GIVEN
+ Qt3DInput::Input::PhysicalDeviceProxy backendPhysicalDeviceProxy;
+ TestPhysicalDevice physicalDevice;
+ TestArbiter arbiter;
+
+ // WHEN
+ Qt3DCore::QBackendNodePrivate::get(&backendPhysicalDeviceProxy)->setArbiter(&arbiter);
+
+ backendPhysicalDeviceProxy.setDevice(&physicalDevice);
+
+ // THEN
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "device");
+ QCOMPARE(change->value().value<Qt3DInput::QAbstractPhysicalDevice *>(), &physicalDevice);
+ QCOMPARE(change->subjectId(), backendPhysicalDeviceProxy.peerId());
+ QCOMPARE(backendPhysicalDeviceProxy.physicalDeviceId(), physicalDevice.id());
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DInput::Input::PhysicalDeviceProxy backendPhysicalDeviceProxy;
+ Qt3DInput::Input::PhysicalDeviceProxyManager manager;
+ TestProxy deviceProxy;
+
+ // WHEN
+ backendPhysicalDeviceProxy.setManager(&manager);
+ simulateInitialization(&deviceProxy, &backendPhysicalDeviceProxy);
+
+ backendPhysicalDeviceProxy.cleanup();
+
+ // THEN
+ QCOMPARE(backendPhysicalDeviceProxy.isEnabled(), false);
+ QCOMPARE(backendPhysicalDeviceProxy.deviceName(), QString());
+ QVERIFY(backendPhysicalDeviceProxy.manager() == nullptr);
+ QVERIFY(backendPhysicalDeviceProxy.physicalDeviceId().isNull());
+ }
+
+};
+
+QTEST_MAIN(tst_PhysicalDeviceProxy)
+
+#include "tst_physicaldeviceproxy.moc"
diff --git a/tests/auto/input/qabstractaxisinput/qabstractaxisinput.pro b/tests/auto/input/qabstractaxisinput/qabstractaxisinput.pro
index 7d34cfc2a..33d3ffb1c 100644
--- a/tests/auto/input/qabstractaxisinput/qabstractaxisinput.pro
+++ b/tests/auto/input/qabstractaxisinput/qabstractaxisinput.pro
@@ -8,5 +8,4 @@ CONFIG += testcase
SOURCES += tst_qabstractaxisinput.cpp
-include(../../render/commons/commons.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/input/qabstractphysicaldeviceproxy/qabstractphysicaldeviceproxy.pro b/tests/auto/input/qabstractphysicaldeviceproxy/qabstractphysicaldeviceproxy.pro
new file mode 100644
index 000000000..6aa43f276
--- /dev/null
+++ b/tests/auto/input/qabstractphysicaldeviceproxy/qabstractphysicaldeviceproxy.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qabstractphysicaldeviceproxy
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qabstractphysicaldeviceproxy.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/input/qabstractphysicaldeviceproxy/tst_qabstractphysicaldeviceproxy.cpp b/tests/auto/input/qabstractphysicaldeviceproxy/tst_qabstractphysicaldeviceproxy.cpp
new file mode 100644
index 000000000..b4dfef05e
--- /dev/null
+++ b/tests/auto/input/qabstractphysicaldeviceproxy/tst_qabstractphysicaldeviceproxy.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testdeviceproxy.h"
+
+class tst_QAbstractPhysicalDeviceProxy : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ TestProxy abstractPhysicalDeviceProxy;
+
+ // THEN
+ QCOMPARE(abstractPhysicalDeviceProxy.deviceName(), QLatin1String("TestProxy"));
+ QCOMPARE(abstractPhysicalDeviceProxy.status(), Qt3DInput::QAbstractPhysicalDeviceProxy::NotFound);
+ QCOMPARE(abstractPhysicalDeviceProxy.axisCount(), 0);
+ QCOMPARE(abstractPhysicalDeviceProxy.buttonCount(), 0);
+ QCOMPARE(abstractPhysicalDeviceProxy.axisNames(), QStringList());
+ QCOMPARE(abstractPhysicalDeviceProxy.buttonNames(), QStringList());
+ QVERIFY(abstractPhysicalDeviceProxy.device() == nullptr);
+ }
+
+
+ void checkDeviceLoading()
+ {
+ // GIVEN
+ TestProxy abstractPhysicalDeviceProxy;
+
+ // WHEN
+ TestPhysicalDevice *device = new TestPhysicalDevice();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("device");
+ change->setValue(QVariant::fromValue(device));
+
+ abstractPhysicalDeviceProxy.simulateSceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(abstractPhysicalDeviceProxy.deviceName(), QLatin1String("TestProxy"));
+ QCOMPARE(abstractPhysicalDeviceProxy.status(), Qt3DInput::QAbstractPhysicalDeviceProxy::Ready);
+ QCOMPARE(abstractPhysicalDeviceProxy.axisCount(), device->axisCount());
+ QCOMPARE(abstractPhysicalDeviceProxy.buttonCount(), device->buttonCount());
+ QCOMPARE(abstractPhysicalDeviceProxy.axisNames(), device->axisNames());
+ QCOMPARE(abstractPhysicalDeviceProxy.buttonNames(), device->buttonNames());
+ QVERIFY(abstractPhysicalDeviceProxy.device() == device);
+ }
+
+ void checkDeviceBookkeeping()
+ {
+ // GIVEN
+ TestProxy *abstractPhysicalDeviceProxy = new TestProxy();
+
+ // WHEN
+ TestPhysicalDevice *device = new TestPhysicalDevice();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("device");
+ change->setValue(QVariant::fromValue(device));
+
+ abstractPhysicalDeviceProxy->simulateSceneChangeEvent(change);
+
+ // THEN
+ QVERIFY(abstractPhysicalDeviceProxy->device() == device);
+
+ // WHEN
+ delete device;
+
+ // THEN -> should not crash
+ QVERIFY(abstractPhysicalDeviceProxy->device() == nullptr);
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ TestProxy abstractPhysicalDeviceProxy;
+
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&abstractPhysicalDeviceProxy);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DInput::QAbstractPhysicalDeviceProxyData>>(creationChanges.first());
+ const Qt3DInput::QAbstractPhysicalDeviceProxyData cloneData = creationChangeData->data;
+
+ QCOMPARE(abstractPhysicalDeviceProxy.deviceName(), cloneData.deviceName);
+ QCOMPARE(abstractPhysicalDeviceProxy.id(), creationChangeData->subjectId());
+ QCOMPARE(abstractPhysicalDeviceProxy.isEnabled(), true);
+ QCOMPARE(abstractPhysicalDeviceProxy.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(abstractPhysicalDeviceProxy.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ abstractPhysicalDeviceProxy.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&abstractPhysicalDeviceProxy);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DInput::QAbstractPhysicalDeviceProxyData>>(creationChanges.first());
+ const Qt3DInput::QAbstractPhysicalDeviceProxyData cloneData = creationChangeData->data;
+
+ QCOMPARE(abstractPhysicalDeviceProxy.deviceName(), cloneData.deviceName);
+ QCOMPARE(abstractPhysicalDeviceProxy.id(), creationChangeData->subjectId());
+ QCOMPARE(abstractPhysicalDeviceProxy.isEnabled(), false);
+ QCOMPARE(abstractPhysicalDeviceProxy.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(abstractPhysicalDeviceProxy.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_QAbstractPhysicalDeviceProxy)
+
+#include "tst_qabstractphysicaldeviceproxy.moc"
diff --git a/tests/auto/input/qaction/qaction.pro b/tests/auto/input/qaction/qaction.pro
index c743e0ffc..7d4fba21f 100644
--- a/tests/auto/input/qaction/qaction.pro
+++ b/tests/auto/input/qaction/qaction.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qaction.cpp
-include(../../render/commons/commons.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/input/qactioninput/qactioninput.pro b/tests/auto/input/qactioninput/qactioninput.pro
index bf8865690..c2bc3c54a 100644
--- a/tests/auto/input/qactioninput/qactioninput.pro
+++ b/tests/auto/input/qactioninput/qactioninput.pro
@@ -8,5 +8,4 @@ CONFIG += testcase
SOURCES += tst_qactioninput.cpp
-include(../../render/commons/commons.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/input/qanalogaxisinput/qanalogaxisinput.pro b/tests/auto/input/qanalogaxisinput/qanalogaxisinput.pro
index e693c160b..6bdc6f021 100644
--- a/tests/auto/input/qanalogaxisinput/qanalogaxisinput.pro
+++ b/tests/auto/input/qanalogaxisinput/qanalogaxisinput.pro
@@ -8,5 +8,4 @@ CONFIG += testcase
SOURCES += tst_qanalogaxisinput.cpp
-include(../../render/commons/commons.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/input/qaxis/qaxis.pro b/tests/auto/input/qaxis/qaxis.pro
index 4645062b1..e52f9f68d 100644
--- a/tests/auto/input/qaxis/qaxis.pro
+++ b/tests/auto/input/qaxis/qaxis.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qaxis.cpp
-include(../../render/commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/input/qaxisaccumulator/qaxisaccumulator.pro b/tests/auto/input/qaxisaccumulator/qaxisaccumulator.pro
index dfc53d12a..4c4b4a4eb 100644
--- a/tests/auto/input/qaxisaccumulator/qaxisaccumulator.pro
+++ b/tests/auto/input/qaxisaccumulator/qaxisaccumulator.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qaxisaccumulator.cpp
-include(../../render/commons/commons.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/input/qbuttonaxisinput/qbuttonaxisinput.pro b/tests/auto/input/qbuttonaxisinput/qbuttonaxisinput.pro
index b149843ea..4a35ee7b4 100644
--- a/tests/auto/input/qbuttonaxisinput/qbuttonaxisinput.pro
+++ b/tests/auto/input/qbuttonaxisinput/qbuttonaxisinput.pro
@@ -8,5 +8,4 @@ CONFIG += testcase
SOURCES += tst_qbuttonaxisinput.cpp
-include(../../render/commons/commons.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/input/qkeyboardhandler/qkeyboardhandler.pro b/tests/auto/input/qkeyboardhandler/qkeyboardhandler.pro
index d27760ce5..0fc435371 100644
--- a/tests/auto/input/qkeyboardhandler/qkeyboardhandler.pro
+++ b/tests/auto/input/qkeyboardhandler/qkeyboardhandler.pro
@@ -8,5 +8,4 @@ CONFIG += testcase
SOURCES += tst_qkeyboardhandler.cpp
-include(../../render/commons/commons.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/input/qlogicaldevice/qlogicaldevice.pro b/tests/auto/input/qlogicaldevice/qlogicaldevice.pro
index 406377269..f8dfef11c 100644
--- a/tests/auto/input/qlogicaldevice/qlogicaldevice.pro
+++ b/tests/auto/input/qlogicaldevice/qlogicaldevice.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qlogicaldevice.cpp
-include(../../render/commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/input/qmousedevice/qmousedevice.pro b/tests/auto/input/qmousedevice/qmousedevice.pro
new file mode 100644
index 000000000..52bbc5a9e
--- /dev/null
+++ b/tests/auto/input/qmousedevice/qmousedevice.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qmousedevice
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qmousedevice.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/input/qmousedevice/tst_qmousedevice.cpp b/tests/auto/input/qmousedevice/tst_qmousedevice.cpp
new file mode 100644
index 000000000..6ea085184
--- /dev/null
+++ b/tests/auto/input/qmousedevice/tst_qmousedevice.cpp
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/qmousedevice.h>
+#include <Qt3DInput/qmouseevent.h>
+#include <Qt3DInput/private/qmousedevice_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QMouseDevice : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DInput::QMouseDevice mouseDevice;
+
+ // THEN
+ QCOMPARE(mouseDevice.sensitivity(), 0.1f);
+ QCOMPARE(mouseDevice.axisCount(), 4);
+ QCOMPARE(mouseDevice.buttonCount(), 3);
+ QCOMPARE(mouseDevice.axisNames(), QStringList()
+ << QStringLiteral("X")
+ << QStringLiteral("Y")
+ << QStringLiteral("WheelX")
+ << QStringLiteral("WheelY"));
+ QCOMPARE(mouseDevice.buttonNames(), QStringList()
+ << QStringLiteral("Left")
+ << QStringLiteral("Right")
+ << QStringLiteral("Center"));
+
+ QVERIFY(mouseDevice.axisIdentifier(QStringLiteral("X")) == Qt3DInput::QMouseDevice::X);
+ QVERIFY(mouseDevice.axisIdentifier(QStringLiteral("Y")) == Qt3DInput::QMouseDevice::Y);
+ QVERIFY(mouseDevice.axisIdentifier(QStringLiteral("WheelX")) == Qt3DInput::QMouseDevice::WheelX);
+ QVERIFY(mouseDevice.axisIdentifier(QStringLiteral("WheelY")) == Qt3DInput::QMouseDevice::WheelY);
+
+ QVERIFY(mouseDevice.buttonIdentifier(QStringLiteral("Left")) == Qt3DInput::QMouseEvent::LeftButton);
+ QVERIFY(mouseDevice.buttonIdentifier(QStringLiteral("Right")) == Qt3DInput::QMouseEvent::RightButton);
+ QVERIFY(mouseDevice.buttonIdentifier(QStringLiteral("Center")) == Qt3DInput::QMouseEvent::MiddleButton);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DInput::QMouseDevice mouseDevice;
+
+ {
+ // WHEN
+ QSignalSpy spy(&mouseDevice, SIGNAL(sensitivityChanged(float)));
+ const float newValue = 0.5f;
+ mouseDevice.setSensitivity(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(mouseDevice.sensitivity(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ mouseDevice.setSensitivity(newValue);
+
+ // THEN
+ QCOMPARE(mouseDevice.sensitivity(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DInput::QMouseDevice mouseDevice;
+
+ mouseDevice.setSensitivity(0.8f);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mouseDevice);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DInput::QMouseDeviceData>>(creationChanges.first());
+ const Qt3DInput::QMouseDeviceData cloneData = creationChangeData->data;
+
+ QCOMPARE(mouseDevice.sensitivity(), cloneData.sensitivity);
+ QCOMPARE(mouseDevice.id(), creationChangeData->subjectId());
+ QCOMPARE(mouseDevice.isEnabled(), true);
+ QCOMPARE(mouseDevice.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mouseDevice.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ mouseDevice.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mouseDevice);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DInput::QMouseDeviceData>>(creationChanges.first());
+ const Qt3DInput::QMouseDeviceData cloneData = creationChangeData->data;
+
+ QCOMPARE(mouseDevice.sensitivity(), cloneData.sensitivity);
+ QCOMPARE(mouseDevice.id(), creationChangeData->subjectId());
+ QCOMPARE(mouseDevice.isEnabled(), false);
+ QCOMPARE(mouseDevice.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mouseDevice.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkSensitivityUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DInput::QMouseDevice mouseDevice;
+ arbiter.setArbiterOnNode(&mouseDevice);
+
+ {
+ // WHEN
+ mouseDevice.setSensitivity(0.7f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "sensitivity");
+ QCOMPARE(change->value().value<float>(), mouseDevice.sensitivity());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ mouseDevice.setSensitivity(0.7f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QMouseDevice)
+
+#include "tst_qmousedevice.moc"
diff --git a/tests/auto/input/utils/tst_utils.cpp b/tests/auto/input/utils/tst_utils.cpp
new file mode 100644
index 000000000..766408ce3
--- /dev/null
+++ b/tests/auto/input/utils/tst_utils.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DInput/private/utils_p.h>
+#include <Qt3DInput/private/axis_p.h>
+#include <Qt3DInput/qanalogaxisinput.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testdeviceproxy.h"
+
+namespace {
+
+class FakeBackendDevice : public Qt3DInput::QAbstractPhysicalDeviceBackendNode
+{
+ // QAbstractPhysicalDeviceBackendNode interface
+public:
+ FakeBackendDevice()
+ : Qt3DInput::QAbstractPhysicalDeviceBackendNode(Qt3DCore::QBackendNode::ReadOnly)
+ {}
+ float axisValue(int) const { return 0.0f; }
+ bool isButtonPressed(int) const { return false; }
+};
+
+class FakeInputDeviceIntegration : public Qt3DInput::QInputDeviceIntegration
+{
+public:
+ explicit FakeInputDeviceIntegration(Qt3DInput::QAbstractPhysicalDevice *device)
+ : Qt3DInput::QInputDeviceIntegration()
+ , m_device(device)
+ {}
+
+ QVector<Qt3DCore::QAspectJobPtr> jobsToExecute(qint64) Q_DECL_OVERRIDE { return QVector<Qt3DCore::QAspectJobPtr>(); }
+ Qt3DInput::QAbstractPhysicalDevice *createPhysicalDevice(const QString &) Q_DECL_OVERRIDE { return nullptr; }
+ QVector<Qt3DCore::QNodeId> physicalDevices() const Q_DECL_OVERRIDE { return QVector<Qt3DCore::QNodeId>(); }
+ QStringList deviceNames() const Q_DECL_OVERRIDE { return QStringList(); }
+
+ Qt3DInput::QAbstractPhysicalDeviceBackendNode *physicalDevice(Qt3DCore::QNodeId deviceId) const Q_DECL_OVERRIDE
+ {
+ if (m_device->id() == deviceId)
+ return new FakeBackendDevice();
+ return nullptr;
+ }
+
+private:
+ void onInitialize() Q_DECL_OVERRIDE {}
+ Qt3DInput::QAbstractPhysicalDevice *m_device;
+};
+
+
+} // anonymous
+
+class tst_Utils : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkPhysicalDeviceForValidAxisInput()
+ {
+ // GIVEN
+ Qt3DInput::QAnalogAxisInput analogAxisInput;
+ Qt3DInput::Input::InputHandler handler;
+ TestPhysicalDevice testPhysicalDevice;
+ FakeInputDeviceIntegration fakeIntegration(&testPhysicalDevice);
+
+ analogAxisInput.setSourceDevice(&testPhysicalDevice);
+
+ // WHEN -> Create backend AnalogAxisInput
+ Qt3DInput::Input::AnalogAxisInput *backendAxisInput = handler.analogAxisInputManager()->getOrCreateResource(analogAxisInput.id());
+ simulateInitialization(&analogAxisInput, backendAxisInput);
+
+ // THEN
+ QCOMPARE(backendAxisInput->axis(), analogAxisInput.axis());
+ QCOMPARE(backendAxisInput->sourceDevice(), testPhysicalDevice.id());
+
+ // Create backend integration
+ handler.addInputDeviceIntegration(&fakeIntegration);
+
+ // WHEN
+ Qt3DInput::QAbstractPhysicalDeviceBackendNode *backendDevice = Qt3DInput::Input::Utils::physicalDeviceForInput(backendAxisInput, &handler);
+
+ // THEN -> FakeIntegration returns something non null if it receives
+ // the same id as the device used to create it
+ QVERIFY(backendDevice != nullptr);
+ delete backendDevice;
+ }
+
+ void checkProxyPhysicalDeviceForValidAxisInput()
+ {
+ // GIVEN
+ Qt3DInput::QAnalogAxisInput analogAxisInput;
+ Qt3DInput::Input::InputHandler handler;
+ TestProxy testProxyPhysicalDevice;
+ TestPhysicalDevice testPhysicalDevice;
+ FakeInputDeviceIntegration fakeIntegration(&testPhysicalDevice);
+
+ analogAxisInput.setSourceDevice(&testProxyPhysicalDevice);
+
+ // WHEN -> Create backend AnalogAxisInput
+ Qt3DInput::Input::AnalogAxisInput *backendAxisInput = handler.analogAxisInputManager()->getOrCreateResource(analogAxisInput.id());
+ simulateInitialization(&analogAxisInput, backendAxisInput);
+
+ // THEN
+ QCOMPARE(backendAxisInput->axis(), analogAxisInput.axis());
+ QCOMPARE(backendAxisInput->sourceDevice(), testProxyPhysicalDevice.id());
+
+ // WHEN -> Create backend PhysicalProxiDevice
+ Qt3DInput::Input::PhysicalDeviceProxy *backendProxyDevice = handler.physicalDeviceProxyManager()->getOrCreateResource(testProxyPhysicalDevice.id());
+ backendProxyDevice->setManager(handler.physicalDeviceProxyManager());
+ simulateInitialization(&testProxyPhysicalDevice, backendProxyDevice);
+ backendProxyDevice->setDevice(&testPhysicalDevice);
+
+ // THEN
+ QCOMPARE(backendProxyDevice->physicalDeviceId(), testPhysicalDevice.id());
+
+ // Create backend integration
+ handler.addInputDeviceIntegration(&fakeIntegration);
+
+ // WHEN
+ Qt3DInput::QAbstractPhysicalDeviceBackendNode *backendDevice = Qt3DInput::Input::Utils::physicalDeviceForInput(backendAxisInput, &handler);
+
+ // THEN -> FakeIntegration returns something non null if it receives
+ // the same id as the device used to create it
+ QVERIFY(backendDevice != nullptr);
+ delete backendDevice;
+ }
+
+ void checkNoPhysicalDeviceForInvalidAxisInput()
+ {
+ // GIVEN
+ Qt3DInput::QAnalogAxisInput analogAxisInput;
+ Qt3DInput::Input::InputHandler handler;
+ TestPhysicalDevice testPhysicalDevice;
+ TestPhysicalDevice testPhysicalDevice2;
+ FakeInputDeviceIntegration fakeIntegration(&testPhysicalDevice);
+
+ analogAxisInput.setSourceDevice(&testPhysicalDevice2);
+
+ // WHEN -> Create backend AnalogAxisInput
+ Qt3DInput::Input::AnalogAxisInput *backendAxisInput = handler.analogAxisInputManager()->getOrCreateResource(analogAxisInput.id());
+ simulateInitialization(&analogAxisInput, backendAxisInput);
+
+ // THEN
+ QCOMPARE(backendAxisInput->axis(), analogAxisInput.axis());
+ QCOMPARE(backendAxisInput->sourceDevice(), testPhysicalDevice2.id());
+
+ // Create backend integration
+ handler.addInputDeviceIntegration(&fakeIntegration);
+
+ // WHEN
+ Qt3DInput::QAbstractPhysicalDeviceBackendNode *backendDevice = Qt3DInput::Input::Utils::physicalDeviceForInput(backendAxisInput, &handler);
+
+ // THEN -> FakeIntegration returns something non null if it receives
+ // the same id as the device used to create it (testPhysicalDevice != testPhysicalDevice2)
+ QVERIFY(backendDevice == nullptr);
+ }
+
+ void checkNoPysicalDeviceForInvalidProxyPhysicalDevice()
+ {
+ // GIVEN
+ Qt3DInput::QAnalogAxisInput analogAxisInput;
+ Qt3DInput::Input::InputHandler handler;
+ TestProxy testProxyPhysicalDevice;
+ TestPhysicalDevice testPhysicalDevice;
+ TestPhysicalDevice testPhysicalDevice2;
+ FakeInputDeviceIntegration fakeIntegration(&testPhysicalDevice);
+
+ analogAxisInput.setSourceDevice(&testProxyPhysicalDevice);
+
+ // WHEN -> Create backend AnalogAxisInput
+ Qt3DInput::Input::AnalogAxisInput *backendAxisInput = handler.analogAxisInputManager()->getOrCreateResource(analogAxisInput.id());
+ simulateInitialization(&analogAxisInput, backendAxisInput);
+
+ // THEN
+ QCOMPARE(backendAxisInput->axis(), analogAxisInput.axis());
+ QCOMPARE(backendAxisInput->sourceDevice(), testProxyPhysicalDevice.id());
+
+ // WHEN -> Create backend PhysicalProxiDevice
+ Qt3DInput::Input::PhysicalDeviceProxy *backendProxyDevice = handler.physicalDeviceProxyManager()->getOrCreateResource(testProxyPhysicalDevice.id());
+ backendProxyDevice->setManager(handler.physicalDeviceProxyManager());
+ simulateInitialization(&testProxyPhysicalDevice, backendProxyDevice);
+ backendProxyDevice->setDevice(&testPhysicalDevice2);
+
+ // THEN
+ QCOMPARE(backendProxyDevice->physicalDeviceId(), testPhysicalDevice2.id());
+
+ // Create backend integration
+ handler.addInputDeviceIntegration(&fakeIntegration);
+
+ // WHEN
+ Qt3DInput::QAbstractPhysicalDeviceBackendNode *backendDevice = Qt3DInput::Input::Utils::physicalDeviceForInput(backendAxisInput, &handler);
+
+ // THEN -> FakeIntegration returns something non null if it receives
+ // the same id as the device used to create it (testPhysicalDevice != testPhysicalDevice2)
+ QVERIFY(backendDevice == nullptr);
+ }
+};
+
+QTEST_MAIN(tst_Utils)
+
+#include "tst_utils.moc"
diff --git a/tests/auto/input/utils/utils.pro b/tests/auto/input/utils/utils.pro
new file mode 100644
index 000000000..7ee2c27d8
--- /dev/null
+++ b/tests/auto/input/utils/utils.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_utils
+
+QT += 3dcore 3dcore-private 3dinput 3dinput-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_utils.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/quick3d/quick3dnodeinstantiator/data/createMultiple.qml b/tests/auto/quick3d/quick3dnodeinstantiator/data/createMultiple.qml
index 67c1e4fe7..c1f3b21ed 100644
--- a/tests/auto/quick3d/quick3dnodeinstantiator/data/createMultiple.qml
+++ b/tests/auto/quick3d/quick3dnodeinstantiator/data/createMultiple.qml
@@ -1,10 +1,12 @@
import QtQml 2.1
import Qt3D.Core 2.0
-NodeInstantiator {
- model: 10
- delegate: Entity {
- property bool success: true
- property int idx: index
+Entity {
+ NodeInstantiator {
+ model: 10
+ delegate: Entity {
+ property bool success: true
+ property int idx: index
+ }
}
}
diff --git a/tests/auto/quick3d/quick3dnodeinstantiator/data/createNone.qml b/tests/auto/quick3d/quick3dnodeinstantiator/data/createNone.qml
index 736a02b45..eef31cb8c 100644
--- a/tests/auto/quick3d/quick3dnodeinstantiator/data/createNone.qml
+++ b/tests/auto/quick3d/quick3dnodeinstantiator/data/createNone.qml
@@ -1,13 +1,15 @@
import QtQml 2.1
import Qt3D.Core 2.0
-NodeInstantiator {
- model: 0
- property bool success: true
- Entity {
+Entity {
+ NodeInstantiator {
+ model: 0
property bool success: true
- property int idx: index
+ Entity {
+ property bool success: true
+ property int idx: index
+ }
+ onObjectChanged: success = false;//Don't create intermediate objects
+ onCountChanged: success = false;//Don't create intermediate objects
}
- onObjectChanged: success = false;//Don't create intermediate objects
- onCountChanged: success = false;//Don't create intermediate objects
}
diff --git a/tests/auto/quick3d/quick3dnodeinstantiator/data/createSingle.qml b/tests/auto/quick3d/quick3dnodeinstantiator/data/createSingle.qml
index 630da9940..5a79d6105 100644
--- a/tests/auto/quick3d/quick3dnodeinstantiator/data/createSingle.qml
+++ b/tests/auto/quick3d/quick3dnodeinstantiator/data/createSingle.qml
@@ -1,9 +1,11 @@
import QtQml 2.1
import Qt3D.Core 2.0
-NodeInstantiator {
- Entity {
- property bool success: true
- property int idx: index
+Entity {
+ NodeInstantiator {
+ Entity {
+ property bool success: true
+ property int idx: index
+ }
}
}
diff --git a/tests/auto/quick3d/quick3dnodeinstantiator/data/inactive.qml b/tests/auto/quick3d/quick3dnodeinstantiator/data/inactive.qml
index 178229059..8ae6994db 100644
--- a/tests/auto/quick3d/quick3dnodeinstantiator/data/inactive.qml
+++ b/tests/auto/quick3d/quick3dnodeinstantiator/data/inactive.qml
@@ -1,10 +1,12 @@
import QtQml 2.1
import Qt3D.Core 2.0
-NodeInstantiator {
- active: false
- Entity {
- property bool success: true
- property int idx: index
+Entity {
+ NodeInstantiator {
+ active: false
+ Entity {
+ property bool success: true
+ property int idx: index
+ }
}
}
diff --git a/tests/auto/quick3d/quick3dnodeinstantiator/data/stringModel.qml b/tests/auto/quick3d/quick3dnodeinstantiator/data/stringModel.qml
index 431c1ebd8..5aa4d399a 100644
--- a/tests/auto/quick3d/quick3dnodeinstantiator/data/stringModel.qml
+++ b/tests/auto/quick3d/quick3dnodeinstantiator/data/stringModel.qml
@@ -1,10 +1,12 @@
import QtQml 2.1
import Qt3D.Core 2.0
-NodeInstantiator {
- model: ["alpha", "beta", "gamma", "delta"]
- delegate: Entity {
- property bool success: index == 1 ? datum.length == 4 : datum.length == 5
- property string datum: modelData
+Entity {
+ NodeInstantiator {
+ model: ["alpha", "beta", "gamma", "delta"]
+ delegate: Entity {
+ property bool success: index == 1 ? datum.length == 4 : datum.length == 5
+ property string datum: modelData
+ }
}
}
diff --git a/tests/auto/quick3d/quick3dnodeinstantiator/tst_quick3dnodeinstantiator.cpp b/tests/auto/quick3d/quick3dnodeinstantiator/tst_quick3dnodeinstantiator.cpp
index fd7f0eb0c..acaba6690 100644
--- a/tests/auto/quick3d/quick3dnodeinstantiator/tst_quick3dnodeinstantiator.cpp
+++ b/tests/auto/quick3d/quick3dnodeinstantiator/tst_quick3dnodeinstantiator.cpp
@@ -60,7 +60,9 @@ void tst_quick3dnodeinstantiator::createNone()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createNone.qml"));
- Quick3DNodeInstantiator *instantiator = qobject_cast<Quick3DNodeInstantiator*>(component.create());
+ const auto root = qobject_cast<Qt3DCore::QNode*>(component.create());
+ QVERIFY(root != 0);
+ const auto instantiator = root->findChild<Quick3DNodeInstantiator*>();
QVERIFY(instantiator != 0);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 0);
@@ -72,7 +74,9 @@ void tst_quick3dnodeinstantiator::createSingle()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createSingle.qml"));
- Quick3DNodeInstantiator *instantiator = qobject_cast<Quick3DNodeInstantiator*>(component.create());
+ const auto root = qobject_cast<Qt3DCore::QNode*>(component.create());
+ QVERIFY(root != 0);
+ const auto instantiator = root->findChild<Quick3DNodeInstantiator*>();
QVERIFY(instantiator != 0);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 1);
@@ -80,7 +84,7 @@ void tst_quick3dnodeinstantiator::createSingle()
QObject *object = instantiator->object();
QVERIFY(object);
- QCOMPARE(object->parent(), instantiator);
+ QCOMPARE(object->parent(), root);
QCOMPARE(object->property("success").toBool(), true);
QCOMPARE(object->property("idx").toInt(), 0);
}
@@ -89,7 +93,9 @@ void tst_quick3dnodeinstantiator::createMultiple()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createMultiple.qml"));
- Quick3DNodeInstantiator *instantiator = qobject_cast<Quick3DNodeInstantiator*>(component.create());
+ const auto root = qobject_cast<Qt3DCore::QNode*>(component.create());
+ QVERIFY(root != 0);
+ const auto instantiator = root->findChild<Quick3DNodeInstantiator*>();
QVERIFY(instantiator != 0);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 10);
@@ -97,7 +103,7 @@ void tst_quick3dnodeinstantiator::createMultiple()
for (int i = 0; i < 10; i++) {
QObject *object = instantiator->objectAt(i);
QVERIFY(object);
- QCOMPARE(object->parent(), instantiator);
+ QCOMPARE(object->parent(), root);
QCOMPARE(object->property("success").toBool(), true);
QCOMPARE(object->property("idx").toInt(), i);
}
@@ -107,7 +113,9 @@ void tst_quick3dnodeinstantiator::stringModel()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stringModel.qml"));
- Quick3DNodeInstantiator *instantiator = qobject_cast<Quick3DNodeInstantiator*>(component.create());
+ const auto root = qobject_cast<Qt3DCore::QNode*>(component.create());
+ QVERIFY(root != 0);
+ const auto instantiator = root->findChild<Quick3DNodeInstantiator*>();
QVERIFY(instantiator != 0);
QCOMPARE(instantiator->isActive(), true);
QCOMPARE(instantiator->count(), 4);
@@ -115,7 +123,7 @@ void tst_quick3dnodeinstantiator::stringModel()
for (int i = 0; i < 4; i++) {
QObject *object = instantiator->objectAt(i);
QVERIFY(object);
- QCOMPARE(object->parent(), instantiator);
+ QCOMPARE(object->parent(), root);
QCOMPARE(object->property("success").toBool(), true);
}
}
@@ -124,7 +132,9 @@ void tst_quick3dnodeinstantiator::activeProperty()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("inactive.qml"));
- Quick3DNodeInstantiator *instantiator = qobject_cast<Quick3DNodeInstantiator*>(component.create());
+ const auto root = qobject_cast<Qt3DCore::QNode*>(component.create());
+ QVERIFY(root != 0);
+ const auto instantiator = root->findChild<Quick3DNodeInstantiator*>();
QVERIFY(instantiator != 0);
QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged()));
QSignalSpy countSpy(instantiator, SIGNAL(countChanged()));
@@ -150,7 +160,7 @@ void tst_quick3dnodeinstantiator::activeProperty()
QObject *object = instantiator->object();
QVERIFY(object);
- QCOMPARE(object->parent(), instantiator);
+ QCOMPARE(object->parent(), root);
QCOMPARE(object->property("success").toBool(), true);
QCOMPARE(object->property("idx").toInt(), 0);
}
@@ -159,7 +169,9 @@ void tst_quick3dnodeinstantiator::intModelChange()
{
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("createMultiple.qml"));
- Quick3DNodeInstantiator *instantiator = qobject_cast<Quick3DNodeInstantiator*>(component.create());
+ const auto root = qobject_cast<Qt3DCore::QNode*>(component.create());
+ QVERIFY(root != 0);
+ const auto instantiator = root->findChild<Quick3DNodeInstantiator*>();
QVERIFY(instantiator != 0);
QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged()));
QSignalSpy countSpy(instantiator, SIGNAL(countChanged()));
@@ -183,7 +195,7 @@ void tst_quick3dnodeinstantiator::intModelChange()
for (int i = 0; i < 2; i++) {
QObject *object = instantiator->objectAt(i);
QVERIFY(object);
- QCOMPARE(object->parent(), instantiator);
+ QCOMPARE(object->parent(), root);
QCOMPARE(object->property("success").toBool(), true);
QCOMPARE(object->property("idx").toInt(), i);
}
diff --git a/tests/auto/render/commons/commons.pri b/tests/auto/render/commons/commons.pri
index 54bc0b949..1364ddb32 100644
--- a/tests/auto/render/commons/commons.pri
+++ b/tests/auto/render/commons/commons.pri
@@ -1,9 +1,7 @@
SOURCES += \
- $$PWD/testpostmanarbiter.cpp \
$$PWD/testrenderer.cpp
HEADERS += \
- $$PWD/testpostmanarbiter.h \
$$PWD/testrenderer.h
INCLUDEPATH += $$PWD
diff --git a/tests/auto/render/computecommand/computecommand.pro b/tests/auto/render/computecommand/computecommand.pro
new file mode 100644
index 000000000..ba3a0807d
--- /dev/null
+++ b/tests/auto/render/computecommand/computecommand.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_computecommand
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_computecommand.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/computecommand/tst_computecommand.cpp b/tests/auto/render/computecommand/tst_computecommand.cpp
new file mode 100644
index 000000000..13688d299
--- /dev/null
+++ b/tests/auto/render/computecommand/tst_computecommand.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qcomputecommand.h>
+#include <Qt3DRender/private/qcomputecommand_p.h>
+#include <Qt3DRender/private/computecommand_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_ComputeCommand : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::ComputeCommand backendComputeCommand;
+
+ // THEN
+ QCOMPARE(backendComputeCommand.isEnabled(), false);
+ QVERIFY(backendComputeCommand.peerId().isNull());
+ QCOMPARE(backendComputeCommand.x(), 1);
+ QCOMPARE(backendComputeCommand.y(), 1);
+ QCOMPARE(backendComputeCommand.z(), 1);
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::ComputeCommand backendComputeCommand;
+
+ // WHEN
+ backendComputeCommand.setEnabled(true);
+
+ backendComputeCommand.cleanup();
+
+ // THEN
+ QCOMPARE(backendComputeCommand.isEnabled(), false);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QComputeCommand computeCommand;
+ computeCommand.setWorkGroupX(256);
+ computeCommand.setWorkGroupY(512);
+ computeCommand.setWorkGroupZ(128);
+
+ {
+ // WHEN
+ Qt3DRender::Render::ComputeCommand backendComputeCommand;
+ simulateInitialization(&computeCommand, &backendComputeCommand);
+
+ // THEN
+ QCOMPARE(backendComputeCommand.isEnabled(), true);
+ QCOMPARE(backendComputeCommand.peerId(), computeCommand.id());
+ QCOMPARE(backendComputeCommand.x(), computeCommand.workGroupX());
+ QCOMPARE(backendComputeCommand.y(), computeCommand.workGroupY());
+ QCOMPARE(backendComputeCommand.z(), computeCommand.workGroupZ());
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::ComputeCommand backendComputeCommand;
+ computeCommand.setEnabled(false);
+ simulateInitialization(&computeCommand, &backendComputeCommand);
+
+ // THEN
+ QCOMPARE(backendComputeCommand.peerId(), computeCommand.id());
+ QCOMPARE(backendComputeCommand.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::ComputeCommand backendComputeCommand;
+ TestRenderer renderer;
+ backendComputeCommand.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendComputeCommand.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendComputeCommand.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const int newValue = 128;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("workGroupX");
+ change->setValue(newValue);
+ backendComputeCommand.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendComputeCommand.x(), newValue);
+ }
+ {
+ // WHEN
+ const int newValue = 64;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("workGroupY");
+ change->setValue(newValue);
+ backendComputeCommand.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendComputeCommand.y(), newValue);
+ }
+ {
+ // WHEN
+ const int newValue = 32;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("workGroupZ");
+ change->setValue(newValue);
+ backendComputeCommand.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendComputeCommand.z(), newValue);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_ComputeCommand)
+
+#include "tst_computecommand.moc"
diff --git a/tests/auto/render/effect/effect.pro b/tests/auto/render/effect/effect.pro
new file mode 100644
index 000000000..15fef9ccb
--- /dev/null
+++ b/tests/auto/render/effect/effect.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_effect
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_effect.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/effect/tst_effect.cpp b/tests/auto/render/effect/tst_effect.cpp
new file mode 100644
index 000000000..30df242f4
--- /dev/null
+++ b/tests/auto/render/effect/tst_effect.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qeffect.h>
+#include <Qt3DRender/qtechnique.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/private/qeffect_p.h>
+#include <Qt3DRender/private/effect_p.h>
+#include <Qt3DRender/private/shaderparameterpack_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+
+class tst_Effect : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Effect backendEffect;
+
+ // THEN
+ QCOMPARE(backendEffect.isEnabled(), false);
+ QVERIFY(backendEffect.peerId().isNull());
+ QVERIFY(backendEffect.techniques().empty());
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Effect backendEffect;
+
+ // WHEN
+ backendEffect.setEnabled(true);
+
+ {
+ Qt3DRender::QEffect effect;
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QParameter parameter;
+ effect.addTechnique(&technique);
+ effect.addParameter(&parameter);
+ simulateInitialization(&effect, &backendEffect);
+ }
+
+ backendEffect.cleanup();
+
+ // THEN
+ QCOMPARE(backendEffect.isEnabled(), false);
+ QCOMPARE(backendEffect.techniques().size(), 0);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QEffect effect;
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QParameter parameter;
+
+ effect.addTechnique(&technique);
+ effect.addParameter(&parameter);
+
+ {
+ // WHEN
+ Qt3DRender::Render::Effect backendEffect;
+ simulateInitialization(&effect, &backendEffect);
+
+ // THEN
+ QCOMPARE(backendEffect.isEnabled(), true);
+ QCOMPARE(backendEffect.peerId(), effect.id());
+ QCOMPARE(backendEffect.techniques().size(), 1);
+ QCOMPARE(backendEffect.techniques().first(), technique.id());
+ QCOMPARE(backendEffect.parameters().size(), 1);
+ QCOMPARE(backendEffect.parameters().first(), parameter.id());
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::Effect backendEffect;
+ effect.setEnabled(false);
+ simulateInitialization(&effect, &backendEffect);
+
+ // THEN
+ QCOMPARE(backendEffect.peerId(), effect.id());
+ QCOMPARE(backendEffect.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::Effect backendEffect;
+ TestRenderer renderer;
+ backendEffect.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendEffect.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendEffect.isEnabled(), newValue);
+ }
+ {
+ Qt3DRender::QTechnique technique;
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &technique);
+ change->setPropertyName("technique");
+ backendEffect.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendEffect.techniques().size(), 1);
+ QCOMPARE(backendEffect.techniques().first(), technique.id());
+ }
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &technique);
+ change->setPropertyName("technique");
+ backendEffect.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendEffect.techniques().size(), 0);
+ }
+ }
+ {
+ Qt3DRender::QParameter parameter;
+
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &parameter);
+ change->setPropertyName("parameter");
+ backendEffect.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendEffect.parameters().size(), 1);
+ QCOMPARE(backendEffect.parameters().first(), parameter.id());
+ }
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &parameter);
+ change->setPropertyName("parameter");
+ backendEffect.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendEffect.parameters().size(), 0);
+ }
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_Effect)
+
+#include "tst_effect.moc"
diff --git a/tests/auto/render/filterkey/filterkey.pro b/tests/auto/render/filterkey/filterkey.pro
new file mode 100644
index 000000000..b5ad86a49
--- /dev/null
+++ b/tests/auto/render/filterkey/filterkey.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_filterkey
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_filterkey.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/filterkey/tst_filterkey.cpp b/tests/auto/render/filterkey/tst_filterkey.cpp
new file mode 100644
index 000000000..15d07d65f
--- /dev/null
+++ b/tests/auto/render/filterkey/tst_filterkey.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qfilterkey.h>
+#include <Qt3DRender/private/qfilterkey_p.h>
+#include <Qt3DRender/private/filterkey_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_FilterKey : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::FilterKey backendFilterKey;
+
+ // THEN
+ QCOMPARE(backendFilterKey.isEnabled(), false);
+ QVERIFY(backendFilterKey.peerId().isNull());
+ QCOMPARE(backendFilterKey.value(), QVariant());
+ QCOMPARE(backendFilterKey.name(), QString());
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::FilterKey backendFilterKey;
+
+ // WHEN
+ backendFilterKey.setEnabled(true);
+
+ {
+ Qt3DRender::QFilterKey filterKey;
+ filterKey.setName(QStringLiteral("Tim"));
+ filterKey.setValue(QVariant(QStringLiteral("McGraw")));
+ simulateInitialization(&filterKey, &backendFilterKey);
+ }
+
+ backendFilterKey.cleanup();
+
+ // THEN
+ QCOMPARE(backendFilterKey.isEnabled(), false);
+ QCOMPARE(backendFilterKey.value(), QVariant());
+ QCOMPARE(backendFilterKey.name(), QString());
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QFilterKey filterKey;
+ filterKey.setName(QStringLiteral("Dallas"));
+ filterKey.setValue(QVariant(QStringLiteral("Smith")));
+
+ {
+ // WHEN
+ Qt3DRender::Render::FilterKey backendFilterKey;
+ simulateInitialization(&filterKey, &backendFilterKey);
+
+ // THEN
+ QCOMPARE(backendFilterKey.isEnabled(), true);
+ QCOMPARE(backendFilterKey.peerId(), filterKey.id());
+ QCOMPARE(backendFilterKey.value(), QVariant(QStringLiteral("Smith")));
+ QCOMPARE(backendFilterKey.name(), QStringLiteral("Dallas"));
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::FilterKey backendFilterKey;
+ filterKey.setEnabled(false);
+ simulateInitialization(&filterKey, &backendFilterKey);
+
+ // THEN
+ QCOMPARE(backendFilterKey.peerId(), filterKey.id());
+ QCOMPARE(backendFilterKey.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::FilterKey backendFilterKey;
+ TestRenderer renderer;
+ backendFilterKey.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendFilterKey.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendFilterKey.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const QVariant newValue(383.0f);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("value");
+ change->setValue(QVariant::fromValue(newValue));
+ backendFilterKey.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendFilterKey.value(), newValue);
+ }
+ {
+ // WHEN
+ const QString newValue = QStringLiteral("Alan");
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("name");
+ change->setValue(QVariant::fromValue(newValue));
+ backendFilterKey.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendFilterKey.name(), newValue);
+ }
+ }
+
+ void checkComparison()
+ {
+ // GIVEN
+ Qt3DRender::Render::FilterKey backendFilterKey1;
+ Qt3DRender::Render::FilterKey backendFilterKey2;
+ Qt3DRender::Render::FilterKey backendFilterKey3;
+ Qt3DRender::Render::FilterKey backendFilterKey4;
+
+ // WHEN
+ {
+ Qt3DRender::QFilterKey filterKey1;
+ filterKey1.setName(QStringLiteral("Dallas"));
+ filterKey1.setValue(QVariant(QStringLiteral("Smith")));
+
+ simulateInitialization(&filterKey1, &backendFilterKey1);
+ simulateInitialization(&filterKey1, &backendFilterKey4);
+
+ Qt3DRender::QFilterKey filterKey2;
+ filterKey2.setName(QStringLiteral("Tim"));
+ filterKey2.setValue(QVariant(QStringLiteral("Smith")));
+
+ simulateInitialization(&filterKey2, &backendFilterKey2);
+
+ Qt3DRender::QFilterKey filterKey3;
+ filterKey3.setName(QStringLiteral("Dallas"));
+ filterKey3.setValue(QVariant(QStringLiteral("McGraw")));
+
+ simulateInitialization(&filterKey3, &backendFilterKey3);
+ }
+
+ // THEN
+ QVERIFY(backendFilterKey1 == backendFilterKey4);
+ QVERIFY(backendFilterKey4 == backendFilterKey1);
+ QVERIFY(backendFilterKey1 != backendFilterKey2);
+ QVERIFY(backendFilterKey2 != backendFilterKey1);
+ QVERIFY(backendFilterKey1 != backendFilterKey3);
+ QVERIFY(backendFilterKey3 != backendFilterKey2);
+ }
+
+};
+
+QTEST_MAIN(tst_FilterKey)
+
+#include "tst_filterkey.moc"
diff --git a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
index 579aae971..5c413b0d0 100644
--- a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
+++ b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
@@ -871,6 +871,7 @@ private Q_SLOTS:
SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
SUPPORTS_FEATURE(GraphicsHelperInterface::Tessellation, false);
+ SUPPORTS_FEATURE(GraphicsHelperInterface::BlitFramebuffer, false);
}
@@ -1352,6 +1353,13 @@ private Q_SLOTS:
// Not supported by GL2
}
+ void blitFramebuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
#define ADD_GL_TYPE_ENTRY(Type, Expected) \
QTest::newRow(#Type) << Type << Expected;
diff --git a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
index e4b9bca39..2a67012ec 100644
--- a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
+++ b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
@@ -523,9 +523,9 @@ private Q_SLOTS:
textures[3]->bind();
m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
textures[3]->release();
- for (const QVector4D c : colors)
+ for (const QVector4D c : colors) {
QVERIFY(c == clearValue1);
-
+ }
// WHEN
const QVector4D clearValue2 = QVector4D(0.4f, 0.5f, 0.4f, 1.0f);
@@ -535,9 +535,9 @@ private Q_SLOTS:
textures[3]->bind();
m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
textures[3]->release();
- for (const QVector4D c : colors)
+ for (const QVector4D c : colors) {
QVERIFY(c == clearValue2);
-
+ }
// Restore
m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
m_func->glDeleteFramebuffers(1, &fboId);
@@ -1162,6 +1162,7 @@ private Q_SLOTS:
SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
// Tesselation could be true or false depending on extensions so not tested
+ SUPPORTS_FEATURE(GraphicsHelperInterface::BlitFramebuffer, true);
}
@@ -1680,7 +1681,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 327.0f };
const GLint location = shaderProgram.uniformLocation("m4");
m_glHelper.glUniformMatrix4fv(location, 1, values);
@@ -1815,7 +1816,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f};
+ GLfloat values[12] = { 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f};
const GLint location = shaderProgram.uniformLocation("m34");
m_glHelper.glUniformMatrix3x4fv(location, 1, values);
@@ -1842,7 +1843,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ GLfloat values[12] = { 55.0f, 5.7f, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
const GLint location = shaderProgram.uniformLocation("m43");
m_glHelper.glUniformMatrix4x3fv(location, 1, values);
@@ -1856,6 +1857,66 @@ private Q_SLOTS:
m_func->glUseProgram(0);
}
+ void blitFramebuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ GLuint fbos[2];
+ GLuint fboTextures[2];
+
+ m_func->glGenFramebuffers(2, fbos);
+ m_func->glGenTextures(2, fboTextures);
+
+ m_func->glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, fboTextures[0]);
+ m_func->glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, 10, 10, true);
+ m_func->glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+
+ m_func->glBindTexture(GL_TEXTURE_2D, fboTextures[1]);
+ m_func->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ m_func->glBindTexture(GL_TEXTURE_2D, 0);
+
+ m_func->glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
+ m_func->glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextures[1], 0);
+
+ GLenum status = m_func->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ m_func->glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
+ m_func->glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextures[0], 0);
+
+ status = m_func->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ m_func->glEnable(GL_MULTISAMPLE);
+ m_func->glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
+ m_func->glClear(GL_COLOR_BUFFER_BIT);
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
+ // WHEN
+ m_glHelper.blitFramebuffer(0,0,10,10,0,0,10,10, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ m_func->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[1]);
+
+ GLuint result[10*10];
+ m_func->glReadPixels(0,0,10,10,GL_RGBA, GL_UNSIGNED_BYTE, result);
+
+ // THEN
+ GLuint v = (0.2f) * 255;
+ v = v | (v<<8) | (v<<16) | (v<<24);
+ for (GLuint value : result) {
+ QCOMPARE(value, v);
+ }
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+
+ m_func->glDeleteFramebuffers(2, fbos);
+ m_func->glDeleteTextures(2, fboTextures);
+ }
+
#define ADD_GL_TYPE_ENTRY(Type, Expected) \
QTest::newRow(#Type) << Type << Expected;
diff --git a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
index bec5cbc1a..19dd23863 100644
--- a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
+++ b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
@@ -275,53 +275,147 @@ private Q_SLOTS:
if (!m_initializationSuccessful)
QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
- // GIVEN
- GLuint fboId;
- m_func->glGenFramebuffers(1, &fboId);
+ {
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
- Attachment attachment;
- attachment.m_point = QRenderTargetOutput::Color0;
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
- GLint maxAttachmentsCount = 0;
- m_func->glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttachmentsCount);
+ GLint maxAttachmentsCount = 0;
+ m_func->glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxAttachmentsCount);
- // THEN
- QVERIFY(fboId != 0);
- QVERIFY(maxAttachmentsCount >= 3);
+ // THEN
+ QVERIFY(fboId != 0);
+ QVERIFY(maxAttachmentsCount >= 3);
- // WHEN
- m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
- QOpenGLTexture texture(QOpenGLTexture::Target2D);
- texture.setSize(512, 512);
- texture.setFormat(QOpenGLTexture::RGBA8U);
- texture.setMinificationFilter(QOpenGLTexture::Linear);
- texture.setMagnificationFilter(QOpenGLTexture::Linear);
- texture.setWrapMode(QOpenGLTexture::ClampToEdge);
- if (!texture.create())
- qWarning() << "Texture creation failed";
- texture.allocateStorage();
- QVERIFY(texture.isStorageAllocated());
- GLint error = m_func->glGetError();
- QVERIFY(error == 0);
- m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA8U);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
- // THEN
- GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
- QCOMPARE(int(status), GL_FRAMEBUFFER_COMPLETE);
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QCOMPARE(int(status), GL_FRAMEBUFFER_COMPLETE);
- error = m_func->glGetError();
- QVERIFY(error == 0);
- GLint textureAttachmentId = 0;
- m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
- &textureAttachmentId);
- QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
-
- // Restore state
- m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- m_func->glDeleteFramebuffers(1, &fboId);
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureAttachmentId = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &textureAttachmentId);
+ QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+ {
+ // GIVEN
+ QOpenGLTexture texture(QOpenGLTexture::TargetCubeMap);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA32F);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ { // Check All Faces
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+ attachment.m_face = Qt3DRender::QAbstractTexture::AllFaces;
+
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureIsLayered = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_LAYERED,
+ &textureIsLayered);
+ QCOMPARE(textureIsLayered, GL_TRUE);
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+ { // Check Specific Faces
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+ attachment.m_face = Qt3DRender::QAbstractTexture::CubeMapNegativeZ;
+
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureFace = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE,
+ &textureFace);
+ QCOMPARE(textureFace, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+ GLint textureIsLayered = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_LAYERED,
+ &textureIsLayered);
+ QCOMPARE(textureIsLayered, GL_FALSE);
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+ }
}
void bindFrameBufferObject()
@@ -527,9 +621,10 @@ private Q_SLOTS:
textures[3]->bind();
m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
textures[3]->release();
- for (const QVector4D c : colors)
- QVERIFY(c == clearValue1);
+ for (const QVector4D c : colors) {
+ QVERIFY(c == clearValue1);
+ }
// WHEN
const QVector4D clearValue2 = QVector4D(0.4f, 0.5f, 0.4f, 1.0f);
@@ -539,9 +634,9 @@ private Q_SLOTS:
textures[3]->bind();
m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
textures[3]->release();
- for (const QVector4D c : colors)
+ for (const QVector4D c : colors) {
QVERIFY(c == clearValue2);
-
+ }
// Restore
m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
m_func->glDeleteFramebuffers(1, &fboId);
@@ -1166,6 +1261,7 @@ private Q_SLOTS:
SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
// Tesselation could be true or false depending on extensions so not tested
+ SUPPORTS_FEATURE(GraphicsHelperInterface::BlitFramebuffer, true);
}
@@ -1684,7 +1780,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 327.0f };
const GLint location = shaderProgram.uniformLocation("m4");
m_glHelper.glUniformMatrix4fv(location, 1, values);
@@ -1819,7 +1915,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f};
+ GLfloat values[12] = { 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f};
const GLint location = shaderProgram.uniformLocation("m34");
m_glHelper.glUniformMatrix3x4fv(location, 1, values);
@@ -1846,7 +1942,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ GLfloat values[12] = { 55.0f, 5.7f, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
const GLint location = shaderProgram.uniformLocation("m43");
m_glHelper.glUniformMatrix4x3fv(location, 1, values);
@@ -1860,6 +1956,67 @@ private Q_SLOTS:
m_func->glUseProgram(0);
}
+
+ void blitFramebuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fbos[2];
+ GLuint fboTextures[2];
+
+ m_func->glGenFramebuffers(2, fbos);
+ m_func->glGenTextures(2, fboTextures);
+
+ m_func->glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, fboTextures[0]);
+ m_func->glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, 10, 10, true);
+ m_func->glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+
+ m_func->glBindTexture(GL_TEXTURE_2D, fboTextures[1]);
+ m_func->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ m_func->glBindTexture(GL_TEXTURE_2D, 0);
+
+ m_func->glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
+ m_func->glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextures[1], 0);
+
+ GLenum status = m_func->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ m_func->glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
+ m_func->glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextures[0], 0);
+
+ status = m_func->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ m_func->glEnable(GL_MULTISAMPLE);
+ m_func->glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
+ m_func->glClear(GL_COLOR_BUFFER_BIT);
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
+ // WHEN
+ m_glHelper.blitFramebuffer(0,0,10,10,0,0,10,10, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ m_func->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[1]);
+
+ GLuint result[10*10];
+ m_func->glReadPixels(0,0,10,10,GL_RGBA, GL_UNSIGNED_BYTE, result);
+
+ // THEN
+ GLuint v = (0.2f) * 255;
+ v = v | (v<<8) | (v<<16) | (v<<24);
+ for (GLuint value : result) {
+ QCOMPARE(value, v);
+ }
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+
+ m_func->glDeleteFramebuffers(2, fbos);
+ m_func->glDeleteTextures(2, fboTextures);
+ }
+
#define ADD_GL_TYPE_ENTRY(Type, Expected) \
QTest::newRow(#Type) << Type << Expected;
diff --git a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
index 25670c545..193856cb9 100644
--- a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
+++ b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
@@ -300,49 +300,143 @@ private Q_SLOTS:
if (!m_initializationSuccessful)
QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
- // GIVEN
- GLuint fboId;
- m_func->glGenFramebuffers(1, &fboId);
+ {
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
- Attachment attachment;
- attachment.m_point = QRenderTargetOutput::Color2;
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color2;
- // THEN
- QVERIFY(fboId != 0);
+ // THEN
+ QVERIFY(fboId != 0);
- // WHEN
- m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
- QOpenGLTexture texture(QOpenGLTexture::Target2D);
- texture.setSize(512, 512);
- texture.setFormat(QOpenGLTexture::RGBA32F);
- texture.setMinificationFilter(QOpenGLTexture::Linear);
- texture.setMagnificationFilter(QOpenGLTexture::Linear);
- texture.setWrapMode(QOpenGLTexture::ClampToEdge);
- if (!texture.create())
- qWarning() << "Texture creation failed";
- texture.allocateStorage();
- QVERIFY(texture.isStorageAllocated());
- GLint error = m_func->glGetError();
- QVERIFY(error == 0);
- m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+ QOpenGLTexture texture(QOpenGLTexture::Target2D);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA32F);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
- // THEN
- GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
- QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
- error = m_func->glGetError();
- QVERIFY(error == 0);
- GLint textureAttachmentId = 0;
- m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0 + 2,
- GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
- &textureAttachmentId);
- QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
-
- // Restore state
- m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- m_func->glDeleteFramebuffers(1, &fboId);
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureAttachmentId = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0 + 2,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &textureAttachmentId);
+ QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+ {
+ // GIVEN
+ QOpenGLTexture texture(QOpenGLTexture::TargetCubeMap);
+ texture.setSize(512, 512);
+ texture.setFormat(QOpenGLTexture::RGBA32F);
+ texture.setMinificationFilter(QOpenGLTexture::Linear);
+ texture.setMagnificationFilter(QOpenGLTexture::Linear);
+ texture.setWrapMode(QOpenGLTexture::ClampToEdge);
+ if (!texture.create())
+ qWarning() << "Texture creation failed";
+ texture.allocateStorage();
+ QVERIFY(texture.isStorageAllocated());
+ GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ { // Check All Faces
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+ attachment.m_face = Qt3DRender::QAbstractTexture::AllFaces;
+
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureIsLayered = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_LAYERED,
+ &textureIsLayered);
+ QCOMPARE(textureIsLayered, GL_TRUE);
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+ { // Check Specific Faces
+
+ // GIVEN
+ GLuint fboId;
+ m_func->glGenFramebuffers(1, &fboId);
+
+ // THEN
+ QVERIFY(fboId != 0);
+
+ // WHEN
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboId);
+
+ Attachment attachment;
+ attachment.m_point = QRenderTargetOutput::Color0;
+ attachment.m_face = Qt3DRender::QAbstractTexture::CubeMapNegativeZ;
+
+ m_glHelper.bindFrameBufferAttachment(&texture, attachment);
+
+ // THEN
+ GLenum status = m_func->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint textureFace = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE,
+ &textureFace);
+ QCOMPARE(textureFace, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+ GLint textureIsLayered = 0;
+ m_func->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_LAYERED,
+ &textureIsLayered);
+ QCOMPARE(textureIsLayered, GL_FALSE);
+
+ // Restore state
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glDeleteFramebuffers(1, &fboId);
+ }
+ }
}
void bindFrameBufferObject()
@@ -625,9 +719,10 @@ private Q_SLOTS:
textures[3]->bind();
m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
textures[3]->release();
- for (const QVector4D c : colors)
- QVERIFY(c == clearValue1);
+ for (const QVector4D c : colors) {
+ QVERIFY(c == clearValue1);
+ }
// WHEN
const QVector4D clearValue2 = QVector4D(0.4f, 0.5f, 0.4f, 1.0f);
@@ -637,9 +732,9 @@ private Q_SLOTS:
textures[3]->bind();
m_func->glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, colors.data());
textures[3]->release();
- for (const QVector4D c : colors)
+ for (const QVector4D c : colors) {
QVERIFY(c == clearValue2);
-
+ }
// Restore
m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
m_func->glDeleteFramebuffers(1, &fboId);
@@ -1258,7 +1353,7 @@ private Q_SLOTS:
void supportsFeature()
{
- for (int i = 0; i <= GraphicsHelperInterface::DrawBuffersBlend; ++i)
+ for (int i = 0; i <= GraphicsHelperInterface::BlitFramebuffer; ++i)
QVERIFY(m_glHelper.supportsFeature(static_cast<GraphicsHelperInterface::Feature>(i)));
}
@@ -1761,7 +1856,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 327.0f };
+ GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 327.0f };
m_glHelper.glUniformMatrix4fv(9, 1, values);
// THEN
@@ -1891,7 +1986,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f,};
+ GLfloat values[12] = { 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f,};
m_glHelper.glUniformMatrix3x4fv(7, 1, values);
// THEN
@@ -1917,7 +2012,7 @@ private Q_SLOTS:
// WHEN
m_func->glUseProgram(shaderProgram.programId());
- GLfloat values[12] = { 55.0f, 5.7, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
+ GLfloat values[12] = { 55.0f, 5.7f, 383.0f, 6.2f, 383.0f, 427.0f, 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f};
m_glHelper.glUniformMatrix4x3fv(8, 1, values);
// THEN
@@ -1930,6 +2025,67 @@ private Q_SLOTS:
m_func->glUseProgram(0);
}
+
+ void blitFramebuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ GLuint fbos[2];
+ GLuint fboTextures[2];
+
+ m_func->glGenFramebuffers(2, fbos);
+ m_func->glGenTextures(2, fboTextures);
+
+ m_func->glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, fboTextures[0]);
+ m_func->glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, 10, 10, true);
+ m_func->glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+
+ m_func->glBindTexture(GL_TEXTURE_2D, fboTextures[1]);
+ m_func->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ m_func->glBindTexture(GL_TEXTURE_2D, 0);
+
+ m_func->glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
+ m_func->glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextures[1], 0);
+
+ GLenum status = m_func->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ m_func->glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
+ m_func->glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextures[0], 0);
+
+ status = m_func->glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
+
+ m_func->glEnable(GL_MULTISAMPLE);
+ m_func->glClearColor(0.2f, 0.2f, 0.2f, 0.2f);
+ m_func->glClear(GL_COLOR_BUFFER_BIT);
+ m_func->glDisable(GL_MULTISAMPLE);
+
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+
+ // WHEN
+ m_glHelper.blitFramebuffer(0,0,10,10,0,0,10,10, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ m_func->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[1]);
+
+ GLuint result[10*10];
+ m_func->glReadPixels(0,0,10,10,GL_RGBA, GL_UNSIGNED_BYTE, result);
+
+ // THEN
+ GLuint v = (0.2f) * 255;
+ v = v | (v<<8) | (v<<16) | (v<<24);
+ for (GLuint value : result) {
+ QCOMPARE(value, v);
+ }
+ m_func->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ m_func->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+
+ m_func->glDeleteFramebuffers(2, fbos);
+ m_func->glDeleteTextures(2, fboTextures);
+ }
+
#define ADD_GL_TYPE_ENTRY(Type, Expected) \
QTest::newRow(#Type) << Type << Expected;
diff --git a/tests/auto/render/materialparametergathererjob/materialparametergathererjob.pro b/tests/auto/render/materialparametergathererjob/materialparametergathererjob.pro
new file mode 100644
index 000000000..ac68b8248
--- /dev/null
+++ b/tests/auto/render/materialparametergathererjob/materialparametergathererjob.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_materialparametergathererjob
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_materialparametergathererjob.cpp
+
+include(../commons/commons.pri)
diff --git a/tests/auto/render/materialparametergathererjob/tst_materialparametergathererjob.cpp b/tests/auto/render/materialparametergathererjob/tst_materialparametergathererjob.cpp
new file mode 100644
index 000000000..cd4ffb651
--- /dev/null
+++ b/tests/auto/render/materialparametergathererjob/tst_materialparametergathererjob.cpp
@@ -0,0 +1,459 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qaspectjobmanager_p.h>
+
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/materialparametergathererjob_p.h>
+#include <Qt3DRender/private/techniquefilternode_p.h>
+#include <Qt3DRender/private/renderpassfilternode_p.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DRender/qeffect.h>
+#include <Qt3DRender/qmaterial.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qtechniquefilter.h>
+#include <Qt3DRender/qrenderpassfilter.h>
+#include <Qt3DRender/qrenderpass.h>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qviewport.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class TestAspect : public Qt3DRender::QRenderAspect
+{
+public:
+ TestAspect(Qt3DCore::QNode *root)
+ : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
+ , m_jobManager(new Qt3DCore::QAspectJobManager())
+ {
+ Qt3DCore::QAbstractAspectPrivate::get(this)->m_jobManager = m_jobManager.data();
+ QRenderAspect::onRegistered();
+
+ const Qt3DCore::QNodeCreatedChangeGenerator generator(root);
+ const QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = generator.creationChanges();
+
+ for (const Qt3DCore::QNodeCreatedChangeBasePtr change : creationChanges)
+ d_func()->createBackendNode(change);
+ }
+
+ ~TestAspect()
+ {
+ QRenderAspect::onUnregistered();
+ }
+
+ Qt3DRender::Render::NodeManagers *nodeManagers() const
+ {
+ return d_func()->m_renderer->nodeManagers();
+ }
+
+ void initializeRenderer()
+ {
+ d_func()->m_renderer->initialize();
+ }
+
+ Render::MaterialParameterGathererJobPtr materialGathererJob() const
+ {
+ Render::MaterialParameterGathererJobPtr job = Render::MaterialParameterGathererJobPtr::create();
+ job->setNodeManagers(nodeManagers());
+ job->setRenderer(static_cast<Render::Renderer *>(d_func()->m_renderer));
+ return job;
+ }
+
+ void onRegistered() { QRenderAspect::onRegistered(); }
+ void onUnregistered() { QRenderAspect::onUnregistered(); }
+
+private:
+ QScopedPointer<Qt3DCore::QAspectJobManager> m_jobManager;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+namespace {
+
+class TestMaterial : public Qt3DRender::QMaterial
+{
+ Q_OBJECT
+public:
+ explicit TestMaterial(Qt3DCore::QNode *parent = nullptr)
+ : Qt3DRender::QMaterial(parent)
+ , m_effect(new Qt3DRender::QEffect())
+ , m_gl3Technique(new Qt3DRender::QTechnique())
+ , m_gl2Technique(new Qt3DRender::QTechnique())
+ , m_es2Technique(new Qt3DRender::QTechnique())
+ , m_gl3Pass(new Qt3DRender::QRenderPass())
+ , m_gl2Pass(new Qt3DRender::QRenderPass())
+ , m_es2Pass(new Qt3DRender::QRenderPass())
+ , m_gl3Program(new Qt3DRender::QShaderProgram())
+ , m_gl2es2Program(new Qt3DRender::QShaderProgram())
+ {
+ m_gl3Pass->setShaderProgram(m_gl3Program);
+ m_gl2Pass->setShaderProgram(m_gl2es2Program);
+ m_es2Pass->setShaderProgram(m_gl2es2Program);
+
+ m_gl3Technique->addRenderPass(m_gl3Pass);
+ m_gl2Technique->addRenderPass(m_gl2Pass);
+ m_es2Technique->addRenderPass(m_es2Pass);
+
+ m_effect->addTechnique(m_gl3Technique);
+ m_effect->addTechnique(m_gl2Technique);
+ m_effect->addTechnique(m_es2Technique);
+
+ setEffect(m_effect);
+ }
+
+ Qt3DRender::QTechnique *gl3Technique() const { return m_gl3Technique; }
+ Qt3DRender::QTechnique *gl2Technique() const { return m_gl2Technique; }
+ Qt3DRender::QTechnique *es2Technique() const { return m_es2Technique; }
+
+ Qt3DRender::QRenderPass *gl3Pass() const { return m_gl3Pass; }
+ Qt3DRender::QRenderPass *gl2Pass() const { return m_gl2Pass; }
+ Qt3DRender::QRenderPass *es2Pass() const { return m_es2Pass; }
+
+ Qt3DRender::QShaderProgram *gl3Shader() const { return m_gl3Program; }
+ Qt3DRender::QShaderProgram *gl2shader() const { return m_gl2es2Program; }
+ Qt3DRender::QShaderProgram *es2Shader() const { return m_gl2es2Program; }
+
+private:
+ Qt3DRender::QEffect *m_effect;
+ Qt3DRender::QTechnique *m_gl3Technique;
+ Qt3DRender::QTechnique *m_gl2Technique;
+ Qt3DRender::QTechnique *m_es2Technique;
+ Qt3DRender::QRenderPass *m_gl3Pass;
+ Qt3DRender::QRenderPass *m_gl2Pass;
+ Qt3DRender::QRenderPass *m_es2Pass;
+ Qt3DRender::QShaderProgram *m_gl3Program;
+ Qt3DRender::QShaderProgram *m_gl2es2Program;
+};
+
+Qt3DRender::QViewport *viewportFrameGraph()
+{
+ Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport();
+ return viewport;
+}
+
+Qt3DRender::QTechniqueFilter *techniqueFilterFrameGraph()
+{
+ Qt3DRender::QTechniqueFilter *techniqueFilter = new Qt3DRender::QTechniqueFilter();
+ return techniqueFilter;
+}
+
+Qt3DRender::QRenderPassFilter *renderPassFilter()
+{
+ Qt3DRender::QRenderPassFilter *passFilter = new Qt3DRender::QRenderPassFilter();
+ return passFilter;
+}
+
+Qt3DCore::QEntity *buildScene(Qt3DRender::QFrameGraphNode *frameGraph, Qt3DRender::QMaterial *material = nullptr)
+{
+ Qt3DCore::QEntity *root = new Qt3DCore::QEntity();
+
+ // FrameGraph
+ Qt3DRender::QRenderSettings* renderSettings = new Qt3DRender::QRenderSettings();
+ renderSettings->setActiveFrameGraph(frameGraph);
+ root->addComponent(renderSettings);
+
+ // Scene
+ for (int i = 0; i < 10; i++) {
+ Qt3DCore::QEntity *e = new Qt3DCore::QEntity();
+ if (material != nullptr)
+ e->addComponent(material);
+ e->setParent(root);
+ }
+
+ return root;
+}
+
+} // anonymous
+
+class tst_MaterialParameterGatherer : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void checkRunNoHandlesNoTechniqueFilterNoPassFilter()
+ {
+ // GIVEN
+ Qt3DCore::QEntity *sceneRoot = buildScene(viewportFrameGraph());
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 0);
+
+ // WHEN
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 0);
+ }
+
+ void checkRunSelectAllNoTechniqueFilterNoPassFilter()
+ {
+ // GIVEN
+ TestMaterial material;
+ Qt3DCore::QEntity *sceneRoot = buildScene(viewportFrameGraph(), &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 1);
+ }
+
+ void checkRunDisabledMaterial()
+ {
+ // GIVEN
+ TestMaterial material;
+ material.setEnabled(false);
+ Qt3DCore::QEntity *sceneRoot = buildScene(viewportFrameGraph(), &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 0);
+ }
+
+ void checkRunSelectAllTechniqueFilterWithNoFilterNoPassFilter()
+ {
+ // GIVEN
+ Qt3DRender::QTechniqueFilter *frameGraphFilter = techniqueFilterFrameGraph();
+
+ TestMaterial material;
+
+ Qt3DRender::QFilterKey techniqueFilterKey;
+ techniqueFilterKey.setName(QStringLiteral("renderingStyle"));
+ techniqueFilterKey.setValue(QVariant(QStringLiteral("backward")));
+
+ material.gl2Technique()->addFilterKey(&techniqueFilterKey);
+ material.gl3Technique()->addFilterKey(&techniqueFilterKey);
+ material.es2Technique()->addFilterKey(&techniqueFilterKey);
+
+ Qt3DCore::QEntity *sceneRoot = buildScene(frameGraphFilter, &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+ Qt3DRender::Render::TechniqueFilter *backendTechniqueFilter = static_cast<Qt3DRender::Render::TechniqueFilter *>(testAspect.nodeManagers()->frameGraphManager()->lookupNode(frameGraphFilter->id()));
+ QVERIFY(backendTechniqueFilter != nullptr);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->setTechniqueFilter(backendTechniqueFilter);
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 1);
+ }
+
+ void checkRunSelectAllTechniqueFilterWithIncompatibleFilterNoPassFilter()
+ {
+ // GIVEN
+ Qt3DRender::QTechniqueFilter *frameGraphFilter = techniqueFilterFrameGraph();
+ TestMaterial material;
+
+ Qt3DRender::QFilterKey techniqueFilterFilterKey;
+ techniqueFilterFilterKey.setName(QStringLiteral("renderingStyle"));
+ techniqueFilterFilterKey.setValue(QVariant(QStringLiteral("forward")));
+
+ Qt3DRender::QFilterKey techniqueFilterKey;
+ techniqueFilterKey.setName(QStringLiteral("renderingStyle"));
+ techniqueFilterKey.setValue(QVariant(QStringLiteral("backward")));
+
+ frameGraphFilter->addMatch(&techniqueFilterFilterKey);
+
+ material.gl2Technique()->addFilterKey(&techniqueFilterKey);
+ material.gl3Technique()->addFilterKey(&techniqueFilterKey);
+ material.es2Technique()->addFilterKey(&techniqueFilterKey);
+
+ Qt3DCore::QEntity *sceneRoot = buildScene(frameGraphFilter, &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+ Qt3DRender::Render::TechniqueFilter *backendTechniqueFilter = static_cast<Qt3DRender::Render::TechniqueFilter *>(testAspect.nodeManagers()->frameGraphManager()->lookupNode(frameGraphFilter->id()));
+ QVERIFY(backendTechniqueFilter != nullptr);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->setTechniqueFilter(backendTechniqueFilter);
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 0);
+ }
+
+ void checkRunSelectAllTechniqueFilterWithCompatibleFilterNoPassFilter()
+ {
+ // GIVEN
+ Qt3DRender::QTechniqueFilter *frameGraphFilter = techniqueFilterFrameGraph();
+ TestMaterial material;
+
+ Qt3DRender::QFilterKey techniqueFilterKey;
+ techniqueFilterKey.setName(QStringLiteral("renderingStyle"));
+ techniqueFilterKey.setValue(QVariant(QStringLiteral("backward")));
+
+ frameGraphFilter->addMatch(&techniqueFilterKey);
+
+ material.gl2Technique()->addFilterKey(&techniqueFilterKey);
+ material.gl3Technique()->addFilterKey(&techniqueFilterKey);
+ material.es2Technique()->addFilterKey(&techniqueFilterKey);
+
+ Qt3DCore::QEntity *sceneRoot = buildScene(frameGraphFilter, &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+ Qt3DRender::Render::TechniqueFilter *backendTechniqueFilter = static_cast<Qt3DRender::Render::TechniqueFilter *>(testAspect.nodeManagers()->frameGraphManager()->lookupNode(frameGraphFilter->id()));
+ QVERIFY(backendTechniqueFilter != nullptr);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->setTechniqueFilter(backendTechniqueFilter);
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 1);
+ }
+
+ void checkRunSelectAllNoTechniqueFilterPassFilterWithNoFilter()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPassFilter *frameGraphFilter = renderPassFilter();
+ TestMaterial material;
+
+ Qt3DRender::QFilterKey passFilterKey;
+ passFilterKey.setName(QStringLiteral("renderingStyle"));
+ passFilterKey.setValue(QVariant(QStringLiteral("backward")));
+
+ material.gl3Pass()->addFilterKey(&passFilterKey);
+ material.gl2Pass()->addFilterKey(&passFilterKey);
+ material.es2Pass()->addFilterKey(&passFilterKey);
+
+ Qt3DCore::QEntity *sceneRoot = buildScene(frameGraphFilter, &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+ Qt3DRender::Render::RenderPassFilter *backendPassFilter = static_cast<Qt3DRender::Render::RenderPassFilter *>(testAspect.nodeManagers()->frameGraphManager()->lookupNode(frameGraphFilter->id()));
+ QVERIFY(backendPassFilter != nullptr);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->setRenderPassFilter(backendPassFilter);
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 1);
+ }
+
+ void checkRunSelectAllNoTechniqueFilterPassFilterWithIncompatibleFilter()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPassFilter *frameGraphFilter = renderPassFilter();
+ TestMaterial material;
+
+ Qt3DRender::QFilterKey passFilterFilterKey;
+ passFilterFilterKey.setName(QStringLiteral("renderingStyle"));
+ passFilterFilterKey.setValue(QVariant(QStringLiteral("forward")));
+
+ Qt3DRender::QFilterKey passFilterKey;
+ passFilterKey.setName(QStringLiteral("renderingStyle"));
+ passFilterKey.setValue(QVariant(QStringLiteral("backward")));
+
+ frameGraphFilter->addMatch(&passFilterFilterKey);
+
+ material.gl3Pass()->addFilterKey(&passFilterKey);
+ material.gl2Pass()->addFilterKey(&passFilterKey);
+ material.es2Pass()->addFilterKey(&passFilterKey);
+
+ Qt3DCore::QEntity *sceneRoot = buildScene(frameGraphFilter, &material);
+ Qt3DRender::TestAspect testAspect(sceneRoot);
+ Qt3DRender::Render::MaterialParameterGathererJobPtr gatherer = testAspect.materialGathererJob();
+
+ testAspect.initializeRenderer();
+
+ // THEN
+ QCOMPARE(testAspect.nodeManagers()->materialManager()->activeHandles().size(), 1);
+ Qt3DRender::Render::RenderPassFilter *backendPassFilter = static_cast<Qt3DRender::Render::RenderPassFilter *>(testAspect.nodeManagers()->frameGraphManager()->lookupNode(frameGraphFilter->id()));
+ QVERIFY(backendPassFilter != nullptr);
+
+ // WHEN
+ gatherer->setHandles(testAspect.nodeManagers()->materialManager()->activeHandles());
+ gatherer->setRenderPassFilter(backendPassFilter);
+ gatherer->run();
+
+ // THEN
+ QCOMPARE(gatherer->materialToPassAndParameter().size(), 0);
+ }
+};
+
+QTEST_MAIN(tst_MaterialParameterGatherer)
+
+#include "tst_materialparametergathererjob.moc"
diff --git a/tests/auto/render/parameter/parameter.pro b/tests/auto/render/parameter/parameter.pro
new file mode 100644
index 000000000..8a0ad9dc1
--- /dev/null
+++ b/tests/auto/render/parameter/parameter.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_parameter
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_parameter.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/parameter/tst_parameter.cpp b/tests/auto/render/parameter/tst_parameter.cpp
new file mode 100644
index 000000000..0043adc86
--- /dev/null
+++ b/tests/auto/render/parameter/tst_parameter.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/private/qparameter_p.h>
+#include <Qt3DRender/private/parameter_p.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/private/stringtoint_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_Parameter : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Parameter backendParameter;
+
+ // THEN
+ QCOMPARE(backendParameter.isEnabled(), false);
+ QVERIFY(backendParameter.peerId().isNull());
+ QCOMPARE(backendParameter.name(), QString());
+ QCOMPARE(backendParameter.uniformValue(), Qt3DRender::Render::UniformValue());
+ QCOMPARE(backendParameter.nameId(), -1);
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Parameter backendParameter;
+ Qt3DRender::QParameter parameter;
+ parameter.setName(QStringLiteral("Cutlass"));
+ parameter.setValue(QVariant(QColor(Qt::blue)));
+
+ // WHEN
+ simulateInitialization(&parameter, &backendParameter);
+ backendParameter.cleanup();
+
+ // THEN
+ QCOMPARE(backendParameter.isEnabled(), false);
+ QCOMPARE(backendParameter.name(), QString());
+ QCOMPARE(backendParameter.uniformValue(), Qt3DRender::Render::UniformValue());
+ QCOMPARE(backendParameter.nameId(), -1);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QParameter parameter;
+
+ parameter.setName(QStringLiteral("Chevelle"));
+ parameter.setValue(QVariant(383.0f));
+
+ {
+ // WHEN
+ Qt3DRender::Render::Parameter backendParameter;
+ simulateInitialization(&parameter, &backendParameter);
+
+ // THEN
+ QCOMPARE(backendParameter.isEnabled(), true);
+ QCOMPARE(backendParameter.peerId(), parameter.id());
+ QCOMPARE(backendParameter.name(), QStringLiteral("Chevelle"));
+ QCOMPARE(backendParameter.uniformValue(), Qt3DRender::Render::UniformValue::fromVariant(parameter.value()));
+ QCOMPARE(backendParameter.nameId(), Qt3DRender::Render::StringToInt::lookupId(QStringLiteral("Chevelle")));
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::Parameter backendParameter;
+ parameter.setEnabled(false);
+ simulateInitialization(&parameter, &backendParameter);
+
+ // THEN
+ QCOMPARE(backendParameter.peerId(), parameter.id());
+ QCOMPARE(backendParameter.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::Parameter backendParameter;
+ TestRenderer renderer;
+ backendParameter.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendParameter.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendParameter.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const QString newValue = QStringLiteral("C7");
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("name");
+ change->setValue(QVariant::fromValue(newValue));
+ backendParameter.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendParameter.name(), newValue);
+ QCOMPARE(backendParameter.nameId(), Qt3DRender::Render::StringToInt::lookupId(newValue));
+ }
+ {
+ // WHEN
+ const QVariant value = QVariant::fromValue(QVector3D(350.0f, 427.0f, 454.0f));
+ const Qt3DRender::Render::UniformValue newValue = Qt3DRender::Render::UniformValue::fromVariant(value);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("value");
+ change->setValue(value);
+ backendParameter.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendParameter.uniformValue(), newValue);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_Parameter)
+
+#include "tst_parameter.moc"
diff --git a/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.pro b/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.pro
new file mode 100644
index 000000000..f89ba0173
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.pro
@@ -0,0 +1,17 @@
+TEMPLATE = app
+
+TARGET = tst_pickboundingvolumejob
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_pickboundingvolumejob.cpp
+
+include(../commons/commons.pri)
+include(../../core/common/common.pri)
+include(../qmlscenereader/qmlscenereader.pri)
+# Extra dependencies to build test scenes needed by the tests
+QT += quick 3dquick 3dquick-private 3dextras 3dquickextras
+
+RESOURCES += \
+ pickboundingvolumejob.qrc
diff --git a/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc b/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc
new file mode 100644
index 000000000..fa356f353
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/pickboundingvolumejob.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>testscene_childentity.qml</file>
+ <file>testscene_dragdisabled.qml</file>
+ <file>testscene_dragenabled.qml</file>
+ <file>testscene_improperframegraph.qml</file>
+ <file>testscene_dragenabledhoverenabled.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/render/pickboundingvolumejob/testscene_childentity.qml b/tests/auto/render/pickboundingvolumejob/testscene_childentity.qml
new file mode 100644
index 000000000..7376b53e5
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/testscene_childentity.qml
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 600
+ height: 600
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+ PhongMaterial { id: material }
+
+ // Parent Entity
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker"
+ dragEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+
+ // Child Entity
+ Entity {
+ property Transform transform: Transform {
+ translation: Qt.vector3d(-5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, transform]
+ }
+ }
+
+}
diff --git a/tests/auto/render/pickboundingvolumejob/testscene_dragdisabled.qml b/tests/auto/render/pickboundingvolumejob/testscene_dragdisabled.qml
new file mode 100644
index 000000000..9b7f973a9
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/testscene_dragdisabled.qml
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 600
+ height: 600
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+ PhongMaterial { id: material }
+
+ // Entity 1
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker1"
+ dragEnabled: false
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+
+ // Entity 2
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker2"
+ dragEnabled: false
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(-5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+}
diff --git a/tests/auto/render/pickboundingvolumejob/testscene_dragenabled.qml b/tests/auto/render/pickboundingvolumejob/testscene_dragenabled.qml
new file mode 100644
index 000000000..747b7e858
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/testscene_dragenabled.qml
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 600
+ height: 600
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+ PhongMaterial { id: material }
+
+ // Entity 1
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker1"
+ dragEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+
+ // Entity 2
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker2"
+ dragEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(-5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+}
diff --git a/examples/qt3d/deferred-renderer-cpp/gbuffer.cpp b/tests/auto/render/pickboundingvolumejob/testscene_dragenabledhoverenabled.qml
index 984dbb1f2..f80726068 100644
--- a/examples/qt3d/deferred-renderer-cpp/gbuffer.cpp
+++ b/tests/auto/render/pickboundingvolumejob/testscene_dragenabledhoverenabled.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -48,59 +48,86 @@
**
****************************************************************************/
-#include "gbuffer.h"
-
-GBuffer::GBuffer(Qt3DCore::QNode *parent)
- : Qt3DRender::QRenderTarget(parent)
-{
- const Qt3DRender::QAbstractTexture::TextureFormat formats[AttachmentsCount] = {
- Qt3DRender::QAbstractTexture::RGBA32F,
- Qt3DRender::QAbstractTexture::RGB32F,
- Qt3DRender::QAbstractTexture::RGB16F,
- Qt3DRender::QAbstractTexture::D32F
- };
-
- const Qt3DRender::QRenderTargetOutput::AttachmentPoint attachmentPoints[AttachmentsCount] = {
- Qt3DRender::QRenderTargetOutput::Color0,
- Qt3DRender::QRenderTargetOutput::Color1,
- Qt3DRender::QRenderTargetOutput::Color2,
- Qt3DRender::QRenderTargetOutput::Depth
- };
-
- for (int i = 0; i < AttachmentsCount; i++) {
- Qt3DRender::QRenderTargetOutput *output = new Qt3DRender::QRenderTargetOutput(this);
-
- m_textures[i] = new Qt3DRender::QTexture2D();
- m_textures[i]->setFormat(formats[i]);
- m_textures[i]->setWidth(1024);
- m_textures[i]->setHeight(1024);
- m_textures[i]->setGenerateMipMaps(false);
- m_textures[i]->setWrapMode(Qt3DRender::QTextureWrapMode(Qt3DRender::QTextureWrapMode::ClampToEdge));
- m_textures[i]->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear);
- m_textures[i]->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear);
-
- output->setTexture(m_textures[i]);
- output->setAttachmentPoint(attachmentPoints[i]);
- addOutput(output);
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 600
+ height: 600
+ visible: true
}
-}
-Qt3DRender::QAbstractTexture *GBuffer::colorTexture() const
-{
- return m_textures[Color];
-}
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
-Qt3DRender::QAbstractTexture *GBuffer::positionTexture() const
-{
- return m_textures[Position];
-}
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
-Qt3DRender::QAbstractTexture *GBuffer::normalTexture() const
-{
- return m_textures[Normal];
-}
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
-Qt3DRender::QAbstractTexture *GBuffer::depthTexture() const
-{
- return m_textures[Depth];
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+ PhongMaterial { id: material }
+
+ // Entity 1
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker1"
+ dragEnabled: true
+ hoverEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+
+ // Entity 2
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker2"
+ dragEnabled: true
+ hoverEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(-5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
}
diff --git a/tests/auto/render/pickboundingvolumejob/testscene_improperframegraph.qml b/tests/auto/render/pickboundingvolumejob/testscene_improperframegraph.qml
new file mode 100644
index 000000000..f0b88acba
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/testscene_improperframegraph.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+ }
+ }
+ ]
+
+ CuboidMesh { id: cubeMesh }
+ PhongMaterial { id: material }
+
+ // Entity 1
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker1"
+ dragEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+
+ // Entity 2
+ Entity {
+ property ObjectPicker picker: ObjectPicker {
+ objectName: "Picker2"
+ dragEnabled: true
+ }
+
+ property Transform transform: Transform {
+ translation: Qt.vector3d(-5, 0, 0)
+ scale: 2.0
+ }
+
+ components: [cubeMesh, material, picker, transform]
+ }
+}
diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
new file mode 100644
index 000000000..f9e177971
--- /dev/null
+++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
@@ -0,0 +1,985 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlscenereader.h"
+#include "testpostmanarbiter.h"
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qaspectjobmanager_p.h>
+#include <QtQuick/qquickwindow.h>
+
+#include <Qt3DRender/QCamera>
+#include <Qt3DRender/QObjectPicker>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DRender/private/pickboundingvolumejob_p.h>
+#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
+#include <Qt3DRender/private/updateworldboundingvolumejob_p.h>
+#include <Qt3DRender/private/updateworldtransformjob_p.h>
+#include <Qt3DRender/private/expandboundingvolumejob_p.h>
+#include <Qt3DRender/private/calcboundingvolumejob_p.h>
+#include <Qt3DRender/private/calcgeometrytrianglevolumes_p.h>
+#include <Qt3DRender/private/loadbufferjob_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class TestAspect : public Qt3DRender::QRenderAspect
+{
+public:
+ TestAspect(Qt3DCore::QNode *root)
+ : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
+ , m_sceneRoot(nullptr)
+ {
+ QRenderAspect::onRegistered();
+
+ const Qt3DCore::QNodeCreatedChangeGenerator generator(root);
+ const QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = generator.creationChanges();
+
+ d_func()->setRootAndCreateNodes(qobject_cast<Qt3DCore::QEntity *>(root), creationChanges);
+
+ Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(rootEntityId());
+ Q_ASSERT(rootEntity);
+ m_sceneRoot = rootEntity;
+ }
+
+ ~TestAspect()
+ {
+ QRenderAspect::onUnregistered();
+ }
+
+ void onRegistered() { QRenderAspect::onRegistered(); }
+ void onUnregistered() { QRenderAspect::onUnregistered(); }
+
+ Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); }
+ Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
+ Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
+ Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
+
+private:
+ Render::Entity *m_sceneRoot;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+namespace {
+
+void runRequiredJobs(Qt3DRender::TestAspect *test)
+{
+ Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform;
+ updateWorldTransform.setRoot(test->sceneRoot());
+ updateWorldTransform.run();
+
+ // For each buffer
+ QVector<Qt3DRender::Render::HBuffer> bufferHandles = test->nodeManagers()->bufferManager()->activeHandles();
+ for (auto bufferHandle : bufferHandles) {
+ Qt3DRender::Render::LoadBufferJob loadBuffer(bufferHandle);
+ loadBuffer.setNodeManager(test->nodeManagers());
+ loadBuffer.run();
+ }
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
+ calcBVolume.setManagers(test->nodeManagers());
+ calcBVolume.setRoot(test->sceneRoot());
+ calcBVolume.run();
+
+ Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
+ updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager());
+ updateWorldBVolume.run();
+
+ Qt3DRender::Render::ExpandBoundingVolumeJob expandBVolume;
+ expandBVolume.setRoot(test->sceneRoot());
+ expandBVolume.run();
+
+ Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList;
+ updateTriangleList.setManagers(test->nodeManagers());
+ updateTriangleList.run();
+
+ // For each geometry id
+ QVector<Qt3DRender::Render::HGeometryRenderer> geometryRenderHandles = test->nodeManagers()->geometryRendererManager()->activeHandles();
+ for (auto geometryRenderHandle : geometryRenderHandles) {
+ Qt3DCore::QNodeId geometryRendererId = test->nodeManagers()->geometryRendererManager()->data(geometryRenderHandle)->peerId();
+ Qt3DRender::Render::CalcGeometryTriangleVolumes calcGeometryTriangles(geometryRendererId, test->nodeManagers());
+ calcGeometryTriangles.run();
+ }
+}
+
+void initializePickBoundingVolumeJob(Qt3DRender::Render::PickBoundingVolumeJob *job, Qt3DRender::TestAspect *test)
+{
+ job->setFrameGraphRoot(test->frameGraphRoot());
+ job->setRoot(test->sceneRoot());
+ job->setManagers(test->nodeManagers());
+ job->setRenderSettings(test->renderSettings());
+}
+
+} // anonymous
+
+class tst_PickBoundingVolumeJob : public QObject
+{
+ Q_OBJECT
+private:
+ void generateAllPickingSettingsCombinations()
+ {
+ QTest::addColumn<Qt3DRender::QPickingSettings::PickMethod>("pickMethod");
+ QTest::addColumn<Qt3DRender::QPickingSettings::PickResultMode>("pickResultMode");
+ QTest::addColumn<Qt3DRender::QPickingSettings::FaceOrientationPickingMode>("faceOrientationPickingMode");
+
+ QTest::newRow("volume, nearest, front") << Qt3DRender::QPickingSettings::BoundingVolumePicking
+ << Qt3DRender::QPickingSettings::NearestPick
+ << Qt3DRender::QPickingSettings::FrontFace;
+
+ QTest::newRow("volume, nearest, back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
+ << Qt3DRender::QPickingSettings::NearestPick
+ << Qt3DRender::QPickingSettings::BackFace;
+
+ QTest::newRow("volume, nearest, front+back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
+ << Qt3DRender::QPickingSettings::NearestPick
+ << Qt3DRender::QPickingSettings::FrontAndBackFace;
+
+ QTest::newRow("volume, all, front") << Qt3DRender::QPickingSettings::BoundingVolumePicking
+ << Qt3DRender::QPickingSettings::AllPicks
+ << Qt3DRender::QPickingSettings::FrontFace;
+
+ QTest::newRow("volume, all, back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
+ << Qt3DRender::QPickingSettings::AllPicks
+ << Qt3DRender::QPickingSettings::BackFace;
+
+ QTest::newRow("volume, all, front+back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
+ << Qt3DRender::QPickingSettings::AllPicks
+ << Qt3DRender::QPickingSettings::FrontAndBackFace;
+
+ QTest::newRow("triangle, nearest, front") << Qt3DRender::QPickingSettings::TrianglePicking
+ << Qt3DRender::QPickingSettings::NearestPick
+ << Qt3DRender::QPickingSettings::FrontFace;
+
+ QTest::newRow("triangle, nearest, back") << Qt3DRender::QPickingSettings::TrianglePicking
+ << Qt3DRender::QPickingSettings::NearestPick
+ << Qt3DRender::QPickingSettings::BackFace;
+
+ QTest::newRow("triangle, nearest, front+back") << Qt3DRender::QPickingSettings::TrianglePicking
+ << Qt3DRender::QPickingSettings::NearestPick
+ << Qt3DRender::QPickingSettings::FrontAndBackFace;
+
+ QTest::newRow("triangle, all, front") << Qt3DRender::QPickingSettings::TrianglePicking
+ << Qt3DRender::QPickingSettings::AllPicks
+ << Qt3DRender::QPickingSettings::FrontFace;
+
+ QTest::newRow("triangle, all, back") << Qt3DRender::QPickingSettings::TrianglePicking
+ << Qt3DRender::QPickingSettings::AllPicks
+ << Qt3DRender::QPickingSettings::BackFace;
+
+ QTest::newRow("triangle, all, front+back") << Qt3DRender::QPickingSettings::TrianglePicking
+ << Qt3DRender::QPickingSettings::AllPicks
+ << Qt3DRender::QPickingSettings::FrontAndBackFace;
+ }
+
+private Q_SLOTS:
+
+ void viewportCameraAreaGather()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // THEN
+ QVERIFY(test->frameGraphRoot() != nullptr);
+ Qt3DRender::QCamera *camera = root->findChild<Qt3DRender::QCamera *>();
+ QVERIFY(camera != nullptr);
+ QQuickWindow *window = root->findChild<QQuickWindow *>();
+ QVERIFY(camera != nullptr);
+ QCOMPARE(window->size(), QSize(600, 600));
+
+ // WHEN
+ Qt3DRender::Render::PickingUtils::ViewportCameraAreaGatherer gatherer;
+ QVector<Qt3DRender::Render::PickingUtils::ViewportCameraAreaTriplet> results = gatherer.gather(test->frameGraphRoot());
+
+ // THEN
+ QCOMPARE(results.size(), 1);
+ auto vca = results.first();
+ QCOMPARE(vca.area, QSize(600, 600));
+ QCOMPARE(vca.cameraId, camera->id());
+ QCOMPARE(vca.viewport, QRectF(0.0f, 0.0f, 1.0f, 1.0f));
+ }
+
+ void entityGatherer()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // THEN
+ QList<Qt3DCore::QEntity *> frontendEntities;
+ frontendEntities << qobject_cast<Qt3DCore::QEntity *>(root.data()) << root->findChildren<Qt3DCore::QEntity *>();
+ QCOMPARE(frontendEntities.size(), 4);
+
+ // WHEN
+ Qt3DRender::Render::PickingUtils::EntityGatherer gatherer(test->nodeManagers()->lookupResource<Qt3DRender::Render::Entity, Qt3DRender::Render::EntityManager>(root->id()));
+ QVector<Qt3DRender::Render::Entity *> entities = gatherer.entities();
+
+ // THEN
+ QCOMPARE(frontendEntities.size(), entities.size());
+
+ std::sort(frontendEntities.begin(), frontendEntities.end(),
+ [] (Qt3DCore::QEntity *a, Qt3DCore::QEntity *b) { return a->id() > b->id(); });
+
+ std::sort(entities.begin(), entities.end(),
+ [] (Qt3DRender::Render::Entity *a, Qt3DRender::Render::Entity *b) { return a->peerId() > b->peerId(); });
+
+ for (int i = 0, e = frontendEntities.size(); i < e; ++i)
+ QCOMPARE(frontendEntities.at(i)->id(), entities.at(i)->peerId());
+ }
+
+ void checkCurrentPickerChange_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkCurrentPickerChange()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ Qt3DRender::QObjectPicker *picker1 = nullptr;
+ Qt3DRender::QObjectPicker *picker2 = nullptr;
+
+ if (pickers.first()->objectName() == QLatin1String("Picker1")) {
+ picker1 = pickers.first();
+ picker2 = pickers.last();
+ } else {
+ picker1 = pickers.last();
+ picker2 = pickers.first();
+ }
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ // THEN
+ QVERIFY(pickBVJob.currentPicker().isNull());
+
+ // WHEN
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!earlyReturn);
+ QVERIFY(!pickBVJob.currentPicker().isNull());
+ Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->data<Qt3DRender::Render::ObjectPicker, Qt3DRender::Render::ObjectPickerManager>(pickBVJob.currentPicker());
+ QVERIFY(backendPicker != nullptr);
+ QCOMPARE(backendPicker->peerId(), picker1->id());
+
+ // WHEN
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!earlyReturn);
+ QVERIFY(pickBVJob.currentPicker().isNull());
+
+ // WHEN
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(390.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!earlyReturn);
+ QVERIFY(!pickBVJob.currentPicker().isNull());
+ backendPicker = test->nodeManagers()->data<Qt3DRender::Render::ObjectPicker, Qt3DRender::Render::ObjectPickerManager>(pickBVJob.currentPicker());
+ QVERIFY(backendPicker != nullptr);
+ QCOMPARE(backendPicker->peerId(), picker2->id());
+
+ // WHEN
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(390.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!earlyReturn);
+ QVERIFY(pickBVJob.currentPicker().isNull());
+ }
+
+ void checkEarlyReturnWhenNoMouseEvents_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkEarlyReturnWhenNoMouseEvents()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ // THEN
+ QVERIFY(pickBVJob.currentPicker().isNull());
+
+ // WHEN
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(earlyReturn);
+
+ // WHEN
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 440.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!earlyReturn);
+ }
+
+ void checkEarlyReturnWhenMoveEventsAndNoCurrentPickers_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkEarlyReturnWhenMoveEventsAndNoCurrentPickers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+
+ // THEN
+ QVERIFY(pickBVJob.currentPicker().isNull());
+
+ // WHEN
+ const bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(earlyReturn);
+ }
+
+ void checkEarlyReturnWhenMoveEventsAndDragDisabledPickers_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkEarlyReturnWhenMoveEventsAndDragDisabledPickers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragdisabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!pickBVJob.currentPicker().isNull());
+ QVERIFY(!earlyReturn);
+
+ // WHEN
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(earlyReturn);
+ }
+
+ void checkNoEarlyReturnWhenMoveEventsAndDragEnabledPickers_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkNoEarlyReturnWhenMoveEventsAndDragEnabledPickers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!pickBVJob.currentPicker().isNull());
+ QVERIFY(!earlyReturn);
+
+ // WHEN
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(!earlyReturn);
+ }
+
+ void checkEarlyReturnWhenNoProperFrameGraph_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkEarlyReturnWhenNoProperFrameGraph()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_improperframegraph.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ const bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN
+ QVERIFY(pickBVJob.currentPicker().isNull());
+ QVERIFY(earlyReturn);
+ }
+
+ void checkDispatchMouseEvent_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkDispatchMouseEvent()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ TestArbiter arbiter;
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ Qt3DRender::QObjectPicker *picker1 = nullptr;
+ if (pickers.first()->objectName() == QLatin1String("Picker1"))
+ picker1 = pickers.first();
+ else
+ picker1 = pickers.last();
+
+ Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(picker1->id());
+ QVERIFY(backendPicker1);
+ Qt3DCore::QBackendNodePrivate::get(backendPicker1)->setArbiter(&arbiter);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN -> Pressed on object
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Pressed
+ QVERIFY(!earlyReturn);
+ QVERIFY(backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pressed");
+
+ arbiter.events.clear();
+
+ // WHEN -> Move on same object
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Moved
+ QVERIFY(!earlyReturn);
+ QVERIFY(backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "moved");
+
+ arbiter.events.clear();
+
+ // WHEN -> Release on object
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Released + Clicked
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 2);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "clicked");
+ change = arbiter.events.last().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "released");
+
+ arbiter.events.clear();
+
+ // WHEN -> Release outside of object
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Released
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 2);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pressed");
+ change = arbiter.events.last().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "released");
+
+ arbiter.events.clear();
+ }
+
+ void checkDispatchHoverEvent_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void checkDispatchHoverEvent()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabledhoverenabled.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ TestArbiter arbiter;
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 2);
+
+ Qt3DRender::QObjectPicker *picker1 = nullptr;
+ if (pickers.first()->objectName() == QLatin1String("Picker1"))
+ picker1 = pickers.first();
+ else
+ picker1 = pickers.last();
+
+ Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(picker1->id());
+ QVERIFY(backendPicker1);
+ Qt3DCore::QBackendNodePrivate::get(backendPicker1)->setArbiter(&arbiter);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN -> Hover on object
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::HoverMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Entered
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "entered");
+
+ arbiter.events.clear();
+
+ // WHEN -> HoverMove Out
+ events.clear();
+ events.push_back(QMouseEvent(QEvent::HoverMove, QPointF(20.0f, 40.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN - Exited
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "exited");
+
+ arbiter.events.clear();
+
+ // WHEN -> HoverMove In + Pressed other
+ events.clear();
+ events.push_back(QMouseEvent(QEvent::HoverMove, QPointF(207.0f, 303.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back(QMouseEvent(QEvent::MouseButtonPress, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN - Entered, Exited
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker1->isPressed());
+ QCOMPARE(arbiter.events.count(), 2);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "entered");
+ change = arbiter.events.last().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "exited");
+
+ arbiter.events.clear();
+ }
+
+ void shouldDispatchMouseEventFromChildren_data()
+ {
+ generateAllPickingSettingsCombinations();
+ }
+
+ void shouldDispatchMouseEventFromChildren()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/testscene_childentity.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+
+ QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
+ QCOMPARE(renderSettings.size(), 1);
+ Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
+
+ QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
+ QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
+ QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
+ settings->setPickMethod(pickMethod);
+ settings->setPickResultMode(pickResultMode);
+ settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
+
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+ TestArbiter arbiter;
+
+ // Runs Required jobs
+ runRequiredJobs(test.data());
+
+ // THEN
+ QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
+ QCOMPARE(pickers.size(), 1);
+
+ Qt3DRender::QObjectPicker *picker = pickers.first();
+ QCOMPARE(pickers.first()->objectName(), QLatin1String("Picker"));
+
+ Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(picker->id());
+ QVERIFY(backendPicker);
+ Qt3DCore::QBackendNodePrivate::get(backendPicker)->setArbiter(&arbiter);
+
+ QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
+ QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
+ QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
+
+ // WHEN -> Pressed on object
+ Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
+ initializePickBoundingVolumeJob(&pickBVJob, test.data());
+
+ QList<QMouseEvent> events;
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ bool earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Pressed
+ QVERIFY(!earlyReturn);
+ QVERIFY(backendPicker->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pressed");
+
+ arbiter.events.clear();
+
+ // WHEN -> Move on same object
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseMove, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Moved
+ QVERIFY(!earlyReturn);
+ QVERIFY(backendPicker->isPressed());
+ QCOMPARE(arbiter.events.count(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "moved");
+
+ arbiter.events.clear();
+
+ // WHEN -> Release on object
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Released + Clicked
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker->isPressed());
+ QCOMPARE(arbiter.events.count(), 2);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "clicked");
+ change = arbiter.events.last().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "released");
+
+ arbiter.events.clear();
+
+ // WHEN -> Release outside of object
+ events.clear();
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0f, 300.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ events.push_back(QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0f, 0.0f), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier));
+ pickBVJob.setMouseEvents(events);
+ earlyReturn = !pickBVJob.runHelper();
+
+ // THEN -> Released
+ QVERIFY(!earlyReturn);
+ QVERIFY(!backendPicker->isPressed());
+ QCOMPARE(arbiter.events.count(), 2);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pressed");
+ change = arbiter.events.last().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "released");
+
+ arbiter.events.clear();
+ }
+};
+
+QTEST_MAIN(tst_PickBoundingVolumeJob)
+
+#include "tst_pickboundingvolumejob.moc"
diff --git a/tests/auto/render/qabstractlight/qabstractlight.pro b/tests/auto/render/qabstractlight/qabstractlight.pro
index 764681f1d..d71c0958f 100644
--- a/tests/auto/render/qabstractlight/qabstractlight.pro
+++ b/tests/auto/render/qabstractlight/qabstractlight.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qabstractlight.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qabstracttexture/qabstracttexture.pro b/tests/auto/render/qabstracttexture/qabstracttexture.pro
new file mode 100644
index 000000000..77f9bd3ff
--- /dev/null
+++ b/tests/auto/render/qabstracttexture/qabstracttexture.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qabstracttexture
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qabstracttexture.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qabstracttexture/tst_qabstracttexture.cpp b/tests/auto/render/qabstracttexture/tst_qabstracttexture.cpp
new file mode 100644
index 000000000..4047cc32d
--- /dev/null
+++ b/tests/auto/render/qabstracttexture/tst_qabstracttexture.cpp
@@ -0,0 +1,889 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qabstracttexture.h>
+#include <Qt3DRender/private/qabstracttexture_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DRender/qabstracttextureimage.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class FakeTexture : public Qt3DRender::QAbstractTexture
+{
+};
+
+class FakeTextureImage : public Qt3DRender::QAbstractTextureImage
+{
+protected:
+ Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const Q_DECL_OVERRIDE
+ {
+ return Qt3DRender::QTextureImageDataGeneratorPtr();
+ }
+};
+
+class tst_QAbstractTexture : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DRender::QAbstractTexture::TextureFormat>("TextureFormat");
+ qRegisterMetaType<Qt3DRender::QAbstractTexture::Filter>("Filter");
+ qRegisterMetaType<Qt3DRender::QAbstractTexture::ComparisonFunction>("ComparisonFunction");
+ qRegisterMetaType<Qt3DRender::QAbstractTexture::ComparisonMode>("ComparisonMode");
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ FakeTexture abstractTexture;
+
+ // THEN
+ QCOMPARE(abstractTexture.target(), Qt3DRender::QAbstractTexture::Target2D);
+ QCOMPARE(abstractTexture.format(), Qt3DRender::QAbstractTexture::Automatic);
+ QCOMPARE(abstractTexture.generateMipMaps(), false);
+ QCOMPARE(abstractTexture.wrapMode()->x(), Qt3DRender::QTextureWrapMode::ClampToEdge);
+ QCOMPARE(abstractTexture.wrapMode()->y(), Qt3DRender::QTextureWrapMode::ClampToEdge);
+ QCOMPARE(abstractTexture.wrapMode()->z(), Qt3DRender::QTextureWrapMode::ClampToEdge);
+ QCOMPARE(abstractTexture.status(), Qt3DRender::QAbstractTexture::None);
+ QCOMPARE(abstractTexture.width(), 1);
+ QCOMPARE(abstractTexture.height(), 1);
+ QCOMPARE(abstractTexture.depth(), 1);
+ QCOMPARE(abstractTexture.magnificationFilter(), Qt3DRender::QAbstractTexture::Nearest);
+ QCOMPARE(abstractTexture.minificationFilter(), Qt3DRender::QAbstractTexture::Nearest);
+ QCOMPARE(abstractTexture.maximumAnisotropy(), 1.0f);
+ QCOMPARE(abstractTexture.comparisonFunction(), Qt3DRender::QAbstractTexture::CompareLessEqual);
+ QCOMPARE(abstractTexture.comparisonMode(), Qt3DRender::QAbstractTexture::CompareNone);
+ QCOMPARE(abstractTexture.layers(), 1);
+ QCOMPARE(abstractTexture.samples(), 1);
+ QCOMPARE(abstractTexture.textureImages().size(), 0);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ FakeTexture abstractTexture;
+
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(formatChanged(TextureFormat)));
+ const Qt3DRender::QAbstractTexture::TextureFormat newValue = Qt3DRender::QAbstractTexture::R8I;
+ abstractTexture.setFormat(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.format(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setFormat(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.format(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(generateMipMapsChanged(bool)));
+ const bool newValue = true;
+ abstractTexture.setGenerateMipMaps(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.generateMipMaps(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setGenerateMipMaps(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.generateMipMaps(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(widthChanged(int)));
+ const int newValue = 383;
+ abstractTexture.setWidth(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.width(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setWidth(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.width(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(heightChanged(int)));
+ const int newValue = 427;
+ abstractTexture.setHeight(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.height(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setHeight(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.height(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(depthChanged(int)));
+ const int newValue = 454;
+ abstractTexture.setDepth(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.depth(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setDepth(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.depth(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(magnificationFilterChanged(Qt3DRender::QAbstractTexture::Filter)));
+ const Qt3DRender::QAbstractTexture::Filter newValue = Qt3DRender::QAbstractTexture::LinearMipMapLinear;
+ abstractTexture.setMagnificationFilter(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.magnificationFilter(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setMagnificationFilter(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.magnificationFilter(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(minificationFilterChanged(Filter)));
+ const Qt3DRender::QAbstractTexture::Filter newValue = Qt3DRender::QAbstractTexture::LinearMipMapNearest;
+ abstractTexture.setMinificationFilter(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.minificationFilter(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setMinificationFilter(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.minificationFilter(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(maximumAnisotropyChanged(float)));
+ const float newValue = 100.0f;
+ abstractTexture.setMaximumAnisotropy(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.maximumAnisotropy(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setMaximumAnisotropy(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.maximumAnisotropy(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(comparisonFunctionChanged(Qt3DRender::QAbstractTexture::ComparisonFunction)));
+ const Qt3DRender::QAbstractTexture::ComparisonFunction newValue = Qt3DRender::QAbstractTexture::CompareGreaterEqual;
+ abstractTexture.setComparisonFunction(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.comparisonFunction(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setComparisonFunction(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.comparisonFunction(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(comparisonModeChanged(Qt3DRender::QAbstractTexture::ComparisonMode)));
+ const Qt3DRender::QAbstractTexture::ComparisonMode newValue = Qt3DRender::QAbstractTexture::CompareRefToTexture;
+ abstractTexture.setComparisonMode(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.comparisonMode(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setComparisonMode(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.comparisonMode(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(layersChanged(int)));
+ const int newValue = 512;
+ abstractTexture.setLayers(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.layers(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setLayers(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.layers(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTexture, SIGNAL(samplesChanged(int)));
+ const int newValue = 1024;
+ abstractTexture.setSamples(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTexture.samples(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTexture.setSamples(newValue);
+
+ // THEN
+ QCOMPARE(abstractTexture.samples(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ FakeTexture abstractTexture;
+
+ abstractTexture.setFormat(Qt3DRender::QAbstractTexture::RG3B2);
+ abstractTexture.setGenerateMipMaps(true);
+ abstractTexture.setWidth(350);
+ abstractTexture.setHeight(383);
+ abstractTexture.setDepth(396);
+ abstractTexture.setMagnificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear);
+ abstractTexture.setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapNearest);
+ abstractTexture.setMaximumAnisotropy(12.0f);
+ abstractTexture.setComparisonFunction(Qt3DRender::QAbstractTexture::CommpareNotEqual);
+ abstractTexture.setComparisonMode(Qt3DRender::QAbstractTexture::CompareRefToTexture);
+ abstractTexture.setLayers(128);
+ abstractTexture.setSamples(256);
+ abstractTexture.setWrapMode(Qt3DRender::QTextureWrapMode(Qt3DRender::QTextureWrapMode::ClampToBorder));
+
+ FakeTextureImage image;
+ FakeTextureImage image2;
+ abstractTexture.addTextureImage(&image);
+ abstractTexture.addTextureImage(&image2);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&abstractTexture);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 3); // Texture + Images
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureData cloneData = creationChangeData->data;
+
+ QCOMPARE(abstractTexture.target(), cloneData.target);
+ QCOMPARE(abstractTexture.format(), cloneData.format);
+ QCOMPARE(abstractTexture.generateMipMaps(), cloneData.autoMipMap);
+ QCOMPARE(abstractTexture.wrapMode()->x(), cloneData.wrapModeX);
+ QCOMPARE(abstractTexture.wrapMode()->x(), cloneData.wrapModeY);
+ QCOMPARE(abstractTexture.wrapMode()->x(), cloneData.wrapModeZ);
+ QCOMPARE(abstractTexture.width(), cloneData.width);
+ QCOMPARE(abstractTexture.height(), cloneData.height);
+ QCOMPARE(abstractTexture.depth(), cloneData.depth);
+ QCOMPARE(abstractTexture.magnificationFilter(), cloneData.magFilter);
+ QCOMPARE(abstractTexture.minificationFilter(), cloneData.minFilter);
+ QCOMPARE(abstractTexture.maximumAnisotropy(), cloneData.maximumAnisotropy);
+ QCOMPARE(abstractTexture.comparisonFunction(), cloneData.comparisonFunction);
+ QCOMPARE(abstractTexture.comparisonMode(), cloneData.comparisonMode);
+ QCOMPARE(abstractTexture.layers(), cloneData.layers);
+ QCOMPARE(abstractTexture.samples(), cloneData.samples);
+ QCOMPARE(abstractTexture.textureImages().size(), cloneData.textureImageIds.size());
+
+ for (int i = 0, m = abstractTexture.textureImages().size(); i < m; ++i)
+ QCOMPARE(abstractTexture.textureImages().at(i)->id(), cloneData.textureImageIds.at(i));
+
+ QCOMPARE(abstractTexture.id(), creationChangeData->subjectId());
+ QCOMPARE(abstractTexture.isEnabled(), true);
+ QCOMPARE(abstractTexture.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(abstractTexture.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ abstractTexture.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&abstractTexture);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 3); // Texture + Images
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureData cloneData = creationChangeData->data;
+
+ QCOMPARE(abstractTexture.target(), cloneData.target);
+ QCOMPARE(abstractTexture.format(), cloneData.format);
+ QCOMPARE(abstractTexture.generateMipMaps(), cloneData.autoMipMap);
+ QCOMPARE(abstractTexture.wrapMode()->x(), cloneData.wrapModeX);
+ QCOMPARE(abstractTexture.wrapMode()->x(), cloneData.wrapModeY);
+ QCOMPARE(abstractTexture.wrapMode()->x(), cloneData.wrapModeZ);
+ QCOMPARE(abstractTexture.width(), cloneData.width);
+ QCOMPARE(abstractTexture.height(), cloneData.height);
+ QCOMPARE(abstractTexture.depth(), cloneData.depth);
+ QCOMPARE(abstractTexture.magnificationFilter(), cloneData.magFilter);
+ QCOMPARE(abstractTexture.minificationFilter(), cloneData.minFilter);
+ QCOMPARE(abstractTexture.maximumAnisotropy(), cloneData.maximumAnisotropy);
+ QCOMPARE(abstractTexture.comparisonFunction(), cloneData.comparisonFunction);
+ QCOMPARE(abstractTexture.comparisonMode(), cloneData.comparisonMode);
+ QCOMPARE(abstractTexture.layers(), cloneData.layers);
+ QCOMPARE(abstractTexture.samples(), cloneData.samples);
+ QCOMPARE(abstractTexture.textureImages().size(), cloneData.textureImageIds.size());
+
+ for (int i = 0, m = abstractTexture.textureImages().size(); i < m; ++i)
+ QCOMPARE(abstractTexture.textureImages().at(i)->id(), cloneData.textureImageIds.at(i));
+
+ QCOMPARE(abstractTexture.id(), creationChangeData->subjectId());
+ QCOMPARE(abstractTexture.isEnabled(), false);
+ QCOMPARE(abstractTexture.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(abstractTexture.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkFormatUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setFormat(Qt3DRender::QAbstractTexture::RG8_UNorm);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "format");
+ QCOMPARE(change->value().value<Qt3DRender::QAbstractTexture::TextureFormat>(), abstractTexture.format());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setFormat(Qt3DRender::QAbstractTexture::RG8_UNorm);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkGenerateMipMapsUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setGenerateMipMaps(true);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "generateMipMaps");
+ QCOMPARE(change->value().value<bool>(), abstractTexture.generateMipMaps());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setGenerateMipMaps(true);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkWidthUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setWidth(1024);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "width");
+ QCOMPARE(change->value().value<int>(), abstractTexture.width());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setWidth(1024);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkHeightUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setHeight(256);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "height");
+ QCOMPARE(change->value().value<int>(), abstractTexture.height());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setHeight(256);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkDepthUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setDepth(512);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "depth");
+ QCOMPARE(change->value().value<int>(), abstractTexture.depth());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setDepth(512);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMagnificationFilterUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setMagnificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "magnificationFilter");
+ QCOMPARE(change->value().value<Qt3DRender::QAbstractTexture::Filter>(), abstractTexture.magnificationFilter());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setMagnificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMinificationFilterUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "minificationFilter");
+ QCOMPARE(change->value().value<Qt3DRender::QAbstractTexture::Filter>(), abstractTexture.minificationFilter());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMaximumAnisotropyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setMaximumAnisotropy(327.0f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "maximumAnisotropy");
+ QCOMPARE(change->value().value<float>(), abstractTexture.maximumAnisotropy());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setMaximumAnisotropy(327.0f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkComparisonFunctionUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setComparisonFunction(Qt3DRender::QAbstractTexture::CompareAlways);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "comparisonFunction");
+ QCOMPARE(change->value().value<Qt3DRender::QAbstractTexture::ComparisonFunction>(), abstractTexture.comparisonFunction());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setComparisonFunction(Qt3DRender::QAbstractTexture::CompareAlways);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkComparisonModeUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setComparisonMode(Qt3DRender::QAbstractTexture::CompareRefToTexture);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "comparisonMode");
+ QCOMPARE(change->value().value<Qt3DRender::QAbstractTexture::ComparisonMode>(), abstractTexture.comparisonMode());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setComparisonMode(Qt3DRender::QAbstractTexture::CompareRefToTexture);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkLayersUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setLayers(64);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "layers");
+ QCOMPARE(change->value().value<int>(), abstractTexture.layers());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setLayers(64);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkSamplesUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.setSamples(16);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "samples");
+ QCOMPARE(change->value().value<int>(), abstractTexture.samples());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTexture.setSamples(16);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkTextureImageAdded()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ FakeTextureImage image;
+ abstractTexture.addTextureImage(&image);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.last().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+ QCOMPARE(change->propertyName(), "textureImage");
+ QCOMPARE(change->addedNodeId(), image.id());
+
+ arbiter.events.clear();
+ }
+ }
+
+ void checkTextureImageRemoved()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTexture abstractTexture;
+ FakeTextureImage image;
+ abstractTexture.addTextureImage(&image);
+ arbiter.setArbiterOnNode(&abstractTexture);
+
+ {
+ // WHEN
+ abstractTexture.removeTextureImage(&image);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.last().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+ QCOMPARE(change->propertyName(), "textureImage");
+ QCOMPARE(change->removedNodeId(), image.id());
+
+ arbiter.events.clear();
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_QAbstractTexture)
+
+#include "tst_qabstracttexture.moc"
diff --git a/tests/auto/render/qabstracttextureimage/qabstracttextureimage.pro b/tests/auto/render/qabstracttextureimage/qabstracttextureimage.pro
new file mode 100644
index 000000000..f494700e2
--- /dev/null
+++ b/tests/auto/render/qabstracttextureimage/qabstracttextureimage.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qabstracttextureimage
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qabstracttextureimage.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qabstracttextureimage/tst_qabstracttextureimage.cpp b/tests/auto/render/qabstracttextureimage/tst_qabstracttextureimage.cpp
new file mode 100644
index 000000000..5875cb9fc
--- /dev/null
+++ b/tests/auto/render/qabstracttextureimage/tst_qabstracttextureimage.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qabstracttextureimage.h>
+#include <Qt3DRender/private/qabstracttextureimage_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class FakeTextureImage : public Qt3DRender::QAbstractTextureImage
+{
+protected:
+ Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const Q_DECL_OVERRIDE
+ {
+ return Qt3DRender::QTextureImageDataGeneratorPtr();
+ }
+};
+
+class tst_QAbstractTextureImage : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DRender::QAbstractTexture::CubeMapFace>("QAbstractTexture::CubeMapFace");
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ FakeTextureImage abstractTextureImage;
+
+ // THEN
+ QCOMPARE(abstractTextureImage.mipLevel(), 0);
+ QCOMPARE(abstractTextureImage.layer(), 0);
+ QCOMPARE(abstractTextureImage.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ FakeTextureImage abstractTextureImage;
+
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTextureImage, SIGNAL(mipLevelChanged(int)));
+ const int newValue = 5;
+ abstractTextureImage.setMipLevel(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTextureImage.mipLevel(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTextureImage.setMipLevel(newValue);
+
+ // THEN
+ QCOMPARE(abstractTextureImage.mipLevel(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTextureImage, SIGNAL(layerChanged(int)));
+ const int newValue = 12;
+ abstractTextureImage.setLayer(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTextureImage.layer(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTextureImage.setLayer(newValue);
+
+ // THEN
+ QCOMPARE(abstractTextureImage.layer(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&abstractTextureImage, SIGNAL(faceChanged(Qt3DRender::QAbstractTexture::CubeMapFace)));
+ const Qt3DRender::QAbstractTexture::CubeMapFace newValue = Qt3DRender::QAbstractTexture::CubeMapNegativeZ;
+ abstractTextureImage.setFace(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(abstractTextureImage.face(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ abstractTextureImage.setFace(newValue);
+
+ // THEN
+ QCOMPARE(abstractTextureImage.face(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ FakeTextureImage abstractTextureImage;
+
+ abstractTextureImage.setMipLevel(32);
+ abstractTextureImage.setLayer(56);
+ abstractTextureImage.setFace(Qt3DRender::QAbstractTexture::CubeMapNegativeY);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&abstractTextureImage);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureImageData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureImageData cloneData = creationChangeData->data;
+
+ QCOMPARE(abstractTextureImage.mipLevel(), cloneData.mipLevel);
+ QCOMPARE(abstractTextureImage.layer(), cloneData.layer);
+ QCOMPARE(abstractTextureImage.face(), cloneData.face);
+ QCOMPARE(abstractTextureImage.id(), creationChangeData->subjectId());
+ QCOMPARE(abstractTextureImage.isEnabled(), true);
+ QCOMPARE(abstractTextureImage.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(abstractTextureImage.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ abstractTextureImage.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&abstractTextureImage);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureImageData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureImageData cloneData = creationChangeData->data;
+
+ QCOMPARE(abstractTextureImage.mipLevel(), cloneData.mipLevel);
+ QCOMPARE(abstractTextureImage.layer(), cloneData.layer);
+ QCOMPARE(abstractTextureImage.face(), cloneData.face);
+ QCOMPARE(abstractTextureImage.id(), creationChangeData->subjectId());
+ QCOMPARE(abstractTextureImage.isEnabled(), false);
+ QCOMPARE(abstractTextureImage.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(abstractTextureImage.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkMipLevelUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTextureImage abstractTextureImage;
+ arbiter.setArbiterOnNode(&abstractTextureImage);
+
+ {
+ // WHEN
+ abstractTextureImage.setMipLevel(9);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "mipLevel");
+ QCOMPARE(change->value().value<int>(), abstractTextureImage.mipLevel());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTextureImage.setMipLevel(9);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkLayerUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTextureImage abstractTextureImage;
+ arbiter.setArbiterOnNode(&abstractTextureImage);
+
+ {
+ // WHEN
+ abstractTextureImage.setLayer(12);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "layer");
+ QCOMPARE(change->value().value<int>(), abstractTextureImage.layer());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTextureImage.setLayer(12);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkFaceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ FakeTextureImage abstractTextureImage;
+ arbiter.setArbiterOnNode(&abstractTextureImage);
+
+ {
+ // WHEN
+ abstractTextureImage.setFace(Qt3DRender::QAbstractTexture::CubeMapPositiveY);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "face");
+ QCOMPARE(change->value().value<Qt3DRender::QAbstractTexture::CubeMapFace>(), abstractTextureImage.face());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ abstractTextureImage.setFace(Qt3DRender::QAbstractTexture::CubeMapPositiveY);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QAbstractTextureImage)
+
+#include "tst_qabstracttextureimage.moc"
diff --git a/tests/auto/render/qattribute/qattribute.pro b/tests/auto/render/qattribute/qattribute.pro
index 50acb9ded..667e9909f 100644
--- a/tests/auto/render/qattribute/qattribute.pro
+++ b/tests/auto/render/qattribute/qattribute.pro
@@ -8,4 +8,5 @@ CONFIG += testcase
SOURCES += tst_qattribute.cpp
+include(../../core/common/common.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/render/qattribute/tst_qattribute.cpp b/tests/auto/render/qattribute/tst_qattribute.cpp
index 2f7deaa43..0b4cac84e 100644
--- a/tests/auto/render/qattribute/tst_qattribute.cpp
+++ b/tests/auto/render/qattribute/tst_qattribute.cpp
@@ -47,6 +47,29 @@ public:
}
private Q_SLOTS:
+ void shouldHaveDefaultAttributeNames()
+ {
+ // GIVEN
+ Qt3DRender::QAttribute attribute;
+
+ // THEN
+ QCOMPARE(Qt3DRender::QAttribute::defaultPositionAttributeName(), QStringLiteral("vertexPosition"));
+ QCOMPARE(Qt3DRender::QAttribute::defaultNormalAttributeName(), QStringLiteral("vertexNormal"));
+ QCOMPARE(Qt3DRender::QAttribute::defaultColorAttributeName(), QStringLiteral("vertexColor"));
+ QCOMPARE(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName(), QStringLiteral("vertexTexCoord"));
+ QCOMPARE(Qt3DRender::QAttribute::defaultTangentAttributeName(), QStringLiteral("vertexTangent"));
+
+ QCOMPARE(attribute.property("defaultPositionAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultPositionAttributeName());
+ QCOMPARE(attribute.property("defaultNormalAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultNormalAttributeName());
+ QCOMPARE(attribute.property("defaultColorAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultColorAttributeName());
+ QCOMPARE(attribute.property("defaultTextureCoordinateAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName());
+ QCOMPARE(attribute.property("defaultTangentAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultTangentAttributeName());
+ }
void checkCloning_data()
{
diff --git a/tests/auto/render/qbuffer/qbuffer.pro b/tests/auto/render/qbuffer/qbuffer.pro
index 7b3e4315e..314bee184 100644
--- a/tests/auto/render/qbuffer/qbuffer.pro
+++ b/tests/auto/render/qbuffer/qbuffer.pro
@@ -8,4 +8,5 @@ CONFIG += testcase
SOURCES += tst_qbuffer.cpp
+include(../../core/common/common.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/render/qcameraselector/qcameraselector.pro b/tests/auto/render/qcameraselector/qcameraselector.pro
index 79f8f660e..c97153ba0 100644
--- a/tests/auto/render/qcameraselector/qcameraselector.pro
+++ b/tests/auto/render/qcameraselector/qcameraselector.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qcameraselector.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qclearbuffers/qclearbuffers.pro b/tests/auto/render/qclearbuffers/qclearbuffers.pro
index fdd10d392..403db558b 100644
--- a/tests/auto/render/qclearbuffers/qclearbuffers.pro
+++ b/tests/auto/render/qclearbuffers/qclearbuffers.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qclearbuffers.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qdispatchcompute/qdispatchcompute.pro b/tests/auto/render/qdispatchcompute/qdispatchcompute.pro
new file mode 100644
index 000000000..163c17010
--- /dev/null
+++ b/tests/auto/render/qdispatchcompute/qdispatchcompute.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qdispatchcompute
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qdispatchcompute.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qdispatchcompute/tst_qdispatchcompute.cpp b/tests/auto/render/qdispatchcompute/tst_qdispatchcompute.cpp
new file mode 100644
index 000000000..6fa55f370
--- /dev/null
+++ b/tests/auto/render/qdispatchcompute/tst_qdispatchcompute.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qdispatchcompute.h>
+#include <Qt3DRender/private/qdispatchcompute_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QDispatchCompute : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QDispatchCompute dispatchCompute;
+
+ // THEN
+ QCOMPARE(dispatchCompute.workGroupX(), 1);
+ QCOMPARE(dispatchCompute.workGroupY(), 1);
+ QCOMPARE(dispatchCompute.workGroupZ(), 1);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QDispatchCompute dispatchCompute;
+
+ {
+ // WHEN
+ QSignalSpy spy(&dispatchCompute, SIGNAL(workGroupXChanged()));
+ const int newValue = 128;
+ dispatchCompute.setWorkGroupX(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(dispatchCompute.workGroupX(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ dispatchCompute.setWorkGroupX(newValue);
+
+ // THEN
+ QCOMPARE(dispatchCompute.workGroupX(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&dispatchCompute, SIGNAL(workGroupYChanged()));
+ const int newValue = 1024;
+ dispatchCompute.setWorkGroupY(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(dispatchCompute.workGroupY(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ dispatchCompute.setWorkGroupY(newValue);
+
+ // THEN
+ QCOMPARE(dispatchCompute.workGroupY(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&dispatchCompute, SIGNAL(workGroupZChanged()));
+ const int newValue = 32;
+ dispatchCompute.setWorkGroupZ(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(dispatchCompute.workGroupZ(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ dispatchCompute.setWorkGroupZ(newValue);
+
+ // THEN
+ QCOMPARE(dispatchCompute.workGroupZ(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QDispatchCompute dispatchCompute;
+
+ dispatchCompute.setWorkGroupX(427);
+ dispatchCompute.setWorkGroupY(454);
+ dispatchCompute.setWorkGroupZ(383);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&dispatchCompute);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QDispatchComputeData>>(creationChanges.first());
+ const Qt3DRender::QDispatchComputeData cloneData = creationChangeData->data;
+
+ QCOMPARE(dispatchCompute.workGroupX(), cloneData.workGroupX);
+ QCOMPARE(dispatchCompute.workGroupY(), cloneData.workGroupY);
+ QCOMPARE(dispatchCompute.workGroupZ(), cloneData.workGroupZ);
+ QCOMPARE(dispatchCompute.id(), creationChangeData->subjectId());
+ QCOMPARE(dispatchCompute.isEnabled(), true);
+ QCOMPARE(dispatchCompute.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(dispatchCompute.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ dispatchCompute.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&dispatchCompute);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QDispatchComputeData>>(creationChanges.first());
+ const Qt3DRender::QDispatchComputeData cloneData = creationChangeData->data;
+
+ QCOMPARE(dispatchCompute.workGroupX(), cloneData.workGroupX);
+ QCOMPARE(dispatchCompute.workGroupY(), cloneData.workGroupY);
+ QCOMPARE(dispatchCompute.workGroupZ(), cloneData.workGroupZ);
+ QCOMPARE(dispatchCompute.id(), creationChangeData->subjectId());
+ QCOMPARE(dispatchCompute.isEnabled(), false);
+ QCOMPARE(dispatchCompute.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(dispatchCompute.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkWorkGroupXUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QDispatchCompute dispatchCompute;
+ arbiter.setArbiterOnNode(&dispatchCompute);
+
+ {
+ // WHEN
+ dispatchCompute.setWorkGroupX(883);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "workGroupX");
+ QCOMPARE(change->value().value<int>(), dispatchCompute.workGroupX());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ dispatchCompute.setWorkGroupX(883);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkWorkGroupYUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QDispatchCompute dispatchCompute;
+ arbiter.setArbiterOnNode(&dispatchCompute);
+
+ {
+ // WHEN
+ dispatchCompute.setWorkGroupY(1340);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "workGroupY");
+ QCOMPARE(change->value().value<int>(), dispatchCompute.workGroupY());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ dispatchCompute.setWorkGroupY(1340);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkWorkGroupZUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QDispatchCompute dispatchCompute;
+ arbiter.setArbiterOnNode(&dispatchCompute);
+
+ {
+ // WHEN
+ dispatchCompute.setWorkGroupZ(1584);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "workGroupZ");
+ QCOMPARE(change->value().value<int>(), dispatchCompute.workGroupZ());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ dispatchCompute.setWorkGroupZ(1584);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QDispatchCompute)
+
+#include "tst_qdispatchcompute.moc"
diff --git a/tests/auto/render/qeffect/qeffect.pro b/tests/auto/render/qeffect/qeffect.pro
new file mode 100644
index 000000000..4cb6abd13
--- /dev/null
+++ b/tests/auto/render/qeffect/qeffect.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qeffect
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qeffect.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qeffect/tst_qeffect.cpp b/tests/auto/render/qeffect/tst_qeffect.cpp
new file mode 100644
index 000000000..7449fee2c
--- /dev/null
+++ b/tests/auto/render/qeffect/tst_qeffect.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qeffect.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qtechnique.h>
+#include <Qt3DRender/private/qeffect_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QEffect : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QEffect effect;
+
+ // THEN
+ QCOMPARE(effect.parameters().size(), 0);
+ QCOMPARE(effect.techniques().size(), 0);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QEffect effect;
+
+ {
+ // WHEN
+ Qt3DRender::QParameter newValue;
+ effect.addParameter(&newValue);
+
+ // THEN
+ QCOMPARE(effect.parameters().size(), 1);
+
+ // WHEN
+ effect.addParameter(&newValue);
+
+ // THEN
+ QCOMPARE(effect.parameters().size(), 1);
+
+ // WHEN
+ effect.removeParameter(&newValue);
+
+ // THEN
+ QCOMPARE(effect.parameters().size(), 0);
+ }
+ {
+ // WHEN
+ Qt3DRender::QTechnique newValue;
+ effect.addTechnique(&newValue);
+
+ // THEN
+ QCOMPARE(effect.techniques().size(), 1);
+
+ // WHEN
+ effect.addTechnique(&newValue);
+
+ // THEN
+ QCOMPARE(effect.techniques().size(), 1);
+
+ // WHEN
+ effect.removeTechnique(&newValue);
+
+ // THEN
+ QCOMPARE(effect.techniques().size(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QEffect effect;
+
+ Qt3DRender::QParameter parameter;
+ effect.addParameter(&parameter);
+ Qt3DRender::QTechnique technique;
+ effect.addTechnique(&technique);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&effect);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 3); // Effect + Parameter + Technique
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QEffectData>>(creationChanges.first());
+ const Qt3DRender::QEffectData cloneData = creationChangeData->data;
+
+ QCOMPARE(cloneData.parameterIds.size(), 1);
+ QCOMPARE(parameter.id(), cloneData.parameterIds.first());
+ QCOMPARE(cloneData.techniqueIds.size(), 1);
+ QCOMPARE(technique.id(), cloneData.techniqueIds.first());
+ QCOMPARE(effect.id(), creationChangeData->subjectId());
+ QCOMPARE(effect.isEnabled(), true);
+ QCOMPARE(effect.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(effect.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ effect.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&effect);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 3); // Effect + Parameter + Technique
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QEffectData>>(creationChanges.first());
+ const Qt3DRender::QEffectData cloneData = creationChangeData->data;
+
+ QCOMPARE(cloneData.parameterIds.size(), 1);
+ QCOMPARE(parameter.id(), cloneData.parameterIds.first());
+ QCOMPARE(cloneData.techniqueIds.size(), 1);
+ QCOMPARE(technique.id(), cloneData.techniqueIds.first());
+ QCOMPARE(effect.id(), creationChangeData->subjectId());
+ QCOMPARE(effect.isEnabled(), false);
+ QCOMPARE(effect.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(effect.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkParameterBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QEffect effect;
+
+ {
+ // WHEN
+ Qt3DRender::QParameter parameter;
+ effect.addParameter(&parameter);
+
+ QCOMPARE(effect.parameters().size(), 1);
+
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(effect.parameters().size(), 0);
+
+ }
+
+ void checkTechniqueBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QEffect effect;
+
+ {
+ // WHEN
+ Qt3DRender::QTechnique technique;
+ effect.addTechnique(&technique);
+
+ QCOMPARE(effect.techniques().size(), 1);
+
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(effect.techniques().size(), 0);
+
+ }
+
+ void checkParameterUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QEffect effect;
+ Qt3DRender::QParameter parameter;
+ arbiter.setArbiterOnNode(&effect);
+
+ {
+ // WHEN
+ effect.addParameter(&parameter);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "parameter");
+ QCOMPARE(change->addedNodeId(), parameter.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ effect.removeParameter(&parameter);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "parameter");
+ QCOMPARE(change->removedNodeId(), parameter.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+
+ }
+
+ void checkTechniqueUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QEffect effect;
+ Qt3DRender::QTechnique technique;
+ arbiter.setArbiterOnNode(&effect);
+
+ {
+ // WHEN
+ effect.addTechnique(&technique);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "technique");
+ QCOMPARE(change->addedNodeId(), technique.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ effect.removeTechnique(&technique);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "technique");
+ QCOMPARE(change->removedNodeId(), technique.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QEffect)
+
+#include "tst_qeffect.moc"
diff --git a/tests/auto/render/qfilterkey/qfilterkey.pro b/tests/auto/render/qfilterkey/qfilterkey.pro
new file mode 100644
index 000000000..fc77c8532
--- /dev/null
+++ b/tests/auto/render/qfilterkey/qfilterkey.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qfilterkey
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qfilterkey.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qfilterkey/tst_qfilterkey.cpp b/tests/auto/render/qfilterkey/tst_qfilterkey.cpp
new file mode 100644
index 000000000..8c8381323
--- /dev/null
+++ b/tests/auto/render/qfilterkey/tst_qfilterkey.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qfilterkey.h>
+#include <Qt3DRender/private/qfilterkey_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QFilterKey : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QFilterKey filterKey;
+
+ // THEN
+ QCOMPARE(filterKey.value(), QVariant());
+ QCOMPARE(filterKey.name(), QString());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QFilterKey filterKey;
+
+ {
+ // WHEN
+ QSignalSpy spy(&filterKey, SIGNAL(valueChanged(QVariant)));
+ const QVariant newValue = QVariant("Tim");
+ filterKey.setValue(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(filterKey.value(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ filterKey.setValue(newValue);
+
+ // THEN
+ QCOMPARE(filterKey.value(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&filterKey, SIGNAL(nameChanged(QString)));
+ const QString newValue = QStringLiteral("Darius");
+ filterKey.setName(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(filterKey.name(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ filterKey.setName(newValue);
+
+ // THEN
+ QCOMPARE(filterKey.name(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QFilterKey filterKey;
+
+ filterKey.setValue(QVariant(QStringLiteral("Taylor")));
+ filterKey.setName(QStringLiteral("Craig"));
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&filterKey);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QFilterKeyData>>(creationChanges.first());
+ const Qt3DRender::QFilterKeyData cloneData = creationChangeData->data;
+
+ QCOMPARE(filterKey.value(), cloneData.value);
+ QCOMPARE(filterKey.name(), cloneData.name);
+ QCOMPARE(filterKey.id(), creationChangeData->subjectId());
+ QCOMPARE(filterKey.isEnabled(), true);
+ QCOMPARE(filterKey.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(filterKey.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ filterKey.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&filterKey);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QFilterKeyData>>(creationChanges.first());
+ const Qt3DRender::QFilterKeyData cloneData = creationChangeData->data;
+
+ QCOMPARE(filterKey.value(), cloneData.value);
+ QCOMPARE(filterKey.name(), cloneData.name);
+ QCOMPARE(filterKey.id(), creationChangeData->subjectId());
+ QCOMPARE(filterKey.isEnabled(), false);
+ QCOMPARE(filterKey.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(filterKey.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkValueUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QFilterKey filterKey;
+ arbiter.setArbiterOnNode(&filterKey);
+
+ {
+ // WHEN
+ filterKey.setValue(QVariant(427));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "value");
+ QCOMPARE(change->value().value<QVariant>(), filterKey.value());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ filterKey.setValue(QVariant(427));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkNameUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QFilterKey filterKey;
+ arbiter.setArbiterOnNode(&filterKey);
+
+ {
+ // WHEN
+ filterKey.setName(QStringLiteral("Easton"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "name");
+ QCOMPARE(change->value().value<QString>(), filterKey.name());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ filterKey.setName(QStringLiteral("Easton"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QFilterKey)
+
+#include "tst_qfilterkey.moc"
diff --git a/tests/auto/render/qframegraphnode/qframegraphnode.pro b/tests/auto/render/qframegraphnode/qframegraphnode.pro
index 0cfce4e68..308e16d57 100644
--- a/tests/auto/render/qframegraphnode/qframegraphnode.pro
+++ b/tests/auto/render/qframegraphnode/qframegraphnode.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qframegraphnode.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qgeometry/qgeometry.pro b/tests/auto/render/qgeometry/qgeometry.pro
index 45b86a089..e19569162 100644
--- a/tests/auto/render/qgeometry/qgeometry.pro
+++ b/tests/auto/render/qgeometry/qgeometry.pro
@@ -8,4 +8,5 @@ CONFIG += testcase
SOURCES += tst_qgeometry.cpp
+include(../../core/common/common.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/render/qgeometryrenderer/qgeometryrenderer.pro b/tests/auto/render/qgeometryrenderer/qgeometryrenderer.pro
index 8d0a700d7..92a52d088 100644
--- a/tests/auto/render/qgeometryrenderer/qgeometryrenderer.pro
+++ b/tests/auto/render/qgeometryrenderer/qgeometryrenderer.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qgeometryrenderer.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qlayerfilter/qlayerfilter.pro b/tests/auto/render/qlayerfilter/qlayerfilter.pro
index 44dfdd08e..61fe3bfc9 100644
--- a/tests/auto/render/qlayerfilter/qlayerfilter.pro
+++ b/tests/auto/render/qlayerfilter/qlayerfilter.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qlayerfilter.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qmaterial/qmaterial.pro b/tests/auto/render/qmaterial/qmaterial.pro
index 5aa07f577..e1e2d2f4f 100644
--- a/tests/auto/render/qmaterial/qmaterial.pro
+++ b/tests/auto/render/qmaterial/qmaterial.pro
@@ -8,4 +8,5 @@ CONFIG += testcase
SOURCES += tst_qmaterial.cpp
+include(../../core/common/common.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/render/qmesh/qmesh.pro b/tests/auto/render/qmesh/qmesh.pro
new file mode 100644
index 000000000..8d0e69abc
--- /dev/null
+++ b/tests/auto/render/qmesh/qmesh.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qmesh
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qmesh.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qmesh/tst_qmesh.cpp b/tests/auto/render/qmesh/tst_qmesh.cpp
new file mode 100644
index 000000000..2122d7eb5
--- /dev/null
+++ b/tests/auto/render/qmesh/tst_qmesh.cpp
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qmesh.h>
+#include <Qt3DRender/private/qmesh_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QMesh : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QMesh mesh;
+
+ // THEN
+ QCOMPARE(mesh.source(), QUrl());
+ QCOMPARE(mesh.meshName(), QString());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QMesh mesh;
+
+ {
+ // WHEN
+ QSignalSpy spy(&mesh, SIGNAL(sourceChanged(QUrl)));
+ const QUrl newValue(QStringLiteral("qrc:/mesh.obj"));
+ mesh.setSource(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(mesh.source(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ mesh.setSource(newValue);
+
+ // THEN
+ QCOMPARE(mesh.source(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&mesh, SIGNAL(meshNameChanged(QString)));
+ const QString newValue = QStringLiteral("MainBody");
+ mesh.setMeshName(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(mesh.meshName(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ mesh.setMeshName(newValue);
+
+ // THEN
+ QCOMPARE(mesh.meshName(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QMesh mesh;
+
+ mesh.setSource(QUrl(QStringLiteral("http://someRemoteURL.com")));
+ mesh.setMeshName(QStringLiteral("RearPropeller"));
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mesh);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QGeometryRendererData>>(creationChanges.first());
+ const Qt3DRender::QGeometryRendererData cloneData = creationChangeData->data;
+
+ Qt3DRender::MeshFunctor meshFunctor(mesh.source(), mesh.meshName());
+
+ QVERIFY(meshFunctor == *cloneData.geometryFactory);
+ QCOMPARE(mesh.id(), creationChangeData->subjectId());
+ QCOMPARE(mesh.isEnabled(), true);
+ QCOMPARE(mesh.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mesh.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ mesh.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mesh);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QGeometryRendererData>>(creationChanges.first());
+
+ QCOMPARE(mesh.id(), creationChangeData->subjectId());
+ QCOMPARE(mesh.isEnabled(), false);
+ QCOMPARE(mesh.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mesh.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkSourceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QMesh mesh;
+ arbiter.setArbiterOnNode(&mesh);
+
+ {
+ // WHEN
+ mesh.setSource(QUrl(QStringLiteral("qrc:/toyplane.obj")));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "geometryFactory");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ Qt3DRender::MeshFunctor meshFunctor(mesh.source());
+ Qt3DRender::QGeometryFactoryPtr factory = change->value().value<Qt3DRender::QGeometryFactoryPtr>();
+ QVERIFY(meshFunctor == *factory);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ mesh.setSource(QStringLiteral("qrc:/toyplane.obj"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMeshNameUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QMesh mesh;
+ arbiter.setArbiterOnNode(&mesh);
+
+ {
+ // WHEN
+ mesh.setMeshName(QStringLiteral("Phil"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "geometryFactory");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ Qt3DRender::MeshFunctor meshFunctor(QUrl(), mesh.meshName());
+ Qt3DRender::QGeometryFactoryPtr factory = change->value().value<Qt3DRender::QGeometryFactoryPtr>();
+ QVERIFY(meshFunctor == *factory);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ mesh.setMeshName(QStringLiteral("Phil"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QMesh)
+
+#include "tst_qmesh.moc"
diff --git a/tests/auto/render/qmlscenereader/qmlscenereader.cpp b/tests/auto/render/qmlscenereader/qmlscenereader.cpp
new file mode 100644
index 000000000..182782edb
--- /dev/null
+++ b/tests/auto/render/qmlscenereader/qmlscenereader.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlscenereader.h"
+#include <QQmlEngine>
+#include <QQmlComponent>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+QmlSceneReader::QmlSceneReader(const QUrl &source)
+ : m_qmlEngine(new QQmlEngine)
+ , m_component(new QQmlComponent(m_qmlEngine.data(), source, QQmlComponent::PreferSynchronous))
+ , m_root(nullptr)
+{
+ loadComplete();
+}
+
+QmlSceneReader::~QmlSceneReader()
+{}
+
+// Caller needs to delete m_root
+QObject *QmlSceneReader::root() const
+{
+ return m_root;
+}
+
+void QmlSceneReader::loadComplete()
+{
+ if (m_component->isError()) {
+ const auto errors = m_component->errors();
+ for (const QQmlError &error : errors) {
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ << error;
+ }
+ return;
+ }
+ m_root = m_component->create();
+ if (m_component->isError()) {
+ const auto errors = m_component->errors();
+ for (const QQmlError &error : errors) {
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ << error;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/render/qmlscenereader/qmlscenereader.h b/tests/auto/render/qmlscenereader/qmlscenereader.h
new file mode 100644
index 000000000..9d4643d93
--- /dev/null
+++ b/tests/auto/render/qmlscenereader/qmlscenereader.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+class QQmlComponent;
+
+class QmlSceneReader : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QmlSceneReader(const QUrl &source);
+ ~QmlSceneReader();
+ QObject *root() const;
+
+private:
+ QScopedPointer<QQmlEngine> m_qmlEngine;
+ QScopedPointer<QQmlComponent> m_component;
+ QObject *m_root;
+
+ void loadComplete();
+};
+
+QT_END_NAMESPACE
diff --git a/tests/auto/render/qmlscenereader/qmlscenereader.pri b/tests/auto/render/qmlscenereader/qmlscenereader.pri
new file mode 100644
index 000000000..829f2a612
--- /dev/null
+++ b/tests/auto/render/qmlscenereader/qmlscenereader.pri
@@ -0,0 +1,7 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += $$PWD/qmlscenereader.cpp
+
+HEADERS += $$PWD/qmlscenereader.h
+
+QT += core-private qml
diff --git a/tests/auto/render/qobjectpicker/qobjectpicker.pro b/tests/auto/render/qobjectpicker/qobjectpicker.pro
index 6010b826c..8cffbf171 100644
--- a/tests/auto/render/qobjectpicker/qobjectpicker.pro
+++ b/tests/auto/render/qobjectpicker/qobjectpicker.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qobjectpicker.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qparameter/qparameter.pro b/tests/auto/render/qparameter/qparameter.pro
new file mode 100644
index 000000000..88759d220
--- /dev/null
+++ b/tests/auto/render/qparameter/qparameter.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qparameter
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qparameter.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qparameter/tst_qparameter.cpp b/tests/auto/render/qparameter/tst_qparameter.cpp
new file mode 100644
index 000000000..f124af809
--- /dev/null
+++ b/tests/auto/render/qparameter/tst_qparameter.cpp
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/private/qparameter_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/qentity.h>
+#include "testpostmanarbiter.h"
+
+class tst_QParameter : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QParameter parameter;
+
+ // THEN
+ QCOMPARE(parameter.name(), QString());
+ QCOMPARE(parameter.value(), QVariant());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QParameter parameter;
+
+ {
+ // WHEN
+ QSignalSpy spy(&parameter, SIGNAL(nameChanged(QString)));
+ const QString newValue = QStringLiteral("SomeName");
+ parameter.setName(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(parameter.name(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ parameter.setName(newValue);
+
+ // THEN
+ QCOMPARE(parameter.name(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&parameter, SIGNAL(valueChanged(QVariant)));
+ const QVariant newValue(454.0f);
+ parameter.setValue(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(parameter.value(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ parameter.setValue(newValue);
+
+ // THEN
+ QCOMPARE(parameter.value(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QParameter parameter;
+
+ parameter.setName(QStringLiteral("TwinCam"));
+ parameter.setValue(QVariant(427));
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&parameter);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QParameterData>>(creationChanges.first());
+ const Qt3DRender::QParameterData cloneData = creationChangeData->data;
+
+ QCOMPARE(parameter.name(), cloneData.name);
+ QCOMPARE(parameter.value(), cloneData.backendValue);
+ QCOMPARE(parameter.id(), creationChangeData->subjectId());
+ QCOMPARE(parameter.isEnabled(), true);
+ QCOMPARE(parameter.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(parameter.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ parameter.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&parameter);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QParameterData>>(creationChanges.first());
+ const Qt3DRender::QParameterData cloneData = creationChangeData->data;
+
+ QCOMPARE(parameter.name(), cloneData.name);
+ QCOMPARE(parameter.value(), cloneData.backendValue);
+ QCOMPARE(parameter.id(), creationChangeData->subjectId());
+ QCOMPARE(parameter.isEnabled(), false);
+ QCOMPARE(parameter.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(parameter.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkNameUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QParameter parameter;
+ arbiter.setArbiterOnNode(&parameter);
+
+ {
+ // WHEN
+ parameter.setName(QStringLiteral("Bruce"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "name");
+ QCOMPARE(change->value().value<QString>(), parameter.name());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ parameter.setName(QStringLiteral("Bruce"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkValueUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QParameter parameter;
+ arbiter.setArbiterOnNode(&parameter);
+
+ {
+ // WHEN
+ parameter.setValue(QVariant(383.0f));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "value");
+ QCOMPARE(change->value().value<QVariant>(), parameter.value());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ parameter.setValue(QVariant(383.0f));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ // WHEN -> QNode -> QNodeId
+ {
+ Qt3DCore::QEntity testEntity;
+
+ {
+ // WHEN
+ parameter.setValue(QVariant::fromValue(&testEntity));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "value");
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(),testEntity.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ parameter.setValue(QVariant::fromValue(&testEntity));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QParameter)
+
+#include "tst_qparameter.moc"
diff --git a/tests/auto/render/qrendercapture/qrendercapture.pro b/tests/auto/render/qrendercapture/qrendercapture.pro
index 999f95a58..deba9a381 100644
--- a/tests/auto/render/qrendercapture/qrendercapture.pro
+++ b/tests/auto/render/qrendercapture/qrendercapture.pro
@@ -9,3 +9,4 @@ CONFIG += testcase
SOURCES += tst_qrendercapture.cpp
include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qrenderpass/qrenderpass.pro b/tests/auto/render/qrenderpass/qrenderpass.pro
new file mode 100644
index 000000000..dbe733839
--- /dev/null
+++ b/tests/auto/render/qrenderpass/qrenderpass.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qrenderpass
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qrenderpass.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qrenderpass/tst_qrenderpass.cpp b/tests/auto/render/qrenderpass/tst_qrenderpass.cpp
new file mode 100644
index 000000000..bcc8e9313
--- /dev/null
+++ b/tests/auto/render/qrenderpass/tst_qrenderpass.cpp
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrenderpass.h>
+#include <Qt3DRender/qfilterkey.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qdepthtest.h>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/private/qrenderpass_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QRenderPass : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DRender::QShaderProgram *>("QShaderProgram *");
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ // THEN
+ QVERIFY(renderPass.shaderProgram() == nullptr);
+ QCOMPARE(renderPass.filterKeys().size(), 0);
+ QCOMPARE(renderPass.renderStates().size(), 0);
+ QCOMPARE(renderPass.parameters().size(), 0);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ {
+ // WHEN
+ QSignalSpy spy(&renderPass, SIGNAL(shaderProgramChanged(QShaderProgram *)));
+ Qt3DRender::QShaderProgram newValue;
+ renderPass.setShaderProgram(&newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(renderPass.shaderProgram(), &newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ renderPass.setShaderProgram(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.shaderProgram(), &newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ Qt3DRender::QFilterKey newValue;
+ renderPass.addFilterKey(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.filterKeys().size(), 1);
+
+ // WHEN
+ renderPass.addFilterKey(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.filterKeys().size(), 1);
+
+ // WHEN
+ renderPass.removeFilterKey(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.filterKeys().size(), 0);
+ }
+ {
+ // WHEN
+ Qt3DRender::QDepthTest newValue;
+ renderPass.addRenderState(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.renderStates().size(), 1);
+
+ // WHEN
+ renderPass.addRenderState(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.renderStates().size(), 1);
+
+ // WHEN
+ renderPass.removeRenderState(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.renderStates().size(), 0);
+ }
+ {
+ // WHEN
+ Qt3DRender::QParameter newValue;
+ renderPass.addParameter(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.parameters().size(), 1);
+
+ // WHEN
+ renderPass.addParameter(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.parameters().size(), 1);
+
+ // WHEN
+ renderPass.removeParameter(&newValue);
+
+ // THEN
+ QCOMPARE(renderPass.parameters().size(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ Qt3DRender::QShaderProgram shader;
+ renderPass.setShaderProgram(&shader);
+ Qt3DRender::QFilterKey filterKey;
+ renderPass.addFilterKey(&filterKey);
+ Qt3DRender::QDepthTest renderState;
+ renderPass.addRenderState(&renderState);
+ Qt3DRender::QParameter parameter;
+ renderPass.addParameter(&parameter);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderPass);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 5); // RenderPass + Shader + FilterKey + Parameter + State
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderPassData>>(creationChanges.first());
+ const Qt3DRender::QRenderPassData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderPass.shaderProgram()->id(), cloneData.shaderId);
+ QCOMPARE(cloneData.filterKeyIds.size(), 1);
+ QCOMPARE(filterKey.id(), cloneData.filterKeyIds.first());
+ QCOMPARE(cloneData.renderStateIds.size(), 1);
+ QCOMPARE(renderState.id(), cloneData.renderStateIds.first());
+ QCOMPARE(cloneData.parameterIds.size(), 1);
+ QCOMPARE(parameter.id(), cloneData.parameterIds.first());
+ QCOMPARE(renderPass.id(), creationChangeData->subjectId());
+ QCOMPARE(renderPass.isEnabled(), true);
+ QCOMPARE(renderPass.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderPass.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ renderPass.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderPass);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 5); // RenderPass + Shader + FilterKey + Parameter + State
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderPassData>>(creationChanges.first());
+ const Qt3DRender::QRenderPassData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderPass.shaderProgram()->id(), cloneData.shaderId);
+ QCOMPARE(cloneData.filterKeyIds.size(), 1);
+ QCOMPARE(filterKey.id(), cloneData.filterKeyIds.first());
+ QCOMPARE(cloneData.renderStateIds.size(), 1);
+ QCOMPARE(renderState.id(), cloneData.renderStateIds.first());
+ QCOMPARE(cloneData.parameterIds.size(), 1);
+ QCOMPARE(parameter.id(), cloneData.parameterIds.first());
+ QCOMPARE(renderPass.id(), creationChangeData->subjectId());
+ QCOMPARE(renderPass.isEnabled(), false);
+ QCOMPARE(renderPass.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderPass.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkShaderProgramBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ {
+ // WHEN
+ Qt3DRender::QShaderProgram shaderProgram;
+ renderPass.setShaderProgram(&shaderProgram);
+
+ QCOMPARE(renderPass.shaderProgram(), &shaderProgram);
+ }
+
+ // THEN -> should not crash
+ QVERIFY(renderPass.shaderProgram() == nullptr);
+ }
+
+ void checkFilterKeyBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ {
+ // WHEN
+ Qt3DRender::QFilterKey filterKey;
+ renderPass.addFilterKey(&filterKey);
+
+ QCOMPARE(renderPass.filterKeys().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(renderPass.filterKeys().size(), 0);
+ }
+
+ void checkRenderStateBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ {
+ // WHEN
+ Qt3DRender::QDepthTest renderState;
+ renderPass.addRenderState(&renderState);
+
+ QCOMPARE(renderPass.renderStates().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(renderPass.renderStates().size(), 0);
+ }
+
+ void checkParameterBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QRenderPass renderPass;
+
+ {
+ // WHEN
+ Qt3DRender::QParameter parameter;
+ renderPass.addParameter(&parameter);
+
+ QCOMPARE(renderPass.parameters().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(renderPass.parameters().size(), 0);
+ }
+
+ void checkShaderProgramUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderPass renderPass;
+ Qt3DRender::QShaderProgram shaderProgram;
+ arbiter.setArbiterOnNode(&renderPass);
+
+ {
+ // WHEN
+ renderPass.setShaderProgram(&shaderProgram);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "shaderProgram");
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), renderPass.shaderProgram()->id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderPass.setShaderProgram(&shaderProgram);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkFilterKeyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderPass renderPass;
+ Qt3DRender::QFilterKey filterKey;
+ arbiter.setArbiterOnNode(&renderPass);
+
+ {
+ // WHEN
+ renderPass.addFilterKey(&filterKey);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "filterKeys");
+ QCOMPARE(change->addedNodeId(), filterKey.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderPass.removeFilterKey(&filterKey);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "filterKeys");
+ QCOMPARE(change->removedNodeId(), filterKey.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+
+ }
+
+ void checkRenderStateUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderPass renderPass;
+ Qt3DRender::QDepthTest renderState;
+ arbiter.setArbiterOnNode(&renderPass);
+
+ {
+ // WHEN
+ renderPass.addRenderState(&renderState);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "renderState");
+ QCOMPARE(change->addedNodeId(), renderState.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderPass.removeRenderState(&renderState);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "renderState");
+ QCOMPARE(change->removedNodeId(), renderState.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+
+ }
+
+ void checkParameterUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderPass renderPass;
+ Qt3DRender::QParameter parameter;
+ arbiter.setArbiterOnNode(&renderPass);
+
+ {
+ // WHEN
+ renderPass.addParameter(&parameter);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "parameter");
+ QCOMPARE(change->addedNodeId(), parameter.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderPass.removeParameter(&parameter);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "parameter");
+ QCOMPARE(change->removedNodeId(), parameter.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QRenderPass)
+
+#include "tst_qrenderpass.moc"
diff --git a/tests/auto/render/qrenderpassfilter/qrenderpassfilter.pro b/tests/auto/render/qrenderpassfilter/qrenderpassfilter.pro
index 0769b3fe5..e2af720d9 100644
--- a/tests/auto/render/qrenderpassfilter/qrenderpassfilter.pro
+++ b/tests/auto/render/qrenderpassfilter/qrenderpassfilter.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qrenderpassfilter.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qrendersettings/qrendersettings.pro b/tests/auto/render/qrendersettings/qrendersettings.pro
new file mode 100644
index 000000000..9de505ff1
--- /dev/null
+++ b/tests/auto/render/qrendersettings/qrendersettings.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qrendersettings
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qrendersettings.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qrendersettings/tst_qrendersettings.cpp b/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
new file mode 100644
index 000000000..1f0a9f066
--- /dev/null
+++ b/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendersettings.h>
+#include <Qt3DRender/qviewport.h>
+#include <Qt3DRender/private/qrendersettings_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QRenderSettings : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DRender::QRenderSettings::RenderPolicy >("RenderPolicy");
+ qRegisterMetaType<Qt3DRender::QPickingSettings::PickMethod>("QPickingSettings::PickMethod");
+ qRegisterMetaType<Qt3DRender::QPickingSettings::PickResultMode>("QPickingSettings::PickResultMode");
+ qRegisterMetaType<Qt3DRender::QPickingSettings::FaceOrientationPickingMode>("QPickingSettings::FaceOrientationPickingMode");
+ qRegisterMetaType<Qt3DRender::QFrameGraphNode*>("QFrameGraphNode *");
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QRenderSettings renderSettings;
+
+ // THEN
+ QVERIFY(renderSettings.pickingSettings() != nullptr);
+ QCOMPARE(renderSettings.renderPolicy(), Qt3DRender::QRenderSettings::Always);
+ QVERIFY(renderSettings.activeFrameGraph() == nullptr);
+ QCOMPARE(renderSettings.pickingSettings()->pickMethod(), Qt3DRender::QPickingSettings::BoundingVolumePicking);
+ QCOMPARE(renderSettings.pickingSettings()->pickResultMode(), Qt3DRender::QPickingSettings::NearestPick);
+ QCOMPARE(renderSettings.pickingSettings()->faceOrientationPickingMode(), Qt3DRender::QPickingSettings::FrontFace);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+
+ {
+ // WHEN
+ QSignalSpy spy(&renderSettings, SIGNAL(renderPolicyChanged(RenderPolicy)));
+ const Qt3DRender::QRenderSettings::RenderPolicy newValue = Qt3DRender::QRenderSettings::OnDemand;
+ renderSettings.setRenderPolicy(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(renderSettings.renderPolicy(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ renderSettings.setRenderPolicy(newValue);
+
+ // THEN
+ QCOMPARE(renderSettings.renderPolicy(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&renderSettings, SIGNAL(activeFrameGraphChanged(QFrameGraphNode *)));
+
+ Qt3DRender::QViewport newValue;
+ renderSettings.setActiveFrameGraph(&newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(renderSettings.activeFrameGraph(), &newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ renderSettings.setActiveFrameGraph(&newValue);
+
+ // THEN
+ QCOMPARE(renderSettings.activeFrameGraph(), &newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(pickingSettings, SIGNAL(pickMethodChanged(QPickingSettings::PickMethod)));
+ const Qt3DRender::QPickingSettings::PickMethod newValue = Qt3DRender::QPickingSettings::TrianglePicking;
+ pickingSettings->setPickMethod(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(pickingSettings->pickMethod(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ pickingSettings->setPickMethod(newValue);
+
+ // THEN
+ QCOMPARE(pickingSettings->pickMethod(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(pickingSettings, SIGNAL(pickResultModeChanged(QPickingSettings::PickResultMode)));
+ const Qt3DRender::QPickingSettings::PickResultMode newValue = Qt3DRender::QPickingSettings::AllPicks;
+ pickingSettings->setPickResultMode(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(pickingSettings->pickResultMode(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ pickingSettings->setPickResultMode(newValue);
+
+ // THEN
+ QCOMPARE(pickingSettings->pickResultMode(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(pickingSettings, SIGNAL(faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)));
+ const Qt3DRender::QPickingSettings::FaceOrientationPickingMode newValue = Qt3DRender::QPickingSettings::FrontAndBackFace;
+ pickingSettings->setFaceOrientationPickingMode(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(pickingSettings->faceOrientationPickingMode(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ pickingSettings->setFaceOrientationPickingMode(newValue);
+
+ // THEN
+ QCOMPARE(pickingSettings->faceOrientationPickingMode(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+ Qt3DRender::QViewport frameGraphRoot;
+
+ renderSettings.setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
+ renderSettings.setActiveFrameGraph(&frameGraphRoot);
+ pickingSettings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
+ pickingSettings->setPickResultMode(Qt3DRender::QPickingSettings::AllPicks);
+ pickingSettings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderSettings);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // RenderSettings + PickingSettings (because it's a QNode)
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderSettingsData>>(creationChanges.first());
+ const Qt3DRender::QRenderSettingsData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderSettings.pickingSettings()->pickMethod(), cloneData.pickMethod);
+ QCOMPARE(renderSettings.pickingSettings()->pickResultMode(), cloneData.pickResultMode);
+ QCOMPARE(renderSettings.pickingSettings()->faceOrientationPickingMode(), cloneData.faceOrientationPickingMode);
+ QCOMPARE(renderSettings.renderPolicy(), cloneData.renderPolicy);
+ QCOMPARE(renderSettings.activeFrameGraph()->id(), cloneData.activeFrameGraphId);
+ QCOMPARE(renderSettings.id(), creationChangeData->subjectId());
+ QCOMPARE(renderSettings.isEnabled(), true);
+ QCOMPARE(renderSettings.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderSettings.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ renderSettings.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderSettings);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // RenderSettings + PickingSettings (because it's a QNode)
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderSettingsData>>(creationChanges.first());
+ const Qt3DRender::QRenderSettingsData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderSettings.pickingSettings()->pickMethod(), cloneData.pickMethod);
+ QCOMPARE(renderSettings.pickingSettings()->pickResultMode(), cloneData.pickResultMode);
+ QCOMPARE(renderSettings.pickingSettings()->faceOrientationPickingMode(), cloneData.faceOrientationPickingMode);
+ QCOMPARE(renderSettings.renderPolicy(), cloneData.renderPolicy);
+ QCOMPARE(renderSettings.activeFrameGraph()->id(), cloneData.activeFrameGraphId);
+ QCOMPARE(renderSettings.id(), creationChangeData->subjectId());
+ QCOMPARE(renderSettings.isEnabled(), false);
+ QCOMPARE(renderSettings.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderSettings.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkRenderPolicyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ arbiter.setArbiterOnNode(&renderSettings);
+
+ {
+ // WHEN
+ renderSettings.setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "renderPolicy");
+ QCOMPARE(change->value().value<Qt3DRender::QRenderSettings::RenderPolicy>(), renderSettings.renderPolicy());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderSettings.setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkActiveFrameGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ arbiter.setArbiterOnNode(&renderSettings);
+ Qt3DRender::QViewport viewport;
+
+ {
+ // WHEN
+ renderSettings.setActiveFrameGraph(&viewport);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "activeFrameGraph");
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), viewport.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderSettings.setActiveFrameGraph(&viewport);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkPickMethodUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+
+ arbiter.setArbiterOnNode(&renderSettings);
+
+ {
+ // WHEN
+ pickingSettings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pickMethod");
+ QCOMPARE(change->value().value<Qt3DRender::QPickingSettings::PickMethod>(), pickingSettings->pickMethod());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ pickingSettings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkPickResultModeUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+
+ arbiter.setArbiterOnNode(&renderSettings);
+
+ {
+ // WHEN
+ pickingSettings->setPickResultMode(Qt3DRender::QPickingSettings::AllPicks);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pickResultMode");
+ QCOMPARE(change->value().value<Qt3DRender::QPickingSettings::PickResultMode>(), pickingSettings->pickResultMode());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ pickingSettings->setPickResultMode(Qt3DRender::QPickingSettings::AllPicks);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkFaceOrientationPickingModeUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+
+ arbiter.setArbiterOnNode(&renderSettings);
+
+ {
+ // WHEN
+ pickingSettings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "faceOrientationPickingMode");
+ QCOMPARE(change->value().value<Qt3DRender::QPickingSettings::FaceOrientationPickingMode>(), pickingSettings->faceOrientationPickingMode());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ pickingSettings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QRenderSettings)
+
+#include "tst_qrendersettings.moc"
diff --git a/tests/auto/render/qrenderstateset/qrenderstateset.pro b/tests/auto/render/qrenderstateset/qrenderstateset.pro
index 836e84171..3a0fb757b 100644
--- a/tests/auto/render/qrenderstateset/qrenderstateset.pro
+++ b/tests/auto/render/qrenderstateset/qrenderstateset.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qrenderstateset.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qrendersurfaceselector/qrendersurfaceselector.pro b/tests/auto/render/qrendersurfaceselector/qrendersurfaceselector.pro
index 57626b9ef..bbd9455d0 100644
--- a/tests/auto/render/qrendersurfaceselector/qrendersurfaceselector.pro
+++ b/tests/auto/render/qrendersurfaceselector/qrendersurfaceselector.pro
@@ -7,4 +7,5 @@ CONFIG += testcase
SOURCES += tst_qrendersurfaceselector.cpp
+include(../../core/common/common.pri)
include(../commons/commons.pri)
diff --git a/tests/auto/render/qrendersurfaceselector/tst_qrendersurfaceselector.cpp b/tests/auto/render/qrendersurfaceselector/tst_qrendersurfaceselector.cpp
index 17c7cf40d..1e003e6b8 100644
--- a/tests/auto/render/qrendersurfaceselector/tst_qrendersurfaceselector.cpp
+++ b/tests/auto/render/qrendersurfaceselector/tst_qrendersurfaceselector.cpp
@@ -32,6 +32,11 @@
#include <Qt3DRender/qrendersettings.h>
#include <Qt3DRender/qrendersurfaceselector.h>
#include <Qt3DRender/private/qrendersurfaceselector_p.h>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
class tst_QRenderSurfaceSelector: public QObject
{
@@ -100,6 +105,250 @@ private Q_SLOTS:
QFETCH(Qt3DRender::QRenderSurfaceSelector*, expected);
QCOMPARE(selector, expected);
}
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QRenderSurfaceSelector renderSurfaceSelector;
+
+ // THEN
+ QVERIFY(renderSurfaceSelector.surface() == nullptr);
+ QCOMPARE(renderSurfaceSelector.externalRenderTargetSize(), QSize());
+ QCOMPARE(renderSurfaceSelector.surfacePixelRatio(), 1.0f);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QRenderSurfaceSelector renderSurfaceSelector;
+
+ {
+ // WHEN
+ QSignalSpy spy(&renderSurfaceSelector, SIGNAL(surfaceChanged(QObject *)));
+ QWindow newValue;
+ renderSurfaceSelector.setSurface(&newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(renderSurfaceSelector.surface(), &newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ renderSurfaceSelector.setSurface(&newValue);
+
+ // THEN
+ QCOMPARE(renderSurfaceSelector.surface(), &newValue);
+ QCOMPARE(spy.count(), 0);
+
+ // Prevents crashes with temporary window being destroyed
+ renderSurfaceSelector.setSurface(nullptr);
+ QCoreApplication::processEvents();
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&renderSurfaceSelector, SIGNAL(externalRenderTargetSizeChanged(QSize)));
+ const QSize newValue(512, 512);
+ renderSurfaceSelector.setExternalRenderTargetSize(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(renderSurfaceSelector.externalRenderTargetSize(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ renderSurfaceSelector.setExternalRenderTargetSize(newValue);
+
+ // THEN
+ QCOMPARE(renderSurfaceSelector.externalRenderTargetSize(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&renderSurfaceSelector, SIGNAL(surfacePixelRatioChanged(float)));
+ const float newValue = 15.0f;
+ renderSurfaceSelector.setSurfacePixelRatio(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(renderSurfaceSelector.surfacePixelRatio(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ renderSurfaceSelector.setSurfacePixelRatio(newValue);
+
+ // THEN
+ QCOMPARE(renderSurfaceSelector.surfacePixelRatio(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QRenderSurfaceSelector renderSurfaceSelector;
+ QWindow newValue;
+
+ renderSurfaceSelector.setSurface(&newValue);
+ renderSurfaceSelector.setExternalRenderTargetSize(QSize(128, 128));
+ renderSurfaceSelector.setSurfacePixelRatio(25.0f);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderSurfaceSelector);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderSurfaceSelectorData>>(creationChanges.first());
+ const Qt3DRender::QRenderSurfaceSelectorData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderSurfaceSelector.surface(), cloneData.surface.data());
+ QCOMPARE(renderSurfaceSelector.externalRenderTargetSize(), cloneData.externalRenderTargetSize);
+ QCOMPARE(renderSurfaceSelector.surfacePixelRatio(), cloneData.surfacePixelRatio);
+ QCOMPARE(renderSurfaceSelector.id(), creationChangeData->subjectId());
+ QCOMPARE(renderSurfaceSelector.isEnabled(), true);
+ QCOMPARE(renderSurfaceSelector.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderSurfaceSelector.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ renderSurfaceSelector.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderSurfaceSelector);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderSurfaceSelectorData>>(creationChanges.first());
+ const Qt3DRender::QRenderSurfaceSelectorData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderSurfaceSelector.surface(), cloneData.surface.data());
+ QCOMPARE(renderSurfaceSelector.externalRenderTargetSize(), cloneData.externalRenderTargetSize);
+ QCOMPARE(renderSurfaceSelector.surfacePixelRatio(), cloneData.surfacePixelRatio);
+ QCOMPARE(renderSurfaceSelector.id(), creationChangeData->subjectId());
+ QCOMPARE(renderSurfaceSelector.isEnabled(), false);
+ QCOMPARE(renderSurfaceSelector.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderSurfaceSelector.metaObject(), creationChangeData->metaObject());
+ }
+
+ // Prevents crashes with temporary window being destroyed
+ renderSurfaceSelector.setSurface(nullptr);
+ }
+
+ void checkSurfaceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSurfaceSelector renderSurfaceSelector;
+ arbiter.setArbiterOnNode(&renderSurfaceSelector);
+ QWindow newWindow;
+
+ {
+ // WHEN
+ renderSurfaceSelector.setSurface(&newWindow);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "surface");
+ QCOMPARE(change->value().value<QObject *>(), renderSurfaceSelector.surface());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderSurfaceSelector.setSurface(&newWindow);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ // Prevents crashes with temporary window being destroyed
+ renderSurfaceSelector.setSurface(nullptr);
+ }
+
+ void checkExternalRenderTargetSizeUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSurfaceSelector renderSurfaceSelector;
+ arbiter.setArbiterOnNode(&renderSurfaceSelector);
+
+ {
+ // WHEN
+ renderSurfaceSelector.setExternalRenderTargetSize(QSize(454, 454));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "externalRenderTargetSize");
+ QCOMPARE(change->value().value<QSize>(), renderSurfaceSelector.externalRenderTargetSize());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderSurfaceSelector.setExternalRenderTargetSize(QSize(454, 454));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkSurfacePixelRatioUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSurfaceSelector renderSurfaceSelector;
+ arbiter.setArbiterOnNode(&renderSurfaceSelector);
+
+ {
+ // WHEN
+ renderSurfaceSelector.setSurfacePixelRatio(99.0f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "surfacePixelRatio");
+ QCOMPARE(change->value().value<float>(), renderSurfaceSelector.surfacePixelRatio());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderSurfaceSelector.setSurfacePixelRatio(99.0f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
};
QTEST_MAIN(tst_QRenderSurfaceSelector)
diff --git a/tests/auto/render/qrendertarget/qrendertarget.pro b/tests/auto/render/qrendertarget/qrendertarget.pro
new file mode 100644
index 000000000..094dd67a7
--- /dev/null
+++ b/tests/auto/render/qrendertarget/qrendertarget.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qrendertarget
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qrendertarget.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qrendertarget/tst_qrendertarget.cpp b/tests/auto/render/qrendertarget/tst_qrendertarget.cpp
new file mode 100644
index 000000000..03a9e5f94
--- /dev/null
+++ b/tests/auto/render/qrendertarget/tst_qrendertarget.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendertarget.h>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <Qt3DRender/private/qrendertarget_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QRenderTarget : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QRenderTarget renderTarget;
+
+ // THEN
+ QVERIFY(renderTarget.outputs().empty());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QRenderTarget renderTarget;
+
+ // WHEN
+ Qt3DRender::QRenderTargetOutput output;
+
+ renderTarget.addOutput(&output);
+
+ // THEN
+ QCOMPARE(renderTarget.outputs().size(), 1);
+
+ // WHEN
+ renderTarget.addOutput(&output);
+
+ // THEN
+ QCOMPARE(renderTarget.outputs().size(), 1);
+
+ // WHEN
+ renderTarget.removeOutput(&output);
+
+ // THEN
+ QCOMPARE(renderTarget.outputs().size(), 0);
+ }
+
+ void checkRenderTargetOutputBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QRenderTarget renderTarget;
+
+ {
+ // WHEN
+ Qt3DRender::QRenderTargetOutput output;
+ renderTarget.addOutput(&output);
+
+ // THEN
+ QCOMPARE(renderTarget.outputs().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(renderTarget.outputs().size(), 0);
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QRenderTarget renderTarget;
+ Qt3DRender::QRenderTargetOutput output;
+
+ renderTarget.addOutput(&output);
+
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderTarget);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // Target + Output
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderTargetData>>(creationChanges.first());
+ const Qt3DRender::QRenderTargetData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderTarget.id(), creationChangeData->subjectId());
+ QCOMPARE(renderTarget.isEnabled(), true);
+ QCOMPARE(renderTarget.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderTarget.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(renderTarget.outputs().size(), cloneData.outputIds.size());
+ QCOMPARE(output.id(), cloneData.outputIds.first());
+ }
+
+ // WHEN
+ renderTarget.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&renderTarget);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // Target + Output
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QRenderTargetData>>(creationChanges.first());
+ const Qt3DRender::QRenderTargetData cloneData = creationChangeData->data;
+
+ QCOMPARE(renderTarget.id(), creationChangeData->subjectId());
+ QCOMPARE(renderTarget.isEnabled(), false);
+ QCOMPARE(renderTarget.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(renderTarget.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(renderTarget.outputs().size(), cloneData.outputIds.size());
+ QCOMPARE(output.id(), cloneData.outputIds.first());
+ }
+ }
+
+ void checkRenderTargetOutputUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderTarget renderTarget;
+ Qt3DRender::QRenderTargetOutput renderTargetOutput;
+ arbiter.setArbiterOnNode(&renderTarget);
+
+ {
+ // WHEN
+ renderTarget.addOutput(&renderTargetOutput);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "output");
+ QCOMPARE(change->addedNodeId(), renderTargetOutput.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ renderTarget.removeOutput(&renderTargetOutput);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "output");
+ QCOMPARE(change->removedNodeId(), renderTargetOutput.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+ }
+};
+
+QTEST_MAIN(tst_QRenderTarget)
+
+#include "tst_qrendertarget.moc"
diff --git a/tests/auto/render/qrendertargetselector/qrendertargetselector.pro b/tests/auto/render/qrendertargetselector/qrendertargetselector.pro
index 8f4c110df..4821b25ec 100644
--- a/tests/auto/render/qrendertargetselector/qrendertargetselector.pro
+++ b/tests/auto/render/qrendertargetselector/qrendertargetselector.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qrendertargetselector.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qsceneloader/qsceneloader.pro b/tests/auto/render/qsceneloader/qsceneloader.pro
index abaf8da86..7f516f19f 100644
--- a/tests/auto/render/qsceneloader/qsceneloader.pro
+++ b/tests/auto/render/qsceneloader/qsceneloader.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qsceneloader.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qsortpolicy/qsortpolicy.pro b/tests/auto/render/qsortpolicy/qsortpolicy.pro
index 1f955d2f0..c9020109f 100644
--- a/tests/auto/render/qsortpolicy/qsortpolicy.pro
+++ b/tests/auto/render/qsortpolicy/qsortpolicy.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qsortpolicy.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qtechnique/qtechnique.pro b/tests/auto/render/qtechnique/qtechnique.pro
new file mode 100644
index 000000000..cf6ecbee9
--- /dev/null
+++ b/tests/auto/render/qtechnique/qtechnique.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qtechnique
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qtechnique.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qtechnique/tst_qtechnique.cpp b/tests/auto/render/qtechnique/tst_qtechnique.cpp
new file mode 100644
index 000000000..1026dddc0
--- /dev/null
+++ b/tests/auto/render/qtechnique/tst_qtechnique.cpp
@@ -0,0 +1,507 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qtechnique.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qfilterkey.h>
+#include <Qt3DRender/qrenderpass.h>
+#include <Qt3DRender/qgraphicsapifilter.h>
+#include <Qt3DRender/private/qgraphicsapifilter_p.h>
+#include <Qt3DRender/private/qtechnique_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QTechnique : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+
+ // THEN
+ QCOMPARE(technique.graphicsApiFilter()->profile(), Qt3DRender::QGraphicsApiFilter::NoProfile);
+ QCOMPARE(technique.graphicsApiFilter()->majorVersion(), 0);
+ QCOMPARE(technique.graphicsApiFilter()->minorVersion(), 0);
+ QVERIFY(technique.renderPasses().empty());
+ QVERIFY(technique.parameters().empty());
+ QVERIFY(technique.filterKeys().empty());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+
+ {
+ // WHEN
+ Qt3DRender::QRenderPass pass;
+
+ technique.addRenderPass(&pass);
+
+ // THEN
+ QCOMPARE(technique.renderPasses().size(), 1);
+
+ // WHEN
+ technique.addRenderPass(&pass);
+
+ // THEN
+ QCOMPARE(technique.renderPasses().size(), 1);
+
+ // WHEN
+ technique.removeRenderPass(&pass);
+
+ // THEN
+ QCOMPARE(technique.renderPasses().size(), 0);
+ }
+ {
+ // WHEN
+ Qt3DRender::QParameter parameter;
+
+ technique.addParameter(&parameter);
+
+ // THEN
+ QCOMPARE(technique.parameters().size(), 1);
+
+ // WHEN
+ technique.addParameter(&parameter);
+
+ // THEN
+ QCOMPARE(technique.parameters().size(), 1);
+
+ // WHEN
+ technique.removeParameter(&parameter);
+
+ // THEN
+ QCOMPARE(technique.parameters().size(), 0);
+ }
+ {
+ // WHEN
+ Qt3DRender::QFilterKey filterKey;
+
+ technique.addFilterKey(&filterKey);
+
+ // THEN
+ QCOMPARE(technique.filterKeys().size(), 1);
+
+ // WHEN
+ technique.addFilterKey(&filterKey);
+
+ // THEN
+ QCOMPARE(technique.filterKeys().size(), 1);
+
+ // WHEN
+ technique.removeFilterKey(&filterKey);
+
+ // THEN
+ QCOMPARE(technique.filterKeys().size(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(technique.graphicsApiFilter(), SIGNAL(graphicsApiFilterChanged()));
+ technique.graphicsApiFilter()->setMajorVersion(3);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(technique.graphicsApiFilter()->majorVersion(), 3);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ technique.graphicsApiFilter()->setMajorVersion(3);
+
+ // THEN
+ QCOMPARE(technique.graphicsApiFilter()->majorVersion(), 3);
+ QCOMPARE(spy.count(), 0);
+
+ // WHEN
+ technique.graphicsApiFilter()->setMinorVersion(2);
+
+ // THEN
+ QCOMPARE(technique.graphicsApiFilter()->minorVersion(), 2);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ technique.graphicsApiFilter()->setMinorVersion(2);
+
+ // THEN
+ QCOMPARE(technique.graphicsApiFilter()->minorVersion(), 2);
+ QCOMPARE(spy.count(), 0);
+
+ // WHEN
+ technique.graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);
+
+ // THEN
+ QCOMPARE(technique.graphicsApiFilter()->profile(), Qt3DRender::QGraphicsApiFilter::CoreProfile);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ technique.graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CoreProfile);
+
+ // THEN
+ QCOMPARE(technique.graphicsApiFilter()->profile(), Qt3DRender::QGraphicsApiFilter::CoreProfile);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkRenderPassBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+
+ {
+ // WHEN
+ Qt3DRender::QRenderPass pass;
+ technique.addRenderPass(&pass);
+
+ // THEN
+ QCOMPARE(technique.renderPasses().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(technique.renderPasses().size(), 0);
+ }
+
+ void checkParameterBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+
+ {
+ // WHEN
+ Qt3DRender::QParameter parameter;
+ technique.addParameter(&parameter);
+
+ // THEN
+ QCOMPARE(technique.parameters().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(technique.parameters().size(), 0);
+ }
+
+ void checkFilterKeyBookkeeping()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+
+ {
+ // WHEN
+ Qt3DRender::QFilterKey filterKey;
+ technique.addFilterKey(&filterKey);
+
+ // THEN
+ QCOMPARE(technique.filterKeys().size(), 1);
+ }
+
+ // THEN -> should not crash
+ QCOMPARE(technique.filterKeys().size(), 0);
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QRenderPass pass;
+ Qt3DRender::QParameter parameter;
+ Qt3DRender::QFilterKey filterKey;
+
+ technique.addRenderPass(&pass);
+ technique.addParameter(&parameter);
+ technique.addFilterKey(&filterKey);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&technique);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 4); // Technique + Pass + Parameter + FilterKey
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QTechniqueData>>(creationChanges.first());
+ const Qt3DRender::QTechniqueData cloneData = creationChangeData->data;
+
+ QCOMPARE(technique.graphicsApiFilter()->minorVersion(), cloneData.graphicsApiFilterData.m_minor);
+ QCOMPARE(technique.graphicsApiFilter()->majorVersion(), cloneData.graphicsApiFilterData.m_major);
+ QCOMPARE(technique.graphicsApiFilter()->profile(), cloneData.graphicsApiFilterData.m_profile);
+ QCOMPARE(technique.graphicsApiFilter()->vendor(), cloneData.graphicsApiFilterData.m_vendor);
+ QCOMPARE(technique.graphicsApiFilter()->extensions(), cloneData.graphicsApiFilterData.m_extensions);
+ QCOMPARE(technique.graphicsApiFilter()->api(), cloneData.graphicsApiFilterData.m_api);
+ QCOMPARE(technique.id(), creationChangeData->subjectId());
+ QCOMPARE(technique.isEnabled(), true);
+ QCOMPARE(technique.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(technique.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(technique.renderPasses().size(), cloneData.renderPassIds.size());
+ QCOMPARE(technique.parameters().size(), cloneData.parameterIds.size());
+ QCOMPARE(technique.filterKeys().size(), cloneData.filterKeyIds.size());
+ QCOMPARE(pass.id(), cloneData.renderPassIds.first());
+ QCOMPARE(parameter.id(), cloneData.parameterIds.first());
+ QCOMPARE(filterKey.id(), cloneData.filterKeyIds.first());
+ }
+
+ // WHEN
+ technique.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&technique);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 4); // Technique + Pass + Parameter + FilterKey
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QTechniqueData>>(creationChanges.first());
+ const Qt3DRender::QTechniqueData cloneData = creationChangeData->data;
+
+ QCOMPARE(technique.graphicsApiFilter()->minorVersion(), cloneData.graphicsApiFilterData.m_minor);
+ QCOMPARE(technique.graphicsApiFilter()->majorVersion(), cloneData.graphicsApiFilterData.m_major);
+ QCOMPARE(technique.graphicsApiFilter()->profile(), cloneData.graphicsApiFilterData.m_profile);
+ QCOMPARE(technique.graphicsApiFilter()->vendor(), cloneData.graphicsApiFilterData.m_vendor);
+ QCOMPARE(technique.graphicsApiFilter()->extensions(), cloneData.graphicsApiFilterData.m_extensions);
+ QCOMPARE(technique.graphicsApiFilter()->api(), cloneData.graphicsApiFilterData.m_api);
+ QCOMPARE(technique.id(), creationChangeData->subjectId());
+ QCOMPARE(technique.isEnabled(), false);
+ QCOMPARE(technique.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(technique.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(technique.renderPasses().size(), cloneData.renderPassIds.size());
+ QCOMPARE(technique.parameters().size(), cloneData.parameterIds.size());
+ QCOMPARE(technique.filterKeys().size(), cloneData.filterKeyIds.size());
+ QCOMPARE(pass.id(), cloneData.renderPassIds.first());
+ QCOMPARE(parameter.id(), cloneData.parameterIds.first());
+ QCOMPARE(filterKey.id(), cloneData.filterKeyIds.first());
+ }
+ }
+
+ void checkRenderPassUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QRenderPass pass;
+ arbiter.setArbiterOnNode(&technique);
+
+ {
+ // WHEN
+ technique.addRenderPass(&pass);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "pass");
+ QCOMPARE(change->addedNodeId(), pass.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ technique.removeRenderPass(&pass);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "pass");
+ QCOMPARE(change->removedNodeId(), pass.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+ }
+
+ void checkParameterUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QParameter parameter;
+ arbiter.setArbiterOnNode(&technique);
+
+ {
+ // WHEN
+ technique.addParameter(&parameter);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "parameter");
+ QCOMPARE(change->addedNodeId(), parameter.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ technique.removeParameter(&parameter);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "parameter");
+ QCOMPARE(change->removedNodeId(), parameter.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+ }
+
+ void checkFilterKeyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QFilterKey filterKey;
+ arbiter.setArbiterOnNode(&technique);
+
+ {
+ // WHEN
+ technique.addFilterKey(&filterKey);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeAddedChange>();
+ QCOMPARE(change->propertyName(), "filterKeys");
+ QCOMPARE(change->addedNodeId(), filterKey.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueAdded);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ technique.removeFilterKey(&filterKey);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyNodeRemovedChange>();
+ QCOMPARE(change->propertyName(), "filterKeys");
+ QCOMPARE(change->removedNodeId(), filterKey.id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyValueRemoved);
+
+ arbiter.events.clear();
+ }
+ }
+
+ void checkGraphicsAPIFilterUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTechnique technique;
+ arbiter.setArbiterOnNode(&technique);
+
+ {
+ // WHEN
+ technique.graphicsApiFilter()->setMajorVersion(4);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "graphicsApiFilterData");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ Qt3DRender::GraphicsApiFilterData data = change->value().value<Qt3DRender::GraphicsApiFilterData>();
+ QCOMPARE(data.m_major, 4);
+
+ arbiter.events.clear();
+ }
+ {
+ // WHEN
+ technique.graphicsApiFilter()->setMinorVersion(5);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "graphicsApiFilterData");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ Qt3DRender::GraphicsApiFilterData data = change->value().value<Qt3DRender::GraphicsApiFilterData>();
+ QCOMPARE(data.m_minor, 5);
+
+ arbiter.events.clear();
+ }
+ {
+ // WHEN
+ technique.graphicsApiFilter()->setVendor(QStringLiteral("AMD"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "graphicsApiFilterData");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ Qt3DRender::GraphicsApiFilterData data = change->value().value<Qt3DRender::GraphicsApiFilterData>();
+ QCOMPARE(data.m_vendor, QStringLiteral("AMD"));
+
+ arbiter.events.clear();
+ }
+ {
+ // WHEN
+ technique.graphicsApiFilter()->setProfile(Qt3DRender::QGraphicsApiFilter::CompatibilityProfile);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "graphicsApiFilterData");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ Qt3DRender::GraphicsApiFilterData data = change->value().value<Qt3DRender::GraphicsApiFilterData>();
+ QCOMPARE(data.m_profile, Qt3DRender::QGraphicsApiFilter::CompatibilityProfile);
+
+ arbiter.events.clear();
+ }
+ }
+};
+
+QTEST_MAIN(tst_QTechnique)
+
+#include "tst_qtechnique.moc"
diff --git a/tests/auto/render/qtechniquefilter/qtechniquefilter.pro b/tests/auto/render/qtechniquefilter/qtechniquefilter.pro
index 772176823..303f9561b 100644
--- a/tests/auto/render/qtechniquefilter/qtechniquefilter.pro
+++ b/tests/auto/render/qtechniquefilter/qtechniquefilter.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qtechniquefilter.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qtextureimage/qtextureimage.pro b/tests/auto/render/qtextureimage/qtextureimage.pro
new file mode 100644
index 000000000..9f556e41b
--- /dev/null
+++ b/tests/auto/render/qtextureimage/qtextureimage.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qtextureimage
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qtextureimage.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qtextureimage/tst_qtextureimage.cpp b/tests/auto/render/qtextureimage/tst_qtextureimage.cpp
new file mode 100644
index 000000000..224784011
--- /dev/null
+++ b/tests/auto/render/qtextureimage/tst_qtextureimage.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qtextureimage.h>
+#include <Qt3DRender/private/qtextureimage_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QTextureImage : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QTextureImage textureImage;
+
+ // THEN
+ QCOMPARE(textureImage.source(), QUrl());
+ QCOMPARE(textureImage.status(), Qt3DRender::QTextureImage::None);
+ QCOMPARE(textureImage.isMirrored(), true);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QTextureImage textureImage;
+
+ {
+ // WHEN
+ QSignalSpy spy(&textureImage, SIGNAL(sourceChanged(QUrl)));
+ const QUrl newValue(QStringLiteral("Boulder"));
+ textureImage.setSource(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(textureImage.source(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ textureImage.setSource(newValue);
+
+ // THEN
+ QCOMPARE(textureImage.source(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&textureImage, SIGNAL(mirroredChanged(bool)));
+ const bool newValue = false;
+ textureImage.setMirrored(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(textureImage.isMirrored(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ textureImage.setMirrored(newValue);
+
+ // THEN
+ QCOMPARE(textureImage.isMirrored(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QTextureImage textureImage;
+
+ textureImage.setSource(QUrl(QStringLiteral("URL")));
+ textureImage.setMirrored(false);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&textureImage);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureImageData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureImageData cloneData = creationChangeData->data;
+
+ QCOMPARE(textureImage.id(), creationChangeData->subjectId());
+ QCOMPARE(textureImage.isEnabled(), true);
+ QCOMPARE(textureImage.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(textureImage.metaObject(), creationChangeData->metaObject());
+
+ const auto generator = qSharedPointerCast<Qt3DRender::QImageTextureDataFunctor>(cloneData.generator);
+ QVERIFY(generator);
+ QCOMPARE(generator->isMirrored(), textureImage.isMirrored());
+ QCOMPARE(generator->url(), textureImage.source());
+
+ }
+
+ // WHEN
+ textureImage.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&textureImage);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureImageData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureImageData cloneData = creationChangeData->data;
+
+ QCOMPARE(textureImage.id(), creationChangeData->subjectId());
+ QCOMPARE(textureImage.isEnabled(), false);
+ QCOMPARE(textureImage.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(textureImage.metaObject(), creationChangeData->metaObject());
+
+ const auto generator = qSharedPointerCast<Qt3DRender::QImageTextureDataFunctor>(cloneData.generator);
+ QVERIFY(generator);
+ QCOMPARE(generator->isMirrored(), textureImage.isMirrored());
+ QCOMPARE(generator->url(), textureImage.source());
+ }
+ }
+
+ void checkSourceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTextureImage textureImage;
+ arbiter.setArbiterOnNode(&textureImage);
+
+ {
+ // WHEN
+ textureImage.setSource(QUrl(QStringLiteral("Qt3D")));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "dataGenerator");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ const auto generator = qSharedPointerCast<Qt3DRender::QImageTextureDataFunctor>(change->value().value<Qt3DRender::QTextureImageDataGeneratorPtr>());
+ QVERIFY(generator);
+ QCOMPARE(generator->url(), textureImage.source());
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ textureImage.setSource(QUrl(QStringLiteral("Qt3D")));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMirroredUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTextureImage textureImage;
+ arbiter.setArbiterOnNode(&textureImage);
+
+ {
+ // WHEN
+ textureImage.setMirrored(false);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "dataGenerator");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ const auto generator = qSharedPointerCast<Qt3DRender::QImageTextureDataFunctor>(change->value().value<Qt3DRender::QTextureImageDataGeneratorPtr>());
+ QVERIFY(generator);
+ QCOMPARE(generator->isMirrored(), textureImage.isMirrored());
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ textureImage.setMirrored(false);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QTextureImage)
+
+#include "tst_qtextureimage.moc"
diff --git a/tests/auto/render/qtextureimagedata/qtextureimagedata.pro b/tests/auto/render/qtextureimagedata/qtextureimagedata.pro
index cfa1bdb51..b734db9d1 100644
--- a/tests/auto/render/qtextureimagedata/qtextureimagedata.pro
+++ b/tests/auto/render/qtextureimagedata/qtextureimagedata.pro
@@ -7,4 +7,4 @@ CONFIG += testcase
SOURCES += tst_qtextureimagedata.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qtextureloader/qtextureloader.pro b/tests/auto/render/qtextureloader/qtextureloader.pro
new file mode 100644
index 000000000..089a2c61a
--- /dev/null
+++ b/tests/auto/render/qtextureloader/qtextureloader.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qtextureloader
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qtextureloader.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qtextureloader/tst_qtextureloader.cpp b/tests/auto/render/qtextureloader/tst_qtextureloader.cpp
new file mode 100644
index 000000000..252bc85af
--- /dev/null
+++ b/tests/auto/render/qtextureloader/tst_qtextureloader.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qtexture.h>
+#include <Qt3DRender/private/qtexture_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include "testpostmanarbiter.h"
+
+class tst_QTextureLoader : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QTextureLoader textureLoader;
+
+ // THEN
+ QCOMPARE(textureLoader.source(), QUrl());
+ QCOMPARE(textureLoader.isMirrored(), true);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QTextureLoader textureLoader;
+
+ {
+ // WHEN
+ QSignalSpy spy(&textureLoader, SIGNAL(sourceChanged(QUrl)));
+ const QUrl newValue(QStringLiteral("http://msn.com"));
+ textureLoader.setSource(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(textureLoader.source(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ textureLoader.setSource(newValue);
+
+ // THEN
+ QCOMPARE(textureLoader.source(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&textureLoader, SIGNAL(mirroredChanged(bool)));
+ const bool newValue = false;
+ textureLoader.setMirrored(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(textureLoader.isMirrored(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ textureLoader.setMirrored(newValue);
+
+ // THEN
+ QCOMPARE(textureLoader.isMirrored(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QTextureLoader textureLoader;
+
+ textureLoader.setSource(QUrl(QStringLiteral("SomeUrl")));
+ textureLoader.setMirrored(false);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&textureLoader);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureData>>(creationChanges.first());
+ const Qt3DRender::QAbstractTextureData cloneData = creationChangeData->data;
+
+ QCOMPARE(textureLoader.id(), creationChangeData->subjectId());
+ QCOMPARE(textureLoader.isEnabled(), true);
+ QCOMPARE(textureLoader.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(textureLoader.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ textureLoader.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&textureLoader);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QAbstractTextureData>>(creationChanges.first());
+
+ QCOMPARE(textureLoader.id(), creationChangeData->subjectId());
+ QCOMPARE(textureLoader.isEnabled(), false);
+ QCOMPARE(textureLoader.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(textureLoader.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkSourceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTextureLoader textureLoader;
+ arbiter.setArbiterOnNode(&textureLoader);
+
+ {
+ // WHEN
+ textureLoader.setSource(QUrl(QStringLiteral("Gary")));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ const auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "generator");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ const auto generator = qSharedPointerCast<Qt3DRender::QTextureFromSourceGenerator>(change->value().value<Qt3DRender::QTextureGeneratorPtr>());
+ QVERIFY(generator);
+ QCOMPARE(generator->url(), QUrl(QStringLiteral("Gary")));
+
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ textureLoader.setSource(QUrl(QStringLiteral("Gary")));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkMirroredUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QTextureLoader textureLoader;
+ arbiter.setArbiterOnNode(&textureLoader);
+
+ {
+ // WHEN
+ textureLoader.setMirrored(false);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ const auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "generator");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ const auto generator = qSharedPointerCast<Qt3DRender::QTextureFromSourceGenerator>(change->value().value<Qt3DRender::QTextureGeneratorPtr>());
+ QVERIFY(generator);
+ QCOMPARE(generator->isMirrored(), false);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ textureLoader.setMirrored(false);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+};
+
+QTEST_MAIN(tst_QTextureLoader)
+
+#include "tst_qtextureloader.moc"
diff --git a/tests/auto/render/qviewport/qviewport.pro b/tests/auto/render/qviewport/qviewport.pro
index 3f0a2f070..bc9931741 100644
--- a/tests/auto/render/qviewport/qviewport.pro
+++ b/tests/auto/render/qviewport/qviewport.pro
@@ -8,4 +8,4 @@ CONFIG += testcase
SOURCES += tst_qviewport.cpp
-include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro
index c5447485c..ac2efd581 100644
--- a/tests/auto/render/render.pro
+++ b/tests/auto/render/render.pro
@@ -64,7 +64,34 @@ qtConfig(private_tests) {
graphicshelpergl3_3 \
graphicshelpergl3_2 \
graphicshelpergl2 \
- gltfplugins
+ gltfplugins \
+ pickboundingvolumejob \
+ sendrendercapturejob \
+ textures \
+ qparameter \
+ parameter \
+ qtextureloader \
+ qtextureimage \
+ qabstracttexture \
+ qabstracttextureimage \
+ qrendersettings \
+ updatemeshtrianglelistjob \
+ updateshaderdatatransformjob \
+ texturedatamanager \
+ rendertarget \
+ transform \
+ computecommand \
+ qrendertarget \
+ qdispatchcompute \
+ qtechnique \
+ qeffect \
+ qrenderpass \
+ qfilterkey \
+ effect \
+ filterkey \
+ qmesh \
+ technique \
+ materialparametergathererjob
!macos: SUBDIRS += graphicshelpergl4
}
diff --git a/tests/auto/render/renderpass/tst_renderpass.cpp b/tests/auto/render/renderpass/tst_renderpass.cpp
index 8b178eca7..a4a2762ba 100644
--- a/tests/auto/render/renderpass/tst_renderpass.cpp
+++ b/tests/auto/render/renderpass/tst_renderpass.cpp
@@ -85,12 +85,47 @@ private slots:
RenderPass backend;
// THEN
+ QVERIFY(!backend.isEnabled());
QVERIFY(backend.shaderProgram().isNull());
QVERIFY(backend.filterKeys().isEmpty());
QVERIFY(backend.renderStates().isEmpty());
QVERIFY(backend.parameters().isEmpty());
}
+ void checkCleanupState()
+ {
+ // GIVEN
+ RenderPass backend;
+
+ // WHEN
+ backend.setEnabled(true);
+
+ {
+ QRenderPass frontend;
+ QShaderProgram program;
+ QBlendEquationArguments state;
+ QParameter parameter;
+ QFilterKey filterKey;
+
+ frontend.addFilterKey(&filterKey);
+ frontend.addParameter(&parameter);
+ frontend.addRenderState(&state);
+ frontend.setShaderProgram(&program);
+
+ simulateInitialization(&frontend, &backend);
+ }
+
+ backend.cleanup();
+
+ // THEN
+ QVERIFY(!backend.isEnabled());
+ QVERIFY(backend.shaderProgram().isNull());
+ QVERIFY(backend.filterKeys().isEmpty());
+ QVERIFY(backend.renderStates().isEmpty());
+ QVERIFY(backend.parameters().isEmpty());
+ QVERIFY(!backend.hasRenderStates());
+ }
+
void shouldHavePropertiesMirroringItsPeer()
{
// GIVEN
@@ -124,6 +159,7 @@ private slots:
QCOMPARE(backend.renderStates().size(), 1);
QCOMPARE(backend.renderStates().first(), backendState->peerId());
+ QVERIFY(backend.hasRenderStates());
}
void shouldHandleShaderPropertyChangeEvents()
@@ -209,10 +245,9 @@ private slots:
QVERIFY(backend.parameters().isEmpty());
}
- void shouldHandlePropertyChangeEvents()
+ void shouldHandleRenderStatePropertyChangeEvents()
{
QRenderState *frontendState = new QBlendEquationArguments();
- QNodePtr frontendStatePtr(frontendState);
RenderPass backend;
TestRenderer renderer;
@@ -240,6 +275,24 @@ private slots:
QVERIFY(backend.renderStates().isEmpty());
}
+ void shouldHandleShaderProgramPropertyChangeEvents()
+ {
+ // GIVEN
+ RenderPass backend;
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+
+ // WHEN
+ Qt3DCore::QNodeId shaderId = Qt3DCore::QNodeId::createId();
+ const auto shaderChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ shaderChange->setPropertyName("shaderProgram");
+ shaderChange->setValue(QVariant::fromValue(shaderId));
+ backend.sceneChangeEvent(shaderChange);
+
+ // THEN
+ QCOMPARE(backend.shaderProgram(), shaderId);
+ }
+
private:
RenderStateManager *m_renderStateManager;
};
diff --git a/tests/auto/render/rendertarget/rendertarget.pro b/tests/auto/render/rendertarget/rendertarget.pro
new file mode 100644
index 000000000..29eaf8b3a
--- /dev/null
+++ b/tests/auto/render/rendertarget/rendertarget.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_rendertarget
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_rendertarget.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/rendertarget/tst_rendertarget.cpp b/tests/auto/render/rendertarget/tst_rendertarget.cpp
new file mode 100644
index 000000000..a5d8cad77
--- /dev/null
+++ b/tests/auto/render/rendertarget/tst_rendertarget.cpp
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qrendertarget.h>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <Qt3DRender/private/qrendertarget_p.h>
+#include <Qt3DRender/private/rendertarget_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_RenderTarget : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+
+ // THEN
+ QCOMPARE(backendRenderTarget.isEnabled(), false);
+ QVERIFY(backendRenderTarget.peerId().isNull());
+ QVERIFY(backendRenderTarget.renderOutputs().empty());
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+
+ // WHEN
+ backendRenderTarget.setEnabled(true);
+ backendRenderTarget.appendRenderOutput(Qt3DCore::QNodeId::createId());
+ backendRenderTarget.appendRenderOutput(Qt3DCore::QNodeId::createId());
+
+ backendRenderTarget.cleanup();
+
+ // THEN
+ QCOMPARE(backendRenderTarget.isEnabled(), false);
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 0);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QRenderTarget renderTarget;
+ Qt3DRender::QRenderTargetOutput renderTargetOuput;
+ renderTarget.addOutput(&renderTargetOuput);
+
+ {
+ // WHEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+ simulateInitialization(&renderTarget, &backendRenderTarget);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.isEnabled(), true);
+ QCOMPARE(backendRenderTarget.peerId(), renderTarget.id());
+ QCOMPARE(backendRenderTarget.renderOutputs(), QVector<Qt3DCore::QNodeId>() << renderTargetOuput.id());
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+ renderTarget.setEnabled(false);
+ simulateInitialization(&renderTarget, &backendRenderTarget);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.peerId(), renderTarget.id());
+ QCOMPARE(backendRenderTarget.isEnabled(), false);
+ }
+ }
+
+ void checkAddNoDuplicateOutput()
+ {
+ // GIVEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 0);
+
+ // WHEN
+ Qt3DCore::QNodeId renderTargetOutputId = Qt3DCore::QNodeId::createId();
+ backendRenderTarget.appendRenderOutput(renderTargetOutputId);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 1);
+
+ // WHEN
+ backendRenderTarget.appendRenderOutput(renderTargetOutputId);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 1);
+ }
+
+ void checkAddRemoveOutput()
+ {
+ // GIVEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 0);
+
+ // WHEN
+ Qt3DCore::QNodeId renderTargetOutputId1 = Qt3DCore::QNodeId::createId();
+ Qt3DCore::QNodeId renderTargetOutputId2 = Qt3DCore::QNodeId::createId();
+ backendRenderTarget.appendRenderOutput(renderTargetOutputId1);
+ backendRenderTarget.appendRenderOutput(renderTargetOutputId2);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 2);
+
+ // WHEN
+ backendRenderTarget.removeRenderOutput(Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 2);
+
+ // WHEN
+ backendRenderTarget.removeRenderOutput(renderTargetOutputId1);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 1);
+
+ // WHEN
+ backendRenderTarget.removeRenderOutput(renderTargetOutputId1);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 1);
+
+ // WHEN
+ backendRenderTarget.removeRenderOutput(renderTargetOutputId2);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 0);
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::RenderTarget backendRenderTarget;
+ TestRenderer renderer;
+ backendRenderTarget.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendRenderTarget.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ Qt3DRender::QRenderTargetOutput targetOutput;
+ const auto addChange = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &targetOutput);
+ addChange->setPropertyName("output");
+ backendRenderTarget.sceneChangeEvent(addChange);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 1);
+ QCOMPARE(backendRenderTarget.renderOutputs().first(), targetOutput.id());
+
+ // WHEN
+ const auto removeChange = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &targetOutput);
+ removeChange->setPropertyName("output");
+ backendRenderTarget.sceneChangeEvent(removeChange);
+
+ // THEN
+ QCOMPARE(backendRenderTarget.renderOutputs().size(), 0);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_RenderTarget)
+
+#include "tst_rendertarget.moc"
diff --git a/tests/auto/render/sendrendercapturejob/sendrendercapturejob.pro b/tests/auto/render/sendrendercapturejob/sendrendercapturejob.pro
new file mode 100644
index 000000000..6aff0bebd
--- /dev/null
+++ b/tests/auto/render/sendrendercapturejob/sendrendercapturejob.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_sendrendercapturejob
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_sendrendercapturejob.cpp
+
+include(../commons/commons.pri)
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp b/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp
new file mode 100644
index 000000000..3310941ed
--- /dev/null
+++ b/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include "Qt3DRender/QRenderAspect"
+#include "Qt3DRender/private/renderer_p.h"
+#include "Qt3DRender/private/nodemanagers_p.h"
+#include "Qt3DRender/private/rendercapture_p.h"
+#include <Qt3DRender/private/sendrendercapturejob_p.h>
+#include "testpostmanarbiter.h"
+
+class tst_SendRenderCaptureJob : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void testSendRenderCaptureRequest()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::Render::RenderCapture *renderCapture = new Qt3DRender::Render::RenderCapture;
+ Qt3DCore::QBackendNodePrivate::get(renderCapture)->setArbiter(&arbiter);
+
+ QImage image(10, 10, QImage::Format_ARGB32);
+
+ Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
+ Qt3DRender::Render::SendRenderCaptureJob job(&renderer);
+
+ Qt3DRender::Render::NodeManagers nodeManagers;
+ nodeManagers.frameGraphManager()->appendNode(renderCapture->peerId(), renderCapture);
+ renderer.setNodeManagers(&nodeManagers);
+ job.setManagers(&nodeManagers);
+
+ renderCapture->requestCapture(42);
+ renderCapture->acknowledgeCaptureRequest();
+ renderCapture->addRenderCapture(image);
+ renderer.addRenderCaptureSendRequest(renderCapture->peerId());
+
+ //WHEN
+ job.run();
+
+ //THEN
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->subjectId(), renderCapture->peerId());
+ QCOMPARE(change->propertyName(), "renderCaptureData");
+ auto data = change->value().value<Qt3DRender::RenderCaptureDataPtr>();
+ QCOMPARE(data.data()->captureId, 42);
+ QCOMPARE(data.data()->image.width(), 10);
+ QCOMPARE(data.data()->image.height(), 10);
+ QCOMPARE(data.data()->image.format(), QImage::Format_ARGB32);
+
+ // renderCapture will be deallocated by the nodeManagers destructor
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_SendRenderCaptureJob)
+
+#include "tst_sendrendercapturejob.moc"
diff --git a/tests/auto/render/technique/technique.pro b/tests/auto/render/technique/technique.pro
new file mode 100644
index 000000000..78a6cf8c5
--- /dev/null
+++ b/tests/auto/render/technique/technique.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_technique
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_technique.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/technique/tst_technique.cpp b/tests/auto/render/technique/tst_technique.cpp
new file mode 100644
index 000000000..a712434d1
--- /dev/null
+++ b/tests/auto/render/technique/tst_technique.cpp
@@ -0,0 +1,484 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qtechnique.h>
+#include <Qt3DRender/qfilterkey.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qrenderpass.h>
+#include <Qt3DRender/private/qtechnique_p.h>
+#include <Qt3DRender/private/technique_p.h>
+#include <Qt3DRender/private/shaderparameterpack_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/filterkey_p.h>
+#include <Qt3DRender/private/techniquemanager_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_Technique : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Technique backendTechnique;
+
+ // THEN
+ QCOMPARE(backendTechnique.isEnabled(), false);
+ QVERIFY(backendTechnique.peerId().isNull());
+
+ QCOMPARE(backendTechnique.graphicsApiFilter()->m_minor, 0);
+ QCOMPARE(backendTechnique.graphicsApiFilter()->m_major, 0);
+ QCOMPARE(backendTechnique.graphicsApiFilter()->m_profile, Qt3DRender::QGraphicsApiFilter::NoProfile);
+ QCOMPARE(backendTechnique.graphicsApiFilter()->m_vendor, QString());
+ QCOMPARE(backendTechnique.graphicsApiFilter()->m_extensions, QStringList());
+
+ QCOMPARE(backendTechnique.parameters().size(), 0);
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ QCOMPARE(backendTechnique.renderPasses().size(), 0);
+ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
+ QVERIFY(backendTechnique.nodeManager() == nullptr);
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Technique backendTechnique;
+ Qt3DRender::Render::NodeManagers nodeManagers;
+
+ // WHEN
+ backendTechnique.setEnabled(true);
+ backendTechnique.setNodeManager(&nodeManagers);
+ backendTechnique.setCompatibleWithRenderer(true);
+
+ {
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QRenderPass pass;
+ Qt3DRender::QParameter parameter;
+ Qt3DRender::QFilterKey filterKey;
+
+ technique.addRenderPass(&pass);
+ technique.addParameter(&parameter);
+ technique.addFilterKey(&filterKey);
+
+ simulateInitialization(&technique, &backendTechnique);
+ }
+
+ backendTechnique.cleanup();
+
+ // THEN
+ QCOMPARE(backendTechnique.isEnabled(), false);
+ QCOMPARE(backendTechnique.parameters().size(), 0);
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ QCOMPARE(backendTechnique.renderPasses().size(), 0);
+ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QTechnique technique;
+ Qt3DRender::QRenderPass pass;
+ Qt3DRender::QParameter parameter;
+ Qt3DRender::QFilterKey filterKey;
+
+ technique.addRenderPass(&pass);
+ technique.addParameter(&parameter);
+ technique.addFilterKey(&filterKey);
+
+ {
+ // WHEN
+ Qt3DRender::Render::Technique backendTechnique;
+ Qt3DRender::Render::NodeManagers nodeManagers;
+
+ backendTechnique.setNodeManager(&nodeManagers);
+ simulateInitialization(&technique, &backendTechnique);
+
+ // THEN
+ QCOMPARE(backendTechnique.isEnabled(), true);
+ QCOMPARE(backendTechnique.peerId(), technique.id());
+ Qt3DRender::GraphicsApiFilterData apiFilterData = Qt3DRender::QGraphicsApiFilterPrivate::get(technique.graphicsApiFilter())->m_data;
+ QCOMPARE(*backendTechnique.graphicsApiFilter(), apiFilterData);
+ QCOMPARE(backendTechnique.parameters().size(), 1);
+ QCOMPARE(backendTechnique.parameters().first(), parameter.id());
+ QCOMPARE(backendTechnique.filterKeys().size(), 1);
+ QCOMPARE(backendTechnique.filterKeys().first(), filterKey.id());
+ QCOMPARE(backendTechnique.renderPasses().size(), 1);
+ QCOMPARE(backendTechnique.renderPasses().first(), pass.id());
+ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
+ const QVector<Qt3DCore::QNodeId> dirtyTechniques = nodeManagers.techniqueManager()->takeDirtyTechniques();
+ QCOMPARE(dirtyTechniques.size(), 1);
+ QCOMPARE(dirtyTechniques.first(), backendTechnique.peerId());
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::Technique backendTechnique;
+ Qt3DRender::Render::NodeManagers nodeManagers;
+
+ backendTechnique.setNodeManager(&nodeManagers);
+ technique.setEnabled(false);
+ simulateInitialization(&technique, &backendTechnique);
+
+ // THEN
+ QCOMPARE(backendTechnique.peerId(), technique.id());
+ QCOMPARE(backendTechnique.isEnabled(), false);
+ }
+ }
+
+ void checkSetCompatibleWithRenderer()
+ {
+ // GIVEN
+ Qt3DRender::Render::Technique backendTechnique;
+
+ // THEN
+ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
+
+ // WHEN
+ backendTechnique.setCompatibleWithRenderer(true);
+
+ // THEN
+ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), true);
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::Technique backendTechnique;
+ Qt3DRender::Render::NodeManagers nodeManagers;
+
+ TestRenderer renderer;
+ backendTechnique.setRenderer(&renderer);
+ backendTechnique.setNodeManager(&nodeManagers);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ backendTechnique.setCompatibleWithRenderer(true);
+ QCOMPARE(nodeManagers.techniqueManager()->takeDirtyTechniques().size(), 0);
+
+ Qt3DRender::GraphicsApiFilterData newValue;
+ newValue.m_major = 4;
+ newValue.m_minor = 5;
+ newValue.m_vendor = QStringLiteral("ATI");
+
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("graphicsApiFilterData");
+ change->setValue(QVariant::fromValue(newValue));
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(*backendTechnique.graphicsApiFilter(), newValue);
+ QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
+
+ const QVector<Qt3DCore::QNodeId> dirtyTechniques = nodeManagers.techniqueManager()->takeDirtyTechniques();
+ QCOMPARE(dirtyTechniques.size(), 1);
+ QCOMPARE(dirtyTechniques.first(), backendTechnique.peerId());
+
+ }
+ {
+ Qt3DRender::QParameter parameter;
+
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &parameter);
+ change->setPropertyName("parameter");
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.parameters().size(), 1);
+ QCOMPARE(backendTechnique.parameters().first(), parameter.id());
+ }
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &parameter);
+ change->setPropertyName("parameter");
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.parameters().size(), 0);
+ }
+ }
+ {
+ Qt3DRender::QFilterKey filterKey;
+
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &filterKey);
+ change->setPropertyName("filterKeys");
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 1);
+ QCOMPARE(backendTechnique.filterKeys().first(), filterKey.id());
+ }
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &filterKey);
+ change->setPropertyName("filterKeys");
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ }
+ }
+ {
+ Qt3DRender::QRenderPass pass;
+
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeAddedChangePtr::create(Qt3DCore::QNodeId(), &pass);
+ change->setPropertyName("pass");
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.renderPasses().size(), 1);
+ QCOMPARE(backendTechnique.renderPasses().first(), pass.id());
+ }
+ {
+ // WHEN
+ const auto change = Qt3DCore::QPropertyNodeRemovedChangePtr::create(Qt3DCore::QNodeId(), &pass);
+ change->setPropertyName("pass");
+ backendTechnique.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTechnique.renderPasses().size(), 0);
+ }
+ }
+ }
+
+ void checkIsCompatibleWithFilters()
+ {
+ // GIVEN
+ Qt3DRender::Render::Technique backendTechnique;
+ Qt3DRender::Render::NodeManagers nodeManagers;
+
+ backendTechnique.setNodeManager(&nodeManagers);
+
+ Qt3DRender::QFilterKey *filterKey1 = new Qt3DRender::QFilterKey();
+ Qt3DRender::QFilterKey *filterKey2 = new Qt3DRender::QFilterKey();
+ Qt3DRender::QFilterKey *filterKey3 = new Qt3DRender::QFilterKey();
+ Qt3DRender::QFilterKey *filterKey4 = new Qt3DRender::QFilterKey();
+ Qt3DRender::QFilterKey *filterKey5 = new Qt3DRender::QFilterKey();
+
+ filterKey1->setName(QStringLiteral("displacement"));
+ filterKey2->setName(QStringLiteral("diffRatio"));
+ filterKey3->setName(QStringLiteral("oil"));
+ filterKey4->setName(QStringLiteral("oil"));
+ filterKey5->setName(QStringLiteral("heads"));
+
+ filterKey1->setValue(QVariant(427.0f));
+ filterKey2->setValue(QVariant(4.11f));
+ filterKey3->setValue(QVariant(QStringLiteral("Valvoline-VR1")));
+ filterKey4->setValue(QVariant(QStringLiteral("Mobil-1")));
+ filterKey5->setName(QStringLiteral("AFR"));
+
+ // Create backend nodes
+ // WHEN
+ Qt3DRender::Render::FilterKey *backendFilterKey1 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey1->id());
+ Qt3DRender::Render::FilterKey *backendFilterKey2 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey2->id());
+ Qt3DRender::Render::FilterKey *backendFilterKey3 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey3->id());
+ Qt3DRender::Render::FilterKey *backendFilterKey4 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey4->id());
+ Qt3DRender::Render::FilterKey *backendFilterKey5 = nodeManagers.filterKeyManager()->getOrCreateResource(filterKey5->id());
+
+ simulateInitialization(filterKey1, backendFilterKey1);
+ simulateInitialization(filterKey2, backendFilterKey2);
+ simulateInitialization(filterKey3, backendFilterKey3);
+ simulateInitialization(filterKey4, backendFilterKey4);
+ simulateInitialization(filterKey5, backendFilterKey5);
+
+ // THEN
+ QCOMPARE(nodeManagers.filterKeyManager()->activeHandles().size(), 5);
+
+ {
+ // WHEN
+ backendTechnique.appendFilterKey(filterKey1->id());
+ backendTechnique.appendFilterKey(filterKey2->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 2);
+
+ // WHEN
+ Qt3DCore::QNodeIdVector techniqueFilters;
+ techniqueFilters.push_back(filterKey1->id());
+ techniqueFilters.push_back(filterKey2->id());
+ techniqueFilters.push_back(filterKey3->id());
+ techniqueFilters.push_back(filterKey5->id());
+
+ // THEN -> incompatible technique doesn't have enough filters
+ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
+
+ // WHEN
+ backendTechnique.removeFilterKey(filterKey1->id());
+ backendTechnique.removeFilterKey(filterKey2->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ }
+
+ {
+ // WHEN
+ backendTechnique.appendFilterKey(filterKey1->id());
+ backendTechnique.appendFilterKey(filterKey2->id());
+ backendTechnique.appendFilterKey(filterKey3->id());
+ backendTechnique.appendFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 4);
+
+ // WHEN
+ Qt3DCore::QNodeIdVector techniqueFilters;
+ techniqueFilters.push_back(filterKey1->id());
+ techniqueFilters.push_back(filterKey2->id());
+ techniqueFilters.push_back(filterKey3->id());
+ techniqueFilters.push_back(filterKey5->id());
+
+ // THEN -> compatible same number
+ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), true);
+
+ // WHEN
+ backendTechnique.removeFilterKey(filterKey1->id());
+ backendTechnique.removeFilterKey(filterKey2->id());
+ backendTechnique.removeFilterKey(filterKey3->id());
+ backendTechnique.removeFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ }
+
+ {
+ // WHEN
+ backendTechnique.appendFilterKey(filterKey1->id());
+ backendTechnique.appendFilterKey(filterKey2->id());
+ backendTechnique.appendFilterKey(filterKey3->id());
+ backendTechnique.appendFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 4);
+
+ // WHEN
+ Qt3DCore::QNodeIdVector techniqueFilters;
+ techniqueFilters.push_back(filterKey1->id());
+ techniqueFilters.push_back(filterKey2->id());
+ techniqueFilters.push_back(filterKey4->id());
+ techniqueFilters.push_back(filterKey5->id());
+
+ // THEN -> compatible same number, one not matching
+ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
+
+ // WHEN
+ backendTechnique.removeFilterKey(filterKey1->id());
+ backendTechnique.removeFilterKey(filterKey2->id());
+ backendTechnique.removeFilterKey(filterKey3->id());
+ backendTechnique.removeFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ }
+
+ {
+ // WHEN
+ backendTechnique.appendFilterKey(filterKey1->id());
+ backendTechnique.appendFilterKey(filterKey2->id());
+ backendTechnique.appendFilterKey(filterKey3->id());
+ backendTechnique.appendFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 4);
+
+ // WHEN
+ Qt3DCore::QNodeIdVector techniqueFilters;
+ techniqueFilters.push_back(filterKey1->id());
+ techniqueFilters.push_back(filterKey2->id());
+ techniqueFilters.push_back(filterKey3->id());
+
+ // THEN -> technique has more than necessary filters
+ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), true);
+
+ // WHEN
+ backendTechnique.removeFilterKey(filterKey1->id());
+ backendTechnique.removeFilterKey(filterKey2->id());
+ backendTechnique.removeFilterKey(filterKey3->id());
+ backendTechnique.removeFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ }
+
+ {
+ // WHEN
+ backendTechnique.appendFilterKey(filterKey1->id());
+ backendTechnique.appendFilterKey(filterKey2->id());
+ backendTechnique.appendFilterKey(filterKey3->id());
+ backendTechnique.appendFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 4);
+
+ // WHEN
+ Qt3DCore::QNodeIdVector techniqueFilters;
+ techniqueFilters.push_back(filterKey1->id());
+ techniqueFilters.push_back(filterKey2->id());
+ techniqueFilters.push_back(filterKey4->id());
+
+ // THEN -> technique has more than necessary filters
+ // but one is not matching
+ QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
+
+ // WHEN
+ backendTechnique.removeFilterKey(filterKey1->id());
+ backendTechnique.removeFilterKey(filterKey2->id());
+ backendTechnique.removeFilterKey(filterKey3->id());
+ backendTechnique.removeFilterKey(filterKey5->id());
+
+ // THEN
+ QCOMPARE(backendTechnique.filterKeys().size(), 0);
+ }
+ }
+};
+
+QTEST_MAIN(tst_Technique)
+
+#include "tst_technique.moc"
diff --git a/tests/auto/render/texture/tst_texture.cpp b/tests/auto/render/texture/tst_texture.cpp
index 5c6bc2b37..361cd3117 100644
--- a/tests/auto/render/texture/tst_texture.cpp
+++ b/tests/auto/render/texture/tst_texture.cpp
@@ -185,12 +185,12 @@ void tst_RenderTexture::checkPropertyMirroring()
// THEN
QCOMPARE(backend.peerId(), frontend.id());
- QCOMPARE(backend.target(), Target);
- QCOMPARE(backend.width(), frontend.width());
- QCOMPARE(backend.height(), frontend.height());
- QCOMPARE(backend.depth(), frontend.depth());
- QCOMPARE(backend.layers(), frontend.layers());
- QCOMPARE(backend.samples(), frontend.samples());
+ QCOMPARE(backend.properties().target, Target);
+ QCOMPARE(backend.properties().width, frontend.width());
+ QCOMPARE(backend.properties().height, frontend.height());
+ QCOMPARE(backend.properties().depth, frontend.depth());
+ QCOMPARE(backend.properties().layers, frontend.layers());
+ QCOMPARE(backend.properties().samples, frontend.samples());
}
void tst_RenderTexture::checkPropertyMirroring()
@@ -222,7 +222,7 @@ void tst_RenderTexture::checkPropertyChanges()
backend.sceneChangeEvent(updateChange);
// THEN
- QCOMPARE(backend.width(), 256);
+ QCOMPARE(backend.properties().width, 256);
// WHEN
updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
@@ -231,7 +231,7 @@ void tst_RenderTexture::checkPropertyChanges()
backend.sceneChangeEvent(updateChange);
// THEN
- QCOMPARE(backend.height(), 128);
+ QCOMPARE(backend.properties().height, 128);
// WHEN
updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
@@ -240,7 +240,7 @@ void tst_RenderTexture::checkPropertyChanges()
backend.sceneChangeEvent(updateChange);
// THEN
- QCOMPARE(backend.depth(), 16);
+ QCOMPARE(backend.properties().depth, 16);
// WHEN
updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
@@ -249,7 +249,7 @@ void tst_RenderTexture::checkPropertyChanges()
backend.sceneChangeEvent(updateChange);
// THEN
- QCOMPARE(backend.layers(), 32);
+ QCOMPARE(backend.properties().layers, 32);
// WHEN
updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
@@ -258,7 +258,7 @@ void tst_RenderTexture::checkPropertyChanges()
backend.sceneChangeEvent(updateChange);
// THEN
- QCOMPARE(backend.samples(), 64);
+ QCOMPARE(backend.properties().samples, 64);
}
QTEST_APPLESS_MAIN(tst_RenderTexture)
diff --git a/tests/auto/render/texturedatamanager/texturedatamanager.pro b/tests/auto/render/texturedatamanager/texturedatamanager.pro
new file mode 100644
index 000000000..cb6f2ee64
--- /dev/null
+++ b/tests/auto/render/texturedatamanager/texturedatamanager.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_texturedatamanager
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_texturedatamanager.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp
new file mode 100644
index 000000000..2b4c9cd91
--- /dev/null
+++ b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/private/texturedatamanager_p.h>
+
+namespace {
+
+class FakeGenerator
+{
+public:
+ explicit FakeGenerator(const QString &name)
+ : m_name(name)
+ {}
+
+ bool operator==(const FakeGenerator &other) const
+ {
+ return other.m_name == m_name;
+ }
+
+ bool operator!=(const FakeGenerator &other) const
+ {
+ return !(other == *this);
+ }
+private:
+ QString m_name;
+};
+typedef QSharedPointer<FakeGenerator> FakeGeneratorPtr;
+
+class FakeData
+{
+public:
+ explicit FakeData(int value)
+ : m_value(value)
+ {}
+
+private:
+ int m_value;
+};
+typedef QSharedPointer<FakeData> FakeDataPtr;
+
+
+struct FakeAPITexture
+{
+};
+
+using Manager = Qt3DRender::Render::GeneratorDataManager<FakeGeneratorPtr, FakeDataPtr, FakeAPITexture>;
+
+} // anonymous
+
+class tst_TextureDataManager : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkAssumptions()
+ {
+ // GIVEN
+ FakeGeneratorPtr zr1(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeGeneratorPtr z06(FakeGeneratorPtr::create(QStringLiteral("Z06")));
+
+ // THEN
+ QVERIFY(*zr1 == *zr1);
+ QVERIFY(*z06 == *z06);
+ QVERIFY(*zr1 != *z06);
+ QVERIFY(*z06 != *zr1);
+ }
+
+ void checkRequestDataShouldCreate()
+ {
+ // GIVEN
+ Manager manager;
+ FakeGeneratorPtr generator(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeAPITexture texture;
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 0);
+
+ // WHEN
+ manager.requestData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+ }
+
+ void checkRequestDataAlreadyExistingGenerator()
+ {
+ // GIVEN
+ Manager manager;
+ FakeGeneratorPtr generator(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeGeneratorPtr generatorClone(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeAPITexture texture;
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 0);
+
+ // WHEN
+ for (int i = 0; i < 5; ++i)
+ manager.requestData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+
+ // WHEN
+ for (int i = 0; i < 5; ++i)
+ manager.requestData(generatorClone, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+ }
+
+
+ void checkReleaseDataInvalidEntry()
+ {
+ // GIVEN
+ Manager manager;
+ FakeGeneratorPtr generator(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeAPITexture texture;
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 0);
+
+ // WHEN
+ manager.releaseData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 0);
+ // and should not crash
+ }
+
+ void checkReleaseDataValidEntry()
+ {
+ // GIVEN
+ Manager manager;
+ FakeGeneratorPtr generator(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeAPITexture texture;
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 0);
+
+ // WHEN
+ manager.requestData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+
+ // WHEN
+ manager.releaseData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 0);
+ }
+
+ void checkAssignGetData()
+ {
+ // GIVEN
+ Manager manager;
+ FakeGeneratorPtr generator(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeDataPtr data(FakeDataPtr::create(883));
+ FakeAPITexture texture;
+
+ // WHEN
+ manager.assignData(generator, data);
+
+ // THEN
+ QVERIFY(manager.getData(generator).isNull());
+
+ // WHEN
+ manager.requestData(generator, &texture);
+ manager.assignData(generator, data);
+
+ // THEN
+ QCOMPARE(data, manager.getData(generator));
+ }
+
+ void checkPendingGenerators()
+ {
+ // GIVEN
+ Manager manager;
+ FakeGeneratorPtr generator(FakeGeneratorPtr::create(QStringLiteral("ZR1")));
+ FakeDataPtr data(FakeDataPtr::create(883));
+ FakeAPITexture texture;
+
+ // WHEN
+ manager.requestData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+ QCOMPARE(manager.pendingGenerators().first(), generator);
+
+ // WHEN
+ manager.requestData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+ QCOMPARE(manager.pendingGenerators().first(), generator);
+
+ // WHEN
+ FakeGeneratorPtr generator2(FakeGeneratorPtr::create(QStringLiteral("Z06")));
+ FakeAPITexture texture2;
+ manager.requestData(generator2, &texture2);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 2);
+ QCOMPARE(manager.pendingGenerators().first(), generator);
+ QCOMPARE(manager.pendingGenerators().last(), generator2);
+
+ // WHEN
+ manager.releaseData(generator, &texture);
+
+ // THEN
+ QCOMPARE(manager.pendingGenerators().size(), 1);
+ QCOMPARE(manager.pendingGenerators().first(), generator2);
+ }
+};
+
+QTEST_MAIN(tst_TextureDataManager)
+
+#include "tst_texturedatamanager.moc"
diff --git a/tests/auto/render/textures/textures.pro b/tests/auto/render/textures/textures.pro
new file mode 100644
index 000000000..0366adfe7
--- /dev/null
+++ b/tests/auto/render/textures/textures.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_textures
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_textures.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/textures/tst_textures.cpp b/tests/auto/render/textures/tst_textures.cpp
new file mode 100644
index 000000000..9246bba34
--- /dev/null
+++ b/tests/auto/render/textures/tst_textures.cpp
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <qbackendnodetester.h>
+#include <qtextureimagedatagenerator.h>
+#include <Qt3DRender/qtexture.h>
+#include <Qt3DRender/qtextureimage.h>
+#include <Qt3DRender/qtexturedata.h>
+
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/texture_p.h>
+#include <Qt3DRender/private/textureimage_p.h>
+#include <Qt3DRender/private/texturedatamanager_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/gltexturemanager_p.h>
+#include <Qt3DRender/private/gltexture_p.h>
+#include <Qt3DRender/private/qtexture_p.h>
+
+/**
+ * @brief Dummy QTextureImageDataGenerator
+ */
+class TestImageDataGenerator : public Qt3DRender::QTextureImageDataGenerator
+{
+ int m_id;
+public:
+ TestImageDataGenerator(int id) : m_id(id) {}
+
+ Qt3DRender::QTextureImageDataPtr operator ()() {
+ return Qt3DRender::QTextureImageDataPtr::create();
+ }
+
+ bool operator ==(const Qt3DRender::QTextureImageDataGenerator &other) const {
+ const TestImageDataGenerator *otherFunctor = functor_cast<TestImageDataGenerator>(&other);
+ return (otherFunctor != Q_NULLPTR && otherFunctor->m_id == m_id);
+ }
+
+ QT3D_FUNCTOR(TestImageDataGenerator)
+};
+
+/**
+ * @brief Dummy QTextureGenerator
+ */
+class TestTextureGenerator : public Qt3DRender::QTextureGenerator
+{
+ int m_id;
+public:
+ TestTextureGenerator(int id) : m_id(id) {}
+
+ Qt3DRender::QTextureDataPtr operator ()() {
+ return Qt3DRender::QTextureDataPtr::create();
+ }
+
+ bool operator ==(const Qt3DRender::QTextureGenerator &other) const {
+ const TestTextureGenerator *otherFunctor = functor_cast<TestTextureGenerator>(&other);
+ return (otherFunctor != Q_NULLPTR && otherFunctor->m_id == m_id);
+ }
+
+ QT3D_FUNCTOR(TestTextureGenerator)
+};
+
+typedef QSharedPointer<TestTextureGenerator> TestTextureGeneratorPtr;
+
+class TestTexturePrivate : public Qt3DRender::QAbstractTexturePrivate
+{
+public:
+ int genId;
+};
+
+/**
+ * @brief Test QTexture. Assign texture data functor if genId > 0.
+ */
+class TestTexture : public Qt3DRender::QAbstractTexture
+{
+public:
+ TestTexture(int genId, Qt3DCore::QNode *p = nullptr)
+ : QAbstractTexture(*new TestTexturePrivate(), p)
+ {
+ d_func()->genId = genId;
+ if (genId > 0)
+ d_func()->setDataFunctor(TestTextureGeneratorPtr::create(genId));
+ }
+private:
+ Q_DECLARE_PRIVATE(TestTexture)
+};
+
+/**
+ * @brief Test QTextureImage
+ */
+class TestTextureImage : public Qt3DRender::QAbstractTextureImage
+{
+public:
+ TestTextureImage(int genId, Qt3DCore::QNode *p = nullptr)
+ : QAbstractTextureImage(p)
+ , m_genId(genId)
+ {
+ }
+
+protected:
+ int m_genId;
+ Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const
+ {
+ return Qt3DRender::QTextureImageDataGeneratorPtr(new TestImageDataGenerator(m_genId));
+ }
+};
+
+class tst_RenderTextures : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+ Qt3DRender::QAbstractTexture *createQTexture(int genId,
+ const QVector<int> &imgGenIds,
+ bool genMipMaps)
+ {
+ TestTexture *tex = new TestTexture(genId);
+
+ for (int imgGen : imgGenIds)
+ tex->addTextureImage(new TestTextureImage(imgGen));
+ tex->setGenerateMipMaps(genMipMaps);
+
+ return tex;
+ }
+
+ Qt3DRender::Render::Texture *createBackendTexture(Qt3DRender::QAbstractTexture *frontend,
+ Qt3DRender::Render::TextureManager *texMgr,
+ Qt3DRender::Render::TextureImageManager *texImgMgr)
+ {
+ Qt3DRender::Render::Texture *backend = texMgr->getOrCreateResource(frontend->id());
+ backend->setTextureImageManager(texImgMgr);
+ simulateInitialization(frontend, backend);
+
+ // create texture images
+ for (const auto texImgFrontend : frontend->textureImages()) {
+ // make sure TextureImageManager has backend node for this QTextureImage
+ if (!texImgMgr->contains(texImgFrontend->id())) {
+ Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(texImgFrontend->id());
+ texImgBackend->setTextureManager(texMgr);
+ simulateInitialization(texImgFrontend, texImgBackend);
+ }
+ backend->addTextureImage(texImgFrontend->id());
+ }
+
+ return backend;
+ }
+
+private Q_SLOTS:
+
+ void shouldCreateSameGLTextures()
+ {
+ QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
+ Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
+ renderer.setNodeManagers(mgrs.data());
+
+ // GIVEN
+ Qt3DRender::QAbstractTexture *tex1a = createQTexture(-1, {1,2}, true);
+ Qt3DRender::QAbstractTexture *tex1b = createQTexture(-1, {1,2}, true);
+
+ // WHEN
+ Qt3DRender::Render::Texture *bt1a = createBackendTexture(tex1a, mgrs->textureManager(), mgrs->textureImageManager());
+ Qt3DRender::Render::Texture *bt1b = createBackendTexture(tex1b, mgrs->textureManager(), mgrs->textureImageManager());
+ renderer.updateTexture(bt1a);
+ renderer.updateTexture(bt1b);
+
+ // THEN
+ QCOMPARE(mgrs->glTextureManager()->lookupResource(bt1a->peerId()), mgrs->glTextureManager()->lookupResource(bt1b->peerId()));
+ }
+
+ void shouldCreateDifferentGLTexturess()
+ {
+ QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
+ Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
+ renderer.setNodeManagers(mgrs.data());
+
+ // GIVEN
+ QVector<Qt3DRender::QAbstractTexture*> textures;
+ textures << createQTexture(-1, {1,2}, true);
+ textures << createQTexture(-1, {1,2}, false);
+ textures << createQTexture(1, {1,2}, true);
+ textures << createQTexture(1, {1,2}, false);
+ textures << createQTexture(1, {1,2,3}, true);
+ textures << createQTexture(1, {1,2,3}, false);
+
+ // WHEN
+ QVector<Qt3DRender::Render::Texture*> backend;
+ for (auto *t : textures) {
+ Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, mgrs->textureManager(), mgrs->textureImageManager());
+ backend.push_back(backendTexture);
+ renderer.updateTexture(backendTexture);
+ }
+
+ // THEN
+
+ // no 2 textures must be the same
+ for (int i = 0; i < backend.size(); i++)
+ for (int k = i+1; k < backend.size(); k++)
+ QVERIFY(mgrs->glTextureManager()->lookupResource(backend[i]->peerId()) != mgrs->glTextureManager()->lookupResource(backend[k]->peerId()));
+
+ QVector<Qt3DRender::Render::GLTexture *> glTextures;
+ for (Qt3DRender::Render::Texture *t : backend)
+ glTextures.push_back(mgrs->glTextureManager()->lookupResource(t->peerId()));
+
+ // some texture generators must be the same
+ QVERIFY(glTextures[0]->textureGenerator().data() == nullptr);
+ QVERIFY(glTextures[1]->textureGenerator().data() == nullptr);
+ QCOMPARE(*(glTextures[2]->textureGenerator()), *(glTextures[3]->textureGenerator()));
+
+ // some images must be the same
+ QCOMPARE(glTextures[0]->images(), glTextures[1]->images());
+ QCOMPARE(glTextures[0]->images(), glTextures[2]->images());
+ QCOMPARE(glTextures[0]->images(), glTextures[3]->images());
+ QCOMPARE(glTextures[4]->images(), glTextures[5]->images());
+
+ QCOMPARE(glTextures[0]->properties(), glTextures[2]->properties());
+ QCOMPARE(glTextures[1]->properties(), glTextures[3]->properties());
+ QVERIFY(glTextures[0]->properties() != glTextures[1]->properties());
+ }
+
+ void generatorsShouldCreateSameData()
+ {
+ QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
+ Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
+ renderer.setNodeManagers(mgrs.data());
+
+ // GIVEN
+ QVector<Qt3DRender::QAbstractTexture*> textures;
+ textures << createQTexture(1, {1}, true);
+ textures << createQTexture(2, {1,2}, true);
+ textures << createQTexture(1, {1,2}, true);
+
+ // WHEN
+ QVector<Qt3DRender::Render::Texture*> backend;
+ for (auto *t : textures) {
+ Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, mgrs->textureManager(), mgrs->textureImageManager());
+ backend.push_back(backendTexture);
+ renderer.updateTexture(backendTexture);
+ }
+
+ Qt3DRender::QTextureImageDataGeneratorPtr idg1a = mgrs->glTextureManager()->lookupResource(backend[0]->peerId())->images()[0].generator;
+ Qt3DRender::QTextureImageDataGeneratorPtr idg1b = mgrs->glTextureManager()->lookupResource(backend[1]->peerId())->images()[0].generator;
+ Qt3DRender::QTextureImageDataGeneratorPtr idg2 = mgrs->glTextureManager()->lookupResource(backend[1]->peerId())->images()[1].generator;
+ Qt3DRender::QTextureGeneratorPtr tg1a = mgrs->glTextureManager()->lookupResource(backend[0]->peerId())->textureGenerator();
+ Qt3DRender::QTextureGeneratorPtr tg1b = mgrs->glTextureManager()->lookupResource(backend[2]->peerId())->textureGenerator();
+ Qt3DRender::QTextureGeneratorPtr tg2 = mgrs->glTextureManager()->lookupResource(backend[1]->peerId())->textureGenerator();
+
+ // THEN
+ QVERIFY(idg1a);
+ QVERIFY(idg1b);
+ QVERIFY(idg2);
+ QVERIFY(tg1a);
+ QVERIFY(tg1b);
+ QVERIFY(tg2);
+
+ QCOMPARE(*idg1a, *idg1b);
+ QVERIFY(!(*idg1a == *idg2));
+ QCOMPARE(*tg1a, *tg1b);
+ QVERIFY(!(*tg1a == *tg2));
+ Qt3DRender::Render::TextureImageDataManager *imgDataMgr = mgrs->textureImageDataManager();
+ Qt3DRender::Render::TextureDataManager *texDataMgr = mgrs->textureDataManager();
+ QVERIFY(imgDataMgr->getData(idg1a) == nullptr);
+ QVERIFY(imgDataMgr->getData(idg2) == nullptr);
+ QVERIFY(texDataMgr->getData(tg1a) == nullptr);
+ QVERIFY(texDataMgr->getData(tg2) == nullptr);
+
+ // WHEN
+ for (const auto gen : imgDataMgr->pendingGenerators())
+ imgDataMgr->assignData(gen, (*gen)());
+ for (const auto gen : texDataMgr->pendingGenerators())
+ texDataMgr->assignData(gen, (*gen)());
+
+ // THEN
+ QVERIFY(imgDataMgr->getData(idg1a) != nullptr);
+ QVERIFY(imgDataMgr->getData(idg1b) != nullptr);
+ QVERIFY(imgDataMgr->getData(idg2) != nullptr);
+ QVERIFY(texDataMgr->getData(tg1a) != nullptr);
+ QVERIFY(texDataMgr->getData(tg1b) != nullptr);
+ QVERIFY(texDataMgr->getData(tg2) != nullptr);
+
+ QCOMPARE(imgDataMgr->getData(idg1a), imgDataMgr->getData(idg1b));
+ QVERIFY(imgDataMgr->getData(idg1a) != imgDataMgr->getData(idg2));
+
+ QCOMPARE(texDataMgr->getData(tg1a), texDataMgr->getData(tg1b));
+ QVERIFY(texDataMgr->getData(tg1a) != texDataMgr->getData(tg2));
+ }
+
+};
+
+QTEST_MAIN(tst_RenderTextures)
+
+#include "tst_textures.moc"
diff --git a/tests/auto/render/transform/transform.pro b/tests/auto/render/transform/transform.pro
new file mode 100644
index 000000000..b671b92fd
--- /dev/null
+++ b/tests/auto/render/transform/transform.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_transform
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_transform.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/transform/tst_transform.cpp b/tests/auto/render/transform/tst_transform.cpp
new file mode 100644
index 000000000..26916b2ab
--- /dev/null
+++ b/tests/auto/render/transform/tst_transform.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/private/qtransform_p.h>
+#include <Qt3DRender/private/transform_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_Transform : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Transform backendTransform;
+
+ // THEN
+ QCOMPARE(backendTransform.isEnabled(), false);
+ QVERIFY(backendTransform.peerId().isNull());
+ QCOMPARE(backendTransform.transformMatrix(), QMatrix4x4());
+ }
+
+ void checkCleanupState()
+ {
+ // GIVEN
+ Qt3DRender::Render::Transform backendTransform;
+
+ // WHEN
+ {
+ Qt3DCore::QTransform transform;
+ transform.setScale3D(QVector3D(1.0f, 2.0f, 3.0f));
+ transform.setTranslation(QVector3D(-1.0, 5.0f, -2.0f));
+ transform.setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1.0f, 0.0f, 0.0), 30.0f));
+ simulateInitialization(&transform, &backendTransform);
+ }
+ backendTransform.setEnabled(true);
+
+ backendTransform.cleanup();
+
+ // THEN
+ QCOMPARE(backendTransform.isEnabled(), false);
+ QCOMPARE(backendTransform.transformMatrix(), QMatrix4x4());
+ QCOMPARE(backendTransform.rotation(), QQuaternion());
+ QCOMPARE(backendTransform.scale(), QVector3D());
+ QCOMPARE(backendTransform.translation(), QVector3D());
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DCore::QTransform transform;
+ transform.setScale3D(QVector3D(1.0f, 2.0f, 3.0f));
+ transform.setTranslation(QVector3D(-1.0, 5.0f, -2.0f));
+ transform.setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1.0f, 0.0f, 0.0), 30.0f));
+
+ {
+ // WHEN
+ Qt3DRender::Render::Transform backendTransform;
+ simulateInitialization(&transform, &backendTransform);
+
+ // THEN
+ QCOMPARE(backendTransform.isEnabled(), true);
+ QCOMPARE(backendTransform.peerId(), transform.id());
+ QCOMPARE(backendTransform.transformMatrix(), transform.matrix());
+ QCOMPARE(backendTransform.rotation(), transform.rotation());
+ QCOMPARE(backendTransform.scale(), transform.scale3D());
+ QCOMPARE(backendTransform.translation(), transform.translation());
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::Transform backendTransform;
+ transform.setEnabled(false);
+ simulateInitialization(&transform, &backendTransform);
+
+ // THEN
+ QCOMPARE(backendTransform.peerId(), transform.id());
+ QCOMPARE(backendTransform.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::Transform backendTransform;
+ TestRenderer renderer;
+ backendTransform.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendTransform.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTransform.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const QQuaternion newValue = QQuaternion::fromAxisAndAngle(QVector3D(0.0f, 1.0f, 0.0f), 45.0f);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("rotation");
+ change->setValue(QVariant::fromValue(newValue));
+ backendTransform.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTransform.rotation(), newValue);
+ }
+ {
+ // WHEN
+ const QVector3D newValue(454.0f, 355.0f, 0.0f);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("scale3D");
+ change->setValue(QVariant::fromValue(newValue));
+ backendTransform.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTransform.scale(), newValue);
+ }
+ {
+ // WHEN
+ const QVector3D newValue(383.0f, 0.0f, 427.0f);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("translation");
+ change->setValue(QVariant::fromValue(newValue));
+ backendTransform.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendTransform.translation(), newValue);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_Transform)
+
+#include "tst_transform.moc"
diff --git a/tests/auto/render/uniform/tst_uniform.cpp b/tests/auto/render/uniform/tst_uniform.cpp
index 255b79646..47e64eafe 100644
--- a/tests/auto/render/uniform/tst_uniform.cpp
+++ b/tests/auto/render/uniform/tst_uniform.cpp
@@ -278,6 +278,43 @@ private Q_SLOTS:
QCOMPARE(v.constData<float>()[14], 0.0f);
QCOMPARE(v.constData<float>()[15], 1.0f);
}
+ {
+ // GIVEN
+ QVariant variants = QVariantList() << QVariant(427.0f) << QVariant(454.0f) << QVariant(883.0f) << QVariant(1340.0f);
+ UniformValue v = UniformValue::fromVariant(variants);
+
+ // THEN
+ QCOMPARE(v.constData<float>()[0], 427.0f);
+ QCOMPARE(v.constData<float>()[1], 454.0f);
+ QCOMPARE(v.constData<float>()[2], 883.0f);
+ QCOMPARE(v.constData<float>()[3], 1340.0f);
+ }
+ {
+ // GIVEN
+ QVariant variants = QVariantList() << QVariant::fromValue(QVector4D(2.0f, 16.0f, 8.0f, 4.0f)) << QVariant(QVector4D(3.0f, 24.0f, 12.0f, 6.0f));
+ UniformValue v = UniformValue::fromVariant(variants);
+
+ // THEN
+ QCOMPARE(v.constData<float>()[0], 2.0f);
+ QCOMPARE(v.constData<float>()[1], 16.0f);
+ QCOMPARE(v.constData<float>()[2], 8.0f);
+ QCOMPARE(v.constData<float>()[3], 4.0f);
+ QCOMPARE(v.constData<float>()[4], 3.0f);
+ QCOMPARE(v.constData<float>()[5], 24.0f);
+ QCOMPARE(v.constData<float>()[6], 12.0f);
+ QCOMPARE(v.constData<float>()[7], 6.0f);
+ }
+ {
+ // GIVEN
+ QVariant variants = QVariantList() << QVariant(427) << QVariant(454) << QVariant(883) << QVariant(1340);
+ UniformValue v = UniformValue::fromVariant(variants);
+
+ // THEN
+ QCOMPARE(v.constData<int>()[0], 427);
+ QCOMPARE(v.constData<int>()[1], 454);
+ QCOMPARE(v.constData<int>()[2], 883);
+ QCOMPARE(v.constData<int>()[3], 1340);
+ }
}
void checkComparison()
diff --git a/examples/qt3d/deferred-renderer-cpp/finaleffect.h b/tests/auto/render/updatemeshtrianglelistjob/test_scene.qml
index 69a1b126c..ecf41f9c0 100644
--- a/examples/qt3d/deferred-renderer-cpp/finaleffect.h
+++ b/tests/auto/render/updatemeshtrianglelistjob/test_scene.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -48,27 +48,55 @@
**
****************************************************************************/
-#ifndef FINALEFFECT_H
-#define FINALEFFECT_H
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
-#include <Qt3DRender/QEffect>
-#include <Qt3DRender/QTechnique>
+Entity {
+ id: sceneRoot
-class FinalEffect : public Qt3DRender::QEffect
-{
-public:
- explicit FinalEffect(Qt3DCore::QNode *parent = 0);
+ Window {
+ id: win
+ width: 800
+ height: 800
+ visible: true
+ }
- QList<Qt3DRender::QFilterKey *> passCriteria() const;
- inline Qt3DRender::QTechnique *gl3Technique() const { return m_gl3Technique; }
- inline Qt3DRender::QTechnique *gl2Technique() const { return m_gl2Technique; }
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
-private :
- Qt3DRender::QTechnique *m_gl3Technique;
- Qt3DRender::QTechnique *m_gl2Technique;
- Qt3DRender::QRenderPass *m_gl2Pass;
- Qt3DRender::QRenderPass *m_gl3Pass;
- Qt3DRender::QFilterKey *m_passCriterion;
-};
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
-#endif // FINALEFFECT_H
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ Entity {
+ components: CuboidMesh { id: cubeMesh }
+ }
+}
diff --git a/tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp b/tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp
new file mode 100644
index 000000000..f3fc2ad9b
--- /dev/null
+++ b/tests/auto/render/updatemeshtrianglelistjob/tst_updatemeshtrianglelistjob.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/loadgeometryjob_p.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include "qmlscenereader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender { // Needs to be in that namespace to be friend with QRenderAspect
+
+class TestAspect : public Qt3DRender::QRenderAspect
+{
+public:
+ TestAspect(Qt3DCore::QNode *root)
+ : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
+ , m_sceneRoot(nullptr)
+ {
+ Qt3DRender::QRenderAspect::onRegistered();
+
+ const Qt3DCore::QNodeCreatedChangeGenerator generator(root);
+ const QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = generator.creationChanges();
+
+ d_func()->setRootAndCreateNodes(qobject_cast<Qt3DCore::QEntity *>(root), creationChanges);
+
+ Qt3DRender::Render::Entity *rootEntity = nodeManagers()->lookupResource<Qt3DRender::Render::Entity, Render::EntityManager>(rootEntityId());
+ Q_ASSERT(rootEntity);
+ m_sceneRoot = rootEntity;
+ }
+
+ ~TestAspect()
+ {
+ QRenderAspect::onUnregistered();
+ }
+
+ void onRegistered() { Qt3DRender::QRenderAspect::onRegistered(); }
+ void onUnregistered() { Qt3DRender::QRenderAspect::onUnregistered(); }
+
+ Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); }
+ Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
+ Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
+ Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
+
+private:
+ Qt3DRender::Render::Entity *m_sceneRoot;
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+namespace {
+
+void runRequiredJobs(Qt3DRender::TestAspect *aspect)
+{
+ Qt3DRender::Render::GeometryRendererManager *geomRendererManager = aspect->nodeManagers()->geometryRendererManager();
+ const QVector<Qt3DCore::QNodeId> dirtyGeometryRenderers = geomRendererManager->dirtyGeometryRenderers();
+ QVector<Qt3DCore::QAspectJobPtr> dirtyGeometryRendererJobs;
+ dirtyGeometryRendererJobs.reserve(dirtyGeometryRenderers.size());
+
+ // Load Geometry
+ for (const Qt3DCore::QNodeId geoRendererId : dirtyGeometryRenderers) {
+ Qt3DRender::Render::HGeometryRenderer geometryRendererHandle = geomRendererManager->lookupHandle(geoRendererId);
+ if (!geometryRendererHandle.isNull()) {
+ auto job = Qt3DRender::Render::LoadGeometryJobPtr::create(geometryRendererHandle);
+ job->setNodeManagers(aspect->nodeManagers());
+ dirtyGeometryRendererJobs.push_back(job);
+ }
+ }
+}
+
+struct NodeCollection
+{
+ explicit NodeCollection(Qt3DRender::TestAspect *aspect, QObject *frontendRoot)
+ : geometryRenderers(frontendRoot->findChildren<Qt3DRender::QGeometryRenderer *>())
+ , attributes(frontendRoot->findChildren<Qt3DRender::QAttribute *>())
+ , buffers(frontendRoot->findChildren<Qt3DRender::QBuffer *>())
+ {
+ // THEN
+ QCOMPARE(aspect->nodeManagers()->geometryManager()->activeHandles().size(), geometryRenderers.size());
+ QCOMPARE(aspect->nodeManagers()->attributeManager()->activeHandles().size(), attributes.size());
+ QCOMPARE(aspect->nodeManagers()->bufferManager()->activeHandles().size(), buffers.size());
+
+ for (const Qt3DRender::QGeometryRenderer *g : qAsConst(geometryRenderers)) {
+ Qt3DRender::Render::GeometryRenderer *backend = aspect->nodeManagers()->geometryRendererManager()->lookupResource(g->id());
+ QVERIFY(backend != nullptr);
+ backendGeometryRenderer.push_back(backend);
+ }
+
+ for (const Qt3DRender::QAttribute *a : qAsConst(attributes)) {
+ Qt3DRender::Render::Attribute *backend = aspect->nodeManagers()->attributeManager()->lookupResource(a->id());
+ QVERIFY(backend != nullptr);
+ backendAttributes.push_back(backend);
+ }
+
+ for (const Qt3DRender::QBuffer *b : qAsConst(buffers)) {
+ Qt3DRender::Render::Buffer *backend = aspect->nodeManagers()->bufferManager()->lookupResource(b->id());
+ QVERIFY(backend != nullptr);
+ backendBuffers.push_back(backend);
+ }
+ }
+
+ QList<Qt3DRender::QGeometryRenderer *> geometryRenderers;
+ QList<Qt3DRender::QAttribute *> attributes;
+ QList<Qt3DRender::QBuffer *> buffers;
+
+ QVector<Qt3DRender::Render::GeometryRenderer *> backendGeometryRenderer;
+ QVector<Qt3DRender::Render::Attribute *> backendAttributes;
+ QVector<Qt3DRender::Render::Buffer *> backendBuffers;
+};
+
+
+} // anonymous
+
+class tst_UpdateMeshTriangleListJob : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob;
+
+ // THEN
+ QVERIFY(backendUpdateMeshTriangleListJob.managers() == nullptr);
+ }
+
+ void checkInitialize()
+ {
+ // GIVEN
+ Qt3DRender::Render::UpdateMeshTriangleListJob updateMeshTriangleListJob;
+ Qt3DRender::Render::NodeManagers managers;
+
+ // WHEN
+ updateMeshTriangleListJob.setManagers(&managers);
+
+ // THEN
+ QVERIFY(updateMeshTriangleListJob.managers() == &managers);
+ }
+
+ void checkRunNoDirtyGeometryRenderNoDirtyAttributesNoDirtyBuffers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Run required jobs to load geometries and meshes
+ runRequiredJobs(test.data());
+
+ // WHEN
+ const NodeCollection collection(test.data(), root.data());
+
+ // THEN
+ QCOMPARE(collection.geometryRenderers.size(), 1);
+ QCOMPARE(collection.attributes.size(), 5);
+ QCOMPARE(collection.buffers.size(), 2);
+
+ // WHEN
+ for (Qt3DRender::Render::GeometryRenderer *g : collection.backendGeometryRenderer)
+ g->unsetDirty();
+ for (Qt3DRender::Render::Attribute *a : collection.backendAttributes)
+ a->unsetDirty();
+ for (Qt3DRender::Render::Buffer *b : collection.backendBuffers)
+ b->unsetDirty();
+
+ Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob;
+ backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers());
+
+ backendUpdateMeshTriangleListJob.run();
+
+ // THEN
+ QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 0);
+ }
+
+ void checkRunDirtyGeometryRenderNoDirtyAttributesNoDirtyBuffers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Run required jobs to load geometries and meshes
+ runRequiredJobs(test.data());
+
+ // WHEN
+ const NodeCollection collection(test.data(), root.data());
+
+ // THEN
+ QCOMPARE(collection.geometryRenderers.size(), 1);
+ QCOMPARE(collection.attributes.size(), 5);
+ QCOMPARE(collection.buffers.size(), 2);
+
+ // WHEN
+ for (Qt3DRender::Render::Attribute *a : collection.backendAttributes)
+ a->unsetDirty();
+ for (Qt3DRender::Render::Buffer *b : collection.backendBuffers)
+ b->unsetDirty();
+
+ Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob;
+ backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers());
+
+ backendUpdateMeshTriangleListJob.run();
+
+ // THEN
+ QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 1);
+ }
+
+ void checkRunDirtyGeometryRenderDirtyAttributesNoDirtyBuffers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Run required jobs to load geometries and meshes
+ runRequiredJobs(test.data());
+
+ // WHEN
+ const NodeCollection collection(test.data(), root.data());
+
+ // THEN
+ QCOMPARE(collection.geometryRenderers.size(), 1);
+ QCOMPARE(collection.attributes.size(), 5);
+ QCOMPARE(collection.buffers.size(), 2);
+
+ // WHEN
+ for (Qt3DRender::Render::Buffer *b : collection.backendBuffers)
+ b->unsetDirty();
+
+ Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob;
+ backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers());
+
+ backendUpdateMeshTriangleListJob.run();
+
+ // THEN
+ QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 1);
+ }
+
+ void checkRunDirtyGeometryRenderDirtyAttributesDirtyBuffers()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/test_scene.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Run required jobs to load geometries and meshes
+ runRequiredJobs(test.data());
+
+ // WHEN
+ const NodeCollection collection(test.data(), root.data());
+
+ // THEN
+ QCOMPARE(collection.geometryRenderers.size(), 1);
+ QCOMPARE(collection.attributes.size(), 5);
+ QCOMPARE(collection.buffers.size(), 2);
+
+ // WHEN
+ for (Qt3DRender::Render::Buffer *b : collection.backendBuffers)
+ b->unsetDirty();
+
+ Qt3DRender::Render::UpdateMeshTriangleListJob backendUpdateMeshTriangleListJob;
+ backendUpdateMeshTriangleListJob.setManagers(test->nodeManagers());
+
+ backendUpdateMeshTriangleListJob.run();
+
+ // THEN
+ QCOMPARE(test->nodeManagers()->geometryRendererManager()->geometryRenderersRequiringTriangleDataRefresh().size(), 1);
+ }
+
+};
+
+QTEST_MAIN(tst_UpdateMeshTriangleListJob)
+
+#include "tst_updatemeshtrianglelistjob.moc"
diff --git a/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro b/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro
new file mode 100644
index 000000000..499f78c72
--- /dev/null
+++ b/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.pro
@@ -0,0 +1,18 @@
+TEMPLATE = app
+
+TARGET = tst_updatemeshtrianglelistjob
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_updatemeshtrianglelistjob.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
+include(../qmlscenereader/qmlscenereader.pri)
+# Extra dependencies to build test scenes needed by the tests
+QT += quick 3dquick 3dquick-private 3dextras 3dquickextras
+
+RESOURCES += \
+ updatemeshtrianglelistjob.qrc
diff --git a/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc b/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc
new file mode 100644
index 000000000..6a6a0433e
--- /dev/null
+++ b/tests/auto/render/updatemeshtrianglelistjob/updatemeshtrianglelistjob.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>test_scene.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml
new file mode 100644
index 000000000..20585b5de
--- /dev/null
+++ b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_eye.qml
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 800
+ height: 800
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ Entity {
+ components: [
+ ShaderData {
+ property vector3d eyePosition: Qt.vector3d(1.0, 1.0, 1.0);
+ property int eyePositionTransformed: 0 // ModelToEye (enum aren't publicly exposed yet)
+ },
+ Transform {
+ translation: Qt.vector3d(0.0, 5.0, 0.0)
+ }
+ ]
+ }
+}
diff --git a/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml
new file mode 100644
index 000000000..d3e766021
--- /dev/null
+++ b/tests/auto/render/updateshaderdatatransformjob/test_scene_model_to_world.qml
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+import QtQuick.Window 2.0
+
+Entity {
+ id: sceneRoot
+
+ Window {
+ id: win
+ width: 800
+ height: 800
+ visible: true
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ components: [
+ RenderSettings {
+ Viewport {
+ normalizedRect: Qt.rect(0.0, 0.0, 1.0, 1.0)
+
+ RenderSurfaceSelector {
+
+ surface: win
+
+ ClearBuffers {
+ buffers : ClearBuffers.ColorDepthBuffer
+ NoDraw {}
+ }
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ ]
+
+ Entity {
+ components: [
+ ShaderData {
+ property vector3d position: Qt.vector3d(1.0, 1.0, 1.0);
+ property int positionTransformed: 1 // ModelToWorld (enum aren't publicly exposed yet)
+ },
+ Transform {
+ translation: Qt.vector3d(5.0, 5.0, 5.0)
+ }
+ ]
+ }
+}
diff --git a/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp b/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp
new file mode 100644
index 000000000..9b53d1f65
--- /dev/null
+++ b/tests/auto/render/updateshaderdatatransformjob/tst_updateshaderdatatransformjob.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/private/updateshaderdatatransformjob_p.h>
+#include <Qt3DRender/private/updateworldtransformjob_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qshaderdata.h>
+#include <Qt3DRender/qcamera.h>
+#include <Qt3DRender/private/shaderdata_p.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include "qmlscenereader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class TestAspect : public Qt3DRender::QRenderAspect
+{
+public:
+ TestAspect(Qt3DCore::QNode *root)
+ : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
+ , m_sceneRoot(nullptr)
+ {
+ Qt3DRender::QRenderAspect::onRegistered();
+
+ const Qt3DCore::QNodeCreatedChangeGenerator generator(root);
+ const QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = generator.creationChanges();
+
+ d_func()->setRootAndCreateNodes(qobject_cast<Qt3DCore::QEntity *>(root), creationChanges);
+
+ Qt3DRender::Render::Entity *rootEntity = nodeManagers()->lookupResource<Qt3DRender::Render::Entity, Render::EntityManager>(rootEntityId());
+ Q_ASSERT(rootEntity);
+ m_sceneRoot = rootEntity;
+ }
+
+ ~TestAspect()
+ {
+ QRenderAspect::onUnregistered();
+ }
+
+ void onRegistered() { Qt3DRender::QRenderAspect::onRegistered(); }
+ void onUnregistered() { Qt3DRender::QRenderAspect::onUnregistered(); }
+
+ Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); }
+ Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
+ Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
+ Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
+
+private:
+ Qt3DRender::Render::Entity *m_sceneRoot;
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+namespace {
+
+void runRequiredJobs(Qt3DRender::TestAspect *test)
+{
+ Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform;
+ updateWorldTransform.setRoot(test->sceneRoot());
+ updateWorldTransform.run();
+}
+
+struct NodeCollection
+{
+ explicit NodeCollection(Qt3DRender::TestAspect *aspect, QObject *frontendRoot)
+ : shaderData(frontendRoot->findChildren<Qt3DRender::QShaderData *>())
+ {
+ // THEN
+ QCOMPARE(aspect->nodeManagers()->shaderDataManager()->activeHandles().size(), shaderData.size());
+
+ for (const Qt3DRender::QShaderData *s : qAsConst(shaderData)) {
+ Qt3DRender::Render::ShaderData *backend = aspect->nodeManagers()->shaderDataManager()->lookupResource(s->id());
+ QVERIFY(backend != nullptr);
+ backendShaderData.push_back(backend);
+ }
+ }
+
+ QList<Qt3DRender::QShaderData *> shaderData;
+ QVector<Qt3DRender::Render::ShaderData *> backendShaderData;
+};
+
+} // anonymous
+
+class tst_UpdateShaderDataTransformJob : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::UpdateShaderDataTransformJob backendUpdateShaderDataTransformJob;
+
+ // THEN
+ QVERIFY(backendUpdateShaderDataTransformJob.managers() == nullptr);
+ }
+
+ void checkInitializeState()
+ {
+ // GIVEN
+ Qt3DRender::Render::UpdateShaderDataTransformJob backendUpdateShaderDataTransformJob;
+ Qt3DRender::Render::NodeManagers managers;
+
+ // WHEN
+ backendUpdateShaderDataTransformJob.setManagers(&managers);
+
+ // THEN
+ QVERIFY(backendUpdateShaderDataTransformJob.managers() == &managers);
+ }
+
+ void checkRunModelToEye()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/test_scene_model_to_eye.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Properly compute the world transforms
+ runRequiredJobs(test.data());
+
+ // WHEN
+ Qt3DRender::QCamera *camera = root->findChild<Qt3DRender::QCamera *>();
+ const NodeCollection collection(test.data(), root.data());
+
+ // THEN
+ QCOMPARE(collection.shaderData.size(), 1);
+ QVERIFY(camera != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::ShaderData *backendShaderData = collection.backendShaderData.first();
+
+ // THEN
+ QCOMPARE(backendShaderData->properties().size(), 2);
+ QVERIFY(backendShaderData->properties().contains(QLatin1String("eyePosition")));
+ QVERIFY(backendShaderData->properties().contains(QLatin1String("eyePositionTransformed")));
+
+ QCOMPARE(backendShaderData->properties()[QLatin1String("eyePosition")].value<QVector3D>(), QVector3D(1.0f, 1.0f, 1.0f));
+ QCOMPARE(backendShaderData->properties()[QLatin1String("eyePositionTransformed")].toInt(), int(Qt3DRender::Render::ShaderData::ModelToEye));
+
+ // WHEN
+ Qt3DRender::Render::UpdateShaderDataTransformJob backendUpdateShaderDataTransformJob;
+ backendUpdateShaderDataTransformJob.setManagers(test->nodeManagers());
+ backendUpdateShaderDataTransformJob.run();
+
+ // THEN
+ // See scene file to find translation
+ QCOMPARE(backendShaderData->getTransformedProperty(QLatin1String("eyePosition"), camera->viewMatrix()).value<QVector3D>(), camera->viewMatrix() * (QVector3D(1.0f, 1.0f, 1.0f) + QVector3D(0.0f, 5.0f, 0.0f)));
+ }
+
+ void checkRunModelToWorld()
+ {
+ // GIVEN
+ QmlSceneReader sceneReader(QUrl("qrc:/test_scene_model_to_world.qml"));
+ QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(sceneReader.root()));
+ QVERIFY(root);
+ QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
+
+ // Properly compute the world transforms
+ runRequiredJobs(test.data());
+
+ // WHEN
+ Qt3DRender::QCamera *camera = root->findChild<Qt3DRender::QCamera *>();
+ const NodeCollection collection(test.data(), root.data());
+
+ // THEN
+ QCOMPARE(collection.shaderData.size(), 1);
+ QVERIFY(camera != nullptr);
+
+ // WHEN
+ Qt3DRender::Render::ShaderData *backendShaderData = collection.backendShaderData.first();
+
+ // THEN
+ QCOMPARE(backendShaderData->properties().size(), 2);
+ QVERIFY(backendShaderData->properties().contains(QLatin1String("position")));
+ QVERIFY(backendShaderData->properties().contains(QLatin1String("positionTransformed")));
+
+ QCOMPARE(backendShaderData->properties()[QLatin1String("position")].value<QVector3D>(), QVector3D(1.0f, 1.0f, 1.0f));
+ QCOMPARE(backendShaderData->properties()[QLatin1String("positionTransformed")].toInt(), int(Qt3DRender::Render::ShaderData::ModelToWorld));
+
+ // WHEN
+ Qt3DRender::Render::UpdateShaderDataTransformJob backendUpdateShaderDataTransformJob;
+ backendUpdateShaderDataTransformJob.setManagers(test->nodeManagers());
+ backendUpdateShaderDataTransformJob.run();
+
+ // THEN
+ // See scene file to find translation
+ QCOMPARE(backendShaderData->getTransformedProperty(QLatin1String("position"), camera->viewMatrix()).value<QVector3D>(), QVector3D(1.0f, 1.0f, 1.0f) + QVector3D(5.0f, 5.0f, 5.0f));
+ }
+};
+
+QTEST_MAIN(tst_UpdateShaderDataTransformJob)
+
+#include "tst_updateshaderdatatransformjob.moc"
diff --git a/tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.pro b/tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.pro
new file mode 100644
index 000000000..07c82acca
--- /dev/null
+++ b/tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.pro
@@ -0,0 +1,18 @@
+TEMPLATE = app
+
+TARGET = tst_updateshaderdatatransformjob
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_updateshaderdatatransformjob.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
+include(../qmlscenereader/qmlscenereader.pri)
+# Extra dependencies to build test scenes needed by the tests
+QT += quick 3dquick 3dquick-private 3dextras 3dquickextras
+
+RESOURCES += \
+ updateshaderdatatransformjob.qrc
diff --git a/tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.qrc b/tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.qrc
new file mode 100644
index 000000000..a21bfdd5d
--- /dev/null
+++ b/tests/auto/render/updateshaderdatatransformjob/updateshaderdatatransformjob.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>test_scene_model_to_eye.qml</file>
+ <file>test_scene_model_to_world.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/benchmarks/render/jobs/tst_bench_jobs.cpp b/tests/benchmarks/render/jobs/tst_bench_jobs.cpp
index 8cf1941d5..454cb9f6a 100644
--- a/tests/benchmarks/render/jobs/tst_bench_jobs.cpp
+++ b/tests/benchmarks/render/jobs/tst_bench_jobs.cpp
@@ -106,8 +106,8 @@ namespace Qt3DRender {
QVector<Qt3DCore::QAspectJobPtr> framePreparationJob()
{
- static_cast<Render::Renderer *>(d_func()->m_renderer)->m_framePreparationJob->setRoot(d_func()->m_renderer->sceneRoot());
- return QVector<Qt3DCore::QAspectJobPtr>() << static_cast<Render::Renderer *>(d_func()->m_renderer)->m_framePreparationJob;
+ static_cast<Render::Renderer *>(d_func()->m_renderer)->m_updateShaderDataTransformJob->setManagers(d_func()->m_renderer->nodeManagers());
+ return QVector<Qt3DCore::QAspectJobPtr>() << static_cast<Render::Renderer *>(d_func()->m_renderer)->m_updateShaderDataTransformJob;
}
QVector<Qt3DCore::QAspectJobPtr> frameCleanupJob()
diff --git a/tests/benchmarks/render/layerfiltering/layerfiltering.pro b/tests/benchmarks/render/layerfiltering/layerfiltering.pro
new file mode 100644
index 000000000..08b2b7165
--- /dev/null
+++ b/tests/benchmarks/render/layerfiltering/layerfiltering.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+
+TARGET = tst_bench_layerfiltering
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_bench_layerfiltering.cpp
+
+include(../../../auto/render/commons/commons.pri)
+
+# Needed to use the TestAspect
+DEFINES += QT_BUILD_INTERNAL
diff --git a/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp b/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp
new file mode 100644
index 000000000..78f264349
--- /dev/null
+++ b/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Paul Lemire
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qaspectjobmanager_p.h>
+
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/qrenderaspect.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DRender/private/filterlayerentityjob_p.h>
+#include <Qt3DRender/qlayer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class TestAspect : public Qt3DRender::QRenderAspect
+{
+public:
+ TestAspect(Qt3DCore::QNode *root)
+ : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
+ , m_jobManager(new Qt3DCore::QAspectJobManager())
+ {
+ Qt3DCore::QAbstractAspectPrivate::get(this)->m_jobManager = m_jobManager.data();
+ QRenderAspect::onRegistered();
+
+ const Qt3DCore::QNodeCreatedChangeGenerator generator(root);
+ const QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = generator.creationChanges();
+
+ for (const Qt3DCore::QNodeCreatedChangeBasePtr change : creationChanges)
+ d_func()->createBackendNode(change);
+ }
+
+ ~TestAspect()
+ {
+ QRenderAspect::onUnregistered();
+ }
+
+ Qt3DRender::Render::NodeManagers *nodeManagers() const
+ {
+ return d_func()->m_renderer->nodeManagers();
+ }
+
+ void onRegistered() { QRenderAspect::onRegistered(); }
+ void onUnregistered() { QRenderAspect::onUnregistered(); }
+
+private:
+ QScopedPointer<Qt3DCore::QAspectJobManager> m_jobManager;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+namespace {
+
+Qt3DCore::QEntity *buildTestScene(int layersCount,
+ int entityCount,
+ QVector<Qt3DCore::QNodeId> &layerIds,
+ bool alwaysEnabled = true)
+{
+ Qt3DCore::QEntity *root = new Qt3DCore::QEntity();
+
+ QVector<Qt3DRender::QLayer *> layers;
+ layers.reserve(layersCount);
+ layerIds.reserve(layersCount);
+
+ for (int i = 0; i < layersCount; ++i) {
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(root);
+ layers.push_back(layer);
+ layerIds.push_back(layer->id());
+ }
+
+ for (int i = 0; i < entityCount; ++i) {
+ Qt3DCore::QEntity *entity = new Qt3DCore::QEntity(root);
+
+ if (layersCount > 0)
+ entity->addComponent(layers.at(qrand() % layersCount));
+
+ if (!alwaysEnabled && i % 128 == 0)
+ entity->setEnabled(false);
+ }
+
+ return root;
+}
+
+} // anonymous
+
+class tst_BenchLayerFiltering : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void filterEntities_data()
+ {
+ QTest::addColumn<Qt3DCore::QEntity *>("entitySubtree");
+ QTest::addColumn<Qt3DCore::QNodeIdVector>("layerIds");
+ QTest::addColumn<bool>("hasLayerFilter");
+
+
+ {
+ Qt3DCore::QNodeIdVector layerIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(0, 5000, layerIds);
+
+ QTest::newRow("Filter-NoLayerFilterAllEnabled") << rootEntity
+ << layerIds
+ << (layerIds.size() != 0);
+ }
+
+ {
+ Qt3DCore::QNodeIdVector layerIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(0, 5000, layerIds, false);
+ QTest::newRow("Filter-NoLayerFilterSomeDisabled") << rootEntity
+ << layerIds
+ << (layerIds.size() != 0);
+ }
+
+ {
+ Qt3DCore::QNodeIdVector layerIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(10, 5000, layerIds);
+
+ QTest::newRow("FilterLayerFilterAllEnabled") << rootEntity
+ << layerIds
+ << (layerIds.size() != 0);
+ }
+
+ {
+ Qt3DCore::QNodeIdVector layerIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(10, 5000, layerIds, false);
+
+ QTest::newRow("FilterLayerFilterSomeDisabled") << rootEntity
+ << layerIds
+ << (layerIds.size() != 0);
+ }
+
+ }
+
+ void filterEntities()
+ {
+ QFETCH(Qt3DCore::QEntity *, entitySubtree);
+ QFETCH(Qt3DCore::QNodeIdVector, layerIds);
+ QFETCH(bool, hasLayerFilter);
+
+ // GIVEN
+ QScopedPointer<Qt3DRender::TestAspect> aspect(new Qt3DRender::TestAspect(entitySubtree));
+
+ // WHEN
+ Qt3DRender::Render::FilterLayerEntityJob filterJob;
+ filterJob.setHasLayerFilter(hasLayerFilter);
+ filterJob.setLayers(layerIds);
+ filterJob.setManager(aspect->nodeManagers());
+
+ QBENCHMARK {
+ filterJob.run();
+ }
+ }
+};
+
+QTEST_MAIN(tst_BenchLayerFiltering)
+
+#include "tst_bench_layerfiltering.moc"
diff --git a/tests/benchmarks/render/render.pro b/tests/benchmarks/render/render.pro
index f1095a347..ddbc6a800 100644
--- a/tests/benchmarks/render/render.pro
+++ b/tests/benchmarks/render/render.pro
@@ -1,5 +1,6 @@
TEMPLATE=subdirs
qtConfig(private_tests) {
- SUBDIRS += jobs
+ SUBDIRS += jobs \
+ layerfiltering
}
diff --git a/tests/manual/additional-attributes-qml/additional-attributes-qml.pro b/tests/manual/additional-attributes-qml/additional-attributes-qml.pro
new file mode 100644
index 000000000..f7612bf99
--- /dev/null
+++ b/tests/manual/additional-attributes-qml/additional-attributes-qml.pro
@@ -0,0 +1,14 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick 3dlogic qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ additional-attributes-qml.qrc
diff --git a/tests/manual/additional-attributes-qml/additional-attributes-qml.qrc b/tests/manual/additional-attributes-qml/additional-attributes-qml.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/additional-attributes-qml/additional-attributes-qml.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/qt3d/deferred-renderer-cpp/pointlightblock.cpp b/tests/manual/additional-attributes-qml/main.cpp
index 36bab9966..32ae912df 100644
--- a/examples/qt3d/deferred-renderer-cpp/pointlightblock.cpp
+++ b/tests/manual/additional-attributes-qml/main.cpp
@@ -48,26 +48,15 @@
**
****************************************************************************/
-#include "pointlightblock.h"
+#include <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
-PointLightBlock::PointLightBlock(Qt3DCore::QNode *parent)
- : Qt3DRender::QShaderData(parent)
+int main(int argc, char* argv[])
{
+ QGuiApplication app(argc, argv);
+ Qt3DExtras::Quick::Qt3DQuickWindow view;
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+ return app.exec();
}
-
-PointLightBlock::~PointLightBlock()
-{
-}
-
-QVector<Qt3DRender::QAbstractLight *> PointLightBlock::lights() const
-{
- return m_lights;
-}
-
-void PointLightBlock::addLight(Qt3DRender::QAbstractLight *light)
-{
- m_lights.append(light);
- emit lightsChanged();
-}
-
diff --git a/tests/manual/additional-attributes-qml/main.qml b/tests/manual/additional-attributes-qml/main.qml
new file mode 100644
index 000000000..75c010a9d
--- /dev/null
+++ b/tests/manual/additional-attributes-qml/main.qml
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.2 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ id: sceneRoot
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ OrbitCameraController {
+ camera: camera
+ }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ clearColor: Qt.rgba(0, 0.5, 1, 1)
+ camera: camera
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+ readonly property Buffer translationBuffer: Buffer {
+ data: {
+ var array = new Float32Array(20 * 3)
+ for (var i = 0; i < 20; ++i) {
+ var j = i * 3;
+ array[j] = i * 4.0;
+ array[j + 1] = 0.0;
+ array[j + 2] = 0.0;
+ }
+ return array;
+ }
+ }
+
+ readonly property Material instancedMaterial: Material {
+ effect: Effect {
+ techniques: Technique {
+ filterKeys: FilterKey { name: "renderingStyle"; value: "forward" }
+
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ majorVersion: 3
+ minorVersion: 2
+ profile: GraphicsApiFilter.CoreProfile
+ }
+
+ renderPasses: RenderPass {
+ shaderProgram: ShaderProgram {
+ vertexShaderCode: "
+ #version 150
+ in vec3 vertexPosition;
+ in vec3 translation;
+ uniform mat4 mvp;
+
+ void main()
+ {
+ gl_Position = mvp * vec4(vertexPosition + translation, 1.0);
+ }
+ "
+
+ fragmentShaderCode: "
+ #version 150
+
+ out vec4 fragColor;
+
+ void main()
+ {
+ fragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ }
+ "
+ }
+ }
+ }
+ }
+ }
+
+ GeometryRenderer {
+ id: torusMesh
+ instanceCount: 20
+ geometry: torusGeometry
+ }
+
+ TorusGeometry {
+ id: torusGeometry
+ minorRadius: 0.5
+ attributes: [
+ Attribute {
+ attributeType: Attribute.VertexAttribute
+ vertexBaseType: Attribute.Float
+ vertexSize: 3
+ byteStride: 3 * 4 // vector3d
+ byteOffset: 0
+ divisor: 1 // One translation per instance
+ name: "translation"
+ buffer: translationBuffer
+ }
+ ]
+ }
+
+ // Doesn't work
+// TorusMesh {
+// id: torusMesh
+// geometry.attributes: [
+// Attribute {
+// attributeType: Attribute.VertexAttribute
+// vertexBaseType: Attribute.Float
+// vertexSize: 3
+// byteStride: 3 * 4 // vector3d
+// byteOffset: 0
+// divisor: 1 // One translation per instance
+// name: "translation"
+// buffer: translationBuffer
+// }
+// ]
+// }
+
+ Transform {
+ id: torusTransform
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ }
+
+ Entity {
+ id: torusEntity
+ components: [ torusMesh, instancedMaterial, torusTransform ]
+ }
+}
diff --git a/tests/manual/clip-planes-qml/ClippingPlanes.qml b/tests/manual/clip-planes-qml/ClippingPlanes.qml
index 62deabc73..2fed0ce9c 100644
--- a/tests/manual/clip-planes-qml/ClippingPlanes.qml
+++ b/tests/manual/clip-planes-qml/ClippingPlanes.qml
@@ -59,7 +59,7 @@ Entity {
property Layer visualizationLayer
property ShaderData sectionData: ShaderData {
- property real sectionsCount: 3
+ property int sectionsCount: 3
property ShaderDataArray sections: ShaderDataArray {
ShaderData {
property vector4d equation: clipPlane0.equation
diff --git a/tests/manual/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc b/tests/manual/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc
index 65311e77f..610270316 100644
--- a/tests/manual/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc
+++ b/tests/manual/deferred-renderer-cpp/doc/src/deferred-renderer-cpp.qdoc
@@ -29,4 +29,25 @@
\example deferred-renderer-cpp
\title Qt 3D: Deferred Renderer C++ Example
\ingroup qt3d-examples-cpp
+ \brief A C++ application that demonstrates rendering to an intermediate
+ G-buffer.
+
+ \e {Deferred Renderer} demonstrates using a two pass rendering method.
+ First, all the meshes in the scene are drawn using the same shader that will
+ output the following values for each fragment: world normal vector, color,
+ depth, and world position vector.
+
+ Each of these values will be stored in a texture, which together form what
+ is called the G-buffer. Nothing is drawn onscreen during the first pass, but
+ rather drawn into the G-buffer ready for later use.
+
+ Once all the meshes have been drawn, the G-buffer is filled with all the
+ meshes that can currently be seen by the camera. The second render pass is
+ then used to render the scene to the back buffer with the final color
+ shading by reading the values from the G-buffer textures and outputting a
+ color onto a full screen quad.
+
+ For more information, see \l{Deferred Renderer}.
+
+ \include examples-run.qdocinc
*/
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 5b17f18a2..5a10e4e0f 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -31,10 +31,13 @@ SUBDIRS += \
tessellation-modes \
transforms-qml \
transparency-qml \
- transparency-qml-scene3d
+ transparency-qml-scene3d \
+ rendercapture-qml \
+ additional-attributes-qml
qtHaveModule(widgets): {
SUBDIRS += \
assimp-cpp \
- paintedtexture-cpp
+ paintedtexture-cpp \
+ rendercapture-cpp
}
diff --git a/tests/manual/rendercapture-cpp/main.cpp b/tests/manual/rendercapture-cpp/main.cpp
new file mode 100644
index 000000000..5d0d6fa49
--- /dev/null
+++ b/tests/manual/rendercapture-cpp/main.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $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 <QApplication>
+
+#include <QWidget>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QCheckBox>
+
+#include <Qt3DCore/QEntity>
+#include <Qt3DCore/QTransform>
+
+#include <Qt3DRender/QCamera>
+#include <Qt3DRender/QRenderCapture>
+
+#include <Qt3DExtras/QPhongMaterial>
+#include <Qt3DExtras/QSphereMesh>
+#include <Qt3DExtras/QTorusMesh>
+
+#include <QPropertyAnimation>
+
+#include "qt3dwindow.h"
+#include "orbittransformcontroller.h"
+#include "qorbitcameracontroller.h"
+#include "mycapture.h"
+
+Qt3DCore::QEntity *createScene()
+{
+ // Root entity
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity;
+
+ // Material
+ Qt3DRender::QMaterial *material = new Qt3DExtras::QPhongMaterial(rootEntity);
+
+ // Torus
+ Qt3DCore::QEntity *torusEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DExtras::QTorusMesh *torusMesh = new Qt3DExtras::QTorusMesh;
+ torusMesh->setRadius(5);
+ torusMesh->setMinorRadius(1);
+ torusMesh->setRings(100);
+ torusMesh->setSlices(20);
+
+ Qt3DCore::QTransform *torusTransform = new Qt3DCore::QTransform;
+ torusTransform->setScale3D(QVector3D(1.5, 1, 0.5));
+ torusTransform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 45.0f));
+
+ torusEntity->addComponent(torusMesh);
+ torusEntity->addComponent(torusTransform);
+ torusEntity->addComponent(material);
+
+ // Sphere
+ Qt3DCore::QEntity *sphereEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DExtras::QSphereMesh *sphereMesh = new Qt3DExtras::QSphereMesh;
+ sphereMesh->setRadius(3);
+
+ Qt3DCore::QTransform *sphereTransform = new Qt3DCore::QTransform;
+ OrbitTransformController *controller = new OrbitTransformController(sphereTransform);
+ controller->setTarget(sphereTransform);
+ controller->setRadius(20.0f);
+
+ QPropertyAnimation *sphereRotateTransformAnimation = new QPropertyAnimation(sphereTransform);
+ sphereRotateTransformAnimation->setTargetObject(controller);
+ sphereRotateTransformAnimation->setPropertyName("angle");
+ sphereRotateTransformAnimation->setStartValue(QVariant::fromValue(0));
+ sphereRotateTransformAnimation->setEndValue(QVariant::fromValue(360));
+ sphereRotateTransformAnimation->setDuration(10000);
+ sphereRotateTransformAnimation->setLoopCount(-1);
+ sphereRotateTransformAnimation->start();
+
+ sphereEntity->addComponent(sphereMesh);
+ sphereEntity->addComponent(sphereTransform);
+ sphereEntity->addComponent(material);
+
+ return rootEntity;
+}
+
+int main(int argc, char* argv[])
+{
+ QApplication app(argc, argv);
+ Qt3DExtras::Qt3DWindow view;
+
+ Qt3DCore::QEntity *scene = createScene();
+ view.setRootEntity(scene);
+ view.resize(600, 600);
+
+ Qt3DRender::QRenderCapture* capture = new Qt3DRender::QRenderCapture;
+ view.activeFrameGraph()->setParent(capture);
+ view.setActiveFrameGraph(capture);
+
+ // Camera
+ Qt3DRender::QCamera *camera = view.camera();
+ camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
+ camera->setPosition(QVector3D(0, 0, 40.0f));
+ camera->setViewCenter(QVector3D(0, 0, 0));
+
+ // For camera controls
+ Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(scene);
+ camController->setLinearSpeed( 50.0f );
+ camController->setLookSpeed( 180.0f );
+ camController->setCamera(camera);
+
+ QWidget *container = QWidget::createWindowContainer(&view);
+ container->setMinimumSize(QSize(600, 600));
+ container->setMaximumSize(QSize(600, 600));
+
+ QPushButton *captureButton = new QPushButton();
+ captureButton->setText("Capture");
+ QCheckBox *checkBox = new QCheckBox();
+ checkBox->setText("continuous");
+
+ QLabel *imageLabel = new QLabel();
+ imageLabel->setBackgroundRole(QPalette::Base);
+ imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+ imageLabel->setScaledContents(true);
+ imageLabel->resize(600, 600);
+ imageLabel->setMinimumSize(QSize(600, 600));
+ imageLabel->setMaximumSize(QSize(600, 600));
+
+ MyCapture myc(capture, imageLabel);
+ QObject::connect(captureButton, &QPushButton::pressed, &myc, &MyCapture::capture);
+ QObject::connect(checkBox, &QCheckBox::clicked, &myc, &MyCapture::setContinuous);
+
+ // create widget
+ QWidget *widget = new QWidget;
+ widget->setWindowTitle(QStringLiteral("RenderCapture example"));
+
+ QWidget* subWidget = new QWidget;
+ QVBoxLayout *vLayout = new QVBoxLayout(subWidget);
+ vLayout->addWidget(captureButton);
+ vLayout->addWidget(checkBox);
+ vLayout->addWidget(imageLabel);
+
+ QHBoxLayout *hLayout = new QHBoxLayout(widget);
+ hLayout->addWidget(container);
+ hLayout->addWidget(subWidget);
+
+ // Show window
+ widget->show();
+ widget->resize(1250, 700);
+
+ return app.exec();
+}
diff --git a/tests/manual/rendercapture-cpp/mycapture.h b/tests/manual/rendercapture-cpp/mycapture.h
new file mode 100644
index 000000000..803ef7336
--- /dev/null
+++ b/tests/manual/rendercapture-cpp/mycapture.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $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 MYCAPTURE_H
+#define MYCAPTURE_H
+
+#include <QLabel>
+#include <Qt3DRender/QRenderCapture>
+
+class MyCapture : public QObject
+{
+ Q_OBJECT
+public:
+ MyCapture(Qt3DRender::QRenderCapture* capture, QLabel *imageLabel)
+ : m_capture(capture)
+ , m_cid(1)
+ , m_imageLabel(imageLabel)
+ , m_reply(nullptr)
+ , m_continuous(false)
+ {
+ }
+
+public slots:
+ void onCompleted(bool isComplete)
+ {
+ if (isComplete) {
+ QObject::disconnect(connection);
+
+ m_imageLabel->setPixmap(QPixmap::fromImage(m_reply->image()));
+
+ ++m_cid;
+
+ m_reply->saveToFile("capture.bmp");
+
+ delete m_reply;
+ m_reply = nullptr;
+
+ if (m_continuous)
+ capture();
+ }
+ }
+
+ void setContinuous(bool continuos)
+ {
+ m_continuous = continuos;
+ }
+
+ void capture()
+ {
+ m_reply = m_capture->requestCapture(m_cid);
+ connection = QObject::connect(m_reply, &Qt3DRender::QRenderCaptureReply::completeChanged,
+ this, &MyCapture::onCompleted);
+ }
+
+private:
+ Qt3DRender::QRenderCapture* m_capture;
+ Qt3DRender::QRenderCaptureReply *m_reply;
+ QMetaObject::Connection connection;
+ QLabel *m_imageLabel;
+ bool m_continuous;
+ int m_cid;
+};
+
+#endif
+
diff --git a/tests/manual/rendercapture-cpp/orbittransformcontroller.cpp b/tests/manual/rendercapture-cpp/orbittransformcontroller.cpp
new file mode 100644
index 000000000..0aa7a68e4
--- /dev/null
+++ b/tests/manual/rendercapture-cpp/orbittransformcontroller.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $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 "orbittransformcontroller.h"
+
+#include <Qt3DCore/qtransform.h>
+
+QT_BEGIN_NAMESPACE
+
+OrbitTransformController::OrbitTransformController(QObject *parent)
+ : QObject(parent)
+ , m_target(nullptr)
+ , m_matrix()
+ , m_radius(1.0f)
+ , m_angle(0.0f)
+{
+}
+
+void OrbitTransformController::setTarget(Qt3DCore::QTransform *target)
+{
+ if (m_target != target) {
+ m_target = target;
+ emit targetChanged();
+ }
+}
+
+Qt3DCore::QTransform *OrbitTransformController::target() const
+{
+ return m_target;
+}
+
+void OrbitTransformController::setRadius(float radius)
+{
+ if (!qFuzzyCompare(radius, m_radius)) {
+ m_radius = radius;
+ updateMatrix();
+ emit radiusChanged();
+ }
+}
+
+float OrbitTransformController::radius() const
+{
+ return m_radius;
+}
+
+void OrbitTransformController::setAngle(float angle)
+{
+ if (!qFuzzyCompare(angle, m_angle)) {
+ m_angle = angle;
+ updateMatrix();
+ emit angleChanged();
+ }
+}
+
+float OrbitTransformController::angle() const
+{
+ return m_angle;
+}
+
+void OrbitTransformController::updateMatrix()
+{
+ m_matrix.setToIdentity();
+ m_matrix.rotate(m_angle, QVector3D(0.0f, 1.0f, 0.0f));
+ m_matrix.translate(m_radius, 0.0f, 0.0f);
+ m_target->setMatrix(m_matrix);
+}
+
+QT_END_NAMESPACE
diff --git a/examples/qt3d/deferred-renderer-cpp/sceneeffect.h b/tests/manual/rendercapture-cpp/orbittransformcontroller.h
index eb361c273..5f41722b6 100644
--- a/examples/qt3d/deferred-renderer-cpp/sceneeffect.h
+++ b/tests/manual/rendercapture-cpp/orbittransformcontroller.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -48,25 +49,52 @@
**
****************************************************************************/
-#ifndef SCENEEFFECT_H
-#define SCENEEFFECT_H
+#ifndef ORBITTRANSFORMCONTROLLER_H
+#define ORBITTRANSFORMCONTROLLER_H
-#include <Qt3DRender/QEffect>
-#include <Qt3DRender/QTechnique>
+#include <QObject>
+#include <QMatrix4x4>
-class SceneEffect : public Qt3DRender::QEffect
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QTransform;
+}
+
+class OrbitTransformController : public QObject
{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DCore::QTransform* target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(float radius READ radius WRITE setRadius NOTIFY radiusChanged)
+ Q_PROPERTY(float angle READ angle WRITE setAngle NOTIFY angleChanged)
+
public:
- explicit SceneEffect(Qt3DCore::QNode *parent = 0);
+ OrbitTransformController(QObject *parent = 0);
+
+ void setTarget(Qt3DCore::QTransform *target);
+ Qt3DCore::QTransform *target() const;
- QList<Qt3DRender::QFilterKey *> passCriteria() const;
+ void setRadius(float radius);
+ float radius() const;
+
+ void setAngle(float angle);
+ float angle() const;
+
+signals:
+ void targetChanged();
+ void radiusChanged();
+ void angleChanged();
+
+protected:
+ void updateMatrix();
private:
- Qt3DRender::QTechnique *m_gl3Technique;
- Qt3DRender::QTechnique *m_gl2Technique;
- Qt3DRender::QRenderPass *m_gl2Pass;
- Qt3DRender::QRenderPass *m_gl3Pass;
- Qt3DRender::QFilterKey *m_passCriterion;
+ Qt3DCore::QTransform *m_target;
+ QMatrix4x4 m_matrix;
+ float m_radius;
+ float m_angle;
};
-#endif // SCENEEFFECT_H
+QT_END_NAMESPACE
+
+#endif // ORBITTRANSFORMCONTROLLER_H
diff --git a/tests/manual/rendercapture-cpp/rendercapture-cpp.pro b/tests/manual/rendercapture-cpp/rendercapture-cpp.pro
new file mode 100644
index 000000000..5f89a7af8
--- /dev/null
+++ b/tests/manual/rendercapture-cpp/rendercapture-cpp.pro
@@ -0,0 +1,13 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dextras widgets
+
+SOURCES += \
+ main.cpp \
+ orbittransformcontroller.cpp
+
+HEADERS += \
+ orbittransformcontroller.h \
+ mycapture.h
diff --git a/tests/manual/rendercapture-qml/CaptureScene.qml b/tests/manual/rendercapture-qml/CaptureScene.qml
new file mode 100644
index 000000000..17fa83a5c
--- /dev/null
+++ b/tests/manual/rendercapture-qml/CaptureScene.qml
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.2 as QQ2
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ id: sceneRoot
+
+ function requestRenderCapture(cid)
+ {
+ return renderCapture.requestCapture(cid)
+ }
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, -40.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ OrbitCameraController {
+ camera: camera
+ }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: RenderCapture {
+ id: renderCapture
+ ForwardRenderer {
+ clearColor: Qt.rgba(0, 0.5, 1, 1)
+ camera: camera
+ }
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+ PhongMaterial {
+ id: material
+ }
+
+ TorusMesh {
+ id: torusMesh
+ radius: 5
+ minorRadius: 1
+ rings: 100
+ slices: 20
+ }
+
+ Transform {
+ id: torusTransform
+ scale3D: Qt.vector3d(1.5, 1, 0.5)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ }
+
+ Entity {
+ id: torusEntity
+ components: [ torusMesh, material, torusTransform ]
+ }
+
+ SphereMesh {
+ id: sphereMesh
+ radius: 3
+ }
+
+ Transform {
+ id: sphereTransform
+ property real userAngle: 0.0
+ matrix: {
+ var m = Qt.matrix4x4();
+ m.rotate(userAngle, Qt.vector3d(0, 1, 0));
+ m.translate(Qt.vector3d(20, 0, 0));
+ return m;
+ }
+ }
+
+ QQ2.NumberAnimation {
+ target: sphereTransform
+ property: "userAngle"
+ duration: 10000
+ from: 0
+ to: 360
+
+ loops: QQ2.Animation.Infinite
+ running: true
+ }
+
+ Entity {
+ id: sphereEntity
+ components: [ sphereMesh, material, sphereTransform ]
+ }
+}
diff --git a/examples/qt3d/deferred-renderer-cpp/pointlightblock.h b/tests/manual/rendercapture-qml/main.cpp
index 9c93528c8..5c581c88e 100644
--- a/examples/qt3d/deferred-renderer-cpp/pointlightblock.h
+++ b/tests/manual/rendercapture-qml/main.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -48,28 +49,27 @@
**
****************************************************************************/
-#ifndef POINTLIGHTBLOCK_H
-#define POINTLIGHTBLOCK_H
+#include <QQuickItem>
+#include <QQuickView>
+#include <Qt3DQuick/QQmlAspectEngine>
+#include <QGuiApplication>
+#include <QQmlEngine>
+#include <QQmlContext>
+#include "rendercaptureprovider.h"
-#include <Qt3DRender/QAbstractLight>
-#include <Qt3DRender/QShaderData>
-class PointLightBlock : public Qt3DRender::QShaderData
+int main(int argc, char* argv[])
{
- Q_OBJECT
- Q_PROPERTY(QVector<Qt3DRender::QAbstractLight *> lights READ lights NOTIFY lightsChanged)
-public:
- explicit PointLightBlock(Qt3DCore::QNode *parent = 0);
- ~PointLightBlock();
+ QGuiApplication app(argc, argv);
+ QQuickView view;
+ RenderCaptureProvider *provider = new RenderCaptureProvider;
+ qmlRegisterType<RenderCaptureProvider>("Extras", 1, 0, "RenderCaptureProvider");
- QVector<Qt3DRender::QAbstractLight *> lights() const;
- void addLight(Qt3DRender::QAbstractLight *light);
+ view.engine()->rootContext()->setContextProperty("_renderCaptureProvider", provider);
+ view.engine()->addImageProvider("rendercapture", provider);
-Q_SIGNALS:
- void lightsChanged();
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
-private:
- QVector<Qt3DRender::QAbstractLight *> m_lights;
-};
-
-#endif // POINTLIGHTBLOCK_H
+ return app.exec();
+}
diff --git a/tests/manual/rendercapture-qml/main.qml b/tests/manual/rendercapture-qml/main.qml
new file mode 100644
index 000000000..83746c3a9
--- /dev/null
+++ b/tests/manual/rendercapture-qml/main.qml
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $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.2
+import QtQuick.Layouts 1.3
+import QtQuick.Controls 1.4
+import Qt3D.Render 2.0
+import QtQuick.Scene3D 2.0
+
+Item {
+
+ width: 1250
+ height: 700
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.margins: 10
+
+ Rectangle {
+ id: background
+ width: 600
+ height: 600
+
+ color: "blue"
+
+ Scene3D {
+ id: scene3d
+ anchors.fill: parent
+ multisample: msacheckbox.checked
+
+ aspects: ["input", "logic"]
+
+ CaptureScene {
+ id: scene
+ }
+ }
+ }
+
+ ColumnLayout {
+
+ Button {
+ id: button
+ anchors.top: parent.top
+ text: "Render Capture"
+
+ property var reply
+ property bool continuous : checkbox.checked
+ property int cid: 1
+
+ function doRenderCapture()
+ {
+ reply = scene.requestRenderCapture(cid)
+ reply.completeChanged.connect(onRenderCaptureComplete)
+ }
+
+ function onRenderCaptureComplete()
+ {
+ _renderCaptureProvider.updateImage(reply)
+ image.source = "image://rendercapture/" + cid
+ reply.saveToFile("capture" + cid + ".png")
+ cid++
+ if (continuous === true)
+ doRenderCapture()
+ }
+
+ onClicked: doRenderCapture()
+ }
+ RowLayout {
+ CheckBox {
+ id: checkbox
+ text: "continuous"
+ }
+ CheckBox {
+ id: msacheckbox
+ text: "multisample"
+ }
+ }
+ Image {
+ id: image
+ cache: false
+ source: "image://rendercapture/0"
+ Layout.maximumWidth: 600
+ Layout.minimumWidth: 600
+ Layout.maximumHeight: 600
+ Layout.minimumHeight: 600
+ }
+ }
+ }
+}
diff --git a/tests/manual/rendercapture-qml/qml.qrc b/tests/manual/rendercapture-qml/qml.qrc
new file mode 100644
index 000000000..310d6dfe3
--- /dev/null
+++ b/tests/manual/rendercapture-qml/qml.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>CaptureScene.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/rendercapture-qml/rendercapture-qml.pro b/tests/manual/rendercapture-qml/rendercapture-qml.pro
new file mode 100644
index 000000000..bea0fc867
--- /dev/null
+++ b/tests/manual/rendercapture-qml/rendercapture-qml.pro
@@ -0,0 +1,18 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dextras 3dquick 3dlogic qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+DISTFILES += \
+ main.qml
+
+RESOURCES += \
+ qml.qrc
+
+HEADERS += \
+ rendercaptureprovider.h
+
diff --git a/examples/qt3d/deferred-renderer-cpp/gbuffer.h b/tests/manual/rendercapture-qml/rendercaptureprovider.h
index dab8b6752..d04dbd276 100644
--- a/examples/qt3d/deferred-renderer-cpp/gbuffer.h
+++ b/tests/manual/rendercapture-qml/rendercaptureprovider.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -48,34 +48,38 @@
**
****************************************************************************/
-#ifndef GBUFFER_H
-#define GBUFFER_H
+#ifndef RENDERCAPTUREPROVIDER_H
+#define RENDERCAPTUREPROVIDER_H
-#include <Qt3DRender/QRenderTarget>
-#include <Qt3DRender/qtexture.h>
-#include <Qt3DRender/QRenderTargetOutput>
+#include <QtQuick/QQuickImageProvider>
+#include <Qt3DRender/QRenderCapture>
-class GBuffer : public Qt3DRender::QRenderTarget
+class RenderCaptureProvider : public QObject, public QQuickImageProvider
{
+ Q_OBJECT
public:
- explicit GBuffer(Qt3DCore::QNode *parent = 0);
+ RenderCaptureProvider()
+ : QObject(), QQuickImageProvider(Image)
+ {
+ m_image = QImage(10,10, QImage::Format_ARGB32);
+ m_image.fill(QColor("blue").rgba());
+ }
- enum Attachments {
- Color = 0,
- Position,
- Normal,
- Depth,
- AttachmentsCount
- };
+ Q_INVOKABLE void updateImage(Qt3DRender::QRenderCaptureReply *reply)
+ {
+ m_image = reply->image();
+ }
- Qt3DRender::QAbstractTexture *colorTexture() const;
- Qt3DRender::QAbstractTexture *positionTexture() const;
- Qt3DRender::QAbstractTexture *normalTexture() const;
- Qt3DRender::QAbstractTexture *depthTexture() const;
+ virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize)
+ {
+ Q_UNUSED(id)
+ Q_UNUSED(requestedSize)
+ *size = m_image.size();
+ return m_image;
+ }
private:
- Qt3DRender::QAbstractTexture *m_textures[AttachmentsCount];
- Qt3DRender::QRenderTargetOutput *m_attachments[AttachmentsCount];
+ QImage m_image;
};
-#endif // GBUFFER_H
+#endif
diff --git a/tools/qgltf/qgltf.pro b/tools/qgltf/qgltf.pro
index a19f2e91c..df6dfa202 100644
--- a/tools/qgltf/qgltf.pro
+++ b/tools/qgltf/qgltf.pro
@@ -1,5 +1,4 @@
option(host_build)
-!cross_compile:load(qt_build_paths)
# Qt3D is free of Q_FOREACH - make sure it stays that way:
DEFINES *= QT_NO_FOREACH
diff --git a/tools/tools.pro b/tools/tools.pro
index 055f41250..09c7d8ebf 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,3 +1,3 @@
TEMPLATE = subdirs
-SUBDIRS = qgltf
+!android:SUBDIRS += qgltf
qgltf.CONFIG += host_build