summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.qmake.conf5
-rw-r--r--config_help.txt6
-rw-r--r--examples/examples.pro5
-rw-r--r--examples/qt3d/advancedcustommaterial/shaders/es2/water.frag24
-rw-r--r--examples/qt3d/advancedcustommaterial/shaders/es2/water.vert25
-rw-r--r--examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag23
-rw-r--r--examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert25
-rw-r--r--examples/qt3d/controls/Logo.qml30
-rw-r--r--examples/qt3d/controls/main.qml9
-rw-r--r--examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_irradiance.ddsbin0 -> 262276 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_specular.ddsbin0 -> 1048708 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf2731
-rw-r--r--examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure0.binbin0 -> 22184 bytes
-rw-r--r--examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple.gltf539
-rw-r--r--examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple0.binbin0 -> 6128 bytes
-rw-r--r--examples/qt3d/exampleresources/envmaps.qrc6
-rw-r--r--examples/qt3d/exampleresources/gltf.qrc4
-rw-r--r--examples/qt3d/phong-cubes/CubeEntity.qml81
-rw-r--r--examples/qt3d/phong-cubes/main.cpp63
-rw-r--r--examples/qt3d/phong-cubes/main.qml157
-rw-r--r--examples/qt3d/phong-cubes/phong-cubes.pro18
-rw-r--r--examples/qt3d/phong-cubes/phong-cubes.qrc6
-rw-r--r--examples/qt3d/planets-qml/PlanetMaterial.qml6
-rw-r--r--examples/qt3d/planets-qml/SolarSystem.qml5
-rw-r--r--examples/qt3d/planets-qml/images/solarsystemscope/qt_attribution.json2
-rw-r--r--examples/qt3d/qt3d.pro3
-rw-r--r--examples/qt3d/scene2d/main.qml4
-rw-r--r--examples/qt3d/wave/shaders/ribbon.vert2
-rw-r--r--src/animation/backend/animationclip.cpp64
-rw-r--r--src/animation/backend/animationclip_p.h2
-rw-r--r--src/animation/backend/animationutils.cpp406
-rw-r--r--src/animation/backend/animationutils_p.h86
-rw-r--r--src/animation/backend/backend.pri10
-rw-r--r--src/animation/backend/blendedclipanimator.cpp53
-rw-r--r--src/animation/backend/blendedclipanimator_p.h17
-rw-r--r--src/animation/backend/channelmapping.cpp62
-rw-r--r--src/animation/backend/channelmapping_p.h31
-rw-r--r--src/animation/backend/clipanimator.cpp50
-rw-r--r--src/animation/backend/clipanimator_p.h16
-rw-r--r--src/animation/backend/clock.cpp87
-rw-r--r--src/animation/backend/clock_p.h82
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob.cpp36
-rw-r--r--src/animation/backend/evaluateblendclipanimatorjob_p.h3
-rw-r--r--src/animation/backend/evaluateclipanimatorjob.cpp20
-rw-r--r--src/animation/backend/evaluateclipanimatorjob_p.h3
-rw-r--r--src/animation/backend/fcurve.cpp4
-rw-r--r--src/animation/backend/fcurve_p.h1
-rw-r--r--src/animation/backend/findrunningclipanimatorsjob.cpp2
-rw-r--r--src/animation/backend/gltfimporter.cpp852
-rw-r--r--src/animation/backend/gltfimporter_p.h232
-rw-r--r--src/animation/backend/handle_types_p.h2
-rw-r--r--src/animation/backend/handler.cpp35
-rw-r--r--src/animation/backend/handler_p.h7
-rw-r--r--src/animation/backend/loadanimationclipjob.cpp1
-rw-r--r--src/animation/backend/managers_p.h21
-rw-r--r--src/animation/backend/skeleton.cpp111
-rw-r--r--src/animation/backend/skeleton_p.h111
-rw-r--r--src/animation/frontend/frontend.pri22
-rw-r--r--src/animation/frontend/qabstractchannelmapping.cpp69
-rw-r--r--src/animation/frontend/qabstractchannelmapping.h70
-rw-r--r--src/animation/frontend/qabstractchannelmapping_p.h85
-rw-r--r--src/animation/frontend/qabstractclipanimator.cpp26
-rw-r--r--src/animation/frontend/qabstractclipanimator.h5
-rw-r--r--src/animation/frontend/qabstractclipanimator_p.h3
-rw-r--r--src/animation/frontend/qanimationaspect.cpp16
-rw-r--r--src/animation/frontend/qanimationcallback.h67
-rw-r--r--src/animation/frontend/qanimationcallbacktrigger.cpp54
-rw-r--r--src/animation/frontend/qanimationcallbacktrigger_p.h85
-rw-r--r--src/animation/frontend/qblendedclipanimator.cpp2
-rw-r--r--src/animation/frontend/qcallbackmapping.cpp168
-rw-r--r--src/animation/frontend/qcallbackmapping.h82
-rw-r--r--src/animation/frontend/qcallbackmapping_p.h85
-rw-r--r--src/animation/frontend/qchannel.cpp11
-rw-r--r--src/animation/frontend/qchannel.h3
-rw-r--r--src/animation/frontend/qchannelmapper.cpp6
-rw-r--r--src/animation/frontend/qchannelmapper.h8
-rw-r--r--src/animation/frontend/qchannelmapper_p.h4
-rw-r--r--src/animation/frontend/qchannelmapping.cpp10
-rw-r--r--src/animation/frontend/qchannelmapping.h5
-rw-r--r--src/animation/frontend/qchannelmapping_p.h5
-rw-r--r--src/animation/frontend/qchannelmappingcreatedchange.cpp75
-rw-r--r--src/animation/frontend/qchannelmappingcreatedchange_p.h101
-rw-r--r--src/animation/frontend/qchannelmappingcreatedchange_p_p.h72
-rw-r--r--src/animation/frontend/qclipanimator.cpp15
-rw-r--r--src/animation/frontend/qclipanimator.h1
-rw-r--r--src/animation/frontend/qclock.cpp91
-rw-r--r--src/animation/frontend/qclock.h76
-rw-r--r--src/animation/frontend/qclock_p.h78
-rw-r--r--src/animation/frontend/qskeletonmapping.cpp108
-rw-r--r--src/animation/frontend/qskeletonmapping.h85
-rw-r--r--src/animation/frontend/qskeletonmapping_p.h85
-rw-r--r--src/core/aspects/aspects.pri2
-rw-r--r--src/core/aspects/qabstractaspect.cpp22
-rw-r--r--src/core/aspects/qabstractaspect.h2
-rw-r--r--src/core/aspects/qabstractaspect_p.h5
-rw-r--r--src/core/aspects/qaspectengine.cpp10
-rw-r--r--src/core/aspects/qaspectengine_p.h10
-rw-r--r--src/core/aspects/qaspectmanager.cpp4
-rw-r--r--src/core/changes/changes.pri10
-rw-r--r--src/core/changes/qnodecommand.cpp155
-rw-r--r--src/core/changes/qnodecommand.h85
-rw-r--r--src/core/changes/qnodecommand_p.h76
-rw-r--r--src/core/changes/qscenechange.cpp1
-rw-r--r--src/core/changes/qscenechange.h2
-rw-r--r--src/core/changes/qskeletoncreatedchange.cpp76
-rw-r--r--src/core/changes/qskeletoncreatedchange_p.h99
-rw-r--r--src/core/changes/qskeletoncreatedchange_p_p.h72
-rw-r--r--src/core/configure.json80
-rw-r--r--src/core/jobs/qaspectjob_p.h6
-rw-r--r--src/core/jobs/qaspectjobmanager.cpp3
-rw-r--r--src/core/jobs/qthreadpooler.cpp17
-rw-r--r--src/core/jobs/qthreadpooler_p.h4
-rw-r--r--src/core/jobs/task.cpp4
-rw-r--r--src/core/nodes/qbackendnode.cpp20
-rw-r--r--src/core/nodes/qbackendnode.h4
-rw-r--r--src/core/nodes/qcomponent_p.h1
-rw-r--r--src/core/nodes/qnode.cpp45
-rw-r--r--src/core/nodes/qnode.h5
-rw-r--r--src/core/qscene.cpp9
-rw-r--r--src/core/qt3dcore_global.h1
-rw-r--r--src/core/qt3dcore_global_p.h1
-rw-r--r--src/core/services/qdownloadhelperservice.cpp216
-rw-r--r--src/core/services/qdownloadhelperservice_p.h130
-rw-r--r--src/core/services/qdownloadhelperservice_p_p.h76
-rw-r--r--src/core/services/qdownloadnetworkworker.cpp148
-rw-r--r--src/core/services/qdownloadnetworkworker_p.h101
-rw-r--r--src/core/services/qservicelocator.cpp11
-rw-r--r--src/core/services/qservicelocator_p.h3
-rw-r--r--src/core/services/services.pri8
-rw-r--r--src/core/transforms/matrix4x4_avx2.cpp64
-rw-r--r--src/core/transforms/matrix4x4_avx2_p.h574
-rw-r--r--src/core/transforms/matrix4x4_p.h82
-rw-r--r--src/core/transforms/matrix4x4_sse.cpp64
-rw-r--r--src/core/transforms/matrix4x4_sse_p.h504
-rw-r--r--src/core/transforms/qabstractskeleton.cpp134
-rw-r--r--src/core/transforms/qabstractskeleton.h77
-rw-r--r--src/core/transforms/qabstractskeleton_p.h81
-rw-r--r--src/core/transforms/qarmature.cpp172
-rw-r--r--src/core/transforms/qarmature.h82
-rw-r--r--src/core/transforms/qarmature_p.h83
-rw-r--r--src/core/transforms/qjoint.cpp414
-rw-r--r--src/core/transforms/qjoint.h115
-rw-r--r--src/core/transforms/qjoint_p.h95
-rw-r--r--src/core/transforms/qmath3d_p.h19
-rw-r--r--src/core/transforms/qskeleton.cpp152
-rw-r--r--src/core/transforms/qskeleton.h79
-rw-r--r--src/core/transforms/qskeleton_p.h82
-rw-r--r--src/core/transforms/qskeletonloader.cpp258
-rw-r--r--src/core/transforms/qskeletonloader.h104
-rw-r--r--src/core/transforms/qskeletonloader_p.h98
-rw-r--r--src/core/transforms/sqt_p.h107
-rw-r--r--src/core/transforms/transforms.pri58
-rw-r--r--src/core/transforms/vector3d_p.h74
-rw-r--r--src/core/transforms/vector3d_sse.cpp141
-rw-r--r--src/core/transforms/vector3d_sse_p.h399
-rw-r--r--src/core/transforms/vector4d_p.h74
-rw-r--r--src/core/transforms/vector4d_sse.cpp59
-rw-r--r--src/core/transforms/vector4d_sse_p.h396
-rw-r--r--src/extras/3dtext/qextrudedtextgeometry.cpp4
-rw-r--r--src/extras/defaults/defaults.pri20
-rw-r--r--src/extras/defaults/qabstractcameracontroller.cpp436
-rw-r--r--src/extras/defaults/qabstractcameracontroller.h126
-rw-r--r--src/extras/defaults/qabstractcameracontroller_p.h141
-rw-r--r--src/extras/defaults/qabstractspritesheet.cpp143
-rw-r--r--src/extras/defaults/qabstractspritesheet.h93
-rw-r--r--src/extras/defaults/qabstractspritesheet_p.h101
-rw-r--r--src/extras/defaults/qdiffusemapmaterial.cpp28
-rw-r--r--src/extras/defaults/qdiffusemapmaterial_p.h3
-rw-r--r--src/extras/defaults/qdiffusespecularmapmaterial.cpp28
-rw-r--r--src/extras/defaults/qdiffusespecularmapmaterial_p.h3
-rw-r--r--src/extras/defaults/qdiffusespecularmaterial.cpp496
-rw-r--r--src/extras/defaults/qdiffusespecularmaterial.h102
-rw-r--r--src/extras/defaults/qdiffusespecularmaterial_p.h (renamed from src/extras/defaults/qtexturedmetalroughmaterial_p.h)69
-rw-r--r--src/extras/defaults/qfirstpersoncameracontroller.cpp305
-rw-r--r--src/extras/defaults/qfirstpersoncameracontroller.h39
-rw-r--r--src/extras/defaults/qfirstpersoncameracontroller_p.h152
-rw-r--r--src/extras/defaults/qforwardrenderer.cpp9
-rw-r--r--src/extras/defaults/qmetalroughmaterial.cpp217
-rw-r--r--src/extras/defaults/qmetalroughmaterial.h36
-rw-r--r--src/extras/defaults/qmetalroughmaterial_p.h12
-rw-r--r--src/extras/defaults/qnormaldiffusemapalphamaterial.cpp26
-rw-r--r--src/extras/defaults/qnormaldiffusemapmaterial.cpp28
-rw-r--r--src/extras/defaults/qnormaldiffusemapmaterial_p.h3
-rw-r--r--src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp28
-rw-r--r--src/extras/defaults/qnormaldiffusespecularmapmaterial_p.h3
-rw-r--r--src/extras/defaults/qorbitcameracontroller.cpp348
-rw-r--r--src/extras/defaults/qorbitcameracontroller.h28
-rw-r--r--src/extras/defaults/qorbitcameracontroller_p.h75
-rw-r--r--src/extras/defaults/qphongalphamaterial.cpp52
-rw-r--r--src/extras/defaults/qphongalphamaterial_p.h5
-rw-r--r--src/extras/defaults/qphongmaterial.cpp29
-rw-r--r--src/extras/defaults/qphongmaterial_p.h3
-rw-r--r--src/extras/defaults/qspritegrid.cpp156
-rw-r--r--src/extras/defaults/qspritegrid.h82
-rw-r--r--src/extras/defaults/qspritegrid_p.h82
-rw-r--r--src/extras/defaults/qspritesheet.cpp173
-rw-r--r--src/extras/defaults/qspritesheet.h81
-rw-r--r--src/extras/defaults/qspritesheet_p.h83
-rw-r--r--src/extras/defaults/qspritesheetitem.cpp127
-rw-r--r--src/extras/defaults/qspritesheetitem.h86
-rw-r--r--src/extras/defaults/qspritesheetitem_p.h81
-rw-r--r--src/extras/defaults/qt3dwindow.cpp37
-rw-r--r--src/extras/defaults/qtexturedmetalroughmaterial.cpp316
-rw-r--r--src/extras/defaults/qtexturedmetalroughmaterial.h41
-rw-r--r--src/extras/defaults/qtexturematerial.cpp46
-rw-r--r--src/extras/defaults/qtexturematerial.h5
-rw-r--r--src/extras/defaults/qtexturematerial_p.h6
-rw-r--r--src/extras/extras.qrc33
-rw-r--r--src/extras/geometries/qconegeometry.cpp4
-rw-r--r--src/extras/geometries/qcuboidgeometry.cpp4
-rw-r--r--src/extras/geometries/qcylindergeometry.cpp4
-rw-r--r--src/extras/geometries/qplanegeometry.cpp4
-rw-r--r--src/extras/geometries/qspheregeometry.cpp4
-rw-r--r--src/extras/geometries/qtorusgeometry.cpp4
-rw-r--r--src/extras/shaders/es2/coordinatesystems.inc87
-rw-r--r--src/extras/shaders/es2/default.vert80
-rw-r--r--src/extras/shaders/es2/diffusemap.frag25
-rw-r--r--src/extras/shaders/es2/diffusemap.vert22
-rw-r--r--src/extras/shaders/es2/diffusespecularmap.frag27
-rw-r--r--src/extras/shaders/es2/light.inc.frag185
-rw-r--r--src/extras/shaders/es2/light.inc.frag100205
-rw-r--r--src/extras/shaders/es2/normaldiffusemap.frag31
-rw-r--r--src/extras/shaders/es2/normaldiffusemap.vert38
-rw-r--r--src/extras/shaders/es2/normaldiffusemapalpha.frag32
-rw-r--r--src/extras/shaders/es2/normaldiffusespecularmap.frag32
-rw-r--r--src/extras/shaders/es2/pervertexcolor.frag11
-rw-r--r--src/extras/shaders/es2/pervertexcolor.vert4
-rw-r--r--src/extras/shaders/es2/phong.frag20
-rw-r--r--src/extras/shaders/es2/phong.inc.frag128
-rw-r--r--src/extras/shaders/es2/phong.inc.frag100142
-rw-r--r--src/extras/shaders/es2/phong.vert17
-rw-r--r--src/extras/shaders/es2/phongalpha.frag22
-rw-r--r--src/extras/shaders/es2/unlittexture.vert5
-rw-r--r--src/extras/shaders/gl3/coordinatesystems.inc70
-rw-r--r--src/extras/shaders/gl3/default.vert (renamed from src/extras/shaders/gl3/metalrough.vert)13
-rw-r--r--src/extras/shaders/gl3/diffusemap.frag27
-rw-r--r--src/extras/shaders/gl3/diffusemap.vert24
-rw-r--r--src/extras/shaders/gl3/diffusespecularmap.frag29
-rw-r--r--src/extras/shaders/gl3/light.inc.frag197
-rw-r--r--src/extras/shaders/gl3/metalrough.frag395
-rw-r--r--src/extras/shaders/gl3/metalrough.inc.frag (renamed from src/extras/shaders/gl3/metalroughuniform.frag)89
-rw-r--r--src/extras/shaders/gl3/normaldiffusemap.frag33
-rw-r--r--src/extras/shaders/gl3/normaldiffusemap.vert47
-rw-r--r--src/extras/shaders/gl3/normaldiffusemapalpha.frag34
-rw-r--r--src/extras/shaders/gl3/normaldiffusespecularmap.frag35
-rw-r--r--src/extras/shaders/gl3/pervertexcolor.frag11
-rw-r--r--src/extras/shaders/gl3/pervertexcolor.vert4
-rw-r--r--src/extras/shaders/gl3/phong.frag22
-rw-r--r--src/extras/shaders/gl3/phong.inc.frag138
-rw-r--r--src/extras/shaders/gl3/phong.vert19
-rw-r--r--src/extras/shaders/gl3/phongalpha.frag24
-rw-r--r--src/extras/shaders/gl3/unlittexture.vert5
-rw-r--r--src/extras/shaders/graphs/metalrough.frag.json569
-rw-r--r--src/extras/shaders/graphs/phong.frag.json466
-rw-r--r--src/extras/text/distancefieldtextrenderer.cpp4
-rw-r--r--src/extras/text/qtextureatlas.cpp2
-rw-r--r--src/logic/manager.cpp5
-rw-r--r--src/logic/manager_p.h1
-rw-r--r--src/logic/qlogicaspect.cpp5
-rw-r--r--src/plugins/geometryloaders/default/plygeometryloader.cpp58
-rw-r--r--src/plugins/geometryloaders/fbx/fbxgeometryloader.cpp30
-rw-r--r--src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp223
-rw-r--r--src/plugins/geometryloaders/gltf/gltfgeometryloader.h31
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.cpp60
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.h6
-rw-r--r--src/plugins/sceneparsers/gltf/gltfimporter.cpp73
-rw-r--r--src/plugins/sceneparsers/gltf/gltfimporter.h5
-rw-r--r--src/plugins/sceneparsers/gltfexport/gltfexporter.cpp44
-rw-r--r--src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp7
-rw-r--r--src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp10
-rw-r--r--src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp13
-rw-r--r--src/quick3d/imports/render/qt3dquick3drenderplugin.cpp8
-rw-r--r--src/quick3d/imports/scene3d/importsscene3d.pro5
-rw-r--r--src/quick3d/imports/scene3d/scene3ditem.cpp20
-rw-r--r--src/quick3d/quick3d/items/items.pri6
-rw-r--r--src/quick3d/quick3d/items/quick3djoint.cpp95
-rw-r--r--src/quick3d/quick3d/items/quick3djoint_p.h88
-rw-r--r--src/quick3d/quick3d/qt3dquicknodefactory.cpp2
-rw-r--r--src/quick3d/quick3danimation/items/quick3dchannelmapper.cpp22
-rw-r--r--src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h14
-rw-r--r--src/quick3d/quick3dextras/items/items.pri6
-rw-r--r--src/quick3d/quick3dextras/items/quick3dspritesheet.cpp100
-rw-r--r--src/quick3d/quick3dextras/items/quick3dspritesheet_p.h89
-rw-r--r--src/quick3d/quick3dextras/qt3dquickextras_global.cpp63
-rw-r--r--src/quick3d/quick3dextras/qt3dquickextras_global_p.h16
-rw-r--r--src/quick3d/quick3dextras/qt3dquickextrasnodefactory.cpp75
-rw-r--r--src/quick3d/quick3dextras/qt3dquickextrasnodefactory_p.h90
-rw-r--r--src/quick3d/quick3dextras/quick3dextras.pro3
-rw-r--r--src/quick3d/quick3drender/items/quick3dbuffer.cpp2
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2d.cpp2
-rw-r--r--src/render/backend/abstractrenderer_p.h20
-rw-r--r--src/render/backend/attachmentpack.cpp2
-rw-r--r--src/render/backend/cameralens.cpp132
-rw-r--r--src/render/backend/cameralens_p.h30
-rw-r--r--src/render/backend/commandexecuter.cpp5
-rw-r--r--src/render/backend/commandexecuter_p.h2
-rw-r--r--src/render/backend/entity.cpp297
-rw-r--r--src/render/backend/entity_p.h201
-rw-r--r--src/render/backend/frameprofiler_p.h13
-rw-r--r--src/render/backend/handle_types_p.h8
-rw-r--r--src/render/backend/layer.cpp33
-rw-r--r--src/render/backend/layer_p.h11
-rw-r--r--src/render/backend/managers.cpp36
-rw-r--r--src/render/backend/managers_p.h59
-rw-r--r--src/render/backend/nodemanagers.cpp34
-rw-r--r--src/render/backend/nodemanagers_p.h28
-rw-r--r--src/render/backend/pointsvisitor.cpp188
-rw-r--r--src/render/backend/pointsvisitor_p.h92
-rw-r--r--src/render/backend/render-backend.pri13
-rw-r--r--src/render/backend/renderer.cpp243
-rw-r--r--src/render/backend/renderer_p.h22
-rw-r--r--src/render/backend/renderercache_p.h86
-rw-r--r--src/render/backend/renderqueue_p.h4
-rw-r--r--src/render/backend/rendersettings.cpp4
-rw-r--r--src/render/backend/rendersettings_p.h5
-rw-r--r--src/render/backend/renderthread.cpp11
-rw-r--r--src/render/backend/renderview.cpp78
-rw-r--r--src/render/backend/renderview_p.h62
-rw-r--r--src/render/backend/renderviewbuilder.cpp257
-rw-r--r--src/render/backend/renderviewbuilder_p.h11
-rw-r--r--src/render/backend/segmentsvisitor.cpp369
-rw-r--r--src/render/backend/segmentsvisitor_p.h93
-rw-r--r--src/render/backend/trianglesvisitor.cpp155
-rw-r--r--src/render/backend/uniform.cpp24
-rw-r--r--src/render/backend/uniform_p.h26
-rw-r--r--src/render/backend/visitorutils_p.h179
-rw-r--r--src/render/framegraph/blitframebuffer.cpp139
-rw-r--r--src/render/framegraph/blitframebuffer_p.h102
-rw-r--r--src/render/framegraph/framegraph.pri14
-rw-r--r--src/render/framegraph/framegraphnode_p.h24
-rw-r--r--src/render/framegraph/layerfilternode.cpp18
-rw-r--r--src/render/framegraph/layerfilternode_p.h6
-rw-r--r--src/render/framegraph/proximityfilter.cpp82
-rw-r--r--src/render/framegraph/proximityfilter_p.h90
-rw-r--r--src/render/framegraph/qblitframebuffer.cpp201
-rw-r--r--src/render/framegraph/qblitframebuffer.h111
-rw-r--r--src/render/framegraph/qblitframebuffer_p.h95
-rw-r--r--src/render/framegraph/qlayerfilter.cpp109
-rw-r--r--src/render/framegraph/qlayerfilter.h17
-rw-r--r--src/render/framegraph/qlayerfilter_p.h4
-rw-r--r--src/render/framegraph/qproximityfilter.cpp196
-rw-r--r--src/render/framegraph/qproximityfilter.h84
-rw-r--r--src/render/framegraph/qproximityfilter_p.h82
-rw-r--r--src/render/framegraph/qrendercapture.cpp32
-rw-r--r--src/render/framegraph/qrendercapture.h3
-rw-r--r--src/render/framegraph/qrendercapture_p.h7
-rw-r--r--src/render/framegraph/rendercapture.cpp19
-rw-r--r--src/render/framegraph/rendercapture_p.h9
-rw-r--r--src/render/framegraph/viewportnode_p.h2
-rw-r--r--src/render/frontend/qcamera.cpp82
-rw-r--r--src/render/frontend/qcamera.h4
-rw-r--r--src/render/frontend/qcameralens.cpp53
-rw-r--r--src/render/frontend/qcameralens.h5
-rw-r--r--src/render/frontend/qcameralens_p.h7
-rw-r--r--src/render/frontend/qitemmodelbuffer.cpp2
-rw-r--r--src/render/frontend/qlayer.cpp45
-rw-r--r--src/render/frontend/qlayer.h8
-rw-r--r--src/render/frontend/qlayer_p.h6
-rw-r--r--src/render/frontend/qpickingsettings.cpp33
-rw-r--r--src/render/frontend/qpickingsettings.h12
-rw-r--r--src/render/frontend/qpickingsettings_p.h1
-rw-r--r--src/render/frontend/qrenderaspect.cpp52
-rw-r--r--src/render/frontend/qrenderaspect_p.h2
-rw-r--r--src/render/frontend/qrendersettings.cpp9
-rw-r--r--src/render/frontend/qrendersettings.h1
-rw-r--r--src/render/frontend/qrendersettings_p.h2
-rw-r--r--src/render/geometry/armature.cpp86
-rw-r--r--src/render/geometry/armature_p.h87
-rw-r--r--src/render/geometry/buffer.cpp9
-rw-r--r--src/render/geometry/buffer_p.h2
-rw-r--r--src/render/geometry/buffermanager.cpp4
-rw-r--r--src/render/geometry/geometry.cpp3
-rw-r--r--src/render/geometry/geometry.pri14
-rw-r--r--src/render/geometry/geometryrenderer.cpp22
-rw-r--r--src/render/geometry/geometryrenderer_p.h2
-rw-r--r--src/render/geometry/gltfskeletonloader.cpp587
-rw-r--r--src/render/geometry/gltfskeletonloader_p.h185
-rw-r--r--src/render/geometry/joint.cpp162
-rw-r--r--src/render/geometry/joint_p.h126
-rw-r--r--src/render/geometry/qattribute.cpp18
-rw-r--r--src/render/geometry/qattribute.h4
-rw-r--r--src/render/geometry/qbuffer.cpp17
-rw-r--r--src/render/geometry/qbuffer.h7
-rw-r--r--src/render/geometry/qbuffer_p.h1
-rw-r--r--src/render/geometry/qgeometryrenderer.cpp29
-rw-r--r--src/render/geometry/qgeometryrenderer.h4
-rw-r--r--src/render/geometry/qgeometryrenderer_p.h2
-rw-r--r--src/render/geometry/qmesh.cpp165
-rw-r--r--src/render/geometry/qmesh_p.h26
-rw-r--r--src/render/geometry/skeleton.cpp442
-rw-r--r--src/render/geometry/skeleton_p.h188
-rw-r--r--src/render/geometry/skeletondata.cpp58
-rw-r--r--src/render/geometry/skeletondata_p.h100
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp272
-rw-r--r--src/render/graphicshelpers/graphicscontext_p.h36
-rw-r--r--src/render/graphicshelpers/graphicshelperes2.cpp70
-rw-r--r--src/render/graphicshelpers/graphicshelperes2_p.h8
-rw-r--r--src/render/graphicshelpers/graphicshelperes3.cpp392
-rw-r--r--src/render/graphicshelpers/graphicshelperes3_2.cpp103
-rw-r--r--src/render/graphicshelpers/graphicshelperes3_2_p.h77
-rw-r--r--src/render/graphicshelpers/graphicshelperes3_p.h26
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2.cpp67
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2_p.h8
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2.cpp77
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2_p.h8
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3.cpp67
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3_p.h8
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4.cpp84
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4_p.h8
-rw-r--r--src/render/graphicshelpers/graphicshelperinterface_p.h9
-rw-r--r--src/render/graphicshelpers/graphicshelpers.pri2
-rw-r--r--src/render/io/glbuffer.cpp2
-rw-r--r--src/render/io/qsceneimporter_p.h3
-rw-r--r--src/render/io/scene.cpp11
-rw-r--r--src/render/io/scenemanager.cpp60
-rw-r--r--src/render/io/scenemanager_p.h28
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp44
-rw-r--r--src/render/jobs/computefilteredboundingvolumejob.cpp130
-rw-r--r--src/render/jobs/computefilteredboundingvolumejob_p.h91
-rw-r--r--src/render/jobs/filterlayerentityjob.cpp185
-rw-r--r--src/render/jobs/filterlayerentityjob_p.h16
-rw-r--r--src/render/jobs/filterproximitydistancejob.cpp119
-rw-r--r--src/render/jobs/filterproximitydistancejob_p.h93
-rw-r--r--src/render/jobs/job_common_p.h6
-rw-r--r--src/render/jobs/jobs.pri12
-rw-r--r--src/render/jobs/loadscenejob.cpp71
-rw-r--r--src/render/jobs/loadscenejob_p.h2
-rw-r--r--src/render/jobs/loadskeletonjob.cpp68
-rw-r--r--src/render/jobs/loadskeletonjob_p.h85
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp109
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h12
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp347
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h70
-rw-r--r--src/render/jobs/renderviewjobutils.cpp26
-rw-r--r--src/render/jobs/updatelevelofdetailjob.cpp21
-rw-r--r--src/render/jobs/updatelevelofdetailjob_p.h6
-rw-r--r--src/render/jobs/updateskinningpalettejob.cpp113
-rw-r--r--src/render/jobs/updateskinningpalettejob_p.h91
-rw-r--r--src/render/lights/qspotlight.h1
-rw-r--r--src/render/materialsystem/materialsystem.pri8
-rw-r--r--src/render/materialsystem/materialsystem.qrc5
-rw-r--r--src/render/materialsystem/parameter.cpp5
-rw-r--r--src/render/materialsystem/prototypes/default.json592
-rw-r--r--src/render/materialsystem/qshaderprogram_p.h6
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder.cpp332
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder.h112
-rw-r--r--src/render/materialsystem/qshaderprogrambuilder_p.h95
-rw-r--r--src/render/materialsystem/shader.cpp49
-rw-r--r--src/render/materialsystem/shader_p.h1
-rw-r--r--src/render/materialsystem/shaderbuilder.cpp335
-rw-r--r--src/render/materialsystem/shaderbuilder_p.h117
-rw-r--r--src/render/picking/picking.pri4
-rw-r--r--src/render/picking/qpicklineevent.cpp173
-rw-r--r--src/render/picking/qpicklineevent.h78
-rw-r--r--src/render/picking/qpickpointevent.cpp131
-rw-r--r--src/render/picking/qpickpointevent.h74
-rw-r--r--src/render/picking/qpicktriangleevent.h3
-rw-r--r--src/render/raycasting/qcollisionqueryresult_p.h15
-rw-r--r--src/render/renderstates/qlinewidth.cpp125
-rw-r--r--src/render/renderstates/qlinewidth.h80
-rw-r--r--src/render/renderstates/qlinewidth_p.h83
-rw-r--r--src/render/renderstates/renderstates.cpp23
-rw-r--r--src/render/renderstates/renderstates.pri3
-rw-r--r--src/render/renderstates/renderstates_p.h7
-rw-r--r--src/render/renderstates/renderstateset.cpp11
-rw-r--r--src/render/renderstates/statemask_p.h1
-rw-r--r--src/render/renderstates/statevariant.cpp5
-rw-r--r--src/render/renderstates/statevariant_p.h1
-rw-r--r--src/render/texture/gltexture.cpp66
-rw-r--r--src/render/texture/gltexture_p.h15
-rw-r--r--src/render/texture/qabstracttexture.cpp40
-rw-r--r--src/render/texture/qabstracttexture.h1
-rw-r--r--src/render/texture/qabstracttexture_p.h1
-rw-r--r--src/render/texture/qtexture.cpp294
-rw-r--r--src/render/texture/qtexture_p.h30
-rw-r--r--src/render/texture/qtextureimagedata.cpp2
-rw-r--r--src/render/texture/renderbuffer.cpp112
-rw-r--r--src/render/texture/renderbuffer_p.h90
-rw-r--r--src/render/texture/texture.cpp77
-rw-r--r--src/render/texture/texture.pri6
-rw-r--r--src/render/texture/texture_p.h8
-rw-r--r--src/src.pro74
-rw-r--r--tests/auto/animation/animation.pro7
-rw-r--r--tests/auto/animation/animationutils/animationutils.qrc1
-rw-r--r--tests/auto/animation/animationutils/clip5.json1401
-rw-r--r--tests/auto/animation/animationutils/tst_animationutils.cpp864
-rw-r--r--tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp7
-rw-r--r--tests/auto/animation/channelmapping/tst_channelmapping.cpp34
-rw-r--r--tests/auto/animation/clipanimator/tst_clipanimator.cpp19
-rw-r--r--tests/auto/animation/clock/clock.pro12
-rw-r--r--tests/auto/animation/clock/tst_clock.cpp111
-rw-r--r--tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp1
-rw-r--r--tests/auto/animation/qcallbackmapping/qcallbackmapping.pro12
-rw-r--r--tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp223
-rw-r--r--tests/auto/animation/qchannelmapping/tst_qchannelmapping.cpp7
-rw-r--r--tests/auto/animation/qclipanimator/tst_qclipanimator.cpp57
-rw-r--r--tests/auto/animation/qclock/qclock.pro12
-rw-r--r--tests/auto/animation/qclock/tst_qclock.cpp165
-rw-r--r--tests/auto/animation/qskeletonmapping/qskeletonmapping.pro12
-rw-r--r--tests/auto/animation/qskeletonmapping/tst_qskeletonmapping.cpp175
-rw-r--r--tests/auto/animation/skeleton/skeleton.pro12
-rw-r--r--tests/auto/animation/skeleton/tst_skeleton.cpp146
-rw-r--r--tests/auto/auto.pro14
-rw-r--r--tests/auto/core/aspectcommanddebugger/tst_aspectcommanddebugger.cpp4
-rw-r--r--tests/auto/core/core.pro27
-rw-r--r--tests/auto/core/qarmature/qarmature.pro11
-rw-r--r--tests/auto/core/qarmature/tst_qarmature.cpp167
-rw-r--r--tests/auto/core/qjoint/qjoint.pro12
-rw-r--r--tests/auto/core/qjoint/tst_qjoint.cpp413
-rw-r--r--tests/auto/core/qskeleton/qskeleton.pro11
-rw-r--r--tests/auto/core/qskeleton/tst_qskeleton.cpp210
-rw-r--r--tests/auto/core/qskeletonloader/qskeletonloader.pro12
-rw-r--r--tests/auto/core/qskeletonloader/tst_qskeletonloader.cpp276
-rw-r--r--tests/auto/core/vector3d_base/tst_vector3d_base.cpp705
-rw-r--r--tests/auto/core/vector3d_base/vector3d_base.pro7
-rw-r--r--tests/auto/core/vector3d_sse/tst_vector3d_sse.cpp816
-rw-r--r--tests/auto/core/vector3d_sse/vector3d_sse.pro8
-rw-r--r--tests/auto/core/vector4d_base/tst_vector4d_base.cpp785
-rw-r--r--tests/auto/core/vector4d_base/vector4d_base.pro7
-rw-r--r--tests/auto/core/vector4d_sse/tst_vector4d_sse.cpp830
-rw-r--r--tests/auto/core/vector4d_sse/vector4d_sse.pro9
-rw-r--r--tests/auto/quick3d/3dcore/3dcore.qml5
-rw-r--r--tests/auto/quick3d/3drender/3drender.qml2
-rw-r--r--tests/auto/render/armature/armature.pro12
-rw-r--r--tests/auto/render/armature/tst_armature.cpp120
-rw-r--r--tests/auto/render/blitframebuffer/blitframebuffer.pro12
-rw-r--r--tests/auto/render/blitframebuffer/tst_blitframebuffer.cpp196
-rw-r--r--tests/auto/render/buffer/tst_buffer.cpp65
-rw-r--r--tests/auto/render/commons/testrenderer.h1
-rw-r--r--tests/auto/render/ddstextures/data/16x16-etc1.pkmbin0 -> 144 bytes
-rw-r--r--tests/auto/render/ddstextures/data/16x16-etc2.pkmbin0 -> 144 bytes
-rw-r--r--tests/auto/render/ddstextures/ddstextures.pro4
-rw-r--r--tests/auto/render/ddstextures/tst_ddstextures.cpp2
-rw-r--r--tests/auto/render/entity/tst_entity.cpp20
-rw-r--r--tests/auto/render/filtercompatibletechniquejob/BLACKLIST7
-rw-r--r--tests/auto/render/geometry/tst_geometry.cpp29
-rw-r--r--tests/auto/render/geometryrenderer/tst_geometryrenderer.cpp88
-rw-r--r--tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp86
-rw-r--r--tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp125
-rw-r--r--tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp125
-rw-r--r--tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp138
-rw-r--r--tests/auto/render/joint/joint.pro13
-rw-r--r--tests/auto/render/joint/tst_joint.cpp242
-rw-r--r--tests/auto/render/layerfiltering/tst_layerfiltering.cpp502
-rw-r--r--tests/auto/render/loadscenejob/tst_loadscenejob.cpp31
-rw-r--r--tests/auto/render/meshfunctors/tst_meshfunctors.cpp32
-rw-r--r--tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp1
-rw-r--r--tests/auto/render/proximityfilter/proximityfilter.pro12
-rw-r--r--tests/auto/render/proximityfilter/tst_proximityfilter.cpp133
-rw-r--r--tests/auto/render/proximityfiltering/proximityfiltering.pro13
-rw-r--r--tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp287
-rw-r--r--tests/auto/render/qattribute/tst_qattribute.cpp6
-rw-r--r--tests/auto/render/qblitframebuffer/qblitframebuffer.pro11
-rw-r--r--tests/auto/render/qblitframebuffer/tst_qblitframebuffer.cpp338
-rw-r--r--tests/auto/render/qbuffer/tst_qbuffer.cpp1
-rw-r--r--tests/auto/render/qgeometryrenderer/tst_qgeometryrenderer.cpp16
-rw-r--r--tests/auto/render/qgraphicsapifilter/tst_qgraphicsapifilter.cpp7
-rw-r--r--tests/auto/render/qmesh/tst_qmesh.cpp34
-rw-r--r--tests/auto/render/qproximityfilter/qproximityfilter.pro12
-rw-r--r--tests/auto/render/qproximityfilter/tst_qproximityfilter.cpp270
-rw-r--r--tests/auto/render/qrendercapture/tst_qrendercapture.cpp7
-rw-r--r--tests/auto/render/qrendersettings/tst_qrendersettings.cpp37
-rw-r--r--tests/auto/render/qshaderprogrambuilder/qshaderprogrambuilder.pro12
-rw-r--r--tests/auto/render/qshaderprogrambuilder/tst_qshaderprogrambuilder.cpp601
-rw-r--r--tests/auto/render/render.pro45
-rw-r--r--tests/auto/render/rendercapture/tst_rendercapture.cpp14
-rw-r--r--tests/auto/render/renderer/renderer.pro9
-rw-r--r--tests/auto/render/renderer/tst_renderer.cpp234
-rw-r--r--tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp350
-rw-r--r--tests/auto/render/sceneloader/tst_sceneloader.cpp4
-rw-r--r--tests/auto/render/segmentvisitor/segmentvisitor.pro12
-rw-r--r--tests/auto/render/segmentvisitor/tst_segmentvisitor.cpp814
-rw-r--r--tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp6
-rw-r--r--tests/auto/render/shader/shader.pro1
-rw-r--r--tests/auto/render/shader/tst_shader.cpp188
-rw-r--r--tests/auto/render/shaderbuilder/input.json90
-rw-r--r--tests/auto/render/shaderbuilder/lightmodel.es2.inc6
-rw-r--r--tests/auto/render/shaderbuilder/lightmodel.gl3.inc6
-rw-r--r--tests/auto/render/shaderbuilder/output.es236
-rw-r--r--tests/auto/render/shaderbuilder/output.gl337
-rw-r--r--tests/auto/render/shaderbuilder/prototypes.json237
-rw-r--r--tests/auto/render/shaderbuilder/shaderbuilder.pro13
-rw-r--r--tests/auto/render/shaderbuilder/shaderbuilder.qrc10
-rw-r--r--tests/auto/render/shaderbuilder/tst_shaderbuilder.cpp548
-rw-r--r--tests/auto/render/skeleton/skeleton.pro13
-rw-r--r--tests/auto/render/skeleton/tst_skeleton.cpp405
-rw-r--r--tests/auto/render/texture/tst_texture.cpp10
-rw-r--r--tests/auto/render/transform/tst_transform.cpp8
-rw-r--r--tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp50
-rw-r--r--tests/auto/render/uniform/tst_uniform.cpp65
-rw-r--r--tests/benchmarks/benchmarks.pro7
-rw-r--r--tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp50
-rw-r--r--tests/manual/animation-keyframe-blendtree/main.qml26
-rw-r--r--tests/manual/animation-keyframe-simple/main.qml22
-rw-r--r--tests/manual/bigscene-instanced-qml/instanced.vert2
-rw-r--r--tests/manual/blitframebuffer-qml/blitframebuffer-qml.pro14
-rw-r--r--tests/manual/blitframebuffer-qml/blitframebuffer-qml.qrc5
-rw-r--r--tests/manual/blitframebuffer-qml/main.cpp72
-rw-r--r--tests/manual/blitframebuffer-qml/main.qml273
-rw-r--r--[-rwxr-xr-x]tests/manual/buffercapture-qml/bufferSetter.comp0
-rw-r--r--tests/manual/custom-mesh-update-data-cpp/main.cpp2
-rw-r--r--tests/manual/downloading/downloading.pro14
-rw-r--r--tests/manual/downloading/downloading.qrc5
-rw-r--r--tests/manual/downloading/main.cpp63
-rw-r--r--tests/manual/downloading/main.qml105
-rw-r--r--tests/manual/layerfilter-qml/layerfilter-qml.pro14
-rw-r--r--tests/manual/layerfilter-qml/layerfilter-qml.qrc5
-rw-r--r--tests/manual/layerfilter-qml/main.cpp63
-rw-r--r--tests/manual/layerfilter-qml/main.qml221
-rw-r--r--tests/manual/manual.pro9
-rw-r--r--tests/manual/pointlinesize/Scene.qml138
-rw-r--r--tests/manual/pointlinesize/main.cpp72
-rw-r--r--tests/manual/pointlinesize/main.qml107
-rw-r--r--tests/manual/pointlinesize/pointlinesize.pro15
-rw-r--r--tests/manual/pointlinesize/pointlinesize.qrc6
-rw-r--r--tests/manual/proximityfilter/main.cpp63
-rw-r--r--tests/manual/proximityfilter/main.qml148
-rw-r--r--tests/manual/proximityfilter/proximityfilter.pro11
-rw-r--r--tests/manual/proximityfilter/proximityfilter.qrc5
-rw-r--r--tests/manual/rendercapture-qml/main.cpp6
-rw-r--r--tests/manual/skinned-mesh/DefaultSceneEntity.qml116
-rw-r--r--tests/manual/skinned-mesh/SkinnedEntity.qml41
-rw-r--r--tests/manual/skinned-mesh/SkinnedPbrEffect.qml39
-rw-r--r--tests/manual/skinned-mesh/jump.json4571
-rw-r--r--tests/manual/skinned-mesh/main.cpp65
-rw-r--r--tests/manual/skinned-mesh/main.qml254
-rw-r--r--tests/manual/skinned-mesh/skinned-mesh.pro23
-rw-r--r--tests/manual/skinned-mesh/skinned-mesh.qrc10
-rw-r--r--tests/manual/skinned-mesh/skinnedPbr.vert94
-rw-r--r--tests/manual/spritegrid/main.cpp63
-rw-r--r--tests/manual/spritegrid/main.qml182
-rw-r--r--tests/manual/spritegrid/spritegrid.pngbin0 -> 19751 bytes
-rw-r--r--tests/manual/spritegrid/spritegrid.pro14
-rw-r--r--tests/manual/spritegrid/spritegrid.qrc6
-rw-r--r--tests/tests.pro9
-rw-r--r--tools/utils/exporters/blender/qt3d_animation_export.py23
-rw-r--r--tools/utils/exporters/blender/qt3d_armature_export.py158
-rw-r--r--tools/utils/exporters/blender/qt3d_path_export.py138
639 files changed, 53123 insertions, 5408 deletions
diff --git a/.gitignore b/.gitignore
index 17ab804c9..2f8201bc2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ doc/qt3d
*~
*.user
*.user.*
+.dir-locals.el
src/quick3d/qt3dquickversion.h
src/threed/qt3dversion.h
tmp
diff --git a/.qmake.conf b/.qmake.conf
index 2108ac6fd..b7100cffc 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -1,3 +1,6 @@
+QT3D_ROOT = $$PWD
+QT3D_BUILD_ROOT = $$shadowed($$PWD)
+
load(qt_build_config)
-MODULE_VERSION = 5.9.3
+MODULE_VERSION = 5.10.0
diff --git a/config_help.txt b/config_help.txt
index 8aeed3007..50fd93229 100644
--- a/config_help.txt
+++ b/config_help.txt
@@ -3,3 +3,9 @@ Qt3D options:
-assimp .............. Select used assimp library [system/qt/no]
-qt3d-profile-jobs ... Enable jobs profiling [no]
-qt3d-profile-gl ..... Enable OpenGL profiling [no]
+ -qt3d-simd ........... Select level of SIMD support [no/sse2/avx2]
+ -qt3d-render ......... Enable the Qt3D Render aspect [yes]
+ -qt3d-input .......... Enable the Qt3D Input aspect [yes]
+ -qt3d-logic .......... Enable the Qt3D Logic aspect [yes]
+ -qt3d-extras ......... Enable the Qt3D Extras aspect [yes]
+ -qt3d-animation....... Enable the Qt3D Animation aspect [yes]
diff --git a/examples/examples.pro b/examples/examples.pro
index 6d61af094..6a3c01d76 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -1,2 +1,5 @@
TEMPLATE = subdirs
-SUBDIRS += qt3d
+
+QT_FOR_CONFIG += 3dcore
+
+qtConfig(qt3d-extras): SUBDIRS += qt3d
diff --git a/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag b/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag
index ea54a87f1..f471504fa 100644
--- a/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag
+++ b/examples/qt3d/advancedcustommaterial/shaders/es2/water.frag
@@ -1,6 +1,8 @@
#define FP highp
varying FP vec3 worldPosition;
+varying FP vec3 worldNormal;
+varying FP vec4 worldTangent;
varying FP vec2 texCoord;
varying FP vec2 waveTexCoord;
varying FP vec2 movtexCoord;
@@ -9,7 +11,6 @@ varying FP vec2 skyTexCoord;
varying FP vec3 vpos;
-varying FP mat3 tangentMatrix;
varying FP vec3 color;
uniform FP sampler2D diffuseTexture;
@@ -23,13 +24,13 @@ uniform FP float offsetx;
uniform FP float offsety;
uniform FP float specularity;
uniform FP float waveStrenght;
-uniform FP vec3 ka;
-uniform FP vec3 specularColor;
+uniform FP vec4 ka;
uniform FP float shininess;
uniform FP float normalAmount;
uniform FP vec3 eyePosition;
-#pragma include light.inc.frag
+#pragma include phong.inc.frag
+#pragma include coordinatesystems.inc
void main()
{
@@ -50,21 +51,24 @@ void main()
// 2 Animated Layers of specularTexture mixed with the newCoord
FP vec4 specularTextureColor = texture2D( specularTexture, multexCoord+newCoord) + (texture2D( specularTexture, movtexCoord+newCoord ));
// 2 Animated Layers of normalTexture mixed with the newCoord
- FP vec3 normal = normalAmount * texture2D( normalTexture, movtexCoord+newCoord ).rgb - vec3( 1.0 )+(normalAmount * texture2D( normalTexture, multexCoord+newCoord ).rgb - vec3( 1.0 ));
+ FP vec3 tNormal = normalAmount * texture2D( normalTexture, movtexCoord+newCoord ).rgb - vec3( 1.0 )+(normalAmount * texture2D( normalTexture, multexCoord+newCoord ).rgb - vec3( 1.0 ));
// Animated skyTexture layer
FP vec4 skycolor = texture2D(skyTexture, skyTexCoord);
skycolor = skycolor * 0.4;
//Animated foamTexture layer
FP vec4 foamTextureColor = texture2D(foamTexture, texCoord);
- // Calculate the lighting model, keeping the specular component separate
- FP vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
+ FP mat3 tangentMatrix = calcWorldSpaceToTangentSpaceMatrix(worldNormal, worldTangent);
+ FP mat3 invertTangentMatrix = transpose(tangentMatrix);
- // Combine final fragment color
- FP vec4 outputColor = vec4(((skycolor.rgb + ka + diffuseTextureColor.rgb * (diffuseColor))+(specularColor * specularTextureColor.a*specularity)), vpos.y );
+ FP vec3 wNormal = normalize(invertTangentMatrix * tNormal);
+ FP vec3 worldView = normalize(eyePosition - worldPosition);
+ FP vec4 diffuse = vec4(diffuseTextureColor.rgb, vpos.y);
+ FP vec4 specular = vec4(specularTextureColor.a*specularity);
+ FP vec4 outputColor = phongFunction(ka, diffuse, specular, shininess, worldPosition, worldView, wNormal);
+ outputColor += vec4(skycolor.rgb, vpos.y);
outputColor += (foamTextureColor.rgba*vpos.y);
gl_FragColor = vec4(outputColor.rgb,1.0);
diff --git a/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert b/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert
index 1a7d46a46..76dd3f8c0 100644
--- a/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert
+++ b/examples/qt3d/advancedcustommaterial/shaders/es2/water.vert
@@ -6,12 +6,13 @@ attribute FP vec2 vertexTexCoord;
attribute FP vec4 vertexTangent;
varying FP vec3 worldPosition;
+varying FP vec3 worldNormal;
+varying FP vec4 worldTangent;
varying FP vec2 texCoord;
varying FP vec2 movtexCoord;
varying FP vec2 multexCoord;
varying FP vec2 waveTexCoord;
varying FP vec2 skyTexCoord;
-varying FP mat3 tangentMatrix;
varying FP vec3 vpos;
uniform FP mat4 modelMatrix;
@@ -42,25 +43,9 @@ void main()
// Transform position, normal, and tangent to world coords
worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0));
- FP vec3 normal = normalize(modelNormalMatrix * vertexNormal);
- FP vec3 tangent = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
-
- // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
- // This allows to build the tangentMatrix below by simply transposing the
- // tangent -> world space matrix (which would now be orthogonal)
- tangent = normalize(tangent - dot(tangent, normal) * normal);
-
- // Calculate binormal vector. No "real" need to renormalize it,
- // as built by crossing two normal vectors.
- // To orient the binormal correctly, use the fourth coordinate of the tangent,
- // which is +1 for a right hand system, and -1 for a left hand system.
- FP vec3 binormal = cross(normal, tangent) * vertexTangent.w;
-
- // Construct matrix to transform from eye coords to tangent space
- tangentMatrix = mat3(
- tangent.x, binormal.x, normal.x,
- tangent.y, binormal.y, normal.y,
- tangent.z, binormal.z, normal.z);
+ worldNormal = normalize(modelNormalMatrix * vertexNormal);
+ worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
+ worldTangent.w = vertexTangent.w;
// Calculate animated vertex positions
diff --git a/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag
index 9657cc63a..6e9722314 100644
--- a/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag
+++ b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.frag
@@ -1,6 +1,8 @@
#version 150 core
in vec3 worldPosition;
+in vec3 worldNormal;
+in vec4 worldTangent;
in vec2 texCoord;
in vec2 waveTexCoord;
in vec2 movtexCoord;
@@ -9,7 +11,6 @@ in vec2 skyTexCoord;
in vec3 vpos;
-in mat3 tangentMatrix;
in vec3 color;
uniform sampler2D diffuseTexture;
@@ -23,7 +24,7 @@ uniform float offsetx;
uniform float offsety;
uniform float specularity;
uniform float waveStrenght;
-uniform vec3 ka;
+uniform vec4 ka;
uniform vec3 specularColor;
uniform float shininess;
uniform float normalAmount;
@@ -31,7 +32,8 @@ uniform vec3 eyePosition;
out vec4 fragColor;
-#pragma include light.inc.frag
+#pragma include phong.inc.frag
+#pragma include coordinatesystems.inc
void main()
{
@@ -52,21 +54,24 @@ void main()
// 2 Animated Layers of specularTexture mixed with the newCoord
vec4 specularTextureColor = texture( specularTexture, multexCoord+newCoord) + (texture( specularTexture, movtexCoord+newCoord ));
// 2 Animated Layers of normalTexture mixed with the newCoord
- vec3 normal = normalAmount * texture( normalTexture, movtexCoord+newCoord ).rgb - vec3( 1.0 )+(normalAmount * texture( normalTexture, multexCoord+newCoord ).rgb - vec3( 1.0 ));
+ vec3 tNormal = normalAmount * texture( normalTexture, movtexCoord+newCoord ).rgb - vec3( 1.0 )+(normalAmount * texture( normalTexture, multexCoord+newCoord ).rgb - vec3( 1.0 ));
// Animated skyTexture layer
vec4 skycolor = texture(skyTexture, skyTexCoord);
skycolor = skycolor * 0.4;
//Animated foamTexture layer
vec4 foamTextureColor = texture(foamTexture, texCoord);
- // Calculate the lighting model, keeping the specular component separate
- vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
+ mat3 tangentMatrix = calcWorldSpaceToTangentSpaceMatrix(worldNormal, worldTangent);
+ mat3 invertTangentMatrix = transpose(tangentMatrix);
- // Combine final fragment color
- vec4 outputColor = vec4(((skycolor.rgb + ka + diffuseTextureColor.rgb * (diffuseColor))+(specularColor * specularTextureColor.a*specularity)), vpos.y );
+ vec3 wNormal = normalize(invertTangentMatrix * tNormal);
+ vec3 worldView = normalize(eyePosition - worldPosition);
+ vec4 diffuse = vec4(diffuseTextureColor.rgb, vpos.y);
+ vec4 specular = vec4(specularTextureColor.a*specularity);
+ vec4 outputColor = phongFunction(ka, diffuse, specular, shininess, worldPosition, worldView, wNormal);
+ outputColor += vec4(skycolor.rgb, vpos.y);
outputColor += (foamTextureColor.rgba*vpos.y);
fragColor = vec4(outputColor.rgb,1.0);
diff --git a/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert
index a4ddcf62b..3af37e9a5 100644
--- a/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert
+++ b/examples/qt3d/advancedcustommaterial/shaders/gl3/water.vert
@@ -6,12 +6,13 @@ in vec2 vertexTexCoord;
in vec4 vertexTangent;
out vec3 worldPosition;
+out vec3 worldNormal;
+out vec4 worldTangent;
out vec2 texCoord;
out vec2 movtexCoord;
out vec2 multexCoord;
out vec2 waveTexCoord;
out vec2 skyTexCoord;
-out mat3 tangentMatrix;
out vec3 vpos;
uniform mat4 modelMatrix;
@@ -42,25 +43,9 @@ void main()
// Transform position, normal, and tangent to world coords
worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0));
- vec3 normal = normalize(modelNormalMatrix * vertexNormal);
- vec3 tangent = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
-
- // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
- // This allows to build the tangentMatrix below by simply transposing the
- // tangent -> world space matrix (which would now be orthogonal)
- tangent = normalize(tangent - dot(tangent, normal) * normal);
-
- // Calculate binormal vector. No "real" need to renormalize it,
- // as built by crossing two normal vectors.
- // To orient the binormal correctly, use the fourth coordinate of the tangent,
- // which is +1 for a right hand system, and -1 for a left hand system.
- vec3 binormal = cross(normal, tangent) * vertexTangent.w;
-
- // Construct matrix to transform from eye coords to tangent space
- tangentMatrix = mat3(
- tangent.x, binormal.x, normal.x,
- tangent.y, binormal.y, normal.y,
- tangent.z, binormal.z, normal.z);
+ worldNormal = normalize(modelNormalMatrix * vertexNormal);
+ worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
+ worldTangent.w = vertexTangent.w;
// Calculate animated vertex positions
diff --git a/examples/qt3d/controls/Logo.qml b/examples/qt3d/controls/Logo.qml
index a686e29bd..62742246f 100644
--- a/examples/qt3d/controls/Logo.qml
+++ b/examples/qt3d/controls/Logo.qml
@@ -56,6 +56,18 @@ import Qt3D.Extras 2.0
Entity {
id: sceneRoot
+ readonly property double cameraZ: camera.position.z
+
+ function viewAll() {
+ camera.viewAll()
+ }
+ function viewLogo() {
+ camera.viewEntity(logoEntity)
+ }
+ function setPositionZ(z) {
+ camera.position = Qt.vector3d( 0.0, 0.0, z )
+ }
+
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
@@ -63,7 +75,7 @@ Entity {
aspectRatio: 4/3
nearPlane : 0.1
farPlane : 1000.0
- position: Qt.vector3d( 0.0, 0.0, viewCenter_z.value )
+ position: Qt.vector3d( 0.0, 0.0, 7.5 )
upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
}
@@ -79,8 +91,8 @@ Entity {
PhongMaterial {
id: material
- ambient: Qt.rgba( color_r.value/255, color_g.value/255, color_b.value/255, 1.0 )
- diffuse: Qt.rgba( 0.1, 0.1, 0.1, 0.5 )
+ diffuse: Qt.rgba( color_r.value/255, color_g.value/255, color_b.value/255, 1.0 )
+ ambient: Qt.rgba( 0.1, 0.1, 0.1, 1.0 )
shininess: shining.value
}
@@ -98,4 +110,16 @@ Entity {
id: logoEntity
components: [ logoMesh, material, logoTransform ]
}
+
+ Entity {
+ components: [
+ PointLight {
+ color: "white"
+ intensity: 0.6
+ },
+ Transform {
+ translation: Qt.vector3d(0, 0, 10)
+ }
+ ]
+ }
}
diff --git a/examples/qt3d/controls/main.qml b/examples/qt3d/controls/main.qml
index 2b438ac20..5d1f9c02c 100644
--- a/examples/qt3d/controls/main.qml
+++ b/examples/qt3d/controls/main.qml
@@ -178,13 +178,20 @@ Item {
spacing: 5
Text { text: "Camera"; font.bold: true }
- Text { text: "View Center Z" }
+ Text { text: "View Ctr Z: " + watch.cameraZ.toFixed(2) }
Slider {
id: viewCenter_z
Layout.fillWidth: true
minimumValue: 4
maximumValue: 12
value: 7.5
+ onValueChanged: watch.setPositionZ(value)
+ }
+ Button {
+ id: viewAll
+ Layout.fillWidth: true
+ text: "View All"
+ onClicked: watch.viewLogo()
}
}
diff --git a/examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_irradiance.dds b/examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_irradiance.dds
new file mode 100644
index 000000000..c08c46301
--- /dev/null
+++ b/examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_irradiance.dds
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_specular.dds b/examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_specular.dds
new file mode 100644
index 000000000..ac9d49cc2
--- /dev/null
+++ b/examples/qt3d/exampleresources/assets/envmaps/cedar-bridge/cedar_bridge_specular.dds
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf
new file mode 100644
index 000000000..0cbcfd04c
--- /dev/null
+++ b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf
@@ -0,0 +1,2731 @@
+{
+ "asset": {
+ "generator": "COLLADA2GLTF",
+ "version": "2.0"
+ },
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 21,
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "mesh": 0,
+ "skin": 0
+ },
+ {
+ "children": [
+ 11,
+ 7,
+ 3
+ ],
+ "translation": [
+ 2.7939699442924854e-9,
+ -1.4156600514070309e-7,
+ 0.6860002279281616
+ ],
+ "rotation": [
+ 0.03792940452694893,
+ 0.002913428470492363,
+ -0.00011058452219003811,
+ -0.9992762207984924
+ ],
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0000001192092896
+ ]
+ },
+ {
+ "children": [
+ 4
+ ],
+ "translation": [
+ -0.06845717132091522,
+ 0.004460853058844805,
+ -0.07147114723920822
+ ],
+ "rotation": [
+ -0.02339874766767025,
+ -0.6542636752128601,
+ 0.754464864730835,
+ 0.046630214899778369
+ ],
+ "scale": [
+ 1.0,
+ 1.000000238418579,
+ 0.9999999403953552
+ ]
+ },
+ {
+ "children": [
+ 5
+ ],
+ "translation": [
+ 0.0,
+ 0.2661120891571045,
+ 1.4901200273698124e-8
+ ],
+ "rotation": [
+ 0.21606147289276124,
+ 0.08108008652925492,
+ -0.010079992935061457,
+ -0.9729552268981934
+ ],
+ "scale": [
+ 1.0000001192092896,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "children": [
+ 6
+ ],
+ "translation": [
+ -7.450579708745408e-9,
+ 0.27582409977912905,
+ -3.725289854372704e-9
+ ],
+ "rotation": [
+ 0.8471670746803284,
+ -0.03204828128218651,
+ -0.024840382859110837,
+ -0.5297772288322449
+ ],
+ "scale": [
+ 0.9999999403953552,
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "translation": [
+ -0.0014585329918190837,
+ -0.06619873642921448,
+ 0.027856800705194478
+ ],
+ "rotation": [
+ -0.03414325416088104,
+ -0.3191778957843781,
+ 0.9461711049079896,
+ -0.04146831855177879
+ ],
+ "scale": [
+ 0.9999999403953552,
+ 0.9999997615814208,
+ 0.9999991655349731
+ ]
+ },
+ {
+ "children": [
+ 8
+ ],
+ "translation": [
+ 0.06761927157640457,
+ 0.004461091011762619,
+ -0.07226461172103882
+ ],
+ "rotation": [
+ 0.21088078618049625,
+ -0.6243308186531067,
+ 0.724772036075592,
+ -0.2011117935180664
+ ],
+ "scale": [
+ 1.0000001192092896,
+ 1.000000238418579,
+ 1.0000001192092896
+ ]
+ },
+ {
+ "children": [
+ 9
+ ],
+ "translation": [
+ 0.0,
+ 0.2661122083663941,
+ 0.0
+ ],
+ "rotation": [
+ 0.2111543715000153,
+ -0.29843246936798098,
+ -0.04688597097992897,
+ -0.92959862947464
+ ],
+ "scale": [
+ 1.0000001192092896,
+ 1.0000001192092896,
+ 0.9999999403953552
+ ]
+ },
+ {
+ "children": [
+ 10
+ ],
+ "translation": [
+ 0.0,
+ 0.27582401037216189,
+ 0.0
+ ],
+ "rotation": [
+ 0.8477688431739807,
+ -0.002281580353155732,
+ -0.006338709034025669,
+ -0.530323326587677
+ ],
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0000001192092896
+ ]
+ },
+ {
+ "translation": [
+ -0.0023464928381145,
+ -0.06617330759763718,
+ 0.02785675972700119
+ ],
+ "rotation": [
+ 0.024532083421945573,
+ -0.3199966549873352,
+ 0.9446004033088684,
+ 0.06878151744604111
+ ],
+ "scale": [
+ 1.0,
+ 1.0000007152557374,
+ 1.0000009536743165
+ ]
+ },
+ {
+ "children": [
+ 12
+ ],
+ "translation": [
+ 0.0009999809553846717,
+ -4.842879874900064e-8,
+ 0.1714905947446823
+ ],
+ "rotation": [
+ -0.7380747199058533,
+ -0.001967150717973709,
+ 0.0021518853027373558,
+ -0.6747126579284668
+ ],
+ "scale": [
+ 1.0000001192092896,
+ 0.9999999403953552,
+ 1.0
+ ]
+ },
+ {
+ "children": [
+ 19,
+ 16,
+ 13
+ ],
+ "translation": [
+ 0.0,
+ 0.2180176973342896,
+ 3.725289854372704e-9
+ ],
+ "rotation": [
+ 0.6378589272499085,
+ -4.2587172677244209e-10,
+ -3.5271871534625629e-10,
+ -0.770153284072876
+ ],
+ "scale": [
+ 1.0,
+ 1.0000001192092896,
+ 1.0
+ ]
+ },
+ {
+ "children": [
+ 14
+ ],
+ "translation": [
+ -0.08800055086612702,
+ -0.0001992879988392815,
+ -0.0009773969650268557
+ ],
+ "rotation": [
+ 0.27643078565597536,
+ 0.05186379700899124,
+ -0.665187418460846,
+ -0.6916804909706116
+ ],
+ "scale": [
+ 1.0,
+ 0.9999999403953552,
+ 0.9999999403953552
+ ]
+ },
+ {
+ "children": [
+ 15
+ ],
+ "translation": [
+ -7.450579708745408e-9,
+ 0.24452559649944304,
+ -5.96045985901128e-8
+ ],
+ "rotation": [
+ -0.2280062586069107,
+ 0.9096477627754213,
+ -0.1480233669281006,
+ -0.31407487392425539
+ ],
+ "scale": [
+ 0.9999999403953552,
+ 0.9999995827674866,
+ 0.9999998211860656
+ ]
+ },
+ {
+ "translation": [
+ -5.96045985901128e-8,
+ 0.1855168044567108,
+ 0.0
+ ],
+ "rotation": [
+ -0.07854889333248139,
+ 0.14253509044647218,
+ -0.014102266170084477,
+ -0.9865672588348388
+ ],
+ "scale": [
+ 1.0000001192092896,
+ 1.0,
+ 0.9999999403953552
+ ]
+ },
+ {
+ "children": [
+ 17
+ ],
+ "translation": [
+ 0.08800055086612702,
+ -0.0001992879988392815,
+ -0.0009773969650268557
+ ],
+ "rotation": [
+ 0.6789423823356628,
+ 0.6879449486732483,
+ -0.24067795276641849,
+ -0.08856399357318878
+ ],
+ "scale": [
+ 1.0000001192092896,
+ 1.0000004768371585,
+ 1.0
+ ]
+ },
+ {
+ "children": [
+ 18
+ ],
+ "translation": [
+ 1.862650034212265e-9,
+ 0.24452590942382813,
+ -5.96045985901128e-8
+ ],
+ "rotation": [
+ 0.002400061814114452,
+ -0.13981154561042789,
+ -0.2718312442302704,
+ -0.9521317481994628
+ ]
+ },
+ {
+ "translation": [
+ 0.0,
+ 0.1855167001485825,
+ 0.0
+ ],
+ "rotation": [
+ -0.05729063600301743,
+ -0.02822729200124741,
+ -0.0555599257349968,
+ -0.996410608291626
+ ],
+ "scale": [
+ 1.0,
+ 1.0000001192092896,
+ 1.0000001192092896
+ ]
+ },
+ {
+ "children": [
+ 20
+ ],
+ "translation": [
+ 0.0,
+ 7.450579886381094e-8,
+ 0.05255972966551781
+ ],
+ "rotation": [
+ -0.635452151298523,
+ -1.0367853739773274e-15,
+ -8.512669473202695e-16,
+ -0.7721402645111084
+ ]
+ },
+ {
+ "translation": [
+ 0.0,
+ 0.06650590896606446,
+ 0.0
+ ],
+ "rotation": [
+ 4.2157907720330458e-10,
+ 0.9999844431877136,
+ -0.005583992227911949,
+ -7.549667913053783e-8
+ ],
+ "scale": [
+ 1.0,
+ 1.0000001192092896,
+ 1.0
+ ]
+ },
+ {
+ "children": [
+ 2
+ ]
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "JOINTS_0": 1,
+ "NORMAL": 2,
+ "POSITION": 3,
+ "WEIGHTS_0": 4
+ },
+ "indices": 0,
+ "mode": 4,
+ "material": 0
+ }
+ ],
+ "name": "Proxy"
+ }
+ ],
+ "animations": [
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 2,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 2,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 2,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 5,
+ "interpolation": "LINEAR",
+ "output": 6
+ },
+ {
+ "input": 5,
+ "interpolation": "LINEAR",
+ "output": 7
+ },
+ {
+ "input": 5,
+ "interpolation": "LINEAR",
+ "output": 8
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 11,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 11,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 11,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 9,
+ "interpolation": "LINEAR",
+ "output": 10
+ },
+ {
+ "input": 9,
+ "interpolation": "LINEAR",
+ "output": 11
+ },
+ {
+ "input": 9,
+ "interpolation": "LINEAR",
+ "output": 12
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 12,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 12,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 12,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 13,
+ "interpolation": "LINEAR",
+ "output": 14
+ },
+ {
+ "input": 13,
+ "interpolation": "LINEAR",
+ "output": 15
+ },
+ {
+ "input": 13,
+ "interpolation": "LINEAR",
+ "output": 16
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 19,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 19,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 19,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 17,
+ "interpolation": "LINEAR",
+ "output": 18
+ },
+ {
+ "input": 17,
+ "interpolation": "LINEAR",
+ "output": 19
+ },
+ {
+ "input": 17,
+ "interpolation": "LINEAR",
+ "output": 20
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 20,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 20,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 20,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 21,
+ "interpolation": "LINEAR",
+ "output": 22
+ },
+ {
+ "input": 21,
+ "interpolation": "LINEAR",
+ "output": 23
+ },
+ {
+ "input": 21,
+ "interpolation": "LINEAR",
+ "output": 24
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 16,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 16,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 16,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 25,
+ "interpolation": "LINEAR",
+ "output": 26
+ },
+ {
+ "input": 25,
+ "interpolation": "LINEAR",
+ "output": 27
+ },
+ {
+ "input": 25,
+ "interpolation": "LINEAR",
+ "output": 28
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 17,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 17,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 17,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 29,
+ "interpolation": "LINEAR",
+ "output": 30
+ },
+ {
+ "input": 29,
+ "interpolation": "LINEAR",
+ "output": 31
+ },
+ {
+ "input": 29,
+ "interpolation": "LINEAR",
+ "output": 32
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 18,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 18,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 18,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 33,
+ "interpolation": "LINEAR",
+ "output": 34
+ },
+ {
+ "input": 33,
+ "interpolation": "LINEAR",
+ "output": 35
+ },
+ {
+ "input": 33,
+ "interpolation": "LINEAR",
+ "output": 36
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 13,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 13,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 13,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 37,
+ "interpolation": "LINEAR",
+ "output": 38
+ },
+ {
+ "input": 37,
+ "interpolation": "LINEAR",
+ "output": 39
+ },
+ {
+ "input": 37,
+ "interpolation": "LINEAR",
+ "output": 40
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 14,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 14,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 14,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 41,
+ "interpolation": "LINEAR",
+ "output": 42
+ },
+ {
+ "input": 41,
+ "interpolation": "LINEAR",
+ "output": 43
+ },
+ {
+ "input": 41,
+ "interpolation": "LINEAR",
+ "output": 44
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 15,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 15,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 15,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 45,
+ "interpolation": "LINEAR",
+ "output": 46
+ },
+ {
+ "input": 45,
+ "interpolation": "LINEAR",
+ "output": 47
+ },
+ {
+ "input": 45,
+ "interpolation": "LINEAR",
+ "output": 48
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 7,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 7,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 7,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 49,
+ "interpolation": "LINEAR",
+ "output": 50
+ },
+ {
+ "input": 49,
+ "interpolation": "LINEAR",
+ "output": 51
+ },
+ {
+ "input": 49,
+ "interpolation": "LINEAR",
+ "output": 52
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 8,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 8,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 8,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 53,
+ "interpolation": "LINEAR",
+ "output": 54
+ },
+ {
+ "input": 53,
+ "interpolation": "LINEAR",
+ "output": 55
+ },
+ {
+ "input": 53,
+ "interpolation": "LINEAR",
+ "output": 56
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 9,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 9,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 9,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 57,
+ "interpolation": "LINEAR",
+ "output": 58
+ },
+ {
+ "input": 57,
+ "interpolation": "LINEAR",
+ "output": 59
+ },
+ {
+ "input": 57,
+ "interpolation": "LINEAR",
+ "output": 60
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 10,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 10,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 10,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 61,
+ "interpolation": "LINEAR",
+ "output": 62
+ },
+ {
+ "input": 61,
+ "interpolation": "LINEAR",
+ "output": 63
+ },
+ {
+ "input": 61,
+ "interpolation": "LINEAR",
+ "output": 64
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 3,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 3,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 3,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 65,
+ "interpolation": "LINEAR",
+ "output": 66
+ },
+ {
+ "input": 65,
+ "interpolation": "LINEAR",
+ "output": 67
+ },
+ {
+ "input": 65,
+ "interpolation": "LINEAR",
+ "output": 68
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 4,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 4,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 4,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 69,
+ "interpolation": "LINEAR",
+ "output": 70
+ },
+ {
+ "input": 69,
+ "interpolation": "LINEAR",
+ "output": 71
+ },
+ {
+ "input": 69,
+ "interpolation": "LINEAR",
+ "output": 72
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 5,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 5,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 5,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 73,
+ "interpolation": "LINEAR",
+ "output": 74
+ },
+ {
+ "input": 73,
+ "interpolation": "LINEAR",
+ "output": 75
+ },
+ {
+ "input": 73,
+ "interpolation": "LINEAR",
+ "output": 76
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 6,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 6,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 6,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 77,
+ "interpolation": "LINEAR",
+ "output": 78
+ },
+ {
+ "input": 77,
+ "interpolation": "LINEAR",
+ "output": 79
+ },
+ {
+ "input": 77,
+ "interpolation": "LINEAR",
+ "output": 80
+ }
+ ]
+ }
+ ],
+ "skins": [
+ {
+ "inverseBindMatrices": 81,
+ "skeleton": 2,
+ "joints": [
+ 2,
+ 11,
+ 12,
+ 19,
+ 20,
+ 16,
+ 13,
+ 17,
+ 14,
+ 18,
+ 15,
+ 7,
+ 3,
+ 8,
+ 4,
+ 9,
+ 5,
+ 10,
+ 6
+ ],
+ "name": "Armature"
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 768,
+ "max": [
+ 369
+ ],
+ "min": [
+ 0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 370,
+ "max": [
+ 18,
+ 18,
+ 18,
+ 18
+ ],
+ "min": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 370,
+ "max": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "min": [
+ -1.0,
+ -1.0,
+ -1.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 4440,
+ "componentType": 5126,
+ "count": 370,
+ "max": [
+ 0.5894609689712524,
+ 0.13091780245304109,
+ 1.4499199390411378
+ ],
+ "min": [
+ -0.5894609689712524,
+ -0.19497710466384889,
+ 0.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 370,
+ "max": [
+ 1.0,
+ 0.9893189072608948,
+ 0.9037013053894044,
+ 0.6776750087738037
+ ],
+ "min": [
+ 0.010514849796891213,
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 4.5896600409101037e-10,
+ -1.1506600117172641e-7,
+ 0.6860000491142273
+ ],
+ "min": [
+ 4.5896600409101037e-10,
+ -1.1506600117172641e-7,
+ 0.6860000491142273
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.03792992979288101,
+ 0.0029135500080883505,
+ -0.00011340532364556566,
+ -0.9992762804031372
+ ],
+ "min": [
+ 0.03792992979288101,
+ 0.0029135500080883505,
+ -0.00011340532364556566,
+ -0.9992762804031372
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 24,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000001192092896,
+ 1.000000238418579,
+ 1.0000004768371585
+ ],
+ "min": [
+ 1.0000001192092896,
+ 1.000000238418579,
+ 1.0000004768371585
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 8,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 48,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.0009999829344451428,
+ -1.8626499453944239e-8,
+ 0.17149099707603458
+ ],
+ "min": [
+ 0.0009999829344451428,
+ -1.8626499453944239e-8,
+ 0.17149099707603458
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 32,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.7380743026733398,
+ -0.001967150252312422,
+ 0.0021518832072615625,
+ -0.6747127175331116
+ ],
+ "min": [
+ -0.7380743026733398,
+ -0.001967150252312422,
+ 0.0021518832072615625,
+ -0.6747127175331116
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 72,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000001192092896,
+ 0.9999994039535524,
+ 0.999999463558197
+ ],
+ "min": [
+ 1.0000001192092896,
+ 0.9999994039535524,
+ 0.999999463558197
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 16,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 96,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -7.105429898699844e-15,
+ 0.2180179059505463,
+ -1.862650034212265e-9
+ ],
+ "min": [
+ -7.105429898699844e-15,
+ 0.2180179059505463,
+ -1.862650034212265e-9
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 64,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.6378593444824219,
+ -4.2613501616273199e-10,
+ -3.5284211663544337e-10,
+ -0.7701532244682312
+ ],
+ "min": [
+ 0.6378593444824219,
+ -4.2613501616273199e-10,
+ -3.5284211663544337e-10,
+ -0.7701532244682312
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 120,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0,
+ 1.0000005960464478,
+ 1.0000005960464478
+ ],
+ "min": [
+ 1.0,
+ 1.0000005960464478,
+ 1.0000005960464478
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 24,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 144,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -8.881779961836516e-15,
+ -1.4901200273698124e-8,
+ 0.05255949124693871
+ ],
+ "min": [
+ -8.881779961836516e-15,
+ -4.470349779239769e-8,
+ 0.05255937948822975
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 96,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.6354526877403259,
+ 6.392766871421429e-11,
+ 1.0194381688637123e-13,
+ -0.6865020394325256
+ ],
+ "min": [
+ -0.7271280288696289,
+ 1.2045594556531206e-13,
+ -1.964862994530137e-11,
+ -0.7721399664878845
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 168,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0,
+ 1.000000238418579,
+ 1.000000238418579
+ ],
+ "min": [
+ 1.0,
+ 1.000000238418579,
+ 1.000000238418579
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 32,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 192,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -5.329069671167804e-15,
+ 0.06650590896606446,
+ 9.313230187046884e-10
+ ],
+ "min": [
+ -5.329069671167804e-15,
+ 0.06650590896606446,
+ 9.313230187046884e-10
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 128,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 6.65661192833511e-10,
+ 0.999984323978424,
+ 0.03202660754323006,
+ -1.1911986064205849e-7
+ ],
+ "min": [
+ -5.476959996641995e-10,
+ 0.9994869232177734,
+ -0.005583993159234524,
+ -1.1920712950086455e-7
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 216,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0,
+ 0.9999995827674866,
+ 0.9999995827674866
+ ],
+ "min": [
+ 1.0,
+ 0.9999995231628418,
+ 0.9999995231628418
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 40,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 240,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.08800006657838822,
+ -0.00019977999909315256,
+ -0.0009799000108614565
+ ],
+ "min": [
+ 0.08799991011619568,
+ -0.0001997949875658378,
+ -0.00098002003505826
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 160,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.6789432764053345,
+ 0.6879453063011169,
+ -0.2406750321388245,
+ -0.08856184780597687
+ ],
+ "min": [
+ 0.6182979345321655,
+ 0.5380411744117737,
+ -0.4743711948394776,
+ -0.32123467326164248
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 264,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000004768371585,
+ 1.000000238418579,
+ 1.000000238418579
+ ],
+ "min": [
+ 1.0000001192092896,
+ 1.0000001192092896,
+ 1.0000001192092896
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 48,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 288,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -2.328309989252375e-9,
+ 0.24452580511569978,
+ 0.0
+ ],
+ "min": [
+ -2.328309989252375e-9,
+ 0.24452580511569978,
+ 0.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 192,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.002399991732090712,
+ -0.13981157541275025,
+ -0.2718312740325928,
+ -0.9521315693855286
+ ],
+ "min": [
+ 0.002399991732090712,
+ -0.13981160521507264,
+ -0.2718312740325928,
+ -0.9521315693855286
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 312,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.9999995231628418,
+ 0.9999997615814208,
+ 1.0000003576278689
+ ],
+ "min": [
+ 0.999999463558197,
+ 0.9999997615814208,
+ 1.0000003576278689
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 56,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 336,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.0,
+ 0.1855167001485825,
+ 5.96045985901128e-8
+ ],
+ "min": [
+ 0.0,
+ 0.1855167001485825,
+ 5.96045985901128e-8
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 224,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.05729068815708161,
+ -0.028227226808667184,
+ -0.055560123175382617,
+ -0.996410608291626
+ ],
+ "min": [
+ -0.05729068815708161,
+ -0.028227226808667184,
+ -0.055560123175382617,
+ -0.996410608291626
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 360,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000001192092896,
+ 1.0000001192092896,
+ 0.9999995827674866
+ ],
+ "min": [
+ 1.0000001192092896,
+ 1.0000001192092896,
+ 0.9999995827674866
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 64,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 384,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.08799999207258225,
+ -0.0001997949875658378,
+ -0.00098002003505826
+ ],
+ "min": [
+ -0.08800006657838822,
+ -0.0001997949875658378,
+ -0.00098002003505826
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 256,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.49575817584991457,
+ 0.3092453181743622,
+ -0.5336208343505859,
+ -0.6114243268966675
+ ],
+ "min": [
+ 0.2764261960983277,
+ 0.05186334997415543,
+ -0.6651891469955444,
+ -0.6916805505752564
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 408,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000001192092896,
+ 0.9999996423721314,
+ 0.9999999403953552
+ ],
+ "min": [
+ 1.0,
+ 0.9999995231628418,
+ 0.9999997615814208
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 72,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 432,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -7.450579708745408e-9,
+ 0.24452559649944304,
+ 0.0
+ ],
+ "min": [
+ -7.450579708745408e-9,
+ 0.24452559649944304,
+ 0.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 288,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.22800640761852265,
+ 0.9096475839614868,
+ -0.1480235904455185,
+ -0.3140750825405121
+ ],
+ "min": [
+ -0.2280064970254898,
+ 0.909647524356842,
+ -0.14802362024784089,
+ -0.31407514214515688
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 456,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.9999998807907105,
+ 0.9999995231628418,
+ 0.9999998807907105
+ ],
+ "min": [
+ 0.9999998211860656,
+ 0.9999993443489076,
+ 0.9999998211860656
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 80,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 480,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.0,
+ 0.1855168044567108,
+ 0.0
+ ],
+ "min": [
+ 0.0,
+ 0.1855168044567108,
+ 0.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 320,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.07854896783828736,
+ 0.1425352245569229,
+ -0.014102344401180745,
+ -0.986567199230194
+ ],
+ "min": [
+ -0.07854896783828736,
+ 0.1425352245569229,
+ -0.014102344401180745,
+ -0.986567199230194
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 504,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.9999998211860656,
+ 0.9999999403953552,
+ 1.0000001192092896
+ ],
+ "min": [
+ 0.9999998211860656,
+ 0.9999999403953552,
+ 1.0000001192092896
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 88,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 528,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.06761901825666428,
+ 0.004460844676941633,
+ -0.07226424664258957
+ ],
+ "min": [
+ 0.06761901825666428,
+ 0.004460844676941633,
+ -0.07226424664258957
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 352,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.21088102459907533,
+ -0.6243306398391724,
+ 0.7247719764709473,
+ -0.20111098885536198
+ ],
+ "min": [
+ 0.21088102459907533,
+ -0.6243306398391724,
+ 0.7247719764709473,
+ -0.20111098885536198
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 552,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000001192092896,
+ 0.9999995231628418,
+ 0.9999994039535524
+ ],
+ "min": [
+ 1.0000001192092896,
+ 0.9999995231628418,
+ 0.9999994039535524
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 96,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 576,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.0,
+ 0.2661122083663941,
+ 1.4901200273698124e-8
+ ],
+ "min": [
+ 0.0,
+ 0.2661122083663941,
+ 1.4901200273698124e-8
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 384,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.21115465462207798,
+ -0.298433005809784,
+ -0.04688597097992897,
+ -0.9295986890792848
+ ],
+ "min": [
+ 0.21115465462207798,
+ -0.298433005809784,
+ -0.04688597097992897,
+ -0.9295986890792848
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 600,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.000000238418579,
+ 1.0000005960464478,
+ 1.000001072883606
+ ],
+ "min": [
+ 1.000000238418579,
+ 1.0000005960464478,
+ 1.000001072883606
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 104,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 624,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.0,
+ 0.27582401037216189,
+ -1.862650034212265e-9
+ ],
+ "min": [
+ 0.0,
+ 0.27582401037216189,
+ -1.862650034212265e-9
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 416,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.8477678298950195,
+ -0.002281581750139594,
+ -0.006338704377412796,
+ -0.5303238034248352
+ ],
+ "min": [
+ 0.8477678298950195,
+ -0.002281581750139594,
+ -0.006338704377412796,
+ -0.5303238034248352
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 648,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0,
+ 0.999999225139618,
+ 0.9999995231628418
+ ],
+ "min": [
+ 1.0,
+ 0.999999225139618,
+ 0.9999995231628418
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 112,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 672,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.002346455818042159,
+ -0.06617335975170136,
+ 0.02785670943558216
+ ],
+ "min": [
+ -0.002346455818042159,
+ -0.06617335975170136,
+ 0.02785670943558216
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 448,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.02453553676605225,
+ -0.3199966251850128,
+ 0.9446002840995788,
+ 0.06878269463777542
+ ],
+ "min": [
+ 0.02453553676605225,
+ -0.3199966251850128,
+ 0.9446002840995788,
+ 0.06878269463777542
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 696,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.000000238418579,
+ 1.0000011920928956,
+ 1.0000007152557374
+ ],
+ "min": [
+ 1.000000238418579,
+ 1.0000011920928956,
+ 1.0000007152557374
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 120,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 720,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.06845720112323761,
+ 0.0044607738964259628,
+ -0.07147085666656494
+ ],
+ "min": [
+ -0.06845720112323761,
+ 0.0044607738964259628,
+ -0.07147085666656494
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 480,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.02340076118707657,
+ -0.6542634963989258,
+ 0.7544646263122559,
+ 0.04662882164120674
+ ],
+ "min": [
+ -0.02340076118707657,
+ -0.6542634963989258,
+ 0.7544646263122559,
+ 0.04662882164120674
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 744,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.9999995827674866,
+ 0.999999463558197,
+ 0.9999994039535524
+ ],
+ "min": [
+ 0.9999995827674866,
+ 0.999999463558197,
+ 0.9999994039535524
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 128,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 768,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 7.450579708745408e-9,
+ 0.2661122083663941,
+ 0.0
+ ],
+ "min": [
+ 7.450579708745408e-9,
+ 0.2661122083663941,
+ 0.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 512,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.2160616368055344,
+ 0.08108014613389969,
+ -0.010079950094223025,
+ -0.9729555249214172
+ ],
+ "min": [
+ 0.2160616368055344,
+ 0.08108014613389969,
+ -0.010079950094223025,
+ -0.9729555249214172
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 792,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0000009536743165,
+ 1.0000003576278689,
+ 1.0000008344650269
+ ],
+ "min": [
+ 1.0000009536743165,
+ 1.0000003576278689,
+ 1.0000008344650269
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 136,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 816,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 7.450579708745408e-9,
+ 0.27582401037216189,
+ -7.450579708745408e-9
+ ],
+ "min": [
+ 7.450579708745408e-9,
+ 0.27582401037216189,
+ -7.450579708745408e-9
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 544,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.8471664786338806,
+ -0.03204827755689621,
+ -0.02484037354588509,
+ -0.5297776460647583
+ ],
+ "min": [
+ 0.8471664786338806,
+ -0.03204827755689621,
+ -0.02484037354588509,
+ -0.5297776460647583
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 840,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.9999998211860656,
+ 1.000000238418579,
+ 0.9999992847442628
+ ],
+ "min": [
+ 0.9999998211860656,
+ 1.000000238418579,
+ 0.9999992847442628
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 144,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.25
+ ],
+ "min": [
+ 0.0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 864,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.001458517974242568,
+ -0.06619883328676224,
+ 0.027856720611453058
+ ],
+ "min": [
+ -0.001458517974242568,
+ -0.06619883328676224,
+ 0.027856720611453058
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 576,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ -0.03414175286889076,
+ -0.3191780745983124,
+ 0.9461711049079896,
+ -0.04146777093410492
+ ],
+ "min": [
+ -0.03414175286889076,
+ -0.3191780745983124,
+ 0.9461711049079896,
+ -0.04146777093410492
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 888,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 0.9999997615814208,
+ 0.9999996423721314,
+ 0.999999225139618
+ ],
+ "min": [
+ 0.9999997615814208,
+ 0.9999996423721314,
+ 0.999999225139618
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 7,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 19,
+ "max": [
+ 1.0,
+ 0.8915184140205383,
+ 0.7523466944694519,
+ 0.0,
+ 0.9980356097221376,
+ 0.9971227049827576,
+ 0.99999338388443,
+ 0.0,
+ 0.7819650173187256,
+ 0.9999932050704956,
+ 0.9971057176589966,
+ 0.0,
+ 0.10768280178308489,
+ 0.5968672037124634,
+ 0.998986840248108,
+ 1.0
+ ],
+ "min": [
+ -1.0,
+ -0.8915209174156189,
+ -0.4486669003963471,
+ 0.0,
+ -0.7738311886787415,
+ -0.993836224079132,
+ -0.9999718070030212,
+ 0.0,
+ -0.10048440098762512,
+ -0.9762102365493774,
+ -0.9998233914375304,
+ 0.0,
+ -0.7611464262008667,
+ -1.1929899454116822,
+ -1.0513299703598025,
+ 1.0
+ ],
+ "type": "MAT4"
+ }
+ ],
+ "materials": [
+ {
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.800000011920929,
+ 0.800000011920929,
+ 0.800000011920929,
+ 1.0
+ ],
+ "metallicFactor": 0.0
+ },
+ "emissiveFactor": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "name": "Default-effect"
+ }
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 20648,
+ "byteLength": 1536,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 17536,
+ "byteLength": 2960,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 8656,
+ "byteLength": 8880,
+ "byteStride": 12,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 1824,
+ "byteLength": 5920,
+ "byteStride": 16,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 20496,
+ "byteLength": 152
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 7744,
+ "byteLength": 912
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 1216,
+ "byteLength": 608
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 1216
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 22184,
+ "uri": "RiggedFigure0.bin"
+ }
+ ]
+}
diff --git a/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure0.bin b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure0.bin
new file mode 100644
index 000000000..121c6aa72
--- /dev/null
+++ b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedFigure/RiggedFigure0.bin
Binary files differ
diff --git a/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple.gltf b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple.gltf
new file mode 100644
index 000000000..ea3a4cb64
--- /dev/null
+++ b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple.gltf
@@ -0,0 +1,539 @@
+{
+ "asset": {
+ "generator": "COLLADA2GLTF",
+ "version": "2.0"
+ },
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 4,
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "mesh": 0,
+ "skin": 0
+ },
+ {
+ "children": [
+ 3
+ ],
+ "translation": [
+ 0.0,
+ -3.156060017772689e-7,
+ -4.1803297996521
+ ],
+ "rotation": [
+ -0.7047404050827026,
+ -0.0,
+ -0.0,
+ -0.7094652056694031
+ ],
+ "scale": [
+ 1.0,
+ 0.9999998807907105,
+ 0.9999998807907105
+ ]
+ },
+ {
+ "translation": [
+ 0.0,
+ 4.18717098236084,
+ 0.0
+ ],
+ "rotation": [
+ -0.0020521103870123626,
+ -9.94789530750495e-8,
+ -0.00029137087403796613,
+ -0.999997854232788
+ ],
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0000001192092896
+ ]
+ },
+ {
+ "children": [
+ 2
+ ]
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "JOINTS_0": 1,
+ "NORMAL": 2,
+ "POSITION": 3,
+ "WEIGHTS_0": 4
+ },
+ "indices": 0,
+ "mode": 4,
+ "material": 0
+ }
+ ],
+ "name": "Cylinder"
+ }
+ ],
+ "animations": [
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 2,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 2,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 2,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 5,
+ "interpolation": "LINEAR",
+ "output": 6
+ },
+ {
+ "input": 5,
+ "interpolation": "LINEAR",
+ "output": 7
+ },
+ {
+ "input": 5,
+ "interpolation": "LINEAR",
+ "output": 8
+ }
+ ]
+ },
+ {
+ "channels": [
+ {
+ "sampler": 0,
+ "target": {
+ "node": 3,
+ "path": "translation"
+ }
+ },
+ {
+ "sampler": 1,
+ "target": {
+ "node": 3,
+ "path": "rotation"
+ }
+ },
+ {
+ "sampler": 2,
+ "target": {
+ "node": 3,
+ "path": "scale"
+ }
+ }
+ ],
+ "samplers": [
+ {
+ "input": 9,
+ "interpolation": "LINEAR",
+ "output": 10
+ },
+ {
+ "input": 9,
+ "interpolation": "LINEAR",
+ "output": 11
+ },
+ {
+ "input": 9,
+ "interpolation": "LINEAR",
+ "output": 12
+ }
+ ]
+ }
+ ],
+ "skins": [
+ {
+ "inverseBindMatrices": 13,
+ "skeleton": 2,
+ "joints": [
+ 2,
+ 3
+ ],
+ "name": "Armature"
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 564,
+ "max": [
+ 95
+ ],
+ "min": [
+ 0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 96,
+ "max": [
+ 1,
+ 1,
+ 0,
+ 0
+ ],
+ "min": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 96,
+ "max": [
+ 0.998198390007019,
+ 0.998198390007019,
+ 0.6888381242752075
+ ],
+ "min": [
+ -0.998198390007019,
+ -0.998198390007019,
+ -0.644473135471344
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 1152,
+ "componentType": 5126,
+ "count": 96,
+ "max": [
+ 1.0,
+ 1.0,
+ 4.575077056884766
+ ],
+ "min": [
+ -1.0,
+ -0.9999995827674866,
+ -4.575077056884766
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 3,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 96,
+ "max": [
+ 1.0,
+ 0.261398196220398,
+ 0.0,
+ 0.0
+ ],
+ "min": [
+ 0.738601803779602,
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 2.083333015441895
+ ],
+ "min": [
+ 0.04166661947965622
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 0.0,
+ -3.156060017772689e-7,
+ -4.1803297996521
+ ],
+ "min": [
+ 0.0,
+ -3.156060017772689e-7,
+ -4.1803297996521
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ -0.7047404050827026,
+ -0.0,
+ -0.0,
+ -0.7094652056694031
+ ],
+ "min": [
+ -0.7047404050827026,
+ -0.0,
+ -0.0,
+ -0.7094652056694031
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 36,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 1.0,
+ 0.9999998807907105,
+ 0.9999998807907105
+ ],
+ "min": [
+ 1.0,
+ 0.9999998807907105,
+ 0.9999998807907105
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 4,
+ "byteOffset": 12,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 2.083333015441895
+ ],
+ "min": [
+ 0.04166661947965622
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 72,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 0.0,
+ 4.18717098236084,
+ 0.0
+ ],
+ "min": [
+ 0.0,
+ 4.18717098236084,
+ 0.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 6,
+ "byteOffset": 48,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 0.2933785021305084,
+ -9.94789530750495e-8,
+ -0.0002783441450446844,
+ -0.9559963345527648
+ ],
+ "min": [
+ -0.0020521103870123626,
+ -0.00008614854596089572,
+ -0.00029137087403796613,
+ -0.999997854232788
+ ],
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 5,
+ "byteOffset": 108,
+ "componentType": 5126,
+ "count": 3,
+ "max": [
+ 1.0,
+ 1.0,
+ 1.0000001192092896
+ ],
+ "min": [
+ 1.0,
+ 1.0,
+ 1.0000001192092896
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 7,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 2,
+ "max": [
+ 1.0,
+ 0.0,
+ 0.000001394809942212305,
+ 0.0,
+ 0.000002896920022976701,
+ 0.006681859027594328,
+ -0.9999778270721436,
+ 0.0,
+ 0.0005827349959872663,
+ 0.9999966025352478,
+ 0.006681739818304777,
+ 0.0,
+ 0.0,
+ 4.18023681640625,
+ 0.02795993909239769,
+ 1.0
+ ],
+ "min": [
+ 0.9999999403953552,
+ -0.0005827400018461049,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.002577662002295256,
+ -0.9999967217445374,
+ 0.0,
+ 0.0,
+ 0.999977707862854,
+ 0.002577601931989193,
+ 0.0,
+ -0.000004012620138382772,
+ -0.006818830035626888,
+ 0.027931740507483484,
+ 1.0
+ ],
+ "type": "MAT4"
+ }
+ ],
+ "materials": [
+ {
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.27963539958000185,
+ 0.6399999856948853,
+ 0.21094390749931336,
+ 1.0
+ ],
+ "metallicFactor": 0.0
+ },
+ "emissiveFactor": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "name": "Material_001-effect"
+ }
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 5000,
+ "byteLength": 1128,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 4208,
+ "byteLength": 768,
+ "byteStride": 8,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 1904,
+ "byteLength": 2304,
+ "byteStride": 12,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 224,
+ "byteLength": 1536,
+ "byteStride": 16,
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 4976,
+ "byteLength": 24
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 1760,
+ "byteLength": 144
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 128,
+ "byteLength": 96
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 128
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 6128,
+ "uri": "RiggedSimple0.bin"
+ }
+ ]
+}
diff --git a/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple0.bin b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple0.bin
new file mode 100644
index 000000000..ed24826b7
--- /dev/null
+++ b/examples/qt3d/exampleresources/assets/gltf/2.0/RiggedSimple/RiggedSimple0.bin
Binary files differ
diff --git a/examples/qt3d/exampleresources/envmaps.qrc b/examples/qt3d/exampleresources/envmaps.qrc
new file mode 100644
index 000000000..25bcea569
--- /dev/null
+++ b/examples/qt3d/exampleresources/envmaps.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>assets/envmaps/cedar-bridge/cedar_bridge_irradiance.dds</file>
+ <file>assets/envmaps/cedar-bridge/cedar_bridge_specular.dds</file>
+ </qresource>
+</RCC>
diff --git a/examples/qt3d/exampleresources/gltf.qrc b/examples/qt3d/exampleresources/gltf.qrc
index 869fb16dc..aa9a994a1 100644
--- a/examples/qt3d/exampleresources/gltf.qrc
+++ b/examples/qt3d/exampleresources/gltf.qrc
@@ -14,5 +14,9 @@
<file>assets/gltf/wine/wine1VS.glsl</file>
<file>assets/gltf/wine/wine3FS.glsl</file>
<file>assets/gltf/wine/wine3VS.glsl</file>
+ <file>assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf</file>
+ <file>assets/gltf/2.0/RiggedFigure/RiggedFigure0.bin</file>
+ <file>assets/gltf/2.0/RiggedSimple/RiggedSimple.gltf</file>
+ <file>assets/gltf/2.0/RiggedSimple/RiggedSimple0.bin</file>
</qresource>
</RCC>
diff --git a/examples/qt3d/phong-cubes/CubeEntity.qml b/examples/qt3d/phong-cubes/CubeEntity.qml
new file mode 100644
index 000000000..558f53327
--- /dev/null
+++ b/examples/qt3d/phong-cubes/CubeEntity.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.0 as Quick
+import Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ id: root
+ property vector3d position: Qt.vector3d()
+ property Material material
+
+ components: [mesh, material, transform]
+
+ CuboidMesh {
+ id: mesh
+ xExtent: 0.5
+ yExtent: xExtent
+ zExtent: xExtent
+ }
+
+ Transform {
+ id: transform
+ translation: root.position
+ rotationZ: 45
+
+ Quick.NumberAnimation on rotationY {
+ from: 0; to: 360
+ loops: Quick.Animation.Infinite
+ duration: 5000
+ }
+ }
+}
diff --git a/examples/qt3d/phong-cubes/main.cpp b/examples/qt3d/phong-cubes/main.cpp
new file mode 100644
index 000000000..dba6e0bff
--- /dev/null
+++ b/examples/qt3d/phong-cubes/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+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();
+}
diff --git a/examples/qt3d/phong-cubes/main.qml b/examples/qt3d/phong-cubes/main.qml
new file mode 100644
index 000000000..311e65a63
--- /dev/null
+++ b/examples/qt3d/phong-cubes/main.qml
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.Input 2.0
+import Qt3D.Extras 2.10
+import QtQuick 2.0
+
+Entity {
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ clearColor: "white"
+ camera: mainCamera
+ }
+ },
+ InputSettings { }
+ ]
+
+ Camera {
+ id: mainCamera
+ position: Qt.vector3d(0.0, 0.0, 7.0)
+ upVector: Qt.vector3d(0.0, 1.0, 0.0)
+ viewCenter: Qt.vector3d(0.0, 0.0, 0.0)
+ }
+
+ FirstPersonCameraController {
+ camera: mainCamera
+ }
+
+ Entity {
+ components: [
+ PointLight {},
+ Transform { translation: mainCamera.position }
+ ]
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(-1, 1, 0)
+ material: DiffuseSpecularMaterial {}
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(0, 1, 0)
+ material: DiffuseSpecularMaterial {
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(1, 1, 0)
+ material: DiffuseSpecularMaterial {
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" }
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(-1, 0, 0)
+ material: DiffuseSpecularMaterial {
+ alphaBlending: true
+ diffuse: Qt.rgba(0.7, 0.7, 0.7, 0.5)
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(0, 0, 0)
+ material: DiffuseSpecularMaterial {
+ normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" }
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(1, 0, 0)
+ material: DiffuseSpecularMaterial {
+ alphaBlending: true
+ normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" }
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(-1, -1, 0)
+ material: DiffuseSpecularMaterial {
+ normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" }
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" }
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(0, -1, 0)
+ material: DiffuseSpecularMaterial {
+ normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" }
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" }
+ }
+ }
+
+ CubeEntity {
+ position: Qt.vector3d(1, -1, 0)
+ material: DiffuseSpecularMaterial {
+ normal: TextureLoader { source: "qrc:/assets/textures/pattern_09/normal.webp" }
+ diffuse: TextureLoader { source: "qrc:/assets/textures/pattern_09/diffuse.webp" }
+ specular: TextureLoader { source: "qrc:/assets/textures/pattern_09/specular.webp" }
+ }
+ }
+}
diff --git a/examples/qt3d/phong-cubes/phong-cubes.pro b/examples/qt3d/phong-cubes/phong-cubes.pro
new file mode 100644
index 000000000..e099b336d
--- /dev/null
+++ b/examples/qt3d/phong-cubes/phong-cubes.pro
@@ -0,0 +1,18 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCE += main.cpp
+
+QT += qml quick 3dcore 3drender 3dinput 3dquick 3dquickextras
+
+OTHER_FILES += \
+ main.qml \
+ CubeEntity.qml
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += \
+ phong-cubes.qrc \
+ ../exampleresources/textures.qrc
diff --git a/examples/qt3d/phong-cubes/phong-cubes.qrc b/examples/qt3d/phong-cubes/phong-cubes.qrc
new file mode 100644
index 000000000..84cec1121
--- /dev/null
+++ b/examples/qt3d/phong-cubes/phong-cubes.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>CubeEntity.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/qt3d/planets-qml/PlanetMaterial.qml b/examples/qt3d/planets-qml/PlanetMaterial.qml
index 4d50aee8d..309acf24d 100644
--- a/examples/qt3d/planets-qml/PlanetMaterial.qml
+++ b/examples/qt3d/planets-qml/PlanetMaterial.qml
@@ -115,7 +115,8 @@ Material {
TextureImage {
id: specularTextureImage
// Get rid of runtime warnings. It's safe, as the texture just isn't used
- source: specularMap !== "" ? specularMap : "qrc:/images/uranusmap.jpg"
+ source: specularMap !== "" ? specularMap
+ : "qrc:/images/solarsystemscope/uranusmap.jpg"
}
}
},
@@ -133,7 +134,8 @@ Material {
TextureImage {
id: normalTextureImage
// Get rid of runtime warnings. It's safe, as the texture just isn't used
- source: normalMap !== "" ? normalMap : "qrc:/images/uranusmap.jpg"
+ source: normalMap !== "" ? normalMap
+ : "qrc:/images/solarsystemscope/uranusmap.jpg"
}
}
},
diff --git a/examples/qt3d/planets-qml/SolarSystem.qml b/examples/qt3d/planets-qml/SolarSystem.qml
index f9353d6dc..8c0cfccd4 100644
--- a/examples/qt3d/planets-qml/SolarSystem.qml
+++ b/examples/qt3d/planets-qml/SolarSystem.qml
@@ -395,7 +395,10 @@ Entity {
var v = Math.atan2(yv, xv)
// Calculate the distance (radius)
- var r = Math.sqrt(xv * xv + yv * yv)
+ // TODO: Math.hypot() is ES6 and QML JS is only ES5 currently. A patch to QtQml is
+ // required to get Math.hypot() to work.
+ //var r = Math.hypot(xv, yv)
+ var r = Math.sqrt(Math.pow(xv, 2) + Math.pow(yv, 2))
// From http://www.davidcolarusso.com/astro/
// Modified to compensate for the right handed coordinate system of OpenGL
diff --git a/examples/qt3d/planets-qml/images/solarsystemscope/qt_attribution.json b/examples/qt3d/planets-qml/images/solarsystemscope/qt_attribution.json
index 35e9afe39..9d32e541d 100644
--- a/examples/qt3d/planets-qml/images/solarsystemscope/qt_attribution.json
+++ b/examples/qt3d/planets-qml/images/solarsystemscope/qt_attribution.json
@@ -6,7 +6,7 @@
"Description": "Solar System Scope provides high quality, free to use textures for objects in the solar system.",
"QtUsage": "Used in Qt 3D planets-qml example.",
- "Homepage": "www.solarsystemscope.com/textures",
+ "Homepage": "https://www.solarsystemscope.com/textures",
"License": "Creative Commons Attribution 4.0",
"LicenseId": "CC-BY-4.0",
"LicenseFile": "license.txt",
diff --git a/examples/qt3d/qt3d.pro b/examples/qt3d/qt3d.pro
index 7ac55bfd2..74049b129 100644
--- a/examples/qt3d/qt3d.pro
+++ b/examples/qt3d/qt3d.pro
@@ -20,7 +20,8 @@ SUBDIRS += \
qardboard \
advancedcustommaterial \
simplecustommaterial \
- scene2d
+ scene2d \
+ phong-cubes
qtHaveModule(multimedia): SUBDIRS += audio-visualizer-qml
diff --git a/examples/qt3d/scene2d/main.qml b/examples/qt3d/scene2d/main.qml
index 35b8f3eb6..ceaac3b34 100644
--- a/examples/qt3d/scene2d/main.qml
+++ b/examples/qt3d/scene2d/main.qml
@@ -97,10 +97,10 @@ Entity {
PhongMaterial {
id: logoMaterial
- ambient: Qt.rgba( logoControls.colorR/255,
+ diffuse: Qt.rgba( logoControls.colorR/255,
logoControls.colorG/255,
logoControls.colorB/255, 1.0 )
- diffuse: Qt.rgba( 0.1, 0.1, 0.1, 0.5 )
+ ambient: Qt.rgba( 0.1, 0.1, 0.1, 1.0 )
shininess: logoControls.shininess
}
diff --git a/examples/qt3d/wave/shaders/ribbon.vert b/examples/qt3d/wave/shaders/ribbon.vert
index e099d53c8..2ff9d2729 100644
--- a/examples/qt3d/wave/shaders/ribbon.vert
+++ b/examples/qt3d/wave/shaders/ribbon.vert
@@ -111,7 +111,7 @@ float snoise(vec3 v)
float height( const in vec3 pos )
{
// Perturb the y position by a wave function in (x, t)
- const float twoPi = 2.0 * 3.14159;
+ const float twoPi = 2.0 * 3.14159265358979323846;
float k = twoPi / lambda;
float omega = twoPi / period;
diff --git a/src/animation/backend/animationclip.cpp b/src/animation/backend/animationclip.cpp
index a7cec8343..e8f8f4552 100644
--- a/src/animation/backend/animationclip.cpp
+++ b/src/animation/backend/animationclip.cpp
@@ -41,6 +41,7 @@
#include <Qt3DAnimation/private/qanimationcliploader_p.h>
#include <Qt3DAnimation/private/animationlogging_p.h>
#include <Qt3DAnimation/private/managers_p.h>
+#include <Qt3DAnimation/private/gltfimporter_p.h>
#include <Qt3DRender/private/qurlhelper_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
@@ -209,28 +210,43 @@ void AnimationClip::loadAnimationFromUrl()
return;
}
- QByteArray animationData = file.readAll();
- QJsonDocument document = QJsonDocument::fromJson(animationData);
- QJsonObject rootObject = document.object();
-
- // TODO: Allow loading of a named animation from a file containing many
- QJsonArray animationsArray = rootObject[QLatin1String("animations")].toArray();
- qCDebug(Jobs) << "Found" << animationsArray.size() << "animations:";
- for (int i = 0; i < animationsArray.size(); ++i) {
- QJsonObject animation = animationsArray.at(i).toObject();
- qCDebug(Jobs) << "Animation Name:" << animation[QLatin1String("animationName")].toString();
- }
+ // TODO: Convert to plugins
+ // Load glTF or "native"
+ if (filePath.endsWith(QLatin1String("gltf"))) {
+ qCDebug(Jobs) << "Loading glTF animation from" << filePath;
+ GLTFImporter gltf;
+ gltf.load(&file);
+ // TODO: Allow loading of a named animation from a file containing many
+ m_name = gltf.animations().first().name;
+ m_channels = gltf.createAnimationData();
+ } else if (filePath.endsWith(QLatin1String("json"))) {
+ // Native format
+ QByteArray animationData = file.readAll();
+ QJsonDocument document = QJsonDocument::fromJson(animationData);
+ QJsonObject rootObject = document.object();
+
+ // TODO: Allow loading of a named animation from a file containing many
+ QJsonArray animationsArray = rootObject[QLatin1String("animations")].toArray();
+ qCDebug(Jobs) << "Found" << animationsArray.size() << "animations:";
+ for (int i = 0; i < animationsArray.size(); ++i) {
+ QJsonObject animation = animationsArray.at(i).toObject();
+ qCDebug(Jobs) << "Animation Name:" << animation[QLatin1String("animationName")].toString();
+ }
- // For now just load the first animation
- // TODO: Allow loading a named animation from within the file analogous to QMesh
- QJsonObject animation = animationsArray.at(0).toObject();
- m_name = animation[QLatin1String("animationName")].toString();
- QJsonArray channelsArray = animation[QLatin1String("channels")].toArray();
- const int channelCount = channelsArray.size();
- m_channels.resize(channelCount);
- for (int i = 0; i < channelCount; ++i) {
- const QJsonObject group = channelsArray.at(i).toObject();
- m_channels[i].read(group);
+ // For now just load the first animation
+ // TODO: Allow loading a named animation from within the file analogous to QMesh
+ QJsonObject animation = animationsArray.at(0).toObject();
+ m_name = animation[QLatin1String("animationName")].toString();
+ QJsonArray channelsArray = animation[QLatin1String("channels")].toArray();
+ const int channelCount = channelsArray.size();
+ m_channels.resize(channelCount);
+ for (int i = 0; i < channelCount; ++i) {
+ const QJsonObject group = channelsArray.at(i).toObject();
+ m_channels[i].read(group);
+ }
+ } else {
+ qWarning() << "Unknown animation clip type. Please use json or glTF 2.0";
+ setStatus(QAnimationClipLoader::Error);
}
}
@@ -270,12 +286,14 @@ void AnimationClip::setDuration(float duration)
notifyObservers(e);
}
-int AnimationClip::channelIndex(const QString &channelName) const
+int AnimationClip::channelIndex(const QString &channelName, int jointIndex) const
{
const int channelCount = m_channels.size();
for (int i = 0; i < channelCount; ++i) {
- if (m_channels[i].name == channelName)
+ if (m_channels[i].name == channelName
+ && (jointIndex == -1 || m_channels[i].jointIndex == jointIndex)) {
return i;
+ }
}
return -1;
}
diff --git a/src/animation/backend/animationclip_p.h b/src/animation/backend/animationclip_p.h
index 7570c76ce..9eb94d45e 100644
--- a/src/animation/backend/animationclip_p.h
+++ b/src/animation/backend/animationclip_p.h
@@ -84,7 +84,7 @@ public:
void loadAnimation();
void setDuration(float duration);
float duration() const { return m_duration; }
- int channelIndex(const QString &channelName) const;
+ int channelIndex(const QString &channelName, int jointIndex) const;
int channelCount() const { return m_channelComponentCount; }
int channelComponentBaseIndex(int channelGroupIndex) const;
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp
index 8308fab34..fb5b19a5d 100644
--- a/src/animation/backend/animationutils.cpp
+++ b/src/animation/backend/animationutils.cpp
@@ -48,6 +48,7 @@
#include <QtGui/qquaternion.h>
#include <QtGui/qcolor.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qvarlengtharray.h>
#include <Qt3DAnimation/private/animationlogging_p.h>
#include <numeric>
@@ -92,22 +93,26 @@ ClipEvaluationData evaluationDataForClip(AnimationClip *clip,
{
// global time values expected in seconds
ClipEvaluationData result;
- result.localTime = localTimeFromGlobalTime(animatorData.globalTime, animatorData.startTime,
- animatorData.playbackRate, clip->duration(),
- animatorData.loopCount, result.currentLoop);
+ result.currentLoop = animatorData.currentLoop;
+ result.localTime = localTimeFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime,
+ animatorData.playbackRate, clip->duration(),
+ animatorData.loopCount, result.currentLoop);
result.isFinalFrame = isFinalFrame(result.localTime, clip->duration(),
result.currentLoop, animatorData.loopCount);
return result;
}
-double localTimeFromGlobalTime(double t_global,
- double t_start_global,
- double playbackRate,
- double duration,
- int loopCount,
- int &currentLoop)
+double localTimeFromElapsedTime(double t_current_local,
+ double t_elapsed_global,
+ double playbackRate,
+ double duration,
+ int loopCount,
+ int &currentLoop)
{
- double t_local = playbackRate * (t_global - t_start_global);
+ // Calculate the new local time.
+ // playhead + rate * dt
+ // where playhead is completed loops * duration + current loop local time
+ double t_local = currentLoop * duration + t_current_local + playbackRate * t_elapsed_global;
double loopNumber = 0;
if (loopCount == 1) {
t_local = qBound(0.0, t_local, duration);
@@ -122,28 +127,30 @@ double localTimeFromGlobalTime(double t_global,
t_local = std::fmod(t_local, duration);
// Ensure we clamp to end of final loop
- if (loopNumber == loopCount) {
+ if (int(loopNumber) == loopCount) {
loopNumber = loopCount - 1;
t_local = duration;
}
}
- qCDebug(Jobs) << "t_global - t_start =" << t_global - t_start_global
- << "current loop =" << loopNumber
+ qCDebug(Jobs) << "current loop =" << loopNumber
<< "t =" << t_local
<< "duration =" << duration;
- currentLoop = loopNumber;
+ currentLoop = int(loopNumber);
return t_local;
}
-double phaseFromGlobalTime(double t_global, double t_start_global,
- double playbackRate, double duration,
- int loopCount, int &currentLoop)
+double phaseFromElapsedTime(double t_current_local,
+ double t_elapsed_global,
+ double playbackRate,
+ double duration,
+ int loopCount,
+ int &currentLoop)
{
- const double t_local = localTimeFromGlobalTime(t_global, t_start_global, playbackRate,
- duration, loopCount, currentLoop);
+ const double t_local = localTimeFromElapsedTime(t_current_local, t_elapsed_global, playbackRate,
+ duration, loopCount, currentLoop);
return t_local / duration;
}
@@ -252,83 +259,126 @@ ClipResults evaluateClipAtPhase(AnimationClip *clip, float phase)
return evaluateClipAtLocalTime(clip, localTime);
}
+QVariant buildPropertyValue(const MappingData &mappingData, const QVector<float> &channelResults)
+{
+ QVariant v;
+
+ switch (mappingData.type) {
+ case QMetaType::Float:
+ case QVariant::Double: {
+ v = QVariant::fromValue(channelResults[mappingData.channelIndices[0]]);
+ break;
+ }
+
+ case QVariant::Vector2D: {
+ const QVector2D vector(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]]);
+ v = QVariant::fromValue(vector);
+ break;
+ }
+
+ case QVariant::Vector3D: {
+ const QVector3D vector(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]]);
+ v = QVariant::fromValue(vector);
+ break;
+ }
+
+ case QVariant::Vector4D: {
+ const QVector4D vector(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]],
+ channelResults[mappingData.channelIndices[3]]);
+ v = QVariant::fromValue(vector);
+ break;
+ }
+
+ case QVariant::Quaternion: {
+ QQuaternion q(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]],
+ channelResults[mappingData.channelIndices[3]]);
+ q.normalize();
+ v = QVariant::fromValue(q);
+ break;
+ }
+
+ case QVariant::Color: {
+ const QColor color = QColor::fromRgbF(channelResults[mappingData.channelIndices[0]],
+ channelResults[mappingData.channelIndices[1]],
+ channelResults[mappingData.channelIndices[2]]);
+ v = QVariant::fromValue(color);
+ break;
+ }
+
+ default:
+ qWarning() << "Unhandled animation type" << mappingData.type;
+ break;
+ }
+
+ return v;
+}
+
QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
const QVector<MappingData> &mappingDataVec,
const QVector<float> &channelResults,
bool finalFrame)
{
QVector<Qt3DCore::QSceneChangePtr> changes;
+ QVarLengthArray<Skeleton *, 4> dirtySkeletons;
+
// Iterate over the mappings
for (const MappingData &mappingData : mappingDataVec) {
- // Construct a property update change, set target, property and delivery options
- auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(mappingData.targetId);
- e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
- e->setPropertyName(mappingData.propertyName);
-
- // Handle intermediate updates vs final flag properly
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isIntermediate = !finalFrame;
+ if (!mappingData.propertyName)
+ continue;
// Build the new value from the channel/fcurve evaluation results
- QVariant v;
- switch (mappingData.type) {
- case QMetaType::Float:
- case QVariant::Double: {
- v = QVariant::fromValue(channelResults[mappingData.channelIndices[0]]);
- break;
- }
-
- case QVariant::Vector2D: {
- const QVector2D vector(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]]);
- v = QVariant::fromValue(vector);
- break;
- }
-
- case QVariant::Vector3D: {
- const QVector3D vector(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]]);
- v = QVariant::fromValue(vector);
- break;
- }
-
- case QVariant::Vector4D: {
- const QVector4D vector(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]],
- channelResults[mappingData.channelIndices[3]]);
- v = QVariant::fromValue(vector);
- break;
- }
-
- case QVariant::Quaternion: {
- QQuaternion q(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]],
- channelResults[mappingData.channelIndices[3]]);
- q.normalize();
- v = QVariant::fromValue(q);
- break;
- }
-
- case QVariant::Color: {
- const QColor color = QColor::fromRgbF(channelResults[mappingData.channelIndices[0]],
- channelResults[mappingData.channelIndices[1]],
- channelResults[mappingData.channelIndices[2]]);
- v = QVariant::fromValue(color);
- break;
- }
-
- default:
- qWarning() << "Unhandled animation type";
+ const QVariant v = buildPropertyValue(mappingData, channelResults);
+ if (!v.isValid())
continue;
- }
- // Assign new value and send
- e->setValue(v);
- changes.push_back(e);
+ // TODO: Avoid wrapping joint transform components up in a variant, just
+ // to immediately unwrap them again. Refactor buildPropertyValue() to call
+ // helper functions that we can call directly here for joints.
+ if (mappingData.skeleton && mappingData.jointIndex != -1) {
+ // Remember that this skeleton is dirty. We will ask each dirty skeleton
+ // to send its set of local poses to observers below.
+ if (!dirtySkeletons.contains(mappingData.skeleton))
+ dirtySkeletons.push_back(mappingData.skeleton);
+
+ switch (mappingData.jointTransformComponent) {
+ case MappingData::Scale:
+ mappingData.skeleton->setJointScale(mappingData.jointIndex, v.value<QVector3D>());
+ break;
+
+ case MappingData::Rotation:
+ mappingData.skeleton->setJointRotation(mappingData.jointIndex, v.value<QQuaternion>());
+ break;
+
+ case MappingData::Translation:
+ mappingData.skeleton->setJointTranslation(mappingData.jointIndex, v.value<QVector3D>());
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ } else {
+ // Construct a property update change, set target, property and delivery options
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(mappingData.targetId);
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName(mappingData.propertyName);
+ // Handle intermediate updates vs final flag properly
+ Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isIntermediate = !finalFrame;
+ // Assign new value and send
+ e->setValue(v);
+ changes.push_back(e);
+ }
}
+ for (const auto skeleton : dirtySkeletons)
+ skeleton->sendLocalPoses();
// If it's the final frame, notify the frontend that we've stopped
if (finalFrame) {
@@ -341,34 +391,142 @@ QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId anim
return changes;
}
+QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec,
+ const QVector<float> &channelResults)
+{
+ QVector<AnimationCallbackAndValue> callbacks;
+ for (const MappingData &mappingData : mappingDataVec) {
+ if (!mappingData.callback)
+ continue;
+ const QVariant v = buildPropertyValue(mappingData, channelResults);
+ if (v.isValid()) {
+ AnimationCallbackAndValue callback;
+ callback.callback = mappingData.callback;
+ callback.flags = mappingData.callbackFlags;
+ callback.value = v;
+ callbacks.append(callback);
+ }
+ }
+ return callbacks;
+}
+
+// TODO: Optimize this even more by combining the work done here with the functions:
+// buildRequiredChannelsAndTypes() and assignChannelComponentIndices(). We are
+// currently repeating the iteration over mappings and extracting/generating
+// channel names, types and joint indices.
QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping*> &channelMappings,
const QVector<ChannelNameAndType> &channelNamesAndTypes,
const QVector<ComponentIndices> &channelComponentIndices)
{
+ // Accumulate the required number of mappings
+ int maxMappingDatas = 0;
+ for (const auto mapping : channelMappings) {
+ switch (mapping->mappingType()) {
+ case ChannelMapping::ChannelMappingType:
+ case ChannelMapping::CallbackMappingType:
+ ++maxMappingDatas;
+ break;
+
+ case ChannelMapping::SkeletonMappingType: {
+ Skeleton *skeleton = mapping->skeleton();
+ maxMappingDatas += 3 * skeleton->jointCount(); // S, R, T
+ break;
+ }
+ }
+ }
QVector<MappingData> mappingDataVec;
- mappingDataVec.reserve(channelMappings.size());
+ mappingDataVec.reserve(maxMappingDatas);
// Iterate over the mappings
for (const auto mapping : channelMappings) {
- // Populate the data we need, easy stuff first
- MappingData mappingData;
- mappingData.targetId = mapping->targetId();
- mappingData.propertyName = mapping->propertyName();
- mappingData.type = mapping->type();
-
- if (mappingData.type == static_cast<int>(QVariant::Invalid)) {
- qWarning() << "Unknown type for node id =" << mappingData.targetId
- << "and property =" << mapping->property();
- continue;
+ switch (mapping->mappingType()) {
+ case ChannelMapping::ChannelMappingType:
+ case ChannelMapping::CallbackMappingType: {
+ // Populate the data we need, easy stuff first
+ MappingData mappingData;
+ mappingData.targetId = mapping->targetId();
+ mappingData.propertyName = mapping->propertyName();
+ mappingData.type = mapping->type();
+ mappingData.callback = mapping->callback();
+ mappingData.callbackFlags = mapping->callbackFlags();
+
+ if (mappingData.type == static_cast<int>(QVariant::Invalid)) {
+ qWarning() << "Unknown type for node id =" << mappingData.targetId
+ << "and property =" << mapping->property()
+ << "and callback =" << mapping->callback();
+ continue;
+ }
+
+ // Try to find matching channel name and type
+ const ChannelNameAndType nameAndType = { mapping->channelName(), mapping->type() };
+ const int index = channelNamesAndTypes.indexOf(nameAndType);
+ if (index != -1) {
+ // Do we have any animation data for this channel? If not, don't bother
+ // adding a mapping for it.
+ if (channelComponentIndices[index].isEmpty())
+ continue;
+
+ // We got one!
+ mappingData.channelIndices = channelComponentIndices[index];
+ mappingDataVec.push_back(mappingData);
+ }
+ break;
}
- // Try to find matching channel name and type
- const ChannelNameAndType nameAndType = { mapping->channelName(), mapping->type() };
- const int index = channelNamesAndTypes.indexOf(nameAndType);
- if (index != -1) {
- // We got one!
- mappingData.channelIndices = channelComponentIndices[index];
- mappingDataVec.push_back(mappingData);
+ case ChannelMapping::SkeletonMappingType: {
+ const QVector<ChannelNameAndType> jointProperties
+ = { { QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) },
+ { QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) },
+ { QLatin1String("Scale"), static_cast<int>(QVariant::Vector3D) } };
+ const QHash<QString, const char *> channelNameToPropertyName
+ = { { QLatin1String("Location"), "translation" },
+ { QLatin1String("Rotation"), "rotation" },
+ { QLatin1String("Scale"), "scale" } };
+ Skeleton *skeleton = mapping->skeleton();
+ const int jointCount = skeleton->jointCount();
+ for (int jointIndex = 0; jointIndex < jointCount; ++jointIndex) {
+ // Populate the data we need, easy stuff first
+ MappingData mappingData;
+ mappingData.targetId = mapping->skeletonId();
+ mappingData.skeleton = mapping->skeleton();
+
+ const int propertyCount = jointProperties.size();
+ for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex) {
+ // Get the name, type and index
+ ChannelNameAndType nameAndType = jointProperties[propertyIndex];
+ nameAndType.jointIndex = jointIndex;
+
+ // Try to find matching channel name and type
+ const int index = channelNamesAndTypes.indexOf(nameAndType);
+
+ // Do we have any animation data for this channel? If not, don't bother
+ // adding a mapping for it.
+ if (channelComponentIndices[index].isEmpty())
+ continue;
+
+ if (index != -1) {
+ // We got one!
+ mappingData.propertyName = channelNameToPropertyName[nameAndType.name];
+ mappingData.type = nameAndType.type;
+ mappingData.channelIndices = channelComponentIndices[index];
+ mappingData.jointIndex = jointIndex;
+
+ // Convert property name for joint transform components to
+ // an enumerated type so we can avoid the string comparisons
+ // when sending the change events after evaluation.
+ if (qstrcmp(mappingData.propertyName, "scale") == 0)
+ mappingData.jointTransformComponent = MappingData::Scale;
+ else if (qstrcmp(mappingData.propertyName, "rotation") == 0)
+ mappingData.jointTransformComponent = MappingData::Rotation;
+ else if (qstrcmp(mappingData.propertyName, "translation") == 0)
+ mappingData.jointTransformComponent = MappingData::Translation;
+
+ mappingDataVec.push_back(mappingData);
+ }
+ }
+ }
+ break;
+ }
}
}
@@ -395,12 +553,44 @@ QVector<ChannelNameAndType> buildRequiredChannelsAndTypes(Handler *handler,
ChannelMapping *mapping = mappingManager->lookupResource(mappingId);
Q_ASSERT(mapping);
- // Get the name and type
- const ChannelNameAndType nameAndType{ mapping->channelName(), mapping->type() };
+ switch (mapping->mappingType()) {
+ case ChannelMapping::ChannelMappingType:
+ case ChannelMapping::CallbackMappingType: {
+ // Get the name and type
+ const ChannelNameAndType nameAndType{ mapping->channelName(), mapping->type() };
+
+ // Add if not already contained
+ if (!namesAndTypes.contains(nameAndType))
+ namesAndTypes.push_back(nameAndType);
+
+ break;
+ }
- // Add if not already contained
- if (!namesAndTypes.contains(nameAndType))
- namesAndTypes.push_back(nameAndType);
+ case ChannelMapping::SkeletonMappingType: {
+ // Add an entry for each scale/rotation/translation property of each joint index
+ // of the target skeleton.
+ const QVector<ChannelNameAndType> jointProperties
+ = { { QLatin1String("Location"), static_cast<int>(QVariant::Vector3D) },
+ { QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion) },
+ { QLatin1String("Scale"), static_cast<int>(QVariant::Vector3D) } };
+ Skeleton *skeleton = handler->skeletonManager()->lookupResource(mapping->skeletonId());
+ const int jointCount = skeleton->jointCount();
+ for (int jointIndex = 0; jointIndex < jointCount; ++jointIndex) {
+ const int propertyCount = jointProperties.size();
+ for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex) {
+ // Get the name, type and index
+ ChannelNameAndType nameAndType = jointProperties[propertyIndex];
+ nameAndType.jointIndex = jointIndex;
+
+ // Add if not already contained
+ if (!namesAndTypes.contains(nameAndType))
+ namesAndTypes.push_back(nameAndType);
+ }
+ }
+
+ break;
+ }
+ }
}
return namesAndTypes;
@@ -467,7 +657,7 @@ QVector<Qt3DCore::QNodeId> gatherValueNodesToEvaluate(Handler *handler,
}
ComponentIndices generateClipFormatIndices(const QVector<ChannelNameAndType> &targetChannels,
- const QVector<ComponentIndices> &targetIndices,
+ QVector<ComponentIndices> &targetIndices,
const AnimationClip *clip)
{
Q_ASSERT(targetChannels.size() == targetIndices.size());
@@ -485,7 +675,8 @@ ComponentIndices generateClipFormatIndices(const QVector<ChannelNameAndType> &ta
for (int i = 0; i < channelCount; ++i) {
// Find the index of the channel from the clip
const ChannelNameAndType &targetChannel = targetChannels[i];
- const int clipChannelIndex = clip->channelIndex(targetChannel.name);
+ const int clipChannelIndex = clip->channelIndex(targetChannel.name,
+ targetChannel.jointIndex);
const int componentCount = targetIndices[i].size();
if (clipChannelIndex != -1) {
@@ -501,6 +692,7 @@ ComponentIndices generateClipFormatIndices(const QVector<ChannelNameAndType> &ta
// No such channel in this clip. We'll use default values when
// mapping from the clip to the formatted clip results.
std::fill(formatIt, formatIt + componentCount, -1);
+ targetIndices[i].clear();
}
formatIt += componentCount;
diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h
index c702ab5c4..d8127d8af 100644
--- a/src/animation/backend/animationutils_p.h
+++ b/src/animation/backend/animationutils_p.h
@@ -49,12 +49,17 @@
//
#include <Qt3DAnimation/private/qt3danimation_global_p.h>
+#include <Qt3DAnimation/private/clock_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
#include <Qt3DCore/qnodeid.h>
#include <Qt3DCore/qscenechange.h>
+#include <QtCore/qdebug.h>
+
QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
+class QAnimationCallback;
namespace Animation {
struct Channel;
@@ -68,17 +73,43 @@ typedef QVector<int> ComponentIndices;
struct MappingData
{
+ enum JointTransformComponent {
+ NoTransformComponent = 0,
+ Scale,
+ Rotation,
+ Translation
+ };
+
Qt3DCore::QNodeId targetId;
+ Skeleton *skeleton = nullptr;
+ int jointIndex = -1;
+ JointTransformComponent jointTransformComponent = NoTransformComponent;
const char *propertyName;
+ QAnimationCallback *callback = nullptr;
+ QAnimationCallback::Flags callbackFlags;
int type;
ComponentIndices channelIndices;
};
+#ifndef QT_NO_DEBUG_STREAM
+inline QDebug operator<<(QDebug dbg, const MappingData &mapping)
+{
+ QDebugStateSaver saver(dbg);
+ dbg << "targetId =" << mapping.targetId << endl
+ << "jointIndex =" << mapping.jointIndex << endl
+ << "jointTransformComponent: " << mapping.jointTransformComponent << endl
+ << "propertyName:" << mapping.propertyName << endl
+ << "channelIndices:" << mapping.channelIndices;
+ return dbg;
+}
+#endif
+
struct AnimatorEvaluationData
{
- double globalTime;
- double startTime;
+ double elapsedTime;
+ double currentTime;
int loopCount;
+ int currentLoop;
double playbackRate;
};
@@ -95,22 +126,47 @@ struct ChannelNameAndType
{
QString name;
int type;
+ int jointIndex;
+
+ static const int invalidIndex = -1;
+
+ ChannelNameAndType()
+ : name()
+ , type(-1)
+ , jointIndex(-1)
+ {}
+
+ ChannelNameAndType(const QString &_name, int _type, int _jointIndex = invalidIndex)
+ : name(_name)
+ , type(_type)
+ , jointIndex(_jointIndex)
+ {}
bool operator==(const ChannelNameAndType &rhs) const
{
- return name == rhs.name && type == rhs.type;
+ return name == rhs.name
+ && type == rhs.type
+ && jointIndex == rhs.jointIndex;
}
};
+struct AnimationCallbackAndValue
+{
+ QAnimationCallback *callback;
+ QAnimationCallback::Flags flags;
+ QVariant value;
+};
+
template<typename Animator>
-AnimatorEvaluationData evaluationDataForAnimator(Animator animator, qint64 globalTime)
+AnimatorEvaluationData evaluationDataForAnimator(Animator animator, Clock* clock, qint64 nsSincePreviousFrame)
{
AnimatorEvaluationData data;
data.loopCount = animator->loops();
- data.playbackRate = 1.0; // should be a property on the animator
+ data.currentLoop = animator->currentLoop();
+ data.playbackRate = clock != nullptr ? clock->playbackRate() : 1.0;
// Convert global time from nsec to sec
- data.startTime = double(animator->startTime()) / 1.0e9;
- data.globalTime = double(globalTime) / 1.0e9;
+ data.elapsedTime = double(nsSincePreviousFrame) / 1.0e9;
+ data.currentTime = animator->lastLocalTime();
return data;
}
@@ -152,11 +208,15 @@ ClipResults evaluateClipAtPhase(AnimationClip *clip,
Q_AUTOTEST_EXPORT
QVector<Qt3DCore::QSceneChangePtr> preparePropertyChanges(Qt3DCore::QNodeId animatorId,
- const QVector<MappingData> &mappingData,
+ const QVector<MappingData> &mappingDataVec,
const QVector<float> &channelResults,
bool finalFrame);
Q_AUTOTEST_EXPORT
+QVector<AnimationCallbackAndValue> prepareCallbacks(const QVector<MappingData> &mappingDataVec,
+ const QVector<float> &channelResults);
+
+Q_AUTOTEST_EXPORT
QVector<MappingData> buildPropertyMappings(const QVector<ChannelMapping *> &channelMappings,
const QVector<ChannelNameAndType> &channelNamesAndTypes,
const QVector<ComponentIndices> &channelComponentIndices);
@@ -169,12 +229,12 @@ Q_AUTOTEST_EXPORT
QVector<ComponentIndices> assignChannelComponentIndices(const QVector<ChannelNameAndType> &namesAndTypes);
Q_AUTOTEST_EXPORT
-double localTimeFromGlobalTime(double t_global, double t_start_global,
- double playbackRate, double duration,
- int loopCount, int &currentLoop);
+double localTimeFromElapsedTime(double t_current_local, double t_elapsed_global,
+ double playbackRate, double duration,
+ int loopCount, int &currentLoop);
Q_AUTOTEST_EXPORT
-double phaseFromGlobalTime(double t_global, double t_start_global,
+double phaseFromElapsedTime(double t_current_local, double t_elapsed_global,
double playbackRate, double duration,
int loopCount, int &currentLoop);
@@ -184,7 +244,7 @@ QVector<Qt3DCore::QNodeId> gatherValueNodesToEvaluate(Handler *handler,
Q_AUTOTEST_EXPORT
ComponentIndices generateClipFormatIndices(const QVector<ChannelNameAndType> &targetChannels,
- const QVector<ComponentIndices> &targetIndices,
+ QVector<ComponentIndices> &targetIndices,
const AnimationClip *clip);
Q_AUTOTEST_EXPORT
diff --git a/src/animation/backend/backend.pri b/src/animation/backend/backend.pri
index 2bc72e1d3..cc1104102 100644
--- a/src/animation/backend/backend.pri
+++ b/src/animation/backend/backend.pri
@@ -26,7 +26,10 @@ HEADERS += \
$$PWD/lerpclipblend_p.h \
$$PWD/additiveclipblend_p.h \
$$PWD/clipblendvalue_p.h \
- $$PWD/animationclip_p.h
+ $$PWD/animationclip_p.h \
+ $$PWD/clock_p.h \
+ $$PWD/skeleton_p.h \
+ $$PWD/gltfimporter_p.h
SOURCES += \
$$PWD/handler.cpp \
@@ -50,4 +53,7 @@ SOURCES += \
$$PWD/lerpclipblend.cpp \
$$PWD/additiveclipblend.cpp \
$$PWD/clipblendvalue.cpp \
- $$PWD/animationclip.cpp
+ $$PWD/animationclip.cpp \
+ $$PWD/clock.cpp \
+ $$PWD/skeleton.cpp \
+ $$PWD/gltfimporter.cpp
diff --git a/src/animation/backend/blendedclipanimator.cpp b/src/animation/backend/blendedclipanimator.cpp
index 08789a5f9..1487d6c3e 100644
--- a/src/animation/backend/blendedclipanimator.cpp
+++ b/src/animation/backend/blendedclipanimator.cpp
@@ -37,6 +37,7 @@
#include "blendedclipanimator_p.h"
#include <Qt3DAnimation/qblendedclipanimator.h>
#include <Qt3DAnimation/private/qblendedclipanimator_p.h>
+#include <Qt3DAnimation/private/qanimationcallbacktrigger_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -47,7 +48,8 @@ namespace Animation {
BlendedClipAnimator::BlendedClipAnimator()
: BackendNode(ReadWrite)
, m_running(false)
- , m_startGlobalTime(0)
+ , m_lastGlobalTimeNS(0)
+ , m_lastLocalTime(0.0)
, m_currentLoop(0)
, m_loops(1)
{
@@ -59,19 +61,42 @@ void BlendedClipAnimator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeB
const QBlendedClipAnimatorData &data = typedChange->data;
m_blendTreeRootId = data.blendTreeRootId;
m_mapperId = data.mapperId;
+ m_clockId = data.clockId;
m_running = data.running;
m_loops = data.loops;
setDirty(Handler::BlendedClipAnimatorDirty);
}
+double BlendedClipAnimator::lastLocalTime() const
+{
+ return m_lastLocalTime;
+}
+
+void BlendedClipAnimator::setLastLocalTime(double lastLocalTime)
+{
+ m_lastLocalTime = lastLocalTime;
+}
+
+void BlendedClipAnimator::setLastGlobalTimeNS(const qint64 &lastGlobalTimeNS)
+{
+ m_lastGlobalTimeNS = lastGlobalTimeNS;
+}
+
+qint64 BlendedClipAnimator::nsSincePreviousFrame(qint64 currentGlobalTimeNS)
+{
+ return currentGlobalTimeNS - m_lastGlobalTimeNS;
+}
+
void BlendedClipAnimator::cleanup()
{
setEnabled(false);
m_handler = nullptr;
m_blendTreeRootId = Qt3DCore::QNodeId();
m_mapperId = Qt3DCore::QNodeId();
+ m_clockId = Qt3DCore::QNodeId();
m_running = false;
- m_startGlobalTime = 0;
+ m_lastGlobalTimeNS = 0;
+ m_lastLocalTime = 0.0;
m_currentLoop = 0;
m_loops = 1;
}
@@ -88,6 +113,12 @@ void BlendedClipAnimator::setMapperId(Qt3DCore::QNodeId mapperId)
setDirty(Handler::BlendedClipAnimatorDirty);
}
+void BlendedClipAnimator::setClockId(Qt3DCore::QNodeId clockId)
+{
+ m_clockId = clockId;
+ setDirty(Handler::BlendedClipAnimatorDirty);
+}
+
void BlendedClipAnimator::setRunning(bool running)
{
m_running = running;
@@ -100,6 +131,22 @@ void BlendedClipAnimator::sendPropertyChanges(const QVector<Qt3DCore::QSceneChan
notifyObservers(change);
}
+void BlendedClipAnimator::sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks)
+{
+ for (const AnimationCallbackAndValue &callback : callbacks) {
+ if (callback.flags.testFlag(QAnimationCallback::OnThreadPool)) {
+ callback.callback->valueChanged(callback.value);
+ } else {
+ auto e = QAnimationCallbackTriggerPtr::create(peerId());
+ e->setCallback(callback.callback);
+ e->setValue(callback.value);
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ notifyObservers(e);
+ }
+ }
+}
+
+
Qt3DCore::QNodeId BlendedClipAnimator::blendTreeRootId() const
{
return m_blendTreeRootId;
@@ -114,6 +161,8 @@ void BlendedClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
setBlendTreeRootId(change->value().value<Qt3DCore::QNodeId>());
else if (change->propertyName() == QByteArrayLiteral("channelMapper"))
setMapperId(change->value().value<Qt3DCore::QNodeId>());
+ else if (change->propertyName() == QByteArrayLiteral("clock"))
+ setClockId(change->value().value<Qt3DCore::QNodeId>());
else if (change->propertyName() == QByteArrayLiteral("running"))
setRunning(change->value().toBool());
else if (change->propertyName() == QByteArrayLiteral("loops"))
diff --git a/src/animation/backend/blendedclipanimator_p.h b/src/animation/backend/blendedclipanimator_p.h
index df2c41b7c..dd99c4274 100644
--- a/src/animation/backend/blendedclipanimator_p.h
+++ b/src/animation/backend/blendedclipanimator_p.h
@@ -68,6 +68,7 @@ public:
Qt3DCore::QNodeId blendTreeRootId() const;
Qt3DCore::QNodeId mapperId() const { return m_mapperId; }
+ Qt3DCore::QNodeId clockId() const { return m_clockId; }
bool isRunning() const { return m_running; }
// Called by BuildBlendTreeJob
@@ -75,10 +76,10 @@ public:
void setBlendTreeRootId(Qt3DCore::QNodeId blendTreeRootId);
void setMapperId(Qt3DCore::QNodeId mapperId);
+ void setClockId(Qt3DCore::QNodeId clockId);
void setRunning(bool running);
- void setStartTime(qint64 globalTime) { m_startGlobalTime = globalTime; }
- qint64 startTime() const { return m_startGlobalTime; }
+ void setStartTime(qint64 globalTime) { m_lastGlobalTimeNS = globalTime; }
void setLoops(int loops) { m_loops = loops; }
int loops() const { return m_loops; }
@@ -90,16 +91,26 @@ public:
QVector<MappingData> mappingData() const { return m_mappingData; }
void sendPropertyChanges(const QVector<Qt3DCore::QSceneChangePtr> &changes);
+ void sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks);
void animationClipMarkedDirty() { setDirty(Handler::BlendedClipAnimatorDirty); }
+ qint64 nsSincePreviousFrame(qint64 currentGlobalTimeNS);
+ void setLastGlobalTimeNS(const qint64 &lastGlobalTimeNS);
+
+ double lastLocalTime() const;
+ void setLastLocalTime(double lastLocalTime);
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
Qt3DCore::QNodeId m_blendTreeRootId;
Qt3DCore::QNodeId m_mapperId;
+ Qt3DCore::QNodeId m_clockId;
bool m_running;
- qint64 m_startGlobalTime;
+ qint64 m_lastGlobalTimeNS;
+ double m_lastLocalTime;
+
int m_currentLoop;
int m_loops;
diff --git a/src/animation/backend/channelmapping.cpp b/src/animation/backend/channelmapping.cpp
index 0fd0f2714..ecae8bbae 100644
--- a/src/animation/backend/channelmapping.cpp
+++ b/src/animation/backend/channelmapping.cpp
@@ -36,8 +36,12 @@
#include "channelmapping_p.h"
#include <Qt3DAnimation/qchannelmapping.h>
+#include <Qt3DAnimation/private/qcallbackmapping_p.h>
#include <Qt3DAnimation/private/qchannelmapping_p.h>
+#include <Qt3DAnimation/private/qskeletonmapping_p.h>
#include <Qt3DAnimation/private/animationlogging_p.h>
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
+#include <Qt3DAnimation/private/managers_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
@@ -52,18 +56,48 @@ ChannelMapping::ChannelMapping()
, m_property()
, m_type(static_cast<int>(QVariant::Invalid))
, m_propertyName(nullptr)
+ , m_callback(nullptr)
+ , m_callbackFlags(0)
+ , m_skeletonId()
+ , m_mappingType(MappingType::ChannelMappingType)
{
}
void ChannelMapping::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
- const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QChannelMappingData>>(change);
- const auto &data = typedChange->data;
- m_channelName = data.channelName;
- m_targetId = data.targetId;
- m_property = data.property;
- m_type = data.type;
- m_propertyName = data.propertyName;
+ const auto createdChange = qSharedPointerCast<QChannelMappingCreatedChangeBase>(change);
+ switch (createdChange->type()) {
+ case QChannelMappingCreatedChangeBase::ChannelMapping: {
+ const auto typedChange = qSharedPointerCast<QChannelMappingCreatedChange<QChannelMappingData>>(change);
+ const auto &data = typedChange->data;
+ m_channelName = data.channelName;
+ m_targetId = data.targetId;
+ m_property = data.property;
+ m_type = data.type;
+ m_propertyName = data.propertyName;
+ m_mappingType = ChannelMappingType;
+ break;
+ }
+
+ case QChannelMappingCreatedChangeBase::SkeletonMapping: {
+ const auto typedChange = qSharedPointerCast<QChannelMappingCreatedChange<QSkeletonMappingData>>(change);
+ const auto &data = typedChange->data;
+ m_skeletonId = data.skeletonId;
+ m_mappingType = SkeletonMappingType;
+ break;
+ }
+
+ case QChannelMappingCreatedChangeBase::CallbackMapping: {
+ const auto typedChange = qSharedPointerCast<QChannelMappingCreatedChange<QCallbackMappingData>>(change);
+ const auto &data = typedChange->data;
+ m_channelName = data.channelName;
+ m_type = data.type;
+ m_callback = data.callback;
+ m_callbackFlags = data.callbackFlags;
+ m_mappingType = ChannelMappingType;
+ break;
+ }
+ }
}
void ChannelMapping::cleanup()
@@ -74,6 +108,9 @@ void ChannelMapping::cleanup()
m_property.clear();
m_type = static_cast<int>(QVariant::Invalid);
m_propertyName = nullptr;
+ m_callback = nullptr;
+ m_callbackFlags = 0;
+ m_skeletonId = Qt3DCore::QNodeId();
}
void ChannelMapping::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -91,6 +128,12 @@ void ChannelMapping::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_type = change->value().toInt();
else if (change->propertyName() == QByteArrayLiteral("propertyName"))
m_propertyName = static_cast<const char *>(const_cast<const void *>(change->value().value<void *>()));
+ else if (change->propertyName() == QByteArrayLiteral("callback"))
+ m_callback = static_cast<QAnimationCallback *>(change->value().value<void *>());
+ else if (change->propertyName() == QByteArrayLiteral("callbackFlags"))
+ m_callbackFlags = QAnimationCallback::Flags(change->value().toInt());
+ else if (change->propertyName() == QByteArrayLiteral("skeleton"))
+ m_skeletonId = change->value().value<Qt3DCore::QNodeId>();
break;
}
@@ -100,6 +143,11 @@ void ChannelMapping::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
QBackendNode::sceneChangeEvent(e);
}
+Skeleton *ChannelMapping::skeleton() const
+{
+ return m_handler->skeletonManager()->lookupResource(m_skeletonId);
+}
+
} // namespace Animation
} // namespace Qt3DAnimation
diff --git a/src/animation/backend/channelmapping_p.h b/src/animation/backend/channelmapping_p.h
index 93cf5efed..72b9975ef 100644
--- a/src/animation/backend/channelmapping_p.h
+++ b/src/animation/backend/channelmapping_p.h
@@ -50,6 +50,7 @@
#include <Qt3DAnimation/private/backendnode_p.h>
#include <Qt3DAnimation/private/fcurve_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
#include <Qt3DCore/qnodeid.h>
#include <QtCore/QMetaProperty>
@@ -57,6 +58,7 @@
QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
+
namespace Animation {
class Handler;
@@ -64,6 +66,12 @@ class Handler;
class Q_AUTOTEST_EXPORT ChannelMapping : public BackendNode
{
public:
+ enum MappingType {
+ ChannelMappingType = 0,
+ SkeletonMappingType,
+ CallbackMappingType
+ };
+
ChannelMapping();
void cleanup();
@@ -85,14 +93,37 @@ public:
void setPropertyName(const char *propertyName) { m_propertyName = propertyName; }
const char *propertyName() const { return m_propertyName; }
+ void setCallback(QAnimationCallback *callback) { m_callback = callback; }
+ QAnimationCallback *callback() const { return m_callback; }
+
+ void setCallbackFlags(QAnimationCallback::Flags flags) { m_callbackFlags = flags; }
+ QAnimationCallback::Flags callbackFlags() const { return m_callbackFlags; }
+
+ void setSkeletonId(Qt3DCore::QNodeId skeletonId) { m_skeletonId = skeletonId; }
+ Qt3DCore::QNodeId skeletonId() const { return m_skeletonId; }
+ Skeleton *skeleton() const;
+
+ void setMappingType(MappingType mappingType) { m_mappingType = mappingType; }
+ MappingType mappingType() const { return m_mappingType; }
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ // Properties from QChannelMapping
QString m_channelName;
Qt3DCore::QNodeId m_targetId;
QString m_property;
int m_type;
const char *m_propertyName;
+
+ // TODO: Properties from QCallbackMapping
+ QAnimationCallback *m_callback;
+ QAnimationCallback::Flags m_callbackFlags;
+
+ // Properties from QSkeletonMapping
+ Qt3DCore::QNodeId m_skeletonId;
+
+ MappingType m_mappingType;
};
} // namespace Animation
diff --git a/src/animation/backend/clipanimator.cpp b/src/animation/backend/clipanimator.cpp
index 92082b74f..21c08b80a 100644
--- a/src/animation/backend/clipanimator.cpp
+++ b/src/animation/backend/clipanimator.cpp
@@ -40,6 +40,7 @@
#include <Qt3DAnimation/private/animationclip_p.h>
#include <Qt3DAnimation/private/managers_p.h>
#include <Qt3DAnimation/private/animationlogging_p.h>
+#include <Qt3DAnimation/private/qanimationcallbacktrigger_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
@@ -52,9 +53,11 @@ ClipAnimator::ClipAnimator()
: BackendNode(ReadWrite)
, m_clipId()
, m_mapperId()
+ , m_clockId()
, m_running(false)
, m_loops(1)
- , m_startGlobalTime(0)
+ , m_lastGlobalTimeNS(0)
+ , m_lastLocalTime(0.0)
, m_mappingData()
, m_currentLoop(0)
{
@@ -66,6 +69,7 @@ void ClipAnimator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr
const auto &data = typedChange->data;
m_clipId = data.clipId;
m_mapperId = data.mapperId;
+ m_clockId = data.clockId;
m_running = data.running;
m_loops = data.loops;
setDirty(Handler::ClipAnimatorDirty);
@@ -88,6 +92,12 @@ void ClipAnimator::setMapperId(Qt3DCore::QNodeId mapperId)
setDirty(Handler::ClipAnimatorDirty);
}
+void ClipAnimator::setClockId(Qt3DCore::QNodeId clockId)
+{
+ m_clockId = clockId;
+ setDirty(Handler::ClipAnimatorDirty);
+}
+
void ClipAnimator::setRunning(bool running)
{
m_running = running;
@@ -102,6 +112,7 @@ void ClipAnimator::cleanup()
m_handler = nullptr;
m_clipId = Qt3DCore::QNodeId();
m_mapperId = Qt3DCore::QNodeId();
+ m_clockId = Qt3DCore::QNodeId();
m_running = false;
m_loops = 1;
m_formatIndices.clear();
@@ -116,6 +127,8 @@ void ClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
setClipId(change->value().value<Qt3DCore::QNodeId>());
else if (change->propertyName() == QByteArrayLiteral("channelMapper"))
setMapperId(change->value().value<Qt3DCore::QNodeId>());
+ else if (change->propertyName() == QByteArrayLiteral("clock"))
+ setClockId(change->value().value<Qt3DCore::QNodeId>());
else if (change->propertyName() == QByteArrayLiteral("running"))
setRunning(change->value().toBool());
else if (change->propertyName() == QByteArrayLiteral("loops"))
@@ -135,6 +148,41 @@ void ClipAnimator::sendPropertyChanges(const QVector<Qt3DCore::QSceneChangePtr>
notifyObservers(change);
}
+void ClipAnimator::sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks)
+{
+ for (const AnimationCallbackAndValue &callback : callbacks) {
+ if (callback.flags.testFlag(QAnimationCallback::OnThreadPool)) {
+ callback.callback->valueChanged(callback.value);
+ } else {
+ auto e = QAnimationCallbackTriggerPtr::create(peerId());
+ e->setCallback(callback.callback);
+ e->setValue(callback.value);
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ notifyObservers(e);
+ }
+ }
+}
+
+qint64 ClipAnimator::nsSincePreviousFrame(qint64 currentGlobalTimeNS)
+{
+ return currentGlobalTimeNS - m_lastGlobalTimeNS;
+}
+
+void ClipAnimator::setLastGlobalTimeNS(qint64 lastGlobalTimeNS)
+{
+ m_lastGlobalTimeNS = lastGlobalTimeNS;
+}
+
+double ClipAnimator::lastLocalTime() const
+{
+ return m_lastLocalTime;
+}
+
+void ClipAnimator::setLastLocalTime(double lastLocalTime)
+{
+ m_lastLocalTime = lastLocalTime;
+}
+
} // namespace Animation
} // namespace Qt3DAnimation
diff --git a/src/animation/backend/clipanimator_p.h b/src/animation/backend/clipanimator_p.h
index 5a9035dff..0f7380d66 100644
--- a/src/animation/backend/clipanimator_p.h
+++ b/src/animation/backend/clipanimator_p.h
@@ -70,6 +70,8 @@ public:
Qt3DCore::QNodeId clipId() const { return m_clipId; }
void setMapperId(Qt3DCore::QNodeId mapperId);
Qt3DCore::QNodeId mapperId() const { return m_mapperId; }
+ void setClockId(Qt3DCore::QNodeId clockId);
+ Qt3DCore::QNodeId clockId() const { return m_clockId; }
void setRunning(bool running);
bool isRunning() const { return m_running; }
@@ -84,29 +86,37 @@ public:
void setMappingData(const QVector<MappingData> &mappingData) { m_mappingData = mappingData; }
QVector<MappingData> mappingData() const { return m_mappingData; }
- void setStartTime(qint64 globalTime) { m_startGlobalTime = globalTime; }
- qint64 startTime() const { return m_startGlobalTime; }
+ void setStartTime(qint64 globalTime) { m_lastGlobalTimeNS = globalTime; }
int currentLoop() const { return m_currentLoop; }
void setCurrentLoop(int currentLoop) { m_currentLoop = currentLoop; }
void sendPropertyChanges(const QVector<Qt3DCore::QSceneChangePtr> &changes);
+ void sendCallbacks(const QVector<AnimationCallbackAndValue> &callbacks);
void animationClipMarkedDirty() { setDirty(Handler::ClipAnimatorDirty); }
void setFormatIndices(const ComponentIndices &formatIndices) { m_formatIndices = formatIndices; }
ComponentIndices formatIndices() const { return m_formatIndices; }
+ qint64 nsSincePreviousFrame(qint64 currentGlobalTimeNS);
+ void setLastGlobalTimeNS(qint64 lastGlobalTimeNS);
+
+ double lastLocalTime() const;
+ void setLastLocalTime(double lastLocalTime);
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
Qt3DCore::QNodeId m_clipId;
Qt3DCore::QNodeId m_mapperId;
+ Qt3DCore::QNodeId m_clockId;
bool m_running;
int m_loops;
// Working state
- qint64 m_startGlobalTime;
+ qint64 m_lastGlobalTimeNS;
+ double m_lastLocalTime;
QVector<MappingData> m_mappingData;
int m_currentLoop;
diff --git a/src/animation/backend/clock.cpp b/src/animation/backend/clock.cpp
new file mode 100644
index 000000000..f5b2bd1d3
--- /dev/null
+++ b/src/animation/backend/clock.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "clock_p.h"
+#include <Qt3DAnimation/qclock.h>
+#include <Qt3DAnimation/private/qclock_p.h>
+#include <Qt3DAnimation/private/animationutils_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+namespace Animation {
+
+Clock::Clock()
+ : BackendNode(ReadOnly)
+ , m_playbackRate(1.f)
+{
+}
+
+void Clock::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QClockData>>(change);
+ const auto &data = typedChange->data;
+ m_playbackRate = data.playbackRate;
+}
+
+void Clock::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ switch (e->type()) {
+ case Qt3DCore::PropertyUpdated: {
+ const auto change = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("playbackRate")) {
+ m_playbackRate = change.data()->value().toDouble();
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ QBackendNode::sceneChangeEvent(e);
+}
+
+void Clock::cleanup()
+{
+ m_playbackRate = 1.f;
+}
+
+} // namespace Animation
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/backend/clock_p.h b/src/animation/backend/clock_p.h
new file mode 100644
index 000000000..77f664d33
--- /dev/null
+++ b/src/animation/backend/clock_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_ANIMATION_CLOCK_P_H
+#define QT3DANIMATION_ANIMATION_CLOCK_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 <Qt3DAnimation/private/backendnode_p.h>
+#include <Qt3DCore/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+namespace Animation {
+
+class Q_AUTOTEST_EXPORT Clock : public BackendNode
+{
+public:
+ Clock();
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e);
+ void cleanup();
+
+ void setPlaybackRate(double playbackRate) { m_playbackRate = playbackRate; }
+ double playbackRate() const { return m_playbackRate; }
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ double m_playbackRate;
+};
+
+} // namespace Animation
+} // namespace Qt3DAnimation
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_ANIMATION_CLOCK_P_H
diff --git a/src/animation/backend/evaluateblendclipanimatorjob.cpp b/src/animation/backend/evaluateblendclipanimatorjob.cpp
index 76d24a4d3..3cde7b32f 100644
--- a/src/animation/backend/evaluateblendclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateblendclipanimatorjob.cpp
@@ -51,6 +51,8 @@ namespace Animation {
EvaluateBlendClipAnimatorJob::EvaluateBlendClipAnimatorJob()
: Qt3DCore::QAspectJob()
+ , m_currentGlobalTime(0.0)
+ , m_lastGlobalTime(0.0)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateBlendClipAnimator, 0);
}
@@ -62,7 +64,15 @@ void EvaluateBlendClipAnimatorJob::run()
// TODO: We should be able to cache this for each blend animator and only
// update when a node indicates its dependencies have changed as a result
// of blend factors changing
+
BlendedClipAnimator *blendedClipAnimator = m_handler->blendedClipAnimatorManager()->data(m_blendClipAnimatorHandle);
+ Q_ASSERT(blendedClipAnimator);
+ if (!blendedClipAnimator->isRunning())
+ return;
+
+ qint64 globalTimeNS = m_handler->simulationTime();
+ qint64 nsSincePreviousFrame = blendedClipAnimator->nsSincePreviousFrame(globalTimeNS);
+
Qt3DCore::QNodeId blendTreeRootId = blendedClipAnimator->blendTreeRootId();
const QVector<Qt3DCore::QNodeId> valueNodeIdsToEvaluate = gatherValueNodesToEvaluate(m_handler, blendTreeRootId);
@@ -72,16 +82,15 @@ void EvaluateBlendClipAnimatorJob::run()
Q_ASSERT(blendTreeRootNode);
const double duration = blendTreeRootNode->duration();
+ Clock *clock = m_handler->clockManager()->lookupResource(blendedClipAnimator->clockId());
+
// Calculate the phase given the blend tree duration and global time
- const qint64 globalTime = m_handler->simulationTime();
- const AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, globalTime);
- int currentLoop = 0;
- const double phase = phaseFromGlobalTime(animatorData.globalTime,
- animatorData.startTime,
- animatorData.playbackRate,
- duration,
- animatorData.loopCount,
- currentLoop);
+ AnimatorEvaluationData animatorData = evaluationDataForAnimator(blendedClipAnimator, clock, nsSincePreviousFrame);
+ const double phase = phaseFromElapsedTime(animatorData.currentTime, animatorData.elapsedTime,
+ animatorData.playbackRate,
+ duration,
+ animatorData.loopCount,
+ animatorData.currentLoop);
// Iterate over the value nodes of the blend tree, evaluate the
// contained animation clips at the current phase and store the results
@@ -105,7 +114,10 @@ void EvaluateBlendClipAnimatorJob::run()
ClipResults blendedResults = evaluateBlendTree(m_handler, blendedClipAnimator, blendTreeRootId);
const double localTime = phase * duration;
- const bool finalFrame = isFinalFrame(localTime, duration, currentLoop, animatorData.loopCount);
+ blendedClipAnimator->setLastGlobalTimeNS(globalTimeNS);
+ blendedClipAnimator->setLastLocalTime(localTime);
+ blendedClipAnimator->setCurrentLoop(animatorData.currentLoop);
+ const bool finalFrame = isFinalFrame(localTime, duration, animatorData.currentLoop, animatorData.loopCount);
// Prepare the property change events
const QVector<MappingData> mappingData = blendedClipAnimator->mappingData();
@@ -115,6 +127,10 @@ void EvaluateBlendClipAnimatorJob::run()
finalFrame);
// Send the property changes
blendedClipAnimator->sendPropertyChanges(changes);
+
+ // Trigger callbacks either on this thread or by notifying the gui thread.
+ const QVector<AnimationCallbackAndValue> callbacks = prepareCallbacks(mappingData, blendedResults);
+ blendedClipAnimator->sendCallbacks(callbacks);
}
} // Animation
diff --git a/src/animation/backend/evaluateblendclipanimatorjob_p.h b/src/animation/backend/evaluateblendclipanimatorjob_p.h
index a7822c8f9..ff578e517 100644
--- a/src/animation/backend/evaluateblendclipanimatorjob_p.h
+++ b/src/animation/backend/evaluateblendclipanimatorjob_p.h
@@ -78,6 +78,9 @@ protected:
private:
HBlendedClipAnimator m_blendClipAnimatorHandle;
Handler *m_handler;
+
+ qint64 m_currentGlobalTime;
+ qint64 m_lastGlobalTime;
};
typedef QSharedPointer<EvaluateBlendClipAnimatorJob> EvaluateBlendClipAnimatorJobPtr;
diff --git a/src/animation/backend/evaluateclipanimatorjob.cpp b/src/animation/backend/evaluateclipanimatorjob.cpp
index 72e16a593..972762033 100644
--- a/src/animation/backend/evaluateclipanimatorjob.cpp
+++ b/src/animation/backend/evaluateclipanimatorjob.cpp
@@ -48,6 +48,8 @@ namespace Animation {
EvaluateClipAnimatorJob::EvaluateClipAnimatorJob()
: Qt3DCore::QAspectJob()
+ , m_currentGlobalTime(0.0)
+ , m_lastGlobalTime(0.0)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::EvaluateClipAnimator, 0);
}
@@ -56,17 +58,21 @@ void EvaluateClipAnimatorJob::run()
{
Q_ASSERT(m_handler);
- const qint64 globalTime = m_handler->simulationTime();
- //qDebug() << Q_FUNC_INFO << "t_global =" << globalTime;
-
ClipAnimator *clipAnimator = m_handler->clipAnimatorManager()->data(m_clipAnimatorHandle);
Q_ASSERT(clipAnimator);
+ if (!clipAnimator->isRunning())
+ return;
+
+ qint64 globalTimeNS = m_handler->simulationTime();
+ qint64 nsSincePreviousFrame = clipAnimator->nsSincePreviousFrame(globalTimeNS);
+
+ Clock *clock = m_handler->clockManager()->lookupResource(clipAnimator->clockId());
// Evaluate the fcurves
AnimationClip *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId());
Q_ASSERT(clip);
// Prepare for evaluation (convert global time to local time ....)
- const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(clipAnimator, globalTime);
+ const AnimatorEvaluationData animatorEvaluationData = evaluationDataForAnimator(clipAnimator, clock, nsSincePreviousFrame);
const ClipEvaluationData preEvaluationDataForClip = evaluationDataForClip(clip, animatorEvaluationData);
const ClipResults rawClipResults = evaluateClipAtLocalTime(clip, preEvaluationDataForClip.localTime);
@@ -78,6 +84,8 @@ void EvaluateClipAnimatorJob::run()
clipAnimator->setRunning(false);
clipAnimator->setCurrentLoop(preEvaluationDataForClip.currentLoop);
+ clipAnimator->setLastGlobalTimeNS(globalTimeNS);
+ clipAnimator->setLastLocalTime(preEvaluationDataForClip.localTime);
// Prepare property changes (if finalFrame it also prepares the change for the running property for the frontend)
const QVector<Qt3DCore::QSceneChangePtr> changes = preparePropertyChanges(clipAnimator->peerId(),
@@ -88,6 +96,10 @@ void EvaluateClipAnimatorJob::run()
// Send the property changes
clipAnimator->sendPropertyChanges(changes);
+ // Trigger callbacks either on this thread or by notifying the gui thread.
+ const QVector<AnimationCallbackAndValue> callbacks = prepareCallbacks(clipAnimator->mappingData(),
+ formattedClipResults);
+ clipAnimator->sendCallbacks(callbacks);
}
} // namespace Animation
diff --git a/src/animation/backend/evaluateclipanimatorjob_p.h b/src/animation/backend/evaluateclipanimatorjob_p.h
index 866032dd1..911341788 100644
--- a/src/animation/backend/evaluateclipanimatorjob_p.h
+++ b/src/animation/backend/evaluateclipanimatorjob_p.h
@@ -82,6 +82,9 @@ protected:
private:
HClipAnimator m_clipAnimatorHandle;
Handler *m_handler;
+
+ qint64 m_currentGlobalTime;
+ qint64 m_lastGlobalTime;
};
} // namespace Animation
diff --git a/src/animation/backend/fcurve.cpp b/src/animation/backend/fcurve.cpp
index 4db5d2169..edb2b6df8 100644
--- a/src/animation/backend/fcurve.cpp
+++ b/src/animation/backend/fcurve.cpp
@@ -186,6 +186,9 @@ void ChannelComponent::setFromQChannelComponent(const QChannelComponent &qcc)
void Channel::read(const QJsonObject &json)
{
name = json[QLatin1String("channelName")].toString();
+ const auto jointIndexValue = json[QLatin1String("jointIndex")];
+ if (!jointIndexValue.isUndefined())
+ jointIndex = jointIndexValue.toInt();
const QJsonArray channelComponentsArray = json[QLatin1String("channelComponents")].toArray();
const int channelCount = channelComponentsArray.size();
channelComponents.resize(channelCount);
@@ -199,6 +202,7 @@ void Channel::read(const QJsonObject &json)
void Channel::setFromQChannel(const QChannel &qch)
{
name = qch.name();
+ jointIndex = qch.jointIndex();
channelComponents.resize(qch.channelComponentCount());
int i = 0;
for (const auto &frontendChannelComponent : qch)
diff --git a/src/animation/backend/fcurve_p.h b/src/animation/backend/fcurve_p.h
index e9138d6a1..8c5cdd54d 100644
--- a/src/animation/backend/fcurve_p.h
+++ b/src/animation/backend/fcurve_p.h
@@ -146,6 +146,7 @@ inline QDebug operator<<(QDebug dbg, const ChannelComponent &channelComponent)
struct Channel
{
QString name;
+ int jointIndex = -1;
QVector<ChannelComponent> channelComponents;
void read(const QJsonObject &json);
diff --git a/src/animation/backend/findrunningclipanimatorsjob.cpp b/src/animation/backend/findrunningclipanimatorsjob.cpp
index 41454004d..16b84359e 100644
--- a/src/animation/backend/findrunningclipanimatorsjob.cpp
+++ b/src/animation/backend/findrunningclipanimatorsjob.cpp
@@ -81,7 +81,7 @@ void FindRunningClipAnimatorsJob::run()
const QVector<ChannelNameAndType> channelNamesAndTypes
= buildRequiredChannelsAndTypes(m_handler, mapper);
- const QVector<ComponentIndices> channelComponentIndices
+ QVector<ComponentIndices> channelComponentIndices
= assignChannelComponentIndices(channelNamesAndTypes);
const AnimationClip *clip = m_handler->animationClipLoaderManager()->lookupResource(clipAnimator->clipId());
diff --git a/src/animation/backend/gltfimporter.cpp b/src/animation/backend/gltfimporter.cpp
new file mode 100644
index 000000000..8d9b5bb60
--- /dev/null
+++ b/src/animation/backend/gltfimporter.cpp
@@ -0,0 +1,852 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "gltfimporter_p.h"
+#include <Qt3DAnimation/private/animationlogging_p.h>
+#include <Qt3DAnimation/private/fcurve_p.h>
+#include <Qt3DAnimation/private/keyframe_p.h>
+
+#include <QtGui/qopengl.h>
+#include <QtGui/qquaternion.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qversionnumber.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+namespace Animation {
+
+namespace {
+
+QString gltfTargetPropertyToChannelName(const QString &propertyName)
+{
+ if (propertyName == QLatin1String("rotation"))
+ return QLatin1String("Rotation");
+ else if (propertyName == QLatin1String("translation"))
+ return QLatin1String("Location");
+ else if (propertyName == QLatin1String("scale"))
+ return QLatin1String("Scale");
+
+ qWarning() << "Unknown target property name";
+ return QString();
+}
+
+QKeyFrame::InterpolationType gltfToQKeyFrameInterpolation(GLTFImporter::Sampler::InterpolationMode mode)
+{
+ switch (mode) {
+ case GLTFImporter::Sampler::Linear:
+ return QKeyFrame::LinearInterpolation;
+ case GLTFImporter::Sampler::Step:
+ return QKeyFrame::ConstantInterpolation;
+ case GLTFImporter::Sampler::CubicSpline:
+ return QKeyFrame::BezierInterpolation;
+ case GLTFImporter::Sampler::CatmullRomSpline:
+ // TODO: Implement this interpolation type
+ qWarning() << "Unhandled interpolation type";
+ return QKeyFrame::LinearInterpolation;
+ }
+
+ return QKeyFrame::LinearInterpolation;
+}
+
+void jsonArrayToSqt(const QJsonArray &jsonArray, Qt3DCore::Sqt &sqt)
+{
+ Q_ASSERT(jsonArray.size() == 16);
+ QMatrix4x4 m;
+ float *data = m.data();
+ int i = 0;
+ for (const auto element : jsonArray)
+ *(data + i++) = static_cast<float>(element.toDouble());
+
+ decomposeQMatrix4x4(m, sqt);
+}
+
+void jsonArrayToVector3D(const QJsonArray &jsonArray, QVector3D &v)
+{
+ Q_ASSERT(jsonArray.size() == 3);
+ v.setX(static_cast<float>(jsonArray.at(0).toDouble()));
+ v.setY(static_cast<float>(jsonArray.at(1).toDouble()));
+ v.setZ(static_cast<float>(jsonArray.at(2).toDouble()));
+}
+
+void jsonArrayToQuaternion(const QJsonArray &jsonArray, QQuaternion &q)
+{
+ Q_ASSERT(jsonArray.size() == 4);
+ q.setX(static_cast<float>(jsonArray.at(0).toDouble()));
+ q.setY(static_cast<float>(jsonArray.at(1).toDouble()));
+ q.setZ(static_cast<float>(jsonArray.at(2).toDouble()));
+ q.setScalar(static_cast<float>(jsonArray.at(3).toDouble()));
+}
+
+}
+
+#define KEY_ACCESSORS QLatin1String("accessors")
+#define KEY_ANIMATIONS QLatin1String("animations")
+#define KEY_ASSET QLatin1String("asset")
+#define KEY_BUFFER QLatin1String("buffer")
+#define KEY_BUFFERS QLatin1String("buffers")
+#define KEY_BUFFER_VIEW QLatin1String("bufferView")
+#define KEY_BUFFER_VIEWS QLatin1String("bufferViews")
+#define KEY_BYTE_LENGTH QLatin1String("byteLength")
+#define KEY_BYTE_OFFSET QLatin1String("byteOffset")
+#define KEY_BYTE_STRIDE QLatin1String("byteStride")
+#define KEY_CAMERA QLatin1String("camera")
+#define KEY_CHANNELS QLatin1String("channels")
+#define KEY_CHILDREN QLatin1String("children")
+#define KEY_COMPONENT_TYPE QLatin1String("componentType")
+#define KEY_COUNT QLatin1String("count")
+#define KEY_JOINTS QLatin1String("joints")
+#define KEY_INPUT QLatin1String("input")
+#define KEY_INTERPOLATION QLatin1String("interpolation")
+#define KEY_INVERSE_BIND_MATRICES QLatin1String("inverseBindMatrices")
+#define KEY_MATRIX QLatin1String("matrix")
+#define KEY_MESH QLatin1String("mesh")
+#define KEY_NAME QLatin1String("name")
+#define KEY_NODE QLatin1String("node")
+#define KEY_NODES QLatin1String("nodes")
+#define KEY_OUTPUT QLatin1String("output")
+#define KEY_PATH QLatin1String("path")
+#define KEY_ROTATION QLatin1String("rotation")
+#define KEY_SAMPLER QLatin1String("sampler")
+#define KEY_SAMPLERS QLatin1String("samplers")
+#define KEY_SCALE QLatin1String("scale")
+#define KEY_SKIN QLatin1String("skin")
+#define KEY_SKINS QLatin1String("skins")
+#define KEY_TARGET QLatin1String("target")
+#define KEY_TRANSLATION QLatin1String("translation")
+#define KEY_TYPE QLatin1String("type")
+#define KEY_URI QLatin1String("uri")
+#define KEY_VERSION QLatin1String("version")
+
+GLTFImporter::BufferData::BufferData()
+ : byteLength(0)
+ , data()
+{
+}
+
+GLTFImporter::BufferData::BufferData(const QJsonObject &json)
+ : byteLength(json.value(KEY_BYTE_LENGTH).toInt())
+ , path(json.value(KEY_URI).toString())
+ , data()
+{
+}
+
+GLTFImporter::BufferView::BufferView()
+ : byteOffset(0)
+ , byteLength(0)
+ , bufferIndex(-1)
+ , target(0)
+{
+}
+
+GLTFImporter::BufferView::BufferView(const QJsonObject &json)
+ : byteOffset(json.value(KEY_BYTE_OFFSET).toInt())
+ , byteLength(json.value(KEY_BYTE_LENGTH).toInt())
+ , bufferIndex(json.value(KEY_BUFFER).toInt())
+ , target(0)
+{
+ const auto targetValue = json.value(KEY_TARGET);
+ if (!targetValue.isUndefined())
+ target = targetValue.toInt();
+}
+
+GLTFImporter::AccessorData::AccessorData()
+ : type(Qt3DRender::QAttribute::Float)
+ , dataSize(0)
+ , count(0)
+ , byteOffset(0)
+ , byteStride(0)
+{
+}
+
+GLTFImporter::AccessorData::AccessorData(const QJsonObject &json)
+ : bufferViewIndex(json.value(KEY_BUFFER_VIEW).toInt(-1))
+ , type(accessorTypeFromJSON(json.value(KEY_COMPONENT_TYPE).toInt()))
+ , dataSize(accessorDataSizeFromJson(json.value(KEY_TYPE).toString()))
+ , count(json.value(KEY_COUNT).toInt())
+ , byteOffset(0)
+ , byteStride(0)
+{
+ const auto byteOffsetValue = json.value(KEY_BYTE_OFFSET);
+ if (!byteOffsetValue.isUndefined())
+ byteOffset = byteOffsetValue.toInt();
+ const auto byteStrideValue = json.value(KEY_BYTE_STRIDE);
+ if (!byteStrideValue.isUndefined())
+ byteStride = byteStrideValue.toInt();
+}
+
+GLTFImporter::Skin::Skin()
+ : inverseBindAccessorIndex(-1)
+ , jointNodeIndices()
+{
+}
+
+GLTFImporter::Skin::Skin(const QJsonObject &json)
+ : name(json.value(KEY_NAME).toString())
+ , inverseBindAccessorIndex(json.value(KEY_INVERSE_BIND_MATRICES).toInt())
+{
+ QJsonArray jointNodes = json.value(KEY_JOINTS).toArray();
+ jointNodeIndices.reserve(jointNodes.size());
+ for (const auto jointNodeValue : jointNodes)
+ jointNodeIndices.push_back(jointNodeValue.toInt());
+}
+
+GLTFImporter::Channel::Channel()
+ : samplerIndex(-1)
+ , targetNodeIndex(-1)
+ , targetProperty()
+{
+}
+
+GLTFImporter::Channel::Channel(const QJsonObject &json)
+ : samplerIndex(json.value(KEY_SAMPLER).toInt())
+ , targetNodeIndex(-1)
+ , targetProperty()
+{
+ const auto targetJson = json.value(KEY_TARGET).toObject();
+ targetNodeIndex = targetJson.value(KEY_NODE).toInt();
+ targetProperty = targetJson.value(KEY_PATH).toString();
+}
+
+GLTFImporter::Sampler::Sampler()
+ : inputAccessorIndex(-1)
+ , outputAccessorIndex(-1)
+ , interpolationMode(Linear)
+{
+}
+
+GLTFImporter::Sampler::Sampler(const QJsonObject &json)
+ : inputAccessorIndex(json.value(KEY_INPUT).toInt())
+ , outputAccessorIndex(json.value(KEY_OUTPUT).toInt())
+ , interpolationMode(Linear)
+{
+ const auto interpolation = json.value(KEY_INTERPOLATION).toString();
+ if (interpolation == QLatin1String("LINEAR"))
+ interpolationMode = Linear;
+ else if (interpolation == QLatin1String("STEP"))
+ interpolationMode = Step;
+ else if (interpolation == QLatin1String("CATMULLROMSPLINE"))
+ interpolationMode = CatmullRomSpline;
+ else if (interpolation == QLatin1String("CUBICSPLINE"))
+ interpolationMode = CubicSpline;
+}
+
+QString GLTFImporter::Sampler::interpolationModeString() const
+{
+ switch (interpolationMode) {
+ case Linear: return QLatin1String("LINEAR");
+ case Step: return QLatin1String("STEP");
+ case CatmullRomSpline: return QLatin1String("CATMULLROMSPLINE");
+ case CubicSpline: return QLatin1String("CUBICSPLINE");
+ }
+
+ return QLatin1String("Unknown");
+}
+
+GLTFImporter::Animation::Animation()
+ : name()
+ , channels()
+ , samplers()
+{
+}
+
+GLTFImporter::Animation::Animation(const QJsonObject &json)
+ : name(json.value(KEY_NAME).toString())
+{
+ QJsonArray channelsArray = json.value(KEY_CHANNELS).toArray();
+ channels.reserve(channelsArray.size());
+ for (const auto channelValue : channelsArray) {
+ Channel channel(channelValue.toObject());
+ channels.push_back(channel);
+ }
+
+ QJsonArray samplersArray = json.value(KEY_SAMPLERS).toArray();
+ samplers.reserve(samplersArray.size());
+ for (const auto samplerValue : samplersArray) {
+ Sampler sampler(samplerValue.toObject());
+ samplers.push_back(sampler);
+ }
+}
+
+GLTFImporter::Node::Node()
+ : localTransform()
+ , childNodeIndices()
+ , name()
+ , parentNodeIndex(-1)
+ , cameraIndex(-1)
+ , meshIndex(-1)
+ , skinIndex(-1)
+{
+}
+
+GLTFImporter::Node::Node(const QJsonObject &json)
+ : localTransform()
+ , childNodeIndices()
+ , name(json.value(KEY_NAME).toString())
+ , parentNodeIndex(-1)
+ , cameraIndex(-1)
+ , meshIndex(-1)
+ , skinIndex(-1)
+{
+ // Child nodes - we setup the parent links in a later pass
+ QJsonArray childNodes = json.value(KEY_CHILDREN).toArray();
+ childNodeIndices.reserve(childNodes.size());
+ for (const auto childNodeValue : childNodes)
+ childNodeIndices.push_back(childNodeValue.toInt());
+
+ // Local transform - matrix or scale, rotation, translation
+ const auto matrixValue = json.value(KEY_MATRIX);
+ if (!matrixValue.isUndefined()) {
+ jsonArrayToSqt(matrixValue.toArray(), localTransform);
+ } else {
+ const auto scaleValue = json.value(KEY_SCALE);
+ const auto rotationValue = json.value(KEY_ROTATION);
+ const auto translationValue = json.value(KEY_TRANSLATION);
+
+ QVector3D s(1.0f, 1.0f, 1.0f);
+ if (!scaleValue.isUndefined())
+ jsonArrayToVector3D(scaleValue.toArray(), localTransform.scale);
+
+ QQuaternion r;
+ if (!rotationValue.isUndefined())
+ jsonArrayToQuaternion(json.value(KEY_ROTATION).toArray(), localTransform.rotation);
+
+ QVector3D t;
+ if (!translationValue.isUndefined())
+ jsonArrayToVector3D(json.value(KEY_TRANSLATION).toArray(), localTransform.translation);
+ }
+
+ // Referenced objects
+ const auto cameraValue = json.value(KEY_CAMERA);
+ if (!cameraValue.isUndefined())
+ cameraIndex = cameraValue.toInt();
+
+ const auto meshValue = json.value(KEY_MESH);
+ if (!meshValue.isUndefined())
+ meshIndex = meshValue.toInt();
+
+ const auto skinValue = json.value(KEY_SKIN);
+ if (!skinValue.isUndefined())
+ skinIndex = skinValue.toInt();
+}
+
+Qt3DRender::QAttribute::VertexBaseType GLTFImporter::accessorTypeFromJSON(int componentType)
+{
+ if (componentType == GL_BYTE)
+ return Qt3DRender::QAttribute::Byte;
+ else if (componentType == GL_UNSIGNED_BYTE)
+ return Qt3DRender::QAttribute::UnsignedByte;
+ else if (componentType == GL_SHORT)
+ return Qt3DRender::QAttribute::Short;
+ else if (componentType == GL_UNSIGNED_SHORT)
+ return Qt3DRender::QAttribute::UnsignedShort;
+ else if (componentType == GL_UNSIGNED_INT)
+ return Qt3DRender::QAttribute::UnsignedInt;
+ else if (componentType == GL_FLOAT)
+ return Qt3DRender::QAttribute::Float;
+
+ // There shouldn't be an invalid case here
+ qWarning("unsupported accessor type %d", componentType);
+ return Qt3DRender::QAttribute::Float;
+}
+
+uint GLTFImporter::accessorTypeSize(Qt3DRender::QAttribute::VertexBaseType componentType)
+{
+ switch (componentType) {
+ case Qt3DRender::QAttribute::Byte:
+ case Qt3DRender::QAttribute::UnsignedByte:
+ return 1;
+
+ case Qt3DRender::QAttribute::Short:
+ case Qt3DRender::QAttribute::UnsignedShort:
+ return 2;
+
+ case Qt3DRender::QAttribute::Int:
+ case Qt3DRender::QAttribute::Float:
+ return 4;
+
+ default:
+ qWarning("Unhandled accessor data type %d", componentType);
+ return 0;
+ }
+}
+
+uint GLTFImporter::accessorDataSizeFromJson(const QString &type)
+{
+ QString typeName = type.toUpper();
+ if (typeName == QLatin1String("SCALAR"))
+ return 1;
+ if (typeName == QLatin1String("VEC2"))
+ return 2;
+ if (typeName == QLatin1String("VEC3"))
+ return 3;
+ if (typeName == QLatin1String("VEC4"))
+ return 4;
+ if (typeName == QLatin1String("MAT2"))
+ return 4;
+ if (typeName == QLatin1String("MAT3"))
+ return 9;
+ if (typeName == QLatin1String("MAT4"))
+ return 16;
+
+ return 0;
+}
+
+GLTFImporter::GLTFImporter()
+{
+}
+
+bool GLTFImporter::load(QIODevice *ioDev)
+{
+ QByteArray jsonData = ioDev->readAll();
+ QJsonDocument sceneDocument = QJsonDocument::fromBinaryData(jsonData);
+ if (sceneDocument.isNull())
+ sceneDocument = QJsonDocument::fromJson(jsonData);
+
+ if (Q_UNLIKELY(!setJSON(sceneDocument))) {
+ qWarning("not a JSON document");
+ return false;
+ }
+
+ auto file = qobject_cast<QFile*>(ioDev);
+ if (file) {
+ QFileInfo finfo(file->fileName());
+ setBasePath(finfo.dir().absolutePath());
+ }
+
+ return parse();
+}
+
+QHash<int, int> GLTFImporter::createNodeIndexToJointIndexMap(const Skin &skin) const
+{
+ const int jointCount = skin.jointNodeIndices.size();
+ QHash<int, int> nodeIndexToJointIndexMap;
+ nodeIndexToJointIndexMap.reserve(jointCount);
+ for (int i = 0; i < jointCount; ++i)
+ nodeIndexToJointIndexMap.insert(skin.jointNodeIndices[i], i);
+ return nodeIndexToJointIndexMap;
+}
+
+QVector<Qt3DAnimation::Animation::Channel> GLTFImporter::createAnimationData(const QString &animationName) const
+{
+ QVector<Qt3DAnimation::Animation::Channel> channels;
+ if (m_animations.isEmpty()) {
+ qCWarning(Jobs) << "File does not contain any animation data";
+ return channels;
+ }
+
+ int animationIndex = 0;
+ if (!animationName.isEmpty()) {
+ for (int i = 0; i < m_animations.size(); ++i) {
+ if (m_animations[i].name == animationName) {
+ animationIndex = i;
+ break;
+ }
+ }
+ }
+ const Animation &animation = m_animations[animationIndex];
+
+ // Create node index to joint index lookup tables for each skin
+ QVector<QHash<int, int>> nodeIndexToJointIndexMaps;
+ nodeIndexToJointIndexMaps.reserve(m_skins.size());
+ for (const auto &skin : m_skins)
+ nodeIndexToJointIndexMaps.push_back(createNodeIndexToJointIndexMap(skin));
+
+ int channelIndex = 0;
+ for (const auto &channel : animation.channels) {
+ Qt3DAnimation::Animation::Channel outputChannel;
+ outputChannel.name = gltfTargetPropertyToChannelName(channel.targetProperty);
+
+ // Find the node index to joint index map that contains the target node and
+ // look up the joint index from it. If no such map is found, the target joint
+ // is not part of a skeleton and so we can just set the jointIndex to -1.
+ int jointIndex = -1;
+ for (const auto &map : nodeIndexToJointIndexMaps) {
+ const auto result = map.find(channel.targetNodeIndex);
+ if (result != map.cend()) {
+ jointIndex = result.value();
+ break;
+ }
+ }
+ outputChannel.jointIndex = jointIndex;
+
+ const auto &sampler = animation.samplers[channel.samplerIndex];
+ const auto interpolationType = gltfToQKeyFrameInterpolation(sampler.interpolationMode);
+
+ if (sampler.inputAccessorIndex == -1 || sampler.outputAccessorIndex == -1) {
+ qWarning() << "Skipping channel due to invalid accessor indices in the sampler" << endl;
+ continue;
+ }
+
+ const auto &inputAccessor = m_accessors[sampler.inputAccessorIndex];
+ const auto &outputAccessor = m_accessors[sampler.outputAccessorIndex];
+
+ if (inputAccessor.type != Qt3DRender::QAttribute::Float) {
+ qWarning() << "Input accessor has wrong data type. Skipping channel.";
+ continue;
+ }
+
+ if (outputAccessor.type != Qt3DRender::QAttribute::Float) {
+ qWarning() << "Output accessor has wrong data type. Skipping channel.";
+ continue;
+ }
+
+ if (inputAccessor.count != outputAccessor.count) {
+ qWarning() << "Warning!!! Input accessor has" << inputAccessor.count
+ << "entries and output accessor has" << outputAccessor.count
+ << "entries. They should match. Please check your data.";
+ continue;
+ }
+
+ // TODO: Allow Qt 3D animation data to share timestamps between multiple
+ // channel components. I.e. allow key frame values of composite types.
+ // Doesn't give as much freedom but more efficient at runtime.
+
+ // Get the key frame times first as these are common to all components of the
+ // key frame values.
+ const int keyFrameCount = inputAccessor.count;
+ QVector<float> keyframeTimes(keyFrameCount);
+ for (int i = 0; i < keyFrameCount; ++i) {
+ const auto rawTimestamp = accessorData(sampler.inputAccessorIndex, i);
+ keyframeTimes[i] = *reinterpret_cast<const float*>(rawTimestamp.data);
+ }
+
+ // Create a ChannelComponent for each component of the output sampler and
+ // populate it with data.
+ switch (outputAccessor.dataSize) {
+ // TODO: Handle other types as needed
+ case 3: {
+ // vec3
+ const int componentCount = 3;
+
+ // Construct the channel component names and add component to the channel
+ const QStringList suffixes
+ = (QStringList() << QLatin1String("X") << QLatin1String("Y") << QLatin1String("Z"));
+ outputChannel.channelComponents.resize(componentCount);
+ for (int componentIndex = 0; componentIndex < componentCount; ++componentIndex) {
+ outputChannel.channelComponents[componentIndex].name
+ = QString(QLatin1String("%1 %2")).arg(outputChannel.name,
+ suffixes[componentIndex]);
+ }
+
+ // Populate the fcurves in the channel components
+ for (int i = 0; i < keyFrameCount; ++i) {
+ const auto rawKeyframeValue = accessorData(sampler.outputAccessorIndex, i);
+ QVector3D v;
+ memcpy(&v, rawKeyframeValue.data, rawKeyframeValue.byteLength);
+
+ for (int componentIndex = 0; componentIndex < componentCount; ++componentIndex) {
+ Keyframe keyFrame;
+ keyFrame.interpolation = interpolationType;
+ keyFrame.value = v[componentIndex];
+ outputChannel.channelComponents[componentIndex].fcurve.appendKeyframe(keyframeTimes[i], keyFrame);
+ }
+ }
+
+ break;
+ } // case 3
+
+ case 4: {
+ // vec4 or quaternion
+ const int componentCount = 4;
+
+ // Construct the channel component names and add component to the channel
+ const QStringList rotationSuffixes = (QStringList()
+ << QLatin1String("X") << QLatin1String("Y") << QLatin1String("Z") << QLatin1String("W"));
+ const QStringList standardSuffixes = (QStringList()
+ << QLatin1String("X") << QLatin1String("Y") << QLatin1String("Z"));
+ const QStringList suffixes = (channel.targetProperty == QLatin1String("rotation"))
+ ? rotationSuffixes : standardSuffixes;
+ outputChannel.channelComponents.resize(componentCount);
+ for (int componentIndex = 0; componentIndex < componentCount; ++componentIndex) {
+ outputChannel.channelComponents[componentIndex].name
+ = QString(QLatin1String("%1 %2")).arg(outputChannel.name,
+ suffixes[componentIndex]);
+ }
+
+ // Populate the fcurves in the channel components
+ for (int i = 0; i < keyFrameCount; ++i) {
+ const auto rawKeyframeValue = accessorData(sampler.outputAccessorIndex, i);
+ QVector4D v;
+ memcpy(&v, rawKeyframeValue.data, rawKeyframeValue.byteLength);
+
+ for (int componentIndex = 0; componentIndex < componentCount; ++componentIndex) {
+ Keyframe keyFrame;
+ keyFrame.interpolation = interpolationType;
+ keyFrame.value = v[componentIndex];
+ outputChannel.channelComponents[componentIndex].fcurve.appendKeyframe(keyframeTimes[i], keyFrame);
+ }
+ }
+
+ break;
+ } // case 4
+ }
+
+ channels.push_back(outputChannel);
+ ++channelIndex;
+ }
+
+ return channels;
+}
+
+GLTFImporter::RawData GLTFImporter::accessorData(int accessorIndex, int index) const
+{
+ const AccessorData &accessor = m_accessors[accessorIndex];
+ const BufferView &bufferView = m_bufferViews[accessor.bufferViewIndex];
+ const BufferData &bufferData = m_bufferDatas[bufferView.bufferIndex];
+ const QByteArray &ba = bufferData.data;
+ const char *rawData = ba.constData() + bufferView.byteOffset + accessor.byteOffset;
+
+ const uint typeSize = accessorTypeSize(accessor.type);
+ const int stride = (accessor.byteStride == 0)
+ ? accessor.dataSize * typeSize
+ : accessor.byteStride;
+
+ const char* data = rawData + index * stride;
+ if (data - rawData > ba.size()) {
+ qWarning("Attempting to access data beyond end of buffer");
+ return RawData{ nullptr, 0 };
+ }
+
+ const quint64 byteLength = accessor.dataSize * typeSize;
+ RawData rd{ data, byteLength };
+
+ return rd;
+}
+
+void GLTFImporter::setBasePath(const QString &path)
+{
+ m_basePath = path;
+}
+
+bool GLTFImporter::setJSON(const QJsonDocument &json)
+{
+ if (!json.isObject())
+ return false;
+ m_json = json;
+ cleanup();
+ return true;
+}
+
+bool GLTFImporter::parse()
+{
+ // Find the glTF version
+ const QJsonObject asset = m_json.object().value(KEY_ASSET).toObject();
+ const QString versionString = asset.value(KEY_VERSION).toString();
+ const auto version = QVersionNumber::fromString(versionString);
+ switch (version.majorVersion()) {
+ case 2:
+ return parseGLTF2();
+
+ default:
+ qWarning() << "Unsupported version of glTF" << versionString;
+ return false;
+ }
+}
+
+bool GLTFImporter::parseGLTF2()
+{
+ bool success = true;
+ const QJsonArray buffers = m_json.object().value(KEY_BUFFERS).toArray();
+ for (const auto &bufferValue : buffers)
+ success &= processJSONBuffer(bufferValue.toObject());
+
+ const QJsonArray bufferViews = m_json.object().value(KEY_BUFFER_VIEWS).toArray();
+ for (const auto &bufferViewValue : bufferViews)
+ success &= processJSONBufferView(bufferViewValue.toObject());
+
+ const QJsonArray accessors = m_json.object().value(KEY_ACCESSORS).toArray();
+ for (const auto &accessorValue : accessors)
+ success &= processJSONAccessor(accessorValue.toObject());
+
+ const QJsonArray skins = m_json.object().value(KEY_SKINS).toArray();
+ for (const auto &skinValue : skins)
+ success &= processJSONSkin(skinValue.toObject());
+
+ const QJsonArray animations = m_json.object().value(KEY_ANIMATIONS).toArray();
+ for (const auto &animationValue : animations)
+ success &= processJSONAnimation(animationValue.toObject());
+
+ const QJsonArray nodes = m_json.object().value(KEY_NODES).toArray();
+ for (const auto &nodeValue : nodes)
+ success &= processJSONNode(nodeValue.toObject());
+ setupNodeParentLinks();
+
+ // TODO: Make a complete GLTF 2 parser by extending to other top level elements:
+ // scenes, animations, meshes etc.
+
+ return success;
+}
+
+void GLTFImporter::cleanup()
+{
+ m_accessors.clear();
+ m_bufferViews.clear();
+ m_bufferDatas.clear();
+}
+
+bool GLTFImporter::processJSONBuffer(const QJsonObject &json)
+{
+ // Store buffer details and load data into memory
+ BufferData buffer(json);
+ buffer.data = resolveLocalData(buffer.path);
+ if (buffer.data.isEmpty())
+ return false;
+
+ m_bufferDatas.push_back(buffer);
+ return true;
+}
+
+bool GLTFImporter::processJSONBufferView(const QJsonObject &json)
+{
+ BufferView bufferView(json);
+
+ // Perform sanity checks
+ const auto bufferIndex = bufferView.bufferIndex;
+ if (Q_UNLIKELY(bufferIndex) >= m_bufferDatas.size()) {
+ qWarning("Unknown buffer %d when processing buffer view", bufferIndex);
+ return false;
+ }
+
+ const auto &bufferData = m_bufferDatas[bufferIndex];
+ if (bufferView.byteOffset > bufferData.byteLength) {
+ qWarning("Bufferview has offset greater than buffer %d length", bufferIndex);
+ return false;
+ }
+
+ if (Q_UNLIKELY(bufferView.byteOffset + bufferView.byteLength > bufferData.byteLength)) {
+ qWarning("BufferView extends beyond end of buffer %d", bufferIndex);
+ return false;
+ }
+
+ m_bufferViews.push_back(bufferView);
+ return true;
+}
+
+bool GLTFImporter::processJSONAccessor(const QJsonObject &json)
+{
+ AccessorData accessor(json);
+
+ // TODO: Perform sanity checks
+
+ m_accessors.push_back(accessor);
+ return true;
+}
+
+bool GLTFImporter::processJSONSkin(const QJsonObject &json)
+{
+ Skin skin(json);
+
+ // TODO: Perform sanity checks
+
+ m_skins.push_back(skin);
+ return true;
+}
+
+bool GLTFImporter::processJSONAnimation(const QJsonObject &json)
+{
+ Animation animation(json);
+
+ for (const auto &channel : animation.channels) {
+ if (channel.samplerIndex == -1)
+ qWarning() << "Invalid sampler index in animation"
+ << animation.name << "for channel targeting node"
+ << channel.targetNodeIndex << " and property"
+ << channel.targetProperty;
+ }
+
+ for (const auto &sampler : animation.samplers) {
+ if (sampler.inputAccessorIndex == -1) {
+ qWarning() << "Sampler for animaton" << animation.name
+ << "references has an invalid input accessor index";
+ }
+
+ if (sampler.outputAccessorIndex == -1) {
+ qWarning() << "Sampler for animaton" << animation.name
+ << "references has an invalid output accessor index";
+ }
+ }
+
+ m_animations.push_back(animation);
+ return true;
+}
+
+bool GLTFImporter::processJSONNode(const QJsonObject &json)
+{
+ Node node(json);
+
+ // TODO: Perform sanity checks
+
+ m_nodes.push_back(node);
+ return true;
+}
+
+void GLTFImporter::setupNodeParentLinks()
+{
+ const int nodeCount = m_nodes.size();
+ for (int i = 0; i < nodeCount; ++i) {
+ const Node &node = m_nodes[i];
+ const QVector<int> &childNodeIndices = node.childNodeIndices;
+ for (const auto childNodeIndex : childNodeIndices) {
+ Q_ASSERT(childNodeIndex < m_nodes.size());
+ Node &childNode = m_nodes[childNodeIndex];
+ Q_ASSERT(childNode.parentNodeIndex == -1);
+ childNode.parentNodeIndex = i;
+ }
+ }
+}
+
+QByteArray GLTFImporter::resolveLocalData(const QString &path) const
+{
+ QDir d(m_basePath);
+ Q_ASSERT(d.exists());
+
+ QString absPath = d.absoluteFilePath(path);
+ QFile f(absPath);
+ f.open(QIODevice::ReadOnly);
+ return f.readAll();
+}
+
+} // namespace Animation
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/backend/gltfimporter_p.h b/src/animation/backend/gltfimporter_p.h
new file mode 100644
index 000000000..ae7674fe7
--- /dev/null
+++ b/src/animation/backend/gltfimporter_p.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_ANIMATION_GLTFIMPORTER_H
+#define QT3DANIMATION_ANIMATION_GLTFIMPORTER_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 <QtGlobal>
+#include <Qt3DAnimation/private/fcurve_p.h>
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DCore/private/sqt_p.h>
+#include <Qt3DCore/private/qmath3d_p.h>
+
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QJsonValue>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+namespace Qt3DAnimation {
+namespace Animation {
+
+class GLTFImporter
+{
+public:
+ class BufferData
+ {
+ public:
+ BufferData();
+ explicit BufferData(const QJsonObject &json);
+
+ quint64 byteLength;
+ QString path;
+ QByteArray data;
+ };
+
+ class BufferView
+ {
+ public:
+ BufferView();
+ explicit BufferView(const QJsonObject &json);
+
+ quint64 byteOffset;
+ quint64 byteLength;
+ int bufferIndex;
+ int target; // Only for per vertex attributes
+ };
+
+ class AccessorData
+ {
+ public:
+ AccessorData();
+ explicit AccessorData(const QJsonObject &json);
+
+ int bufferViewIndex;
+ Qt3DRender::QAttribute::VertexBaseType type;
+ uint dataSize;
+ int count;
+ int byteOffset;
+ int byteStride; // Only for per vertex attributes
+
+ // TODO: Extend to support sparse accessors
+ };
+
+ class Skin
+ {
+ public:
+ Skin();
+ explicit Skin(const QJsonObject &json);
+
+ QString name;
+ int inverseBindAccessorIndex;
+ QVector<int> jointNodeIndices;
+ };
+
+ class Channel
+ {
+ public:
+ Channel();
+ explicit Channel(const QJsonObject &json);
+
+ int samplerIndex;
+ int targetNodeIndex;
+ QString targetProperty;
+ };
+
+ class Sampler
+ {
+ public:
+ Sampler();
+ explicit Sampler(const QJsonObject &json);
+
+ enum InterpolationMode {
+ Linear,
+ Step,
+ CatmullRomSpline,
+ CubicSpline
+ };
+
+ QString interpolationModeString() const;
+
+ int inputAccessorIndex;
+ int outputAccessorIndex;
+ InterpolationMode interpolationMode;
+ };
+
+ class Animation
+ {
+ public:
+ Animation();
+ explicit Animation(const QJsonObject &json);
+
+ QString name;
+ QVector<Channel> channels;
+ QVector<Sampler> samplers;
+ };
+
+ class Node
+ {
+ public:
+ Node();
+ explicit Node(const QJsonObject &json);
+
+ Qt3DCore::Sqt localTransform;
+ QVector<int> childNodeIndices;
+ QString name;
+ int parentNodeIndex;
+ int cameraIndex;
+ int meshIndex;
+ int skinIndex;
+ };
+
+ GLTFImporter();
+
+ bool load(QIODevice *ioDev);
+ const QVector<Animation> animations() const { return m_animations; }
+
+ QVector<Qt3DAnimation::Animation::Channel> createAnimationData(const QString &animationName = QString()) const;
+
+private:
+ static Qt3DRender::QAttribute::VertexBaseType accessorTypeFromJSON(int componentType);
+ static uint accessorTypeSize(Qt3DRender::QAttribute::VertexBaseType componentType);
+ static uint accessorDataSizeFromJson(const QString &type);
+
+ struct RawData
+ {
+ const char *data;
+ quint64 byteLength;
+ };
+
+ void setBasePath(const QString &path);
+ bool setJSON(const QJsonDocument &json);
+
+ bool parse();
+ bool parseGLTF2();
+ void cleanup();
+ QHash<int, int> createNodeIndexToJointIndexMap(const Skin &skin) const;
+
+ bool processJSONBuffer(const QJsonObject &json);
+ bool processJSONBufferView(const QJsonObject &json);
+ bool processJSONAccessor(const QJsonObject &json);
+ bool processJSONSkin(const QJsonObject &json);
+ bool processJSONAnimation(const QJsonObject &json);
+ bool processJSONNode(const QJsonObject &json);
+ void setupNodeParentLinks();
+ QByteArray resolveLocalData(const QString &path) const;
+
+ RawData accessorData(int accessorIndex, int index) const;
+
+ QJsonDocument m_json;
+ QString m_basePath;
+ QVector<BufferData> m_bufferDatas;
+ QVector<BufferView> m_bufferViews;
+ QVector<AccessorData> m_accessors;
+ QVector<Skin> m_skins;
+ QVector<Animation> m_animations;
+ QVector<Node> m_nodes;
+};
+
+} // namespace Animation
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_ANIMATION_GLTFIMPORTER_H
diff --git a/src/animation/backend/handle_types_p.h b/src/animation/backend/handle_types_p.h
index f6f77eb20..f05df22fe 100644
--- a/src/animation/backend/handle_types_p.h
+++ b/src/animation/backend/handle_types_p.h
@@ -63,12 +63,14 @@ class ClipAnimator;
class BlendedClipAnimator;
class ChannelMapping;
class ChannelMapper;
+class Skeleton;
typedef Qt3DCore::QHandle<AnimationClip, 16> HAnimationClip;
typedef Qt3DCore::QHandle<ClipAnimator, 16> HClipAnimator;
typedef Qt3DCore::QHandle<BlendedClipAnimator, 12> HBlendedClipAnimator;
typedef Qt3DCore::QHandle<ChannelMapping, 16> HChannelMapping;
typedef Qt3DCore::QHandle<ChannelMapper, 16> HChannelMapper;
+typedef Qt3DCore::QHandle<Skeleton, 16> HSkeleton;
} // namespace Animation
} // namespace Qt3DAnimation
diff --git a/src/animation/backend/handler.cpp b/src/animation/backend/handler.cpp
index daa98ed54..ed48d281f 100644
--- a/src/animation/backend/handler.cpp
+++ b/src/animation/backend/handler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -52,11 +52,13 @@ namespace Animation {
Handler::Handler()
: m_animationClipLoaderManager(new AnimationClipLoaderManager)
+ , m_clockManager(new ClockManager)
, m_clipAnimatorManager(new ClipAnimatorManager)
, m_blendedClipAnimatorManager(new BlendedClipAnimatorManager)
, m_channelMappingManager(new ChannelMappingManager)
, m_channelMapperManager(new ChannelMapperManager)
, m_clipBlendNodeManager(new ClipBlendNodeManager)
+ , m_skeletonManager(new SkeletonManager)
, m_loadAnimationClipJob(new LoadAnimationClipJob)
, m_findRunningClipAnimatorsJob(new FindRunningClipAnimatorsJob)
, m_buildBlendTreesJob(new BuildBlendTreesJob)
@@ -147,6 +149,16 @@ void Handler::setBlendedClipAnimatorRunning(const HBlendedClipAnimator &handle,
// The vectors may get outdated when the application removes/deletes an
// animator component in the meantime. Recognize this. This should be
// relatively infrequent so in most cases the vectors will not change at all.
+void Handler::cleanupHandleList(QVector<HAnimationClip> *clips)
+{
+ for (auto it = clips->begin(); it != clips->end(); ) {
+ if (!m_animationClipLoaderManager->data(*it))
+ clips->erase(it);
+ else
+ ++it;
+ }
+}
+
void Handler::cleanupHandleList(QVector<HClipAnimator> *animators)
{
for (auto it = animators->begin(); it != animators->end(); ) {
@@ -180,8 +192,10 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
// If there are any dirty animation clips that need loading,
// queue up a job for them
- if (!m_dirtyAnimationClips.isEmpty()) {
+ const bool hasLoadAnimationClipJob = !m_dirtyAnimationClips.isEmpty();
+ if (hasLoadAnimationClipJob) {
qCDebug(HandlerLogic) << "Added LoadAnimationClipJob";
+ cleanupHandleList(&m_dirtyAnimationClips);
m_loadAnimationClipJob->addDirtyAnimationClips(m_dirtyAnimationClips);
jobs.push_back(m_loadAnimationClipJob);
m_dirtyAnimationClips.clear();
@@ -190,19 +204,22 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
// If there are dirty clip animators, find the set that are able to
// run. I.e. are marked as running and have animation clips and
// channel mappings
- if (!m_dirtyClipAnimators.isEmpty()) {
+
+ const bool hasFindRunningClipAnimatorsJob = !m_dirtyClipAnimators.isEmpty();
+ if (hasFindRunningClipAnimatorsJob) {
qCDebug(HandlerLogic) << "Added FindRunningClipAnimatorsJob";
m_findRunningClipAnimatorsJob->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>());
cleanupHandleList(&m_dirtyClipAnimators);
m_findRunningClipAnimatorsJob->setDirtyClipAnimators(m_dirtyClipAnimators);
jobs.push_back(m_findRunningClipAnimatorsJob);
- if (jobs.contains(m_loadAnimationClipJob))
+ if (hasLoadAnimationClipJob)
m_findRunningClipAnimatorsJob->addDependency(m_loadAnimationClipJob);
m_dirtyClipAnimators.clear();
}
// Rebuild blending trees if a blend tree is dirty
- if (!m_dirtyBlendedAnimators.isEmpty()) {
+ const bool hasBuildBlendTreesJob = !m_dirtyBlendedAnimators.isEmpty();
+ if (hasBuildBlendTreesJob) {
const QVector<HBlendedClipAnimator> dirtyBlendedAnimators = std::move(m_dirtyBlendedAnimators);
m_buildBlendTreesJob->setBlendedClipAnimators(dirtyBlendedAnimators);
jobs.push_back(m_buildBlendTreesJob);
@@ -231,9 +248,9 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
for (int i = 0; i < newSize; ++i) {
m_evaluateClipAnimatorJobs[i]->setClipAnimator(m_runningClipAnimators[i]);
m_evaluateClipAnimatorJobs[i]->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>());
- if (jobs.contains(m_loadAnimationClipJob))
+ if (hasLoadAnimationClipJob)
m_evaluateClipAnimatorJobs[i]->addDependency(m_loadAnimationClipJob);
- if (jobs.contains(m_findRunningClipAnimatorsJob))
+ if (hasFindRunningClipAnimatorsJob)
m_evaluateClipAnimatorJobs[i]->addDependency(m_findRunningClipAnimatorsJob);
jobs.push_back(m_evaluateClipAnimatorJobs[i]);
}
@@ -257,9 +274,9 @@ QVector<Qt3DCore::QAspectJobPtr> Handler::jobsToExecute(qint64 time)
for (int i = 0; i < newSize; ++i) {
m_evaluateBlendClipAnimatorJobs[i]->setBlendClipAnimator(m_runningBlendedClipAnimators[i]);
m_evaluateBlendClipAnimatorJobs[i]->removeDependency(QWeakPointer<Qt3DCore::QAspectJob>());
- if (jobs.contains(m_loadAnimationClipJob))
+ if (hasLoadAnimationClipJob)
m_evaluateBlendClipAnimatorJobs[i]->addDependency(m_loadAnimationClipJob);
- if (jobs.contains(m_buildBlendTreesJob))
+ if (hasBuildBlendTreesJob)
m_evaluateBlendClipAnimatorJobs[i]->addDependency(m_buildBlendTreesJob);
jobs.push_back(m_evaluateBlendClipAnimatorJobs[i]);
}
diff --git a/src/animation/backend/handler_p.h b/src/animation/backend/handler_p.h
index 467cd3a0e..99e2ae1f6 100644
--- a/src/animation/backend/handler_p.h
+++ b/src/animation/backend/handler_p.h
@@ -66,6 +66,7 @@ namespace Animation {
class AnimationClip;
class AnimationClipLoaderManager;
+class ClockManager;
class ClipAnimator;
class ClipAnimatorManager;
class BlendedClipAnimator;
@@ -75,6 +76,7 @@ class ChannelMappingManager;
class ChannelMapper;
class ChannelMapperManager;
class ClipBlendNodeManager;
+class SkeletonManager;
class FindRunningClipAnimatorsJob;
class LoadAnimationClipJob;
@@ -109,25 +111,30 @@ public:
QVector<HBlendedClipAnimator> runningBlenndedClipAnimators() const { return m_runningBlendedClipAnimators; }
AnimationClipLoaderManager *animationClipLoaderManager() const Q_DECL_NOTHROW { return m_animationClipLoaderManager.data(); }
+ ClockManager *clockManager() const Q_DECL_NOTHROW { return m_clockManager.data(); }
ClipAnimatorManager *clipAnimatorManager() const Q_DECL_NOTHROW { return m_clipAnimatorManager.data(); }
BlendedClipAnimatorManager *blendedClipAnimatorManager() const Q_DECL_NOTHROW { return m_blendedClipAnimatorManager.data(); }
ChannelMappingManager *channelMappingManager() const Q_DECL_NOTHROW { return m_channelMappingManager.data(); }
ChannelMapperManager *channelMapperManager() const Q_DECL_NOTHROW { return m_channelMapperManager.data(); }
ClipBlendNodeManager *clipBlendNodeManager() const Q_DECL_NOTHROW { return m_clipBlendNodeManager.data(); }
+ SkeletonManager *skeletonManager() const Q_DECL_NOTHROW { return m_skeletonManager.data(); }
QVector<Qt3DCore::QAspectJobPtr> jobsToExecute(qint64 time);
+ void cleanupHandleList(QVector<HAnimationClip> *clips);
void cleanupHandleList(QVector<HClipAnimator> *animators);
void cleanupHandleList(QVector<HBlendedClipAnimator> *animators);
private:
QMutex m_mutex;
QScopedPointer<AnimationClipLoaderManager> m_animationClipLoaderManager;
+ QScopedPointer<ClockManager> m_clockManager;
QScopedPointer<ClipAnimatorManager> m_clipAnimatorManager;
QScopedPointer<BlendedClipAnimatorManager> m_blendedClipAnimatorManager;
QScopedPointer<ChannelMappingManager> m_channelMappingManager;
QScopedPointer<ChannelMapperManager> m_channelMapperManager;
QScopedPointer<ClipBlendNodeManager> m_clipBlendNodeManager;
+ QScopedPointer<SkeletonManager> m_skeletonManager;
QVector<HAnimationClip> m_dirtyAnimationClips;
QVector<HChannelMapper> m_dirtyChannelMappers;
diff --git a/src/animation/backend/loadanimationclipjob.cpp b/src/animation/backend/loadanimationclipjob.cpp
index c0201e0e9..4584449bc 100644
--- a/src/animation/backend/loadanimationclipjob.cpp
+++ b/src/animation/backend/loadanimationclipjob.cpp
@@ -72,6 +72,7 @@ void LoadAnimationClipJob::run()
AnimationClipLoaderManager *animationClipManager = m_handler->animationClipLoaderManager();
for (const auto animationClipHandle : qAsConst(m_animationClipHandles)) {
AnimationClip *animationClip = animationClipManager->data(animationClipHandle);
+ Q_ASSERT(animationClip);
animationClip->loadAnimation();
}
diff --git a/src/animation/backend/managers_p.h b/src/animation/backend/managers_p.h
index 3c670a8d2..b88f1b8ae 100644
--- a/src/animation/backend/managers_p.h
+++ b/src/animation/backend/managers_p.h
@@ -54,10 +54,12 @@
#include <QtGlobal>
#include <Qt3DAnimation/private/handle_types_p.h>
#include <Qt3DAnimation/private/animationclip_p.h>
+#include <Qt3DAnimation/private/clock_p.h>
#include <Qt3DAnimation/private/blendedclipanimator_p.h>
#include <Qt3DAnimation/private/clipanimator_p.h>
#include <Qt3DAnimation/private/channelmapping_p.h>
#include <Qt3DAnimation/private/channelmapper_p.h>
+#include <Qt3DAnimation/private/skeleton_p.h>
#include <Qt3DCore/private/qresourcemanager_p.h>
QT_BEGIN_NAMESPACE
@@ -76,6 +78,15 @@ public:
AnimationClipLoaderManager() {}
};
+class ClockManager : public Qt3DCore::QResourceManager<
+ Clock,
+ Qt3DCore::QNodeId,
+ 16>
+{
+public:
+ ClockManager() {}
+};
+
class ClipAnimatorManager : public Qt3DCore::QResourceManager<
ClipAnimator,
Qt3DCore::QNodeId,
@@ -127,6 +138,15 @@ private:
QHash<Qt3DCore::QNodeId, ClipBlendNode *> m_nodes;
};
+class SkeletonManager : public Qt3DCore::QResourceManager<
+ Skeleton,
+ Qt3DCore::QNodeId,
+ 16>
+{
+public:
+ SkeletonManager() {}
+};
+
} // namespace Animation
} // namespace Qt3DAnimation
@@ -135,6 +155,7 @@ Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ClipAnimator, Q_REQUIRES_CLEAN
Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::BlendedClipAnimator, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ChannelMapping, Q_REQUIRES_CLEANUP)
Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::ChannelMapper, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DAnimation::Animation::Skeleton, Q_REQUIRES_CLEANUP)
QT_END_NAMESPACE
diff --git a/src/animation/backend/skeleton.cpp b/src/animation/backend/skeleton.cpp
new file mode 100644
index 000000000..dcfaf55e7
--- /dev/null
+++ b/src/animation/backend/skeleton.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "skeleton_p.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DAnimation {
+namespace Animation {
+
+// Rather than store backend nodes for the individual joints, the
+// animation aspect operates on the vector of local poses as aggregated
+// by the skeleton. This allows us to animate a skeleton even when the
+// frontend QSkeletonLoader does not instantiate the frontend QJoint nodes.
+// It also means we don't need a QChannelMapping for each property of each
+// joint.
+
+Skeleton::Skeleton()
+ : BackendNode(Qt3DCore::QBackendNode::ReadWrite)
+{
+}
+
+void Skeleton::cleanup()
+{
+ m_jointNames.clear();
+ m_jointLocalPoses.clear();
+}
+
+void Skeleton::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ // Nothing to initialize from the frontend. We get all of our internal state
+ // from whatever aspect loads the skeleton data - the render aspect in the
+ // default case.
+ Q_UNUSED(change);
+}
+
+void Skeleton::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ // Get the joint names and initial local poses from a change sent
+ // by the render aspect when the skeleton has been loaded.
+ switch (e->type()) {
+ case PropertyUpdated: {
+ const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("jointNamesAndLocalPoses")) {
+ const auto payload = change->value().value<JointNamesAndLocalPoses>();
+ m_jointNames = payload.names;
+ m_jointLocalPoses = payload.localPoses;
+
+ // TODO: Mark joint info as dirty so we can rebuild any indexes used
+ // by the animators and channel mappings.
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ BackendNode::sceneChangeEvent(e);
+}
+
+void Skeleton::sendLocalPoses()
+{
+ auto e = QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::BackendNodes);
+ e->setPropertyName("localPoses");
+ e->setValue(QVariant::fromValue(m_jointLocalPoses));
+ notifyObservers(e);
+}
+
+} // namespace Animation
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/backend/skeleton_p.h b/src/animation/backend/skeleton_p.h
new file mode 100644
index 000000000..e26e276d9
--- /dev/null
+++ b/src/animation/backend/skeleton_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_ANIMATION_SKELETON_H
+#define QT3DANIMATION_ANIMATION_SKELETON_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 <Qt3DAnimation/private/backendnode_p.h>
+#include <Qt3DCore/private/sqt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+namespace Animation {
+
+class Q_AUTOTEST_EXPORT Skeleton : public BackendNode
+{
+public:
+ Skeleton();
+
+ void cleanup();
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
+ int jointCount() const { return m_jointLocalPoses.size(); }
+
+ void setJointScale(int jointIndex, const QVector3D &scale)
+ {
+ m_jointLocalPoses[jointIndex].scale = scale;
+ }
+
+ void setJointRotation(int jointIndex, const QQuaternion &rotation)
+ {
+ m_jointLocalPoses[jointIndex].rotation = rotation;
+ }
+
+ void setJointTranslation(int jointIndex, const QVector3D &translation)
+ {
+ m_jointLocalPoses[jointIndex].translation = translation;
+ }
+
+ void sendLocalPoses();
+
+#if defined(QT_BUILD_INTERNAL)
+ void setJointCount(int jointCount)
+ {
+ m_jointNames.resize(jointCount);
+ m_jointLocalPoses.resize(jointCount);
+ }
+ void setJointNames(const QVector<QString> &names) { m_jointNames = names; }
+ QVector<QString> jointNames() const { return m_jointNames; }
+ void setJointLocalPoses(const QVector<Qt3DCore::Sqt> &localPoses) { m_jointLocalPoses = localPoses; }
+ QVector<Qt3DCore::Sqt> jointLocalPoses() const { return m_jointLocalPoses; }
+#endif
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ QVector<QString> m_jointNames;
+ QVector<Qt3DCore::Sqt> m_jointLocalPoses;
+};
+
+} // namespace Animation
+} // namespace Qt3DAnimation
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_ANIMATION_SKELETON_H
diff --git a/src/animation/frontend/frontend.pri b/src/animation/frontend/frontend.pri
index 9ea438395..baff81dd0 100644
--- a/src/animation/frontend/frontend.pri
+++ b/src/animation/frontend/frontend.pri
@@ -44,7 +44,19 @@ HEADERS += \
$$PWD/qchannelcomponent.h \
$$PWD/qkeyframe.h \
$$PWD/qanimationclip.h \
- $$PWD/qanimationclip_p.h
+ $$PWD/qanimationclip_p.h \
+ $$PWD/qanimationcallback.h \
+ $$PWD/qanimationcallbacktrigger_p.h \
+ $$PWD/qclock.h \
+ $$PWD/qclock_p.h \
+ $$PWD/qabstractchannelmapping.h \
+ $$PWD/qabstractchannelmapping_p.h \
+ $$PWD/qchannelmappingcreatedchange_p.h \
+ $$PWD/qchannelmappingcreatedchange_p_p.h \
+ $$PWD/qskeletonmapping.h \
+ $$PWD/qskeletonmapping_p.h \
+ $$PWD/qcallbackmapping.h \
+ $$PWD/qcallbackmapping_p.h
SOURCES += \
$$PWD/qanimationaspect.cpp \
@@ -71,6 +83,12 @@ SOURCES += \
$$PWD/qchannel.cpp \
$$PWD/qchannelcomponent.cpp \
$$PWD/qkeyframe.cpp \
- $$PWD/qanimationclip.cpp
+ $$PWD/qanimationclip.cpp \
+ $$PWD/qanimationcallbacktrigger.cpp \
+ $$PWD/qclock.cpp \
+ $$PWD/qabstractchannelmapping.cpp \
+ $$PWD/qchannelmappingcreatedchange.cpp \
+ $$PWD/qskeletonmapping.cpp \
+ $$PWD/qcallbackmapping.cpp
INCLUDEPATH += $$PWD
diff --git a/src/animation/frontend/qabstractchannelmapping.cpp b/src/animation/frontend/qabstractchannelmapping.cpp
new file mode 100644
index 000000000..3249e6876
--- /dev/null
+++ b/src/animation/frontend/qabstractchannelmapping.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qabstractchannelmapping.h"
+#include "qabstractchannelmapping_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QAbstractChannelMappingPrivate::QAbstractChannelMappingPrivate()
+ : Qt3DCore::QNodePrivate()
+{
+}
+
+/*! \internal */
+const QAbstractChannelMappingPrivate *QAbstractChannelMappingPrivate::get(const QAbstractChannelMapping *q)
+{
+ return q->d_func();
+}
+
+QAbstractChannelMapping::QAbstractChannelMapping(QAbstractChannelMappingPrivate &dd, Qt3DCore::QNode *parent)
+ : Qt3DCore::QNode(dd, parent)
+{
+}
+
+QAbstractChannelMapping::~QAbstractChannelMapping()
+{
+}
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qabstractchannelmapping.h b/src/animation/frontend/qabstractchannelmapping.h
new file mode 100644
index 000000000..564f51191
--- /dev/null
+++ b/src/animation/frontend/qabstractchannelmapping.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DANIMATION_QABSTRACTCHANNELMAPPING_H
+#define QT3DANIMATION_QABSTRACTCHANNELMAPPING_H
+
+#include <Qt3DCore/qnode.h>
+#include <Qt3DAnimation/qt3danimation_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QAbstractChannelMappingPrivate;
+
+class QT3DANIMATIONSHARED_EXPORT QAbstractChannelMapping : public Qt3DCore::QNode
+{
+ Q_OBJECT
+
+public:
+ ~QAbstractChannelMapping();
+
+protected:
+ QAbstractChannelMapping(QAbstractChannelMappingPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractChannelMapping)
+};
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QABSTRACTCHANNELMAPPING_H
diff --git a/src/animation/frontend/qabstractchannelmapping_p.h b/src/animation/frontend/qabstractchannelmapping_p.h
new file mode 100644
index 000000000..1a1de4ba9
--- /dev/null
+++ b/src/animation/frontend/qabstractchannelmapping_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DANIMATION_QABSTRACTCHANNELMAPPING_P_H
+#define QT3DANIMATION_QABSTRACTCHANNELMAPPING_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/private/qnode_p.h>
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QAbstractChannelMapping;
+
+class QAbstractChannelMappingPrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QAbstractChannelMappingPrivate();
+
+ static const QAbstractChannelMappingPrivate *get(const Qt3DAnimation::QAbstractChannelMapping *q);
+
+ Q_DECLARE_PUBLIC(QAbstractChannelMapping)
+
+ QChannelMappingCreatedChangeBase::MappingType m_mappingType;
+};
+
+struct QAbstractChannelMappingData
+{
+ // TODO: Add members that should be sent to the backend
+};
+
+} // namespace Qt3DAnimation
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QABSTRACTCHANNELMAPPING_P_H
diff --git a/src/animation/frontend/qabstractclipanimator.cpp b/src/animation/frontend/qabstractclipanimator.cpp
index 3fe660599..78ad01508 100644
--- a/src/animation/frontend/qabstractclipanimator.cpp
+++ b/src/animation/frontend/qabstractclipanimator.cpp
@@ -40,6 +40,7 @@
#include "qabstractclipanimator.h"
#include "qabstractclipanimator_p.h"
#include <Qt3DAnimation/qchannelmapper.h>
+#include <Qt3DAnimation/qclock.h>
QT_BEGIN_NAMESPACE
@@ -48,6 +49,7 @@ namespace Qt3DAnimation {
QAbstractClipAnimatorPrivate::QAbstractClipAnimatorPrivate()
: Qt3DCore::QComponentPrivate()
, m_mapper(nullptr)
+ , m_clock(nullptr)
, m_running(false)
, m_loops(1)
{
@@ -174,6 +176,12 @@ int QAbstractClipAnimator::loopCount() const
return d->m_loops;
}
+QClock *QAbstractClipAnimator::clock() const
+{
+ Q_D(const QAbstractClipAnimator);
+ return d->m_clock;
+}
+
void QAbstractClipAnimator::setRunning(bool running)
{
Q_D(QAbstractClipAnimator);
@@ -213,6 +221,24 @@ void QAbstractClipAnimator::setLoopCount(int loops)
emit loopCountChanged(loops);
}
+void QAbstractClipAnimator::setClock(QClock *clock)
+{
+ Q_D(QAbstractClipAnimator);
+ if (d->m_clock == clock)
+ return;
+
+ if (d->m_clock)
+ d->unregisterDestructionHelper(d->m_clock);
+
+ if (clock && !clock->parent())
+ clock->setParent(this);
+ d->m_clock = clock;
+
+ if (d->m_clock)
+ d->registerDestructionHelper(d->m_clock, &QAbstractClipAnimator::setClock, d->m_clock);
+ emit clockChanged(clock);
+}
+
/*!
Starts the animation.
*/
diff --git a/src/animation/frontend/qabstractclipanimator.h b/src/animation/frontend/qabstractclipanimator.h
index bd38fd68b..8fdb114f3 100644
--- a/src/animation/frontend/qabstractclipanimator.h
+++ b/src/animation/frontend/qabstractclipanimator.h
@@ -49,6 +49,7 @@ namespace Qt3DAnimation {
class QAnimationClip;
class QChannelMapper;
+class QClock;
class QAbstractClipAnimatorPrivate;
class QT3DANIMATIONSHARED_EXPORT QAbstractClipAnimator : public Qt3DCore::QComponent
@@ -57,6 +58,7 @@ class QT3DANIMATIONSHARED_EXPORT QAbstractClipAnimator : public Qt3DCore::QCompo
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
Q_PROPERTY(int loops READ loopCount WRITE setLoopCount NOTIFY loopCountChanged)
Q_PROPERTY(Qt3DAnimation::QChannelMapper *channelMapper READ channelMapper WRITE setChannelMapper NOTIFY channelMapperChanged)
+ Q_PROPERTY(Qt3DAnimation::QClock *clock READ clock WRITE setClock NOTIFY clockChanged)
public:
enum Loops { Infinite = -1 };
@@ -67,11 +69,13 @@ public:
bool isRunning() const;
Qt3DAnimation::QChannelMapper *channelMapper() const;
int loopCount() const;
+ Qt3DAnimation::QClock *clock() const;
public Q_SLOTS:
void setRunning(bool running);
void setChannelMapper(Qt3DAnimation::QChannelMapper *channelMapper);
void setLoopCount(int loops);
+ void setClock(Qt3DAnimation::QClock *clock);
void start();
void stop();
@@ -80,6 +84,7 @@ Q_SIGNALS:
void runningChanged(bool running);
void channelMapperChanged(Qt3DAnimation::QChannelMapper *channelMapper);
void loopCountChanged(int loops);
+ void clockChanged(Qt3DAnimation::QClock *clock);
protected:
explicit QAbstractClipAnimator(Qt3DCore::QNode *parent = nullptr);
diff --git a/src/animation/frontend/qabstractclipanimator_p.h b/src/animation/frontend/qabstractclipanimator_p.h
index 58553c8c1..4b0ef3339 100644
--- a/src/animation/frontend/qabstractclipanimator_p.h
+++ b/src/animation/frontend/qabstractclipanimator_p.h
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
class QChannelMapper;
+class QClock;
class QAbstractClipAnimatorPrivate : public Qt3DCore::QComponentPrivate
{
@@ -67,6 +68,7 @@ public:
Q_DECLARE_PUBLIC(QAbstractClipAnimator)
Qt3DAnimation::QChannelMapper *m_mapper;
+ Qt3DAnimation::QClock *m_clock;
bool m_running;
int m_loops;
};
@@ -74,6 +76,7 @@ public:
struct QAbstractClipAnimatorData
{
Qt3DCore::QNodeId mapperId;
+ Qt3DCore::QNodeId clockId;
bool running;
int loops;
};
diff --git a/src/animation/frontend/qanimationaspect.cpp b/src/animation/frontend/qanimationaspect.cpp
index 00f97d5b6..9b23a7b1d 100644
--- a/src/animation/frontend/qanimationaspect.cpp
+++ b/src/animation/frontend/qanimationaspect.cpp
@@ -40,9 +40,10 @@
#include "qanimationaspect.h"
#include "qanimationaspect_p.h"
#include <Qt3DAnimation/qabstractanimationclip.h>
+#include <Qt3DAnimation/qabstractchannelmapping.h>
+#include <Qt3DAnimation/qclock.h>
#include <Qt3DAnimation/qblendedclipanimator.h>
#include <Qt3DAnimation/qclipanimator.h>
-#include <Qt3DAnimation/qchannelmapping.h>
#include <Qt3DAnimation/qchannelmapper.h>
#include <Qt3DAnimation/qlerpclipblend.h>
#include <Qt3DAnimation/qadditiveclipblend.h>
@@ -53,6 +54,8 @@
#include <Qt3DAnimation/private/lerpclipblend_p.h>
#include <Qt3DAnimation/private/clipblendvalue_p.h>
#include <Qt3DAnimation/private/additiveclipblend_p.h>
+#include <Qt3DAnimation/private/skeleton_p.h>
+#include <Qt3DCore/qabstractskeleton.h>
QT_BEGIN_NAMESPACE
@@ -92,17 +95,21 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent)
Q_D(QAnimationAspect);
qRegisterMetaType<Qt3DAnimation::QAnimationClipLoader*>();
qRegisterMetaType<Qt3DAnimation::QChannelMapper*>();
+ qRegisterMetaType<QVector<Qt3DCore::Sqt>>();
registerBackendType<QAbstractAnimationClip>(
QSharedPointer<Animation::NodeFunctor<Animation::AnimationClip, Animation::AnimationClipLoaderManager>>::create(d->m_handler.data(),
- d->m_handler->animationClipLoaderManager()));
+ d->m_handler->animationClipLoaderManager()));
+ registerBackendType<QClock>(
+ QSharedPointer<Animation::NodeFunctor<Animation::Clock, Animation::ClockManager>>::create(d->m_handler.data(),
+ d->m_handler->clockManager()));
registerBackendType<QClipAnimator>(
QSharedPointer<Animation::NodeFunctor<Animation::ClipAnimator, Animation::ClipAnimatorManager>>::create(d->m_handler.data(),
d->m_handler->clipAnimatorManager()));
registerBackendType<QBlendedClipAnimator>(
QSharedPointer<Animation::NodeFunctor<Animation::BlendedClipAnimator, Animation::BlendedClipAnimatorManager>>::create(d->m_handler.data(),
d->m_handler->blendedClipAnimatorManager()));
- registerBackendType<QChannelMapping>(
+ registerBackendType<QAbstractChannelMapping>(
QSharedPointer<Animation::NodeFunctor<Animation::ChannelMapping, Animation::ChannelMappingManager>>::create(d->m_handler.data(),
d->m_handler->channelMappingManager()));
registerBackendType<QChannelMapper>(
@@ -117,6 +124,9 @@ QAnimationAspect::QAnimationAspect(QAnimationAspectPrivate &dd, QObject *parent)
registerBackendType<QClipBlendValue>(
QSharedPointer<Animation::ClipBlendNodeFunctor<Animation::ClipBlendValue, Animation::ClipAnimatorManager>>::create(d->m_handler.data(),
d->m_handler->clipBlendNodeManager()));
+ registerBackendType<Qt3DCore::QAbstractSkeleton>(
+ QSharedPointer<Animation::NodeFunctor<Animation::Skeleton, Animation::SkeletonManager>>::create(d->m_handler.data(),
+ d->m_handler->skeletonManager()));
}
/*! \internal */
diff --git a/src/animation/frontend/qanimationcallback.h b/src/animation/frontend/qanimationcallback.h
new file mode 100644
index 000000000..1fcbd657c
--- /dev/null
+++ b/src/animation/frontend/qanimationcallback.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QANIMATIONCALLBACK_H
+#define QT3DANIMATION_QANIMATIONCALLBACK_H
+
+#include <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DCore/qnode.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QT3DANIMATIONSHARED_EXPORT QAnimationCallback
+{
+public:
+ enum Flag {
+ OnOwningThread = 0x0,
+ OnThreadPool = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ virtual ~QAnimationCallback() { }
+
+ virtual void valueChanged(const QVariant &value) = 0;
+};
+
+} // namespace Qt3DAnimation
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt3DAnimation::QAnimationCallback::Flags)
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QANIMATIONCALLBACK_H
diff --git a/src/animation/frontend/qanimationcallbacktrigger.cpp b/src/animation/frontend/qanimationcallbacktrigger.cpp
new file mode 100644
index 000000000..83fccb5a4
--- /dev/null
+++ b/src/animation/frontend/qanimationcallbacktrigger.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** 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 "qanimationcallbacktrigger_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QAnimationCallbackTrigger::QAnimationCallbackTrigger(Qt3DCore::QNodeId subjectId)
+ : Qt3DCore::QSceneChange(Qt3DCore::CallbackTriggered, subjectId),
+ m_callback(nullptr)
+{
+}
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qanimationcallbacktrigger_p.h b/src/animation/frontend/qanimationcallbacktrigger_p.h
new file mode 100644
index 000000000..9a05d421f
--- /dev/null
+++ b/src/animation/frontend/qanimationcallbacktrigger_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 QT3DANIMATION_QANIMATIONCALLBACKTRIGGER_P_H
+#define QT3DANIMATION_QANIMATIONCALLBACKTRIGGER_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 <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DAnimation/qanimationcallback.h>
+#include <Qt3DCore/qscenechange.h>
+#include <QtCore/qsharedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class Q_AUTOTEST_EXPORT QAnimationCallbackTrigger : public Qt3DCore::QSceneChange
+{
+public:
+ QAnimationCallbackTrigger(Qt3DCore::QNodeId subjectId);
+
+ void setCallback(QAnimationCallback *callback) { m_callback = callback; }
+ QAnimationCallback *callback() const { return m_callback; }
+
+ void setValue(const QVariant &value) { m_value = value; }
+ QVariant value() const { return m_value; }
+
+private:
+ QAnimationCallback *m_callback;
+ QVariant m_value;
+};
+
+typedef QSharedPointer<QAnimationCallbackTrigger> QAnimationCallbackTriggerPtr;
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QANIMATIONCALLBACKTRIGGER_P_H
diff --git a/src/animation/frontend/qblendedclipanimator.cpp b/src/animation/frontend/qblendedclipanimator.cpp
index 93cc27f50..785c810d3 100644
--- a/src/animation/frontend/qblendedclipanimator.cpp
+++ b/src/animation/frontend/qblendedclipanimator.cpp
@@ -40,6 +40,7 @@
#include "qblendedclipanimator_p.h"
#include <Qt3DAnimation/qabstractclipblendnode.h>
#include <Qt3DAnimation/qchannelmapper.h>
+#include <Qt3DAnimation/qclock.h>
QT_BEGIN_NAMESPACE
@@ -312,6 +313,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QBlendedClipAnimator::createNodeCreationChan
Q_D(const QBlendedClipAnimator);
data.blendTreeRootId = Qt3DCore::qIdForNode(d->m_blendTreeRoot);
data.mapperId = Qt3DCore::qIdForNode(d->m_mapper);
+ data.clockId = Qt3DCore::qIdForNode(d->m_clock);
data.running = d->m_running;
data.loops = d->m_loops;
return creationChange;
diff --git a/src/animation/frontend/qcallbackmapping.cpp b/src/animation/frontend/qcallbackmapping.cpp
new file mode 100644
index 000000000..3fcc7cf5e
--- /dev/null
+++ b/src/animation/frontend/qcallbackmapping.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "qcallbackmapping.h"
+#include "qcallbackmapping_p.h"
+
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+#include <QtCore/qmetaobject.h>
+#include <QtCore/QMetaProperty>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QCallbackMappingPrivate::QCallbackMappingPrivate()
+ : QAbstractChannelMappingPrivate()
+ , m_channelName()
+ , m_type(static_cast<int>(QVariant::Invalid))
+ , m_callback(nullptr)
+ , m_callbackFlags(0)
+{
+ m_mappingType = QChannelMappingCreatedChangeBase::CallbackMapping;
+}
+
+/*!
+ \class QCallbackMapping
+ \inherits Qt3DCore::QAbstractChannelMapping
+ \inmodule Qt3DAnimation
+ \brief Allows to map the channels within the clip onto an invocation
+ of a callback object.
+*/
+
+QCallbackMapping::QCallbackMapping(Qt3DCore::QNode *parent)
+ : QAbstractChannelMapping(*new QCallbackMappingPrivate, parent)
+{
+}
+
+QCallbackMapping::QCallbackMapping(QCallbackMappingPrivate &dd, Qt3DCore::QNode *parent)
+ : QAbstractChannelMapping(dd, parent)
+{
+}
+
+QCallbackMapping::~QCallbackMapping()
+{
+}
+
+QString QCallbackMapping::channelName() const
+{
+ Q_D(const QCallbackMapping);
+ return d->m_channelName;
+}
+
+QAnimationCallback *QCallbackMapping::callback() const
+{
+ Q_D(const QCallbackMapping);
+ return d->m_callback;
+}
+
+void QCallbackMapping::setChannelName(const QString &channelName)
+{
+ Q_D(QCallbackMapping);
+ if (d->m_channelName == channelName)
+ return;
+
+ d->m_channelName = channelName;
+ emit channelNameChanged(channelName);
+}
+
+/*!
+ Associates a \a callback object with this channel mapping.
+
+ Such mappings do not have to have a target object and property name. When
+ the \a callback object is set, every change in the animated value will lead
+ to invoking the callback's
+ \l{QAnimationCallback::onValueChanged()}{onValueChanged()} function either
+ on the gui/main thread, or directly on one of the thread pool's worker
+ thread. This is controlled by \a flags.
+
+ \a type specifies the type (for example, QVariant::Vector3D,
+ QVariant::Color, or QMetaType::Float) of the animated value. When animating
+ node properties this does not need to be provided separately, however it
+ becomes important to supply this when there is only a callback.
+
+ \note A mapping can be associated both with a node property and a
+ callback. It is important however that \a type matches the type of the
+ property in this case. Note also that for properties of type QVariant (for
+ example, QParameter::value), the \a type is the type of the value stored in
+ the QVariant.
+
+ \note The \a callback pointer is expected to stay valid while any
+ associated animators are running.
+ */
+void QCallbackMapping::setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags)
+{
+ Q_D(QCallbackMapping);
+ if (d->m_type != type) {
+ d->m_type = type;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
+ e->setPropertyName("type");
+ e->setValue(QVariant(d->m_type));
+ notifyObservers(e);
+ }
+ if (d->m_callback != callback) {
+ d->m_callback = callback;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
+ e->setPropertyName("callback");
+ e->setValue(QVariant::fromValue(static_cast<void *>(d->m_callback)));
+ notifyObservers(e);
+ }
+ if (d->m_callbackFlags != flags) {
+ d->m_callbackFlags = flags;
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(id());
+ e->setPropertyName("callbackFlags");
+ e->setValue(QVariant::fromValue(int(d->m_callbackFlags)));
+ notifyObservers(e);
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QCallbackMapping::createNodeCreationChange() const
+{
+ auto creationChange = QChannelMappingCreatedChangePtr<QCallbackMappingData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QCallbackMapping);
+ data.channelName = d->m_channelName;
+ data.type = d->m_type;
+ data.callback = d->m_callback;
+ data.callbackFlags = d->m_callbackFlags;
+ return creationChange;
+}
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qcallbackmapping.h b/src/animation/frontend/qcallbackmapping.h
new file mode 100644
index 000000000..c52e284ff
--- /dev/null
+++ b/src/animation/frontend/qcallbackmapping.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QCALLBACKMAPPING_H
+#define QT3DANIMATION_QCALLBACKMAPPING_H
+
+#include <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DAnimation/qanimationcallback.h>
+#include <Qt3DAnimation/qabstractchannelmapping.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QCallbackMappingPrivate;
+
+class QT3DANIMATIONSHARED_EXPORT QCallbackMapping : public QAbstractChannelMapping
+{
+ Q_OBJECT
+ Q_PROPERTY(QString channelName READ channelName WRITE setChannelName NOTIFY channelNameChanged)
+
+public:
+ explicit QCallbackMapping(Qt3DCore::QNode *parent = nullptr);
+ ~QCallbackMapping();
+
+ QString channelName() const;
+ QAnimationCallback *callback() const;
+
+ void setCallback(int type, QAnimationCallback *callback, QAnimationCallback::Flags flags = QAnimationCallback::OnOwningThread);
+
+public Q_SLOTS:
+ void setChannelName(const QString &channelName);
+
+Q_SIGNALS:
+ void channelNameChanged(QString channelName);
+
+protected:
+ explicit QCallbackMapping(QCallbackMappingPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QCallbackMapping)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QCALLBACKMAPPING_H
diff --git a/src/animation/frontend/qcallbackmapping_p.h b/src/animation/frontend/qcallbackmapping_p.h
new file mode 100644
index 000000000..c966ca552
--- /dev/null
+++ b/src/animation/frontend/qcallbackmapping_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QCALLBACKMAPPING_P_H
+#define QT3DANIMATION_QCALLBACKMAPPING_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 <Qt3DAnimation/private/qabstractchannelmapping_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
+#include <Qt3DAnimation/qcallbackmapping.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QCallbackMappingPrivate : public QAbstractChannelMappingPrivate
+{
+public:
+ QCallbackMappingPrivate();
+
+ Q_DECLARE_PUBLIC(QCallbackMapping)
+
+ QString m_channelName;
+ int m_type;
+ QAnimationCallback *m_callback;
+ QAnimationCallback::Flags m_callbackFlags;
+};
+
+struct QCallbackMappingData
+{
+ QString channelName;
+ int type;
+ QAnimationCallback *callback;
+ QAnimationCallback::Flags callbackFlags;
+};
+
+} // namespace Qt3DAnimation
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QCALLBACKMAPPING_P_H
diff --git a/src/animation/frontend/qchannel.cpp b/src/animation/frontend/qchannel.cpp
index 9c74fad09..f5e4ac7a3 100644
--- a/src/animation/frontend/qchannel.cpp
+++ b/src/animation/frontend/qchannel.cpp
@@ -50,6 +50,7 @@ class QChannelPrivate
public:
QVector<QChannelComponent> m_channelComponents;
QString m_name;
+ int m_jointIndex = -1;
};
QChannel::QChannel()
@@ -90,6 +91,16 @@ QString QChannel::name() const
return d->m_name;
}
+void QChannel::setJointIndex(int jointIndex)
+{
+ d->m_jointIndex = jointIndex;
+}
+
+int QChannel::jointIndex() const
+{
+ return d->m_jointIndex;
+}
+
int QChannel::channelComponentCount() const
{
return d->m_channelComponents.size();
diff --git a/src/animation/frontend/qchannel.h b/src/animation/frontend/qchannel.h
index b94780689..50e574756 100644
--- a/src/animation/frontend/qchannel.h
+++ b/src/animation/frontend/qchannel.h
@@ -63,6 +63,9 @@ public:
void setName(const QString &name);
QString name() const;
+ void setJointIndex(int jointIndex);
+ int jointIndex() const;
+
int channelComponentCount() const;
void appendChannelComponent(const QChannelComponent &component);
void insertChannelComponent(int index, const QChannelComponent &component);
diff --git a/src/animation/frontend/qchannelmapper.cpp b/src/animation/frontend/qchannelmapper.cpp
index ef7353e9b..da0408c3a 100644
--- a/src/animation/frontend/qchannelmapper.cpp
+++ b/src/animation/frontend/qchannelmapper.cpp
@@ -70,7 +70,7 @@ QChannelMapper::~QChannelMapper()
{
}
-void QChannelMapper::addMapping(QChannelMapping *mapping)
+void QChannelMapper::addMapping(QAbstractChannelMapping *mapping)
{
Q_ASSERT(mapping);
Q_D(QChannelMapper);
@@ -95,7 +95,7 @@ void QChannelMapper::addMapping(QChannelMapping *mapping)
}
}
-void QChannelMapper::removeMapping(QChannelMapping *mapping)
+void QChannelMapper::removeMapping(QAbstractChannelMapping *mapping)
{
Q_ASSERT(mapping);
Q_D(QChannelMapper);
@@ -109,7 +109,7 @@ void QChannelMapper::removeMapping(QChannelMapping *mapping)
d->unregisterDestructionHelper(mapping);
}
-QVector<QChannelMapping *> QChannelMapper::mappings() const
+QVector<QAbstractChannelMapping *> QChannelMapper::mappings() const
{
Q_D(const QChannelMapper);
return d->m_mappings;
diff --git a/src/animation/frontend/qchannelmapper.h b/src/animation/frontend/qchannelmapper.h
index 14319f29b..fce59f6ab 100644
--- a/src/animation/frontend/qchannelmapper.h
+++ b/src/animation/frontend/qchannelmapper.h
@@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
class QChannelMapperPrivate;
-class QChannelMapping;
+class QAbstractChannelMapping;
class QT3DANIMATIONSHARED_EXPORT QChannelMapper : public Qt3DCore::QNode
{
@@ -55,9 +55,9 @@ public:
explicit QChannelMapper(Qt3DCore::QNode *parent = nullptr);
~QChannelMapper();
- void addMapping(QChannelMapping *mapping);
- void removeMapping(QChannelMapping *mapping);
- QVector<QChannelMapping *> mappings() const;
+ void addMapping(QAbstractChannelMapping *mapping);
+ void removeMapping(QAbstractChannelMapping *mapping);
+ QVector<QAbstractChannelMapping *> mappings() const;
protected:
explicit QChannelMapper(QChannelMapperPrivate &dd, Qt3DCore::QNode *parent = nullptr);
diff --git a/src/animation/frontend/qchannelmapper_p.h b/src/animation/frontend/qchannelmapper_p.h
index d05ea3277..45f8b0422 100644
--- a/src/animation/frontend/qchannelmapper_p.h
+++ b/src/animation/frontend/qchannelmapper_p.h
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
-class QChannelMapping;
+class QAbstractChannelMapping;
class QChannelMapperPrivate : public Qt3DCore::QNodePrivate
{
@@ -63,7 +63,7 @@ public:
Q_DECLARE_PUBLIC(QChannelMapper)
- QVector<QChannelMapping *> m_mappings;
+ QVector<QAbstractChannelMapping *> m_mappings;
};
struct QChannelMapperData
diff --git a/src/animation/frontend/qchannelmapping.cpp b/src/animation/frontend/qchannelmapping.cpp
index faa77f5db..722ce24b0 100644
--- a/src/animation/frontend/qchannelmapping.cpp
+++ b/src/animation/frontend/qchannelmapping.cpp
@@ -37,6 +37,7 @@
#include "qchannelmapping.h"
#include "qchannelmapping_p.h"
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <QtCore/qmetaobject.h>
@@ -47,13 +48,14 @@ QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
QChannelMappingPrivate::QChannelMappingPrivate()
- : Qt3DCore::QNodePrivate()
+ : QAbstractChannelMappingPrivate()
, m_channelName()
, m_target(nullptr)
, m_property()
, m_propertyName(nullptr)
, m_type(static_cast<int>(QVariant::Invalid))
{
+ m_mappingType = QChannelMappingCreatedChangeBase::ChannelMapping;
}
/*!
@@ -117,12 +119,12 @@ void QChannelMappingPrivate::updatePropertyNameAndType()
*/
QChannelMapping::QChannelMapping(Qt3DCore::QNode *parent)
- : Qt3DCore::QNode(*new QChannelMappingPrivate, parent)
+ : QAbstractChannelMapping(*new QChannelMappingPrivate, parent)
{
}
QChannelMapping::QChannelMapping(QChannelMappingPrivate &dd, Qt3DCore::QNode *parent)
- : Qt3DCore::QNode(dd, parent)
+ : QAbstractChannelMapping(dd, parent)
{
}
@@ -192,7 +194,7 @@ void QChannelMapping::setProperty(const QString &property)
Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const
{
- auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QChannelMappingData>::create(this);
+ auto creationChange = QChannelMappingCreatedChangePtr<QChannelMappingData>::create(this);
auto &data = creationChange->data;
Q_D(const QChannelMapping);
data.channelName = d->m_channelName;
diff --git a/src/animation/frontend/qchannelmapping.h b/src/animation/frontend/qchannelmapping.h
index d768298fe..893b98e86 100644
--- a/src/animation/frontend/qchannelmapping.h
+++ b/src/animation/frontend/qchannelmapping.h
@@ -38,7 +38,8 @@
#define QT3DANIMATION_QCHANNELMAPPING_H
#include <Qt3DAnimation/qt3danimation_global.h>
-#include <Qt3DCore/qnode.h>
+#include <Qt3DAnimation/qanimationcallback.h>
+#include <Qt3DAnimation/qabstractchannelmapping.h>
QT_BEGIN_NAMESPACE
@@ -46,7 +47,7 @@ namespace Qt3DAnimation {
class QChannelMappingPrivate;
-class QT3DANIMATIONSHARED_EXPORT QChannelMapping : public Qt3DCore::QNode
+class QT3DANIMATIONSHARED_EXPORT QChannelMapping : public QAbstractChannelMapping
{
Q_OBJECT
Q_PROPERTY(QString channelName READ channelName WRITE setChannelName NOTIFY channelNameChanged)
diff --git a/src/animation/frontend/qchannelmapping_p.h b/src/animation/frontend/qchannelmapping_p.h
index 2c48b0485..b7de3b821 100644
--- a/src/animation/frontend/qchannelmapping_p.h
+++ b/src/animation/frontend/qchannelmapping_p.h
@@ -48,13 +48,14 @@
// We mean it.
//
-#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DAnimation/private/qabstractchannelmapping_p.h>
+#include <Qt3DAnimation/qanimationcallback.h>
QT_BEGIN_NAMESPACE
namespace Qt3DAnimation {
-class QChannelMappingPrivate : public Qt3DCore::QNodePrivate
+class QChannelMappingPrivate : public QAbstractChannelMappingPrivate
{
public:
QChannelMappingPrivate();
diff --git a/src/animation/frontend/qchannelmappingcreatedchange.cpp b/src/animation/frontend/qchannelmappingcreatedchange.cpp
new file mode 100644
index 000000000..6da1eb23e
--- /dev/null
+++ b/src/animation/frontend/qchannelmappingcreatedchange.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "qchannelmappingcreatedchange_p.h"
+#include "qchannelmappingcreatedchange_p_p.h"
+#include <Qt3DAnimation/private/qabstractchannelmapping_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QChannelMappingCreatedChangeBasePrivate::QChannelMappingCreatedChangeBasePrivate(const QAbstractChannelMapping *mapping)
+ : Qt3DCore::QNodeCreatedChangeBasePrivate(mapping)
+ , m_mappingType(QAbstractChannelMappingPrivate::get(mapping)->m_mappingType)
+{
+}
+
+/*!
+ \class QChannelmappingCreatedChangeBase
+ \inmodule Qt3DCore
+ \brief Base class for handling creation changes for QAbstractSkeleton sub-classes
+*/
+QChannelMappingCreatedChangeBase::QChannelMappingCreatedChangeBase(const QAbstractChannelMapping *mapping)
+ : Qt3DCore::QNodeCreatedChangeBase(*new QChannelMappingCreatedChangeBasePrivate(mapping), mapping)
+{
+}
+
+/*! \internal */
+QChannelMappingCreatedChangeBase::~QChannelMappingCreatedChangeBase()
+{
+}
+
+/*! \internal */
+QChannelMappingCreatedChangeBase::MappingType QChannelMappingCreatedChangeBase::type() const
+{
+ Q_D(const QChannelMappingCreatedChangeBase);
+ return d->m_mappingType;
+}
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qchannelmappingcreatedchange_p.h b/src/animation/frontend/qchannelmappingcreatedchange_p.h
new file mode 100644
index 000000000..b01a97acc
--- /dev/null
+++ b/src/animation/frontend/qchannelmappingcreatedchange_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QCHANNELMAPPINGCREATEDCHANGE_P_H
+#define QT3DANIMATION_QCHANNELMAPPINGCREATEDCHANGE_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/qnodecreatedchange.h>
+#include <Qt3DAnimation/qabstractchannelmapping.h>
+#include <Qt3DAnimation/private/qt3danimation_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QChannelMappingCreatedChangeBasePrivate;
+
+class QT3DANIMATIONSHARED_PRIVATE_EXPORT QChannelMappingCreatedChangeBase : public Qt3DCore::QNodeCreatedChangeBase
+{
+public:
+ explicit QChannelMappingCreatedChangeBase(const QAbstractChannelMapping *mapping);
+ ~QChannelMappingCreatedChangeBase();
+
+ enum MappingType {
+ ChannelMapping = 0,
+ SkeletonMapping,
+ CallbackMapping
+ };
+
+ MappingType type() const;
+
+private:
+ Q_DECLARE_PRIVATE(QChannelMappingCreatedChangeBase)
+};
+
+typedef QSharedPointer<QChannelMappingCreatedChangeBase> QChannelMappingCreatedChangeBasePtr;
+
+template<typename T>
+class QChannelMappingCreatedChange : public QChannelMappingCreatedChangeBase
+{
+public:
+ explicit QChannelMappingCreatedChange(const QAbstractChannelMapping *_mapping)
+ : QChannelMappingCreatedChangeBase(_mapping)
+ , data()
+ {
+ }
+
+ T data;
+};
+
+template<typename T>
+using QChannelMappingCreatedChangePtr = QSharedPointer<QChannelMappingCreatedChange<T>>;
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QCHANNELMAPPINGCREATEDCHANGE_P_H
diff --git a/src/animation/frontend/qchannelmappingcreatedchange_p_p.h b/src/animation/frontend/qchannelmappingcreatedchange_p_p.h
new file mode 100644
index 000000000..8a89104a8
--- /dev/null
+++ b/src/animation/frontend/qchannelmappingcreatedchange_p_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QCHANNELMAPPINGCREATEDCHANGE_P_P_H
+#define QT3DANIMATION_QCHANNELMAPPINGCREATEDCHANGE_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 <Qt3DCore/private/qnodecreatedchange_p.h>
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QAbstractChannelMapping;
+
+class QChannelMappingCreatedChangeBasePrivate : public Qt3DCore::QNodeCreatedChangeBasePrivate
+{
+public:
+ QChannelMappingCreatedChangeBasePrivate(const QAbstractChannelMapping *mapping);
+
+ QChannelMappingCreatedChangeBase::MappingType m_mappingType;
+};
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QCHANNELMAPPINGCREATEDCHANGE_P_P_H
diff --git a/src/animation/frontend/qclipanimator.cpp b/src/animation/frontend/qclipanimator.cpp
index 750da352d..6b503e87f 100644
--- a/src/animation/frontend/qclipanimator.cpp
+++ b/src/animation/frontend/qclipanimator.cpp
@@ -41,6 +41,8 @@
#include "qclipanimator_p.h"
#include <Qt3DAnimation/qabstractanimationclip.h>
#include <Qt3DAnimation/qchannelmapper.h>
+#include <Qt3DAnimation/qclock.h>
+#include <Qt3DAnimation/private/qanimationcallbacktrigger_p.h>
QT_BEGIN_NAMESPACE
@@ -159,11 +161,24 @@ Qt3DCore::QNodeCreatedChangeBasePtr QClipAnimator::createNodeCreationChange() co
Q_D(const QClipAnimator);
data.clipId = Qt3DCore::qIdForNode(d->m_clip);
data.mapperId = Qt3DCore::qIdForNode(d->m_mapper);
+ data.clockId = Qt3DCore::qIdForNode(d->m_clock);
data.running = d->m_running;
data.loops = d->m_loops;
return creationChange;
}
+/*! \internal */
+void QClipAnimator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ if (change->type() == Qt3DCore::CallbackTriggered) {
+ QAnimationCallbackTriggerPtr callbackTrigger = qSharedPointerCast<Qt3DAnimation::QAnimationCallbackTrigger>(change);
+ if (callbackTrigger->callback())
+ callbackTrigger->callback()->valueChanged(callbackTrigger->value());
+ } else if (change->type() == Qt3DCore::PropertyUpdated) {
+ QAbstractClipAnimator::sceneChangeEvent(change);
+ }
+}
+
} // namespace Qt3DAnimation
QT_END_NAMESPACE
diff --git a/src/animation/frontend/qclipanimator.h b/src/animation/frontend/qclipanimator.h
index 311ac4ab0..7b06f9878 100644
--- a/src/animation/frontend/qclipanimator.h
+++ b/src/animation/frontend/qclipanimator.h
@@ -70,6 +70,7 @@ Q_SIGNALS:
protected:
QClipAnimator(QClipAnimatorPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QClipAnimator)
diff --git a/src/animation/frontend/qclock.cpp b/src/animation/frontend/qclock.cpp
new file mode 100644
index 000000000..6dd851b88
--- /dev/null
+++ b/src/animation/frontend/qclock.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "qclock.h"
+#include "qclock_p.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QClockPrivate::QClockPrivate()
+ : Qt3DCore::QNodePrivate()
+ , m_playbackRate(1.0f)
+{
+}
+
+QClock::QClock(Qt3DCore::QNode* parent)
+ : Qt3DCore::QNode(*new QClockPrivate, parent)
+{
+}
+
+QClock::QClock(QClockPrivate &dd, Qt3DCore::QNode *parent)
+ : Qt3DCore::QNode(dd, parent)
+{
+}
+
+QClock::~QClock()
+{
+}
+
+double QClock::playbackRate() const
+{
+ Q_D(const QClock);
+ return d->m_playbackRate;
+}
+
+void QClock::setPlaybackRate(double playbackRate)
+{
+ Q_D(QClock);
+ if (qFuzzyCompare(playbackRate, d->m_playbackRate))
+ return;
+ d->m_playbackRate = playbackRate;
+ emit playbackRateChanged(playbackRate);
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QClock::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QClockData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QClock);
+ data.playbackRate = d->m_playbackRate;
+ return creationChange;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qclock.h b/src/animation/frontend/qclock.h
new file mode 100644
index 000000000..d2bf91103
--- /dev/null
+++ b/src/animation/frontend/qclock.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+ ** 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$
+ **
+ ****************************************************************************/
+
+#ifndef QT3DANIMATION_QCLOCK_H
+#define QT3DANIMATION_QCLOCK_H
+
+#include <Qt3DAnimation/qt3danimation_global.h>
+#include <Qt3DCore/qnode.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QClockPrivate;
+
+class QT3DANIMATIONSHARED_EXPORT QClock : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(double playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
+
+public:
+ explicit QClock(Qt3DCore::QNode *parent = nullptr);
+ ~QClock();
+
+ double playbackRate() const;
+ void setPlaybackRate(double playbackRate);
+
+Q_SIGNALS:
+ void playbackRateChanged(double playbackRate);
+
+protected:
+ QClock(QClockPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QClock)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QCLOCK_H
diff --git a/src/animation/frontend/qclock_p.h b/src/animation/frontend/qclock_p.h
new file mode 100644
index 000000000..c862d9082
--- /dev/null
+++ b/src/animation/frontend/qclock_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DANIMATION_QCLOCK_P_H
+#define QT3DANIMATION_QCLOCK_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/private/qnode_p.h>
+#include "qclock.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+class QClockPrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QClockPrivate();
+
+ Q_DECLARE_PUBLIC(QClock)
+
+ double m_playbackRate;
+};
+
+struct QClockData
+{
+ double playbackRate;
+};
+
+} // namespace Qt3DAnimation
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QCLOCK_P_H
diff --git a/src/animation/frontend/qskeletonmapping.cpp b/src/animation/frontend/qskeletonmapping.cpp
new file mode 100644
index 000000000..7569a5bab
--- /dev/null
+++ b/src/animation/frontend/qskeletonmapping.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qskeletonmapping.h"
+#include "qskeletonmapping_p.h"
+#include <Qt3DCore/qabstractskeleton.h>
+
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DAnimation {
+
+QSkeletonMappingPrivate::QSkeletonMappingPrivate()
+ : QAbstractChannelMappingPrivate()
+ , m_skeleton(nullptr)
+{
+ m_mappingType = QChannelMappingCreatedChangeBase::SkeletonMapping;
+}
+
+QSkeletonMapping::QSkeletonMapping(Qt3DCore::QNode *parent)
+ : QAbstractChannelMapping(*new QSkeletonMappingPrivate, parent)
+{
+}
+
+QSkeletonMapping::QSkeletonMapping(QSkeletonMappingPrivate &dd, Qt3DCore::QNode *parent)
+ : QAbstractChannelMapping(dd, parent)
+{
+}
+
+QSkeletonMapping::~QSkeletonMapping()
+{
+}
+
+Qt3DCore::QAbstractSkeleton *QSkeletonMapping::skeleton() const
+{
+ Q_D(const QSkeletonMapping);
+ return d->m_skeleton;
+}
+
+void QSkeletonMapping::setSkeleton(Qt3DCore::QAbstractSkeleton *skeleton)
+{
+ Q_D(QSkeletonMapping);
+ if (d->m_skeleton == skeleton)
+ return;
+
+ if (d->m_skeleton)
+ d->unregisterDestructionHelper(d->m_skeleton);
+
+ if (skeleton && !skeleton->parent())
+ skeleton->setParent(this);
+ d->m_skeleton = skeleton;
+
+ // Ensures proper bookkeeping
+ if (d->m_skeleton)
+ d->registerDestructionHelper(d->m_skeleton, &QSkeletonMapping::setSkeleton, d->m_skeleton);
+
+ emit skeletonChanged(skeleton);
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QSkeletonMapping::createNodeCreationChange() const
+{
+ auto creationChange = QChannelMappingCreatedChangePtr<QSkeletonMappingData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QSkeletonMapping);
+ data.skeletonId = Qt3DCore::qIdForNode(d->m_skeleton);
+ return creationChange;
+}
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
diff --git a/src/animation/frontend/qskeletonmapping.h b/src/animation/frontend/qskeletonmapping.h
new file mode 100644
index 000000000..2c698da8e
--- /dev/null
+++ b/src/animation/frontend/qskeletonmapping.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DANIMATION_QSKELETONMAPPING_H
+#define QT3DANIMATION_QSKELETONMAPPING_H
+
+#include <Qt3DAnimation/qabstractchannelmapping.h>
+#include <Qt3DAnimation/qt3danimation_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QAbstractSkeleton;
+}
+
+namespace Qt3DAnimation {
+
+class QSkeletonMappingPrivate;
+
+class QT3DANIMATIONSHARED_EXPORT QSkeletonMapping : public QAbstractChannelMapping
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DCore::QAbstractSkeleton* skeleton READ skeleton WRITE setSkeleton NOTIFY skeletonChanged)
+
+public:
+ explicit QSkeletonMapping(Qt3DCore::QNode *parent = nullptr);
+ ~QSkeletonMapping();
+
+ Qt3DCore::QAbstractSkeleton *skeleton() const;
+
+public Q_SLOTS:
+ void setSkeleton(Qt3DCore::QAbstractSkeleton *skeleton);
+
+Q_SIGNALS:
+ void skeletonChanged(Qt3DCore::QAbstractSkeleton *skeleton);
+
+protected:
+ QSkeletonMapping(QSkeletonMappingPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QSkeletonMapping)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DAnimation
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QSKELETONMAPPING_H
diff --git a/src/animation/frontend/qskeletonmapping_p.h b/src/animation/frontend/qskeletonmapping_p.h
new file mode 100644
index 000000000..af8382b23
--- /dev/null
+++ b/src/animation/frontend/qskeletonmapping_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DANIMATION_QSKELETONMAPPING_P_H
+#define QT3DANIMATION_QSKELETONMAPPING_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 <Qt3DAnimation//private/qabstractchannelmapping_p.h>
+#include <Qt3DAnimation/qskeletonmapping.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QAbstractSkeleton;
+}
+
+namespace Qt3DAnimation {
+
+class QSkeletonMappingPrivate : public QAbstractChannelMappingPrivate
+{
+public:
+ QSkeletonMappingPrivate();
+
+ Q_DECLARE_PUBLIC(QSkeletonMapping)
+
+ Qt3DCore::QAbstractSkeleton *m_skeleton;
+};
+
+struct QSkeletonMappingData
+{
+ Qt3DCore::QNodeId skeletonId;
+};
+
+} // namespace Qt3DAnimation
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DANIMATION_QSKELETONMAPPING_P_H
diff --git a/src/core/aspects/aspects.pri b/src/core/aspects/aspects.pri
index 54d939138..ced33f310 100644
--- a/src/core/aspects/aspects.pri
+++ b/src/core/aspects/aspects.pri
@@ -18,7 +18,7 @@ HEADERS += \
INCLUDEPATH += $$PWD
-include($$OUT_PWD/../core/qt3dcore-config.pri)
+include($$QT3D_BUILD_ROOT/src/core/qt3dcore-config.pri)
QT_FOR_CONFIG += 3dcore-private
qtConfig(qt3d-profile-jobs): {
HEADERS += $$PWD/aspectcommanddebugger_p.h
diff --git a/src/core/aspects/qabstractaspect.cpp b/src/core/aspects/qabstractaspect.cpp
index 710522356..dd1f37da4 100644
--- a/src/core/aspects/qabstractaspect.cpp
+++ b/src/core/aspects/qabstractaspect.cpp
@@ -219,8 +219,6 @@ QBackendNode *QAbstractAspectPrivate::createBackendNode(const QNodeCreatedChange
QBackendNodePrivate *backendPriv = QBackendNodePrivate::get(backend);
backendPriv->setEnabled(change->isNodeEnabled());
- backend->initializeFromPeer(change);
-
// TO DO: Find a way to specify the changes to observe
// Register backendNode with QChangeArbiter
if (m_arbiter != nullptr) { // Unit tests may not have the arbiter registered
@@ -230,6 +228,9 @@ QBackendNode *QAbstractAspectPrivate::createBackendNode(const QNodeCreatedChange
if (backend->mode() == QBackendNode::ReadWrite)
m_arbiter->scene()->addObservable(backendPriv, backend->peerId());
}
+
+ backend->initializeFromPeer(change);
+
return backend;
}
@@ -290,7 +291,15 @@ QAbstractAspectJobManager *QAbstractAspectPrivate::jobManager() const
QVector<QAspectJobPtr> QAbstractAspectPrivate::jobsToExecute(qint64 time)
{
Q_Q(QAbstractAspect);
- return q->jobsToExecute(time);
+ auto res = q->jobsToExecute(time);
+
+ {
+ QMutexLocker lock(&m_singleShotMutex);
+ res << m_singleShotJobs;
+ m_singleShotJobs.clear();
+ }
+
+ return res;
}
/*!
@@ -332,6 +341,13 @@ void QAbstractAspect::onEngineShutdown()
{
}
+void QAbstractAspect::scheduleSingleShotJob(const Qt3DCore::QAspectJobPtr &job)
+{
+ Q_D(QAbstractAspect);
+ QMutexLocker lock(&d->m_singleShotMutex);
+ d->m_singleShotJobs.push_back(job);
+}
+
namespace Debug {
AsynchronousCommandReply::AsynchronousCommandReply(const QString &commandName, QObject *parent)
diff --git a/src/core/aspects/qabstractaspect.h b/src/core/aspects/qabstractaspect.h
index 66f0bdc24..8ac1b251f 100644
--- a/src/core/aspects/qabstractaspect.h
+++ b/src/core/aspects/qabstractaspect.h
@@ -68,6 +68,8 @@ public:
explicit QAbstractAspect(QObject *parent = nullptr);
~QAbstractAspect();
+ void scheduleSingleShotJob(const Qt3DCore::QAspectJobPtr &job);
+
protected:
explicit QAbstractAspect(QAbstractAspectPrivate &dd, QObject *parent = nullptr);
diff --git a/src/core/aspects/qabstractaspect_p.h b/src/core/aspects/qabstractaspect_p.h
index e64970649..a6c47c494 100644
--- a/src/core/aspects/qabstractaspect_p.h
+++ b/src/core/aspects/qabstractaspect_p.h
@@ -61,6 +61,9 @@
#include <Qt3DCore/private/qt3dcore_global_p.h>
#include <QtCore/private/qobject_p.h>
+#include <QMutex>
+#include <QVector>
+
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
@@ -137,6 +140,8 @@ public:
QAbstractAspectJobManager *m_jobManager;
QChangeArbiter *m_arbiter;
QHash<const QMetaObject*, QBackendNodeMapperPtr> m_backendCreatorFunctors;
+ QMutex m_singleShotMutex;
+ QVector<QAspectJobPtr> m_singleShotJobs;
static QAbstractAspectPrivate *get(QAbstractAspect *aspect);
};
diff --git a/src/core/aspects/qaspectengine.cpp b/src/core/aspects/qaspectengine.cpp
index ef4faa4bd..1467f0cff 100644
--- a/src/core/aspects/qaspectengine.cpp
+++ b/src/core/aspects/qaspectengine.cpp
@@ -59,7 +59,7 @@
#include <Qt3DCore/private/qservicelocator_p.h>
#include <Qt3DCore/qt3dcore-config.h>
-#if defined(QT3D_JOBS_RUN_STATS)
+#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
#endif
@@ -77,9 +77,9 @@ QAspectEnginePrivate::QAspectEnginePrivate()
, m_postman(nullptr)
, m_scene(nullptr)
, m_initialized(false)
- #ifdef QT3D_JOBS_RUN_STATS
+ #if QT_CONFIG(qt3d_profile_jobs)
, m_commandDebugger(new Debug::AspectCommandDebugger(q_func()))
- #endif // QT3D_JOBS_RUN_STATS
+ #endif
{
qRegisterMetaType<Qt3DCore::QAbstractAspect *>();
qRegisterMetaType<Qt3DCore::QObserverInterface *>();
@@ -235,10 +235,10 @@ void QAspectEnginePrivate::initialize()
"setScene",
Q_ARG(Qt3DCore::QScene*, m_scene));
m_initialized = true;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
m_commandDebugger->setAspectEngine(q_func());
m_commandDebugger->initialize();
-#endif // QT3D_JOBS_RUN_STATS
+#endif
}
/*!
diff --git a/src/core/aspects/qaspectengine_p.h b/src/core/aspects/qaspectengine_p.h
index a7311d054..6b0aae9cb 100644
--- a/src/core/aspects/qaspectengine_p.h
+++ b/src/core/aspects/qaspectengine_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <Qt3DCore/qt3dcore-config.h>
+#include <Qt3DCore/private/qt3dcore_global_p.h>
#include <Qt3DCore/qnodecreatedchange.h>
#include <QtCore/qsharedpointer.h>
@@ -69,11 +69,11 @@ class QAspectThread;
class QPostman;
class QScene;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
namespace Debug {
class AspectCommandDebugger;
} // Debug
-#endif // QT3D_JOBS_RUN_STATS
+#endif
class QT3DCORE_PRIVATE_EXPORT QAspectEnginePrivate : public QObjectPrivate
{
@@ -92,9 +92,9 @@ public:
QHash<QString, QAbstractAspect *> m_namedAspects;
bool m_initialized;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
Debug::AspectCommandDebugger *m_commandDebugger;
-#endif // QT3D_JOBS_RUN_STATS
+#endif
void initialize();
void shutdown();
diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp
index 5ccc89b9e..e2f0d9383 100644
--- a/src/core/aspects/qaspectmanager.cpp
+++ b/src/core/aspects/qaspectmanager.cpp
@@ -289,7 +289,7 @@ void QAspectManager::exec()
//
// Doing this as the first call in the new frame ensures the lock free approach works
// without any such data race.
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
const quint32 arbiterId = 4096;
JobRunStats changeArbiterStats;
changeArbiterStats.jobId.typeAndInstance[0] = arbiterId;
@@ -298,7 +298,7 @@ void QAspectManager::exec()
changeArbiterStats.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
#endif
m_changeArbiter->syncChanges();
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
changeArbiterStats.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
QThreadPooler::addJobLogStatsEntry(changeArbiterStats);
#endif
diff --git a/src/core/changes/changes.pri b/src/core/changes/changes.pri
index 49d560a56..39c6a4022 100644
--- a/src/core/changes/changes.pri
+++ b/src/core/changes/changes.pri
@@ -35,7 +35,11 @@ HEADERS += \
$$PWD/qpropertyvalueaddedchange.h \
$$PWD/qpropertyvalueaddedchange_p.h \
$$PWD/qpropertyvalueremovedchange.h \
- $$PWD/qpropertyvalueremovedchange_p.h
+ $$PWD/qpropertyvalueremovedchange_p.h \
+ $$PWD/qnodecommand.h \
+ $$PWD/qnodecommand_p.h \
+ $$PWD/qskeletoncreatedchange_p.h \
+ $$PWD/qskeletoncreatedchange_p_p.h
SOURCES += \
$$PWD/qscenechange.cpp \
@@ -54,4 +58,6 @@ SOURCES += \
$$PWD/qpropertynodeaddedchange.cpp \
$$PWD/qpropertynoderemovedchange.cpp \
$$PWD/qpropertyvalueaddedchange.cpp \
- $$PWD/qpropertyvalueremovedchange.cpp
+ $$PWD/qpropertyvalueremovedchange.cpp \
+ $$PWD/qnodecommand.cpp \
+ $$PWD/qskeletoncreatedchange.cpp
diff --git a/src/core/changes/qnodecommand.cpp b/src/core/changes/qnodecommand.cpp
new file mode 100644
index 000000000..ae5ae46f1
--- /dev/null
+++ b/src/core/changes/qnodecommand.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "qnodecommand.h"
+#include "qnodecommand_p.h"
+#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/private/qnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QNodeCommandPrivate::QNodeCommandPrivate()
+ : QSceneChangePrivate()
+ , m_commandId(createId())
+ , m_replyToCommandId()
+{
+}
+
+QNodeCommandPrivate::~QNodeCommandPrivate()
+{
+}
+
+QNodeCommand::CommandId QNodeCommandPrivate::createId()
+{
+ static QBasicAtomicInteger<QNodeCommand::CommandId> next = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return next.fetchAndAddRelaxed(1) + 1;
+}
+
+/*!
+ * \class Qt3DCore::QNodeCommand
+ * \inheaderfile Qt3DCore/QNodeCommand
+ * \inherits Qt3DCore::QSceneChange
+ * \inmodule Qt3DCore
+ * \since 5.9
+ * \brief The QNodeCommand class is the base class for all CommandRequested QSceneChange events
+ *
+ * The QNodeCommand class is the base class for all QSceneChange events that
+ * have the changeType() CommandRequested.
+ *
+ * You can subclass this to create your own node update types for communication between
+ * your QNode and QBackendNode subclasses when writing your own aspects.
+ */
+
+/*!
+ * \typedef Qt3DCore::QNodeCommandPtr
+ * \relates Qt3DCore::QNodeCommand
+ *
+ * A shared pointer for QNodeCommand.
+ */
+
+/*!
+ * Constructs a new QNodeCommand with \a node.
+ */
+QNodeCommand::QNodeCommand(QNodeId id)
+ : QSceneChange(*new QNodeCommandPrivate(), CommandRequested, id)
+{
+}
+
+QNodeCommand::QNodeCommand(QNodeCommandPrivate &dd, QNodeId id)
+ : QSceneChange(dd, CommandRequested, id)
+{
+}
+
+QNodeCommand::~QNodeCommand()
+{
+}
+
+/*!
+ * \return commandId.
+ */
+QNodeCommand::CommandId QNodeCommand::commandId() const
+{
+ Q_D(const QNodeCommand);
+ return d->m_commandId;
+}
+
+/*!
+ * \return name.
+ */
+QString QNodeCommand::name() const
+{
+ Q_D(const QNodeCommand);
+ return d->m_name;
+}
+
+void QNodeCommand::setName(const QString &name)
+{
+ Q_D(QNodeCommand);
+ d->m_name = name;
+}
+
+/*!
+ * \return data.
+ */
+QVariant QNodeCommand::data() const
+{
+ Q_D(const QNodeCommand);
+ return d->m_data;
+}
+
+void QNodeCommand::setData(const QVariant &data)
+{
+ Q_D(QNodeCommand);
+ d->m_data = data;
+}
+
+QNodeCommand::CommandId QNodeCommand::inReplyTo() const
+{
+ Q_D(const QNodeCommand);
+ return d->m_replyToCommandId;
+}
+
+void QNodeCommand::setReplyToCommandId(QNodeCommand::CommandId id)
+{
+ Q_D(QNodeCommand);
+ d->m_replyToCommandId = id;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/changes/qnodecommand.h b/src/core/changes/qnodecommand.h
new file mode 100644
index 000000000..f4371b03c
--- /dev/null
+++ b/src/core/changes/qnodecommand.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DCORE_QNODECOMMAND_H
+#define QT3DCORE_QNODECOMMAND_H
+
+#include <Qt3DCore/qt3dcore_global.h>
+#include <Qt3DCore/qscenechange.h>
+
+#include <QtCore/qsharedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QNodeCommandPrivate;
+
+class QT3DCORESHARED_EXPORT QNodeCommand : public QSceneChange
+{
+public:
+#if defined(Q_ATOMIC_INT64_IS_SUPPORTED)
+ typedef quint64 CommandId;
+#else
+ typedef quint32 CommandId;
+#endif
+
+ explicit QNodeCommand(QNodeId id);
+ ~QNodeCommand();
+
+ CommandId commandId() const;
+
+ QString name() const;
+ void setName(const QString &name);
+ QVariant data() const;
+ void setData(const QVariant &data);
+ CommandId inReplyTo() const;
+ void setReplyToCommandId(CommandId id);
+
+protected:
+ explicit QNodeCommand(QNodeCommandPrivate &dd, QNodeId id);
+
+private:
+ Q_DECLARE_PRIVATE(QNodeCommand)
+};
+
+typedef QSharedPointer<QNodeCommand> QNodeCommandPtr;
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QNODECOMMAND_H
diff --git a/src/core/changes/qnodecommand_p.h b/src/core/changes/qnodecommand_p.h
new file mode 100644
index 000000000..dd4259b20
--- /dev/null
+++ b/src/core/changes/qnodecommand_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DCORE_QNODECOMMAND_P_H
+#define QT3DCORE_QNODECOMMAND_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 <private/qt3dcore_global_p.h>
+#include <private/qscenechange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QT3DCORE_PRIVATE_EXPORT QNodeCommandPrivate : public QSceneChangePrivate
+{
+public:
+ QNodeCommandPrivate();
+ ~QNodeCommandPrivate();
+
+ static QNodeCommand::CommandId createId();
+
+ QNodeCommand::CommandId m_commandId;
+ QNodeCommand::CommandId m_replyToCommandId;
+ QString m_name;
+ QVariant m_data;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QNODECOMMAND_P_H
diff --git a/src/core/changes/qscenechange.cpp b/src/core/changes/qscenechange.cpp
index df15e239d..03fe7e5d7 100644
--- a/src/core/changes/qscenechange.cpp
+++ b/src/core/changes/qscenechange.cpp
@@ -58,6 +58,7 @@ namespace Qt3DCore {
* \value PropertyValueRemoved A QNode has been removed from the scene.
* \value ComponentAdded A QComponent has been added to a QEntity.
* \value ComponentRemoved A QComponent has been removed from a QEntity.
+ * \value CallbackTriggered A QNode triggered a callback.
* \value AllChanges Allows an observer to monitor for any of the above changes.
*/
diff --git a/src/core/changes/qscenechange.h b/src/core/changes/qscenechange.h
index 378c2f676..7679fb030 100644
--- a/src/core/changes/qscenechange.h
+++ b/src/core/changes/qscenechange.h
@@ -56,6 +56,8 @@ enum ChangeFlag {
PropertyValueRemoved = 1 << 4,
ComponentAdded = 1 << 5,
ComponentRemoved = 1 << 6,
+ CommandRequested = 1 << 7,
+ CallbackTriggered = 1 << 8,
AllChanges = 0xFFFFFFFF
};
Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag)
diff --git a/src/core/changes/qskeletoncreatedchange.cpp b/src/core/changes/qskeletoncreatedchange.cpp
new file mode 100644
index 000000000..c1d58150d
--- /dev/null
+++ b/src/core/changes/qskeletoncreatedchange.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "qskeletoncreatedchange_p.h"
+#include "qskeletoncreatedchange_p_p.h"
+#include <Qt3DCore/private/qabstractskeleton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QSkeletonCreatedChangeBasePrivate::QSkeletonCreatedChangeBasePrivate(const QAbstractSkeleton *skeleton)
+ : Qt3DCore::QNodeCreatedChangeBasePrivate(skeleton)
+ , m_type(QAbstractSkeletonPrivate::get(skeleton)->m_type)
+{
+
+}
+
+/*!
+ \class QSkeletonCreatedChangeBase
+ \inmodule Qt3DCore
+ \brief Base class for handling creation changes for QAbstractSkeleton sub-classes
+*/
+QSkeletonCreatedChangeBase::QSkeletonCreatedChangeBase(const QAbstractSkeleton *skeleton)
+ : Qt3DCore::QNodeCreatedChangeBase(*new QSkeletonCreatedChangeBasePrivate(skeleton), skeleton)
+{
+}
+
+/*! \internal */
+QSkeletonCreatedChangeBase::~QSkeletonCreatedChangeBase()
+{
+}
+
+/*! \internal */
+QSkeletonCreatedChangeBase::SkeletonType QSkeletonCreatedChangeBase::type() const
+{
+ Q_D(const QSkeletonCreatedChangeBase);
+ return d->m_type;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/changes/qskeletoncreatedchange_p.h b/src/core/changes/qskeletoncreatedchange_p.h
new file mode 100644
index 000000000..337a4bf26
--- /dev/null
+++ b/src/core/changes/qskeletoncreatedchange_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DCORE_QSKELETONCREATEDCHANGE_P_H
+#define QT3DCORE_QSKELETONCREATEDCHANGE_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/qnodecreatedchange.h>
+#include <Qt3DCore/qabstractskeleton.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QSkeletonCreatedChangeBasePrivate;
+
+class QT3DCORESHARED_EXPORT QSkeletonCreatedChangeBase : public QNodeCreatedChangeBase
+{
+public:
+ explicit QSkeletonCreatedChangeBase(const QAbstractSkeleton *skeleton);
+ ~QSkeletonCreatedChangeBase();
+
+ enum SkeletonType {
+ Skeleton = 0,
+ SkeletonLoader
+ };
+
+ SkeletonType type() const;
+
+private:
+ Q_DECLARE_PRIVATE(QSkeletonCreatedChangeBase)
+};
+
+typedef QSharedPointer<QSkeletonCreatedChangeBase> QSkeletonCreatedChangeBasePtr;
+
+template<typename T>
+class QSkeletonCreatedChange : public QSkeletonCreatedChangeBase
+{
+public:
+ explicit QSkeletonCreatedChange(const QAbstractSkeleton *_skeleton)
+ : QSkeletonCreatedChangeBase(_skeleton)
+ , data()
+ {
+ }
+
+ T data;
+};
+
+template<typename T>
+using QSkeletonCreatedChangePtr = QSharedPointer<QSkeletonCreatedChange<T>>;
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QSKELETONCREATEDCHANGE_P_H
diff --git a/src/core/changes/qskeletoncreatedchange_p_p.h b/src/core/changes/qskeletoncreatedchange_p_p.h
new file mode 100644
index 000000000..961458ab6
--- /dev/null
+++ b/src/core/changes/qskeletoncreatedchange_p_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DCORE_QSKELETONCREATEDCHANGE_P_P_H
+#define QT3DCORE_QSKELETONCREATEDCHANGE_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 <Qt3DCore/private/qnodecreatedchange_p.h>
+#include <Qt3DCore/private/qskeletoncreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QAbstractSkeleton;
+
+class QSkeletonCreatedChangeBasePrivate : public Qt3DCore::QNodeCreatedChangeBasePrivate
+{
+public:
+ QSkeletonCreatedChangeBasePrivate(const QAbstractSkeleton *skeleton);
+
+ QSkeletonCreatedChangeBase::SkeletonType m_type;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QSKELETONCREATEDCHANGE_P_P_H
diff --git a/src/core/configure.json b/src/core/configure.json
index 47a726d82..c7ada271e 100644
--- a/src/core/configure.json
+++ b/src/core/configure.json
@@ -6,7 +6,13 @@
"options": {
"assimp": { "type": "enum", "values": [ "qt", "system", "no" ] },
"qt3d-profile-jobs": "boolean",
- "qt3d-profile-gl": "boolean"
+ "qt3d-profile-gl": "boolean",
+ "qt3d-render": "boolean",
+ "qt3d-input": "boolean",
+ "qt3d-logic": "boolean",
+ "qt3d-extras": "boolean",
+ "qt3d-animation": "boolean",
+ "qt3d-simd": { "type": "optionalString", "values": [ "no", "sse2", "avx2" ] }
}
},
@@ -36,18 +42,60 @@
"qt3d-profile-jobs": {
"label": "Output Qt3D Job traces",
"autoDetect": false,
- "output": [
- "privateFeature",
- { "type": "define", "name": "QT3D_JOBS_RUN_STATS", "value": 1 }
- ]
+ "output": [ "privateFeature" ]
},
"qt3d-profile-gl": {
"label": "Output Qt3D GL traces",
"autoDetect": false,
- "output": [
- "privateFeature",
- { "type": "define", "name": "QT3D_OPENGL_RUN_STATS", "value": 1 }
- ]
+ "output": [ "privateFeature" ]
+ },
+ "qt3d-render": {
+ "label": "Render aspect",
+ "purpose": "Use the 3D Render Aspect library",
+ "section": "Aspects",
+ "output": [ "publicFeature" ]
+ },
+ "qt3d-input": {
+ "label": "Input aspect",
+ "purpose": "Use the 3D Input Aspect library",
+ "section": "Aspects",
+ "output": [ "publicFeature" ]
+ },
+ "qt3d-logic": {
+ "label": "Logic aspect",
+ "purpose": "Use the 3D Logic Aspect library",
+ "section": "Aspects",
+ "output": [ "publicFeature" ]
+ },
+ "qt3d-extras": {
+ "label": "Extras aspect",
+ "purpose": "Use the 3D Extra library",
+ "section": "Aspects",
+ "condition": "features.qt3d-render && features.qt3d-input && features.qt3d-logic",
+ "output": [ "publicFeature" ]
+ },
+ "qt3d-animation": {
+ "label": "Animation aspect",
+ "purpose": "Use the 3D Animation Aspect library",
+ "section": "Aspects",
+ "condition": "features.qt3d-render",
+ "output": [ "publicFeature" ]
+ },
+ "qt3d-simd-sse2": {
+ "label": "Use SSE2 instructions",
+ "purpose": "Use SSE2 SIMD instructions to accelerate matrix operations",
+ "autoDetect": "features.sse2",
+ "enable": "input.qt3d-simd == 'sse2' || input.qt3d-simd == 'avx2'",
+ "disable": "input.qt3d-simd == 'no' || (config.win32-msvc2013 && arch.i386)",
+ "output": [ "privateFeature" ]
+ },
+ "qt3d-simd-avx2": {
+ "label": "Use AVX2 instructions",
+ "purpose": "Use AVX2 SIMD instructions to accelerate matrix operations",
+ "autoDetect": false,
+ "enable": "input.qt3d-simd == 'avx2'",
+ "disable": "input.qt3d-simd == 'sse2' || input.qt3d-simd == 'no' || (config.win32-msvc2013 && arch.i386)",
+ "output": [ "privateFeature" ]
}
},
@@ -61,7 +109,19 @@
"assimp",
"system-assimp",
"qt3d-profile-jobs",
- "qt3d-profile-gl"
+ "qt3d-profile-gl",
+ "qt3d-simd-sse2",
+ "qt3d-simd-avx2",
+ {
+ "section": "Aspects",
+ "entries": [
+ "qt3d-render",
+ "qt3d-input",
+ "qt3d-logic",
+ "qt3d-animation",
+ "qt3d-extras"
+ ]
+ }
]
}
]
diff --git a/src/core/jobs/qaspectjob_p.h b/src/core/jobs/qaspectjob_p.h
index 6786ccef7..ff708443e 100644
--- a/src/core/jobs/qaspectjob_p.h
+++ b/src/core/jobs/qaspectjob_p.h
@@ -62,7 +62,7 @@ namespace Qt3DCore {
class QAspectJob;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
struct FrameHeader
{
FrameHeader()
@@ -111,14 +111,14 @@ public:
static QAspectJobPrivate *get(QAspectJob *job);
QVector<QWeakPointer<QAspectJob> > m_dependencies;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
JobRunStats m_stats;
#endif
};
} // Qt3D
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/qaspectjob_p.h>
diff --git a/src/core/jobs/qaspectjobmanager.cpp b/src/core/jobs/qaspectjobmanager.cpp
index 702eebfe3..328899433 100644
--- a/src/core/jobs/qaspectjobmanager.cpp
+++ b/src/core/jobs/qaspectjobmanager.cpp
@@ -98,7 +98,8 @@ void QAspectJobManager::enqueueJobs(const QVector<QAspectJobPtr> &jobQueue)
taskDepender->m_dependerCount += dependerCount;
}
-#ifdef QT3D_JOBS_RUN_STATS
+
+#if QT_CONFIG(qt3d_profile_jobs)
QThreadPooler::writeFrameJobLogStats();
#endif
m_threadPooler->mapDependables(taskList);
diff --git a/src/core/jobs/qthreadpooler.cpp b/src/core/jobs/qthreadpooler.cpp
index 3c9834418..6819faca7 100644
--- a/src/core/jobs/qthreadpooler.cpp
+++ b/src/core/jobs/qthreadpooler.cpp
@@ -38,10 +38,10 @@
****************************************************************************/
#include "qthreadpooler_p.h"
-#include <Qt3DCore/qt3dcore-config.h>
#include <QtCore/QDebug>
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
+#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QThreadStorage>
#include <QtCore/QDateTime>
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DCore {
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
QElapsedTimer QThreadPooler::m_jobsStatTimer;
#endif
@@ -62,9 +62,16 @@ QThreadPooler::QThreadPooler(QObject *parent)
, m_mutex()
, m_taskCount(0)
{
+ const QByteArray maxThreadCount = qgetenv("QT3D_MAX_THREAD_COUNT");
+ if (!maxThreadCount.isEmpty()) {
+ bool conversionOK = false;
+ const int maxThreadCountValue = maxThreadCount.toInt(&conversionOK);
+ if (conversionOK)
+ m_threadPool.setMaxThreadCount(maxThreadCountValue);
+ }
// Ensures that threads will never be recycled
m_threadPool.setExpiryTimeout(-1);
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
QThreadPooler::m_jobsStatTimer.start();
#endif
}
@@ -179,7 +186,7 @@ int QThreadPooler::maxThreadCount() const
return m_threadPool.maxThreadCount();
}
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
QThreadStorage<QVector<JobRunStats> *> jobStatsCached;
diff --git a/src/core/jobs/qthreadpooler_p.h b/src/core/jobs/qthreadpooler_p.h
index d03e55624..00742f8fc 100644
--- a/src/core/jobs/qthreadpooler_p.h
+++ b/src/core/jobs/qthreadpooler_p.h
@@ -60,7 +60,7 @@
#include <Qt3DCore/private/qaspectjob_p.h>
#include <Qt3DCore/private/task_p.h>
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
#include <QtCore/QElapsedTimer>
#endif
@@ -81,7 +81,7 @@ public:
QFuture<void> future();
int maxThreadCount() const;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
static QElapsedTimer m_jobsStatTimer;
// Aspects + Job threads
diff --git a/src/core/jobs/task.cpp b/src/core/jobs/task.cpp
index 6e053eb73..4291a4779 100644
--- a/src/core/jobs/task.cpp
+++ b/src/core/jobs/task.cpp
@@ -68,7 +68,7 @@ AspectTaskRunnable::~AspectTaskRunnable()
void AspectTaskRunnable::run()
{
if (m_job) {
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
QAspectJobPrivate *jobD = QAspectJobPrivate::get(m_job.data());
if (m_pooler) {
jobD->m_stats.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
@@ -76,7 +76,7 @@ void AspectTaskRunnable::run()
}
#endif
m_job->run();
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
if (m_pooler) {
jobD->m_stats.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
// Add current job's stats to log output
diff --git a/src/core/nodes/qbackendnode.cpp b/src/core/nodes/qbackendnode.cpp
index dc751cb93..65d140067 100644
--- a/src/core/nodes/qbackendnode.cpp
+++ b/src/core/nodes/qbackendnode.cpp
@@ -42,6 +42,7 @@
#include <Qt3DCore/qaspectengine.h>
#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/qnodecommand.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/corelogging_p.h>
@@ -206,6 +207,25 @@ void QBackendNode::notifyObservers(const QSceneChangePtr &e)
d->notifyObservers(e);
}
+QNodeCommand::CommandId QBackendNode::sendCommand(const QString &name,
+ const QVariant &data,
+ QNodeCommand::CommandId replyTo)
+{
+ auto e = QNodeCommandPtr::create(peerId());
+ e->setName(name);
+ e->setData(data);
+ e->setReplyToCommandId(replyTo);
+ e->setDeliveryFlags(QSceneChange::Nodes);
+ notifyObservers(e);
+ return e->commandId();
+}
+
+void QBackendNode::sendReply(const QNodeCommandPtr &command)
+{
+ command->setDeliveryFlags(QSceneChange::Nodes);
+ notifyObservers(command);
+}
+
void QBackendNode::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
{
Q_UNUSED(change);
diff --git a/src/core/nodes/qbackendnode.h b/src/core/nodes/qbackendnode.h
index d2cae5696..99e483cff 100644
--- a/src/core/nodes/qbackendnode.h
+++ b/src/core/nodes/qbackendnode.h
@@ -42,6 +42,7 @@
#include <Qt3DCore/qnodecreatedchange.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/qnodecommand.h>
#include <Qt3DCore/qscenechange.h>
#include <Qt3DCore/qt3dcore_global.h>
@@ -90,6 +91,9 @@ protected:
Q_DECLARE_PRIVATE(QBackendNode)
explicit QBackendNode(QBackendNodePrivate &dd);
void notifyObservers(const QSceneChangePtr &e);
+ QNodeCommand::CommandId sendCommand(const QString &name, const QVariant &data,
+ QNodeCommand::CommandId replyTo = QNodeCommand::CommandId());
+ void sendReply(const QNodeCommandPtr &command);
virtual void sceneChangeEvent(const QSceneChangePtr &e);
QBackendNodePrivate *d_ptr;
diff --git a/src/core/nodes/qcomponent_p.h b/src/core/nodes/qcomponent_p.h
index 6c7c3c89d..0b3a961ab 100644
--- a/src/core/nodes/qcomponent_p.h
+++ b/src/core/nodes/qcomponent_p.h
@@ -53,6 +53,7 @@
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qt3dcore_global_p.h>
+#include <Qt3DCore/qcomponent.h>
QT_BEGIN_NAMESPACE
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index ce5e76a55..58e016cda 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -902,6 +902,51 @@ QNodeCreatedChangeBasePtr QNode::createNodeCreationChange() const
return QNodeCreatedChangeBasePtr::create(this);
}
+/*!
+ * \brief Sends a command messages to the backend node
+ *
+ * Creates a QNodeCommand message and dispatches it to the backend node. The
+ * command is given and a \a name and some \a data which can be used in the
+ * backend node to performe various operations.
+ * This returns a CommandId which can be used to identify the initial command
+ * when receiving a message in reply. If the command message is to be sent in
+ * reply to another command, \a replyTo contains the id of that command.
+ *
+ * \sa QNodeCommand, QNode::sendReply
+ */
+QNodeCommand::CommandId QNode::sendCommand(const QString &name,
+ const QVariant &data,
+ QNodeCommand::CommandId replyTo)
+{
+ Q_D(QNode);
+
+ // Bail out early if we can to avoid operator new
+ if (d->m_blockNotifications)
+ return QNodeCommand::CommandId(0);
+
+ auto e = QNodeCommandPtr::create(d->m_id);
+ e->setName(name);
+ e->setData(data);
+ e->setReplyToCommandId(replyTo);
+ d->notifyObservers(e);
+ return e->commandId();
+}
+
+/*!
+ * \brief Send a command back to the backend node
+ *
+ * Assumes the command is to be to sent back in reply to itself to the backend node
+ *
+ * \sa QNodeCommand, QNode::sendCommand
+ */
+void QNode::sendReply(const QNodeCommandPtr &command)
+{
+ Q_D(QNode);
+ command->setDeliveryFlags(QSceneChange::BackendNodes);
+ d->notifyObservers(command);
+}
+
+
namespace {
/*! \internal */
diff --git a/src/core/nodes/qnode.h b/src/core/nodes/qnode.h
index cf3a16301..1fe03f5e0 100644
--- a/src/core/nodes/qnode.h
+++ b/src/core/nodes/qnode.h
@@ -42,6 +42,7 @@
#include <Qt3DCore/qnodecreatedchange.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DCore/qnodecommand.h>
#include <Qt3DCore/qscenechange.h>
#include <Qt3DCore/qt3dcore_global.h>
#include <QtCore/QObject>
@@ -98,6 +99,10 @@ public:
void clearPropertyTracking(const QString &propertyName);
void clearPropertyTrackings();
+ QNodeCommand::CommandId sendCommand(const QString &name, const QVariant &data = QVariant(),
+ QNodeCommand::CommandId replyTo = QNodeCommand::CommandId());
+ void sendReply(const QNodeCommandPtr &command);
+
public Q_SLOTS:
void setParent(QNode *parent);
void setEnabled(bool isEnabled);
diff --git a/src/core/qscene.cpp b/src/core/qscene.cpp
index 043b3f11b..b5895c7aa 100644
--- a/src/core/qscene.cpp
+++ b/src/core/qscene.cpp
@@ -222,13 +222,8 @@ bool QScene::hasEntityForComponent(QNodeId componentUuid, QNodeId entityUuid)
{
Q_D(QScene);
QReadLocker lock(&d->m_lock);
- auto it = d->m_componentToEntities.find(componentUuid);
- while (it != d->m_componentToEntities.end() && it.key() == componentUuid) {
- if (it.value() == entityUuid)
- return true;
- ++it;
- }
- return false;
+ const auto range = d->m_componentToEntities.equal_range(componentUuid);
+ return std::find(range.first, range.second, entityUuid) != range.second;
}
QScene::NodePropertyTrackData QScene::lookupNodePropertyTrackData(QNodeId id) const
diff --git a/src/core/qt3dcore_global.h b/src/core/qt3dcore_global.h
index e11907cad..a449a2e52 100644
--- a/src/core/qt3dcore_global.h
+++ b/src/core/qt3dcore_global.h
@@ -41,6 +41,7 @@
#define QT3DCORE_GLOBAL_H
#include <QtCore/qglobal.h>
+#include <Qt3DCore/qt3dcore-config.h>
QT_BEGIN_NAMESPACE
diff --git a/src/core/qt3dcore_global_p.h b/src/core/qt3dcore_global_p.h
index e872844d7..2d6793744 100644
--- a/src/core/qt3dcore_global_p.h
+++ b/src/core/qt3dcore_global_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/qt3dcore_global.h>
+#include <Qt3DCore/private/qt3dcore-config_p.h>
#define QT3DCORE_PRIVATE_EXPORT QT3DCORESHARED_EXPORT
diff --git a/src/core/services/qdownloadhelperservice.cpp b/src/core/services/qdownloadhelperservice.cpp
new file mode 100644
index 000000000..70a2cbfe4
--- /dev/null
+++ b/src/core/services/qdownloadhelperservice.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qdownloadhelperservice_p.h"
+#include "qdownloadnetworkworker_p.h"
+#include <Qt3DCore/QAspectEngine>
+#include <Qt3DCore/private/qabstractserviceprovider_p.h>
+#include <Qt3DCore/private/qaspectengine_p.h>
+#include <Qt3DCore/private/qaspectthread_p.h>
+#include <Qt3DCore/private/qaspectmanager_p.h>
+#include <Qt3DCore/private/qservicelocator_p.h>
+
+#include <QFile>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QDownloadRequest::QDownloadRequest(const QUrl &url)
+ : m_url(url)
+ , m_succeeded(false)
+ , m_cancelled(false)
+{
+
+}
+
+QDownloadRequest::~QDownloadRequest()
+{
+
+}
+
+void QDownloadRequest::onDownloaded()
+{
+ // this is called in dl thread. It's an opportunity to do long running tasks
+ // like loading the data into a QImage
+}
+
+
+class Q_AUTOTEST_EXPORT QDownloadHelperServicePrivate : public QAbstractServiceProviderPrivate
+{
+public:
+ explicit QDownloadHelperServicePrivate(const QString &description);
+ ~QDownloadHelperServicePrivate();
+
+ void init();
+ void shutdown();
+ void _q_onRequestCompleted(const QDownloadRequestPtr &request);
+
+ Q_DECLARE_PUBLIC(QDownloadHelperService)
+
+ QThread *m_downloadThread;
+ QDownloadNetworkWorker *m_downloadWorker;
+};
+
+
+QDownloadHelperServicePrivate::QDownloadHelperServicePrivate(const QString &description)
+ : QAbstractServiceProviderPrivate(QServiceLocator::DownloadHelperService, description)
+ , m_downloadThread(nullptr)
+ , m_downloadWorker(nullptr)
+{
+}
+
+QDownloadHelperServicePrivate::~QDownloadHelperServicePrivate()
+{
+}
+
+void QDownloadHelperServicePrivate::init()
+{
+ Q_Q(QDownloadHelperService);
+ m_downloadThread = new QThread(q);
+ m_downloadWorker = new QDownloadNetworkWorker;
+ m_downloadWorker->moveToThread(m_downloadThread);
+ QObject::connect(m_downloadWorker, SIGNAL(requestDownloaded(const Qt3DCore::QDownloadRequestPtr &)),
+ q, SLOT(_q_onRequestCompleted(const Qt3DCore::QDownloadRequestPtr &)));
+ m_downloadThread->start();
+}
+
+void QDownloadHelperServicePrivate::shutdown()
+{
+ emit m_downloadWorker->cancelAllRequests();
+ m_downloadThread->exit();
+ m_downloadThread->wait();
+ m_downloadWorker->deleteLater();
+}
+
+void QDownloadHelperServicePrivate::_q_onRequestCompleted(const Qt3DCore::QDownloadRequestPtr &request)
+{
+ request->onCompleted();
+}
+
+
+QDownloadHelperService::QDownloadHelperService(const QString &description)
+ : QAbstractServiceProvider(*new QDownloadHelperServicePrivate(description))
+{
+ Q_D(QDownloadHelperService);
+ d->init();
+ qRegisterMetaType<Qt3DCore::QDownloadRequestPtr>();
+}
+
+QDownloadHelperService::~QDownloadHelperService()
+{
+ Q_D(QDownloadHelperService);
+ d->shutdown();
+}
+
+void QDownloadHelperService::submitRequest(const Qt3DCore::QDownloadRequestPtr &request)
+{
+ Q_D(QDownloadHelperService);
+
+ if (isLocal(request->url())) {
+ QFile file(urlToLocalFileOrQrc(request->url()));
+ if (file.open(QIODevice::ReadOnly)) {
+ request->m_data = file.readAll();
+ file.close();
+ request->m_succeeded = true;
+ } else {
+ request->m_succeeded = false;
+ }
+ request->onCompleted();
+ } else {
+ emit d->m_downloadWorker->submitRequest(request);
+ }
+}
+
+void QDownloadHelperService::cancelRequest(const Qt3DCore::QDownloadRequestPtr &request)
+{
+ Q_D(QDownloadHelperService);
+ request->m_cancelled = true;
+ emit d->m_downloadWorker->cancelRequest(request);
+}
+
+void QDownloadHelperService::cancelAllRequests()
+{
+ Q_D(QDownloadHelperService);
+ emit d->m_downloadWorker->cancelAllRequests();
+}
+
+QString QDownloadHelperService::urlToLocalFileOrQrc(const QUrl &url)
+{
+ const QString scheme(url.scheme().toLower());
+ if (scheme == QLatin1String("qrc")) {
+ if (url.authority().isEmpty())
+ return QLatin1Char(':') + url.path();
+ return QString();
+ }
+
+#if defined(Q_OS_ANDROID)
+ if (scheme == QLatin1String("assets")) {
+ if (url.authority().isEmpty())
+ return url.toString();
+ return QString();
+ }
+#endif
+
+ return url.toLocalFile();
+}
+
+QDownloadHelperService *QDownloadHelperService::getService(QAspectEngine *engine)
+{
+ auto enginePrivate = Qt3DCore::QAspectEnginePrivate::get(engine);
+ return enginePrivate->m_aspectThread->aspectManager()->serviceLocator()->downloadHelperService();
+}
+
+bool QDownloadHelperService::isLocal(const QUrl &url)
+{
+ const QString scheme(url.scheme().toLower());
+ if (scheme == QLatin1String("file") || scheme == QLatin1String("qrc"))
+ return true;
+#if defined(Q_OS_ANDROID)
+ if (scheme == QLatin1String("assets"))
+ return true;
+#endif
+ return false;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#include "moc_qdownloadhelperservice_p.cpp"
diff --git a/src/core/services/qdownloadhelperservice_p.h b/src/core/services/qdownloadhelperservice_p.h
new file mode 100644
index 000000000..780ed4806
--- /dev/null
+++ b/src/core/services/qdownloadhelperservice_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QDOWNLOADHELPERSERVICE_P_H
+#define QT3DCORE_QDOWNLOADHELPERSERVICE_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 <QSharedPointer>
+#include <QObject>
+#include <QUrl>
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DCore/qt3dcore_global.h>
+#include <Qt3DCore/private/qservicelocator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+class QNetworkAccessManager;
+class QNetworkReply;
+
+namespace Qt3DCore {
+
+class QAspectEngine;
+class QDownloadNetworkWorker;
+class QDownloadHelperService;
+class QDownloadHelperServicePrivate;
+
+class QT3DCORESHARED_EXPORT QDownloadRequest
+{
+public:
+ QDownloadRequest(const QUrl &url);
+ virtual ~QDownloadRequest();
+
+ QUrl url() const { return m_url; }
+ bool succeeded() const { return m_succeeded; }
+ bool cancelled() const { return m_cancelled; }
+
+ virtual void onDownloaded(); // this is called in dl thread
+ virtual void onCompleted() = 0; // this is called in job thread
+
+protected:
+ QUrl m_url;
+ QByteArray m_data;
+
+private:
+ friend class QDownloadNetworkWorker;
+ friend class QDownloadHelperService;
+ bool m_succeeded;
+ bool m_cancelled;
+};
+
+typedef QSharedPointer<QDownloadRequest> QDownloadRequestPtr;
+
+
+class QT3DCORESHARED_EXPORT QDownloadHelperService : public QAbstractServiceProvider
+{
+ Q_OBJECT
+public:
+ explicit QDownloadHelperService(const QString &description = QString());
+ ~QDownloadHelperService();
+
+ void submitRequest(const QDownloadRequestPtr &request);
+ void cancelRequest(const QDownloadRequestPtr &request);
+ void cancelAllRequests();
+
+ static QString urlToLocalFileOrQrc(const QUrl &url);
+ static bool isLocal(const QUrl &url);
+ static QDownloadHelperService *getService(QAspectEngine *engine);
+
+private:
+ Q_DECLARE_PRIVATE(QDownloadHelperService)
+ Q_PRIVATE_SLOT(d_func(), void _q_onRequestCompleted(const Qt3DCore::QDownloadRequestPtr &))
+};
+
+typedef QSharedPointer<QDownloadHelperService> QDownloadHelperServicePtr;
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DCore::QDownloadRequestPtr) // LCOV_EXCL_LINE
+
+#endif // QT3DCORE_QDOWNLOADHELPERSERVICE_P_H
diff --git a/src/core/services/qdownloadhelperservice_p_p.h b/src/core/services/qdownloadhelperservice_p_p.h
new file mode 100644
index 000000000..202ae5236
--- /dev/null
+++ b/src/core/services/qdownloadhelperservice_p_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Paul Lemire
+** 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 QT3DCORE_QDOWNLOADHELPERSERVICE_P_P_H
+#define QT3DCORE_QDOWNLOADHELPERSERVICE_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 <QSharedPointer>
+#include <QObject>
+#include <QUrl>
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DCore/private/qservicelocator_p.h>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
+#include <Qt3DCore/private/qabstractserviceprovider_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+class QNetworkAccessManager;
+class QNetworkReply;
+
+namespace Qt3DCore {
+
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QDOWNLOADHELPERSERVICE_P_P_H
diff --git a/src/core/services/qdownloadnetworkworker.cpp b/src/core/services/qdownloadnetworkworker.cpp
new file mode 100644
index 000000000..c728a1779
--- /dev/null
+++ b/src/core/services/qdownloadnetworkworker.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qdownloadhelperservice_p.h"
+#include "qdownloadnetworkworker_p.h"
+
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QDataStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QDownloadNetworkWorker::QDownloadNetworkWorker(QObject *parent)
+ : QObject(parent)
+ , m_networkManager(nullptr)
+{
+ connect(this, &QDownloadNetworkWorker::submitRequest,
+ this, &QDownloadNetworkWorker::onRequestSubmited);
+ connect(this, &QDownloadNetworkWorker::cancelRequest,
+ this, &QDownloadNetworkWorker::onRequestCancelled);
+ connect(this, &QDownloadNetworkWorker::cancelAllRequests,
+ this, &QDownloadNetworkWorker::onAllRequestsCancelled);
+}
+
+void QDownloadNetworkWorker::onRequestSubmited(const QDownloadRequestPtr &request)
+{
+ QMutexLocker l(&m_mutex);
+ if (!m_networkManager) {
+ m_networkManager = new QNetworkAccessManager(this);
+ connect(m_networkManager, &QNetworkAccessManager::finished,
+ this, &QDownloadNetworkWorker::onRequestFinished);
+ }
+ auto reply = m_networkManager->get(QNetworkRequest(request->url()));
+ m_requests << QPair<QDownloadRequestPtr, QNetworkReply *>(request, reply);
+ connect(reply, &QNetworkReply::downloadProgress, this, &QDownloadNetworkWorker::onDownloadProgressed);
+}
+
+void QDownloadNetworkWorker::onRequestCancelled(const QDownloadRequestPtr &request)
+{
+ QMutexLocker l(&m_mutex);
+ auto it = std::find_if(m_requests.begin(), m_requests.end(),
+ [request](QPair<QDownloadRequestPtr, QNetworkReply *> e) {
+ return e.first == request;
+ });
+ if (it == m_requests.end())
+ return;
+
+ (*it).first->m_cancelled = true;
+ (*it).second->abort();
+}
+
+void QDownloadNetworkWorker::onAllRequestsCancelled()
+{
+ QMutexLocker l(&m_mutex);
+ for (auto e: qAsConst(m_requests)) {
+ e.first->m_cancelled = true;
+ e.second->abort();
+ }
+ m_requests.clear();
+}
+
+void QDownloadNetworkWorker::onRequestFinished(QNetworkReply *reply)
+{
+ QMutexLocker l(&m_mutex);
+ auto it = std::find_if(m_requests.begin(), m_requests.end(),
+ [reply](QPair<QDownloadRequestPtr, QNetworkReply *> e) {
+ return e.second == reply;
+ });
+ if (it == m_requests.end())
+ return;
+
+ auto request = (*it).first;
+ if (reply->error() == QNetworkReply::NoError) {
+ request->m_succeeded = true;
+ }
+ request->onDownloaded();
+ emit requestDownloaded(request);
+
+ m_requests.erase(it);
+}
+
+void QDownloadNetworkWorker::onDownloadProgressed(qint64 bytesReceived, qint64 bytesTotal)
+{
+ Q_UNUSED(bytesReceived);
+ Q_UNUSED(bytesTotal);
+ // TODO forward progress details somewhere
+
+ QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
+ if (!reply)
+ return;
+
+ QMutexLocker l(&m_mutex);
+ auto it = std::find_if(m_requests.begin(), m_requests.end(),
+ [reply](QPair<QDownloadRequestPtr, QNetworkReply *> e) {
+ return e.second == reply;
+ });
+ if (it == m_requests.end())
+ return;
+
+ auto request = (*it).first;
+ QDataStream stream(&request->m_data, QIODevice::Append);
+ QByteArray data = reply->readAll();
+ stream.writeRawData(data.data(), data.size());
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
diff --git a/src/core/services/qdownloadnetworkworker_p.h b/src/core/services/qdownloadnetworkworker_p.h
new file mode 100644
index 000000000..faecbca2f
--- /dev/null
+++ b/src/core/services/qdownloadnetworkworker_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QDOWNLOADNETWORKWORKER_P_H
+#define QT3DCORE_QDOWNLOADNETWORKWORKER_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 <QSharedPointer>
+#include <QObject>
+#include <QUrl>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
+#include <QMutex>
+
+QT_BEGIN_NAMESPACE
+
+class QThread;
+class QNetworkAccessManager;
+class QNetworkReply;
+
+namespace Qt3DCore {
+
+class QDownloadRequest;
+typedef QSharedPointer<QDownloadRequest> QDownloadRequestPtr;
+
+class QDownloadNetworkWorker : public QObject
+{
+ Q_OBJECT
+public:
+ QDownloadNetworkWorker(QObject *parent = nullptr);
+
+signals:
+ void submitRequest(const Qt3DCore::QDownloadRequestPtr &request);
+ void cancelRequest(const Qt3DCore::QDownloadRequestPtr &request);
+ void cancelAllRequests();
+
+ void requestDownloaded(const Qt3DCore::QDownloadRequestPtr &request);
+
+private Q_SLOTS:
+ void onRequestSubmited(const Qt3DCore::QDownloadRequestPtr &request);
+ void onRequestCancelled(const Qt3DCore::QDownloadRequestPtr &request);
+ void onAllRequestsCancelled();
+ void onRequestFinished(QNetworkReply *reply);
+ void onDownloadProgressed(qint64 bytesReceived, qint64 bytesTotal);
+
+private:
+ QNetworkAccessManager *m_networkManager;
+ QVector< QPair<QDownloadRequestPtr, QNetworkReply *> > m_requests;
+ QMutex m_mutex;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QDOWNLOADNETWORKWORKER_P_H
diff --git a/src/core/services/qservicelocator.cpp b/src/core/services/qservicelocator.cpp
index 9d12cfe2c..bdcb4a521 100644
--- a/src/core/services/qservicelocator.cpp
+++ b/src/core/services/qservicelocator.cpp
@@ -43,9 +43,11 @@
#include <Qt3DCore/private/nullservices_p.h>
#include <Qt3DCore/private/qabstractserviceprovider_p.h>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include <Qt3DCore/private/qtickclockservice_p.h>
+
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
@@ -96,6 +98,7 @@ public:
NullOpenGLInformationService m_nullOpenGLInfo;
QTickClockService m_defaultFrameAdvanceService;
QEventFilterService m_eventFilterService;
+ QDownloadHelperService m_downloadHelperService;
int m_nonNullDefaultServices;
};
@@ -229,6 +232,12 @@ QEventFilterService *QServiceLocator::eventFilterService()
return static_cast<QEventFilterService *>(d->m_services.value(EventFilterService, &d->m_eventFilterService));
}
+QDownloadHelperService *QServiceLocator::downloadHelperService()
+{
+ Q_D(QServiceLocator);
+ return static_cast<QDownloadHelperService *>(d->m_services.value(DownloadHelperService, &d->m_downloadHelperService));
+}
+
/*
\internal
*/
@@ -244,6 +253,8 @@ QAbstractServiceProvider *QServiceLocator::_q_getServiceHelper(int type)
return frameAdvanceService();
case EventFilterService:
return eventFilterService();
+ case DownloadHelperService:
+ return downloadHelperService();
default:
return d->m_services.value(type, nullptr);
}
diff --git a/src/core/services/qservicelocator_p.h b/src/core/services/qservicelocator_p.h
index 1c5db4a5b..9534b33ce 100644
--- a/src/core/services/qservicelocator_p.h
+++ b/src/core/services/qservicelocator_p.h
@@ -84,6 +84,7 @@ class QOpenGLInformationService;
class QSystemInformationService;
class QServiceLocatorPrivate;
class QEventFilterService;
+class QDownloadHelperService;
class QT3DCORESHARED_EXPORT QServiceLocator
{
@@ -97,6 +98,7 @@ public:
CollisionService,
FrameAdvanceService,
EventFilterService,
+ DownloadHelperService,
#if !defined(Q_QDOC)
DefaultServiceCount, // Add additional default services before here
#endif
@@ -120,6 +122,7 @@ public:
QOpenGLInformationService *openGLInformation();
QAbstractFrameAdvanceService *frameAdvanceService();
QEventFilterService *eventFilterService();
+ QDownloadHelperService *downloadHelperService();
private:
Q_DISABLE_COPY(QServiceLocator)
diff --git a/src/core/services/services.pri b/src/core/services/services.pri
index ae0cfd9f8..f311b8329 100644
--- a/src/core/services/services.pri
+++ b/src/core/services/services.pri
@@ -5,7 +5,9 @@ SOURCES += \
$$PWD/qopenglinformationservice.cpp \
$$PWD/qtickclockservice.cpp \
$$PWD/qabstractframeadvanceservice.cpp \
- $$PWD/qeventfilterservice.cpp
+ $$PWD/qeventfilterservice.cpp \
+ $$PWD/qdownloadhelperservice.cpp \
+ $$PWD/qdownloadnetworkworker.cpp
HEADERS += \
$$PWD/qservicelocator_p.h \
@@ -18,6 +20,8 @@ HEADERS += \
$$PWD/qtickclockservice_p.h \
$$PWD/qabstractframeadvanceservice_p.h \
$$PWD/qabstractframeadvanceservice_p_p.h \
- $$PWD/qeventfilterservice_p.h
+ $$PWD/qeventfilterservice_p.h \
+ $$PWD/qdownloadhelperservice_p.h \
+ $$PWD/qdownloadnetworkworker_p.h
INCLUDEPATH += $$PWD
diff --git a/src/core/transforms/matrix4x4_avx2.cpp b/src/core/transforms/matrix4x4_avx2.cpp
new file mode 100644
index 000000000..556e778d0
--- /dev/null
+++ b/src/core/transforms/matrix4x4_avx2.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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: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 "matrix4x4_avx2_p.h"
+
+#ifdef QT_COMPILER_SUPPORTS_AVX2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QDebug operator<<(QDebug dbg, const Matrix4x4_AVX2 &m)
+{
+ dbg.nospace() << "Matrix4x4_AVX2(" << endl
+ << qSetFieldWidth(10)
+ << m.m11() << m.m12() << m.m13() << m.m14() << endl
+ << m.m21() << m.m22() << m.m23() << m.m24() << endl
+ << m.m31() << m.m32() << m.m33() << m.m34() << endl
+ << m.m41() << m.m42() << m.m43() << m.m44() << endl
+ << qSetFieldWidth(0) << ')';
+ return dbg;
+}
+
+} // Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/core/transforms/matrix4x4_avx2_p.h b/src/core/transforms/matrix4x4_avx2_p.h
new file mode 100644
index 000000000..d5f77041b
--- /dev/null
+++ b/src/core/transforms/matrix4x4_avx2_p.h
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_MATRIX4X4_AVX2_P_H
+#define QT3DCORE_MATRIX4X4_AVX2_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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/private/vector4d_p.h>
+#include <Qt3DCore/private/vector3d_p.h>
+#include <private/qsimd_p.h>
+#include <QMatrix4x4>
+
+#ifdef QT_COMPILER_SUPPORTS_AVX2
+
+// Some GCC versions don't have _mm256_set_m128 available
+// Work around that
+#define _mm256_set_m128(va, vb) \
+ _mm256_insertf128_ps(_mm256_castps128_ps256(vb), va, 1)
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class Matrix4x4_AVX2
+{
+public:
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2() { setToIdentity(); }
+ explicit Q_ALWAYS_INLINE Matrix4x4_AVX2(Qt::Initialization) {}
+
+ // Assumes data is 32 bytes aligned (and in column major order)
+ explicit Q_ALWAYS_INLINE Matrix4x4_AVX2(float *data)
+ {
+ m_col12 = _mm256_load_ps(data);
+ m_col34 = _mm256_load_ps(data + 8);
+ }
+
+ // QMatrix4x4::constData returns in column major order
+ explicit Q_ALWAYS_INLINE Matrix4x4_AVX2(const QMatrix4x4 &mat)
+ {
+ // data may not be properly aligned, using unaligned loads
+ const float *data = mat.constData();
+ m_col12 = _mm256_loadu_ps(data);
+ m_col34 = _mm256_loadu_ps(data + 8);
+ }
+
+ // In (row major) but we store in column major order
+ explicit Q_ALWAYS_INLINE Matrix4x4_AVX2(float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44)
+ {
+ m_col12 = _mm256_set_ps(m42, m32, m22, m12, m41, m31, m21, m11);
+ m_col34 = _mm256_set_ps(m44, m34, m24, m14, m43, m33, m23, m13);
+ }
+
+ Q_ALWAYS_INLINE void setToIdentity()
+ {
+ // 23 instructions
+ m_col12 = _mm256_set_ps(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+ m_col34 = _mm256_set_ps(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
+
+ // 23 instructions
+ // 1, 0, 0, 0
+ // __m128 vec = _mm_set_ss(1.0f);
+ // // 0, 1, 0, 0
+ // // 0b01010001 == 0x51
+ // __m128 tmp = _mm_permute_ps(vec, 0x51);
+
+ // // 1, 0, 0, 0, 0, 1, 0, 0
+ // m_col12 = _mm256_set_m128(tmp, vec);
+
+ // // 0, 0, 1, 0
+ // // 0b01000101 == 0x45
+ // tmp = _mm_permute_ps(vec, 0x45);
+
+ // // 0, 0, 0, 1
+ // // 0b00010101 == 0x15
+ // vec = _mm_permute_ps(vec, 0x15);
+
+ // // 0, 0, 1, 0, 0, 0, 0, 1
+ // m_col34 = _mm256_set_m128(vec, tmp);
+
+ // Using a static identity matrix and assigning it is 27 instructions
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 operator*(const Matrix4x4_AVX2 &other) const
+ {
+ // Shuffling: (Latency 1)
+ // (8 bits -> first two pairs used to select from the first vector, second pairs from second vector)
+
+ // 00 01 10 11, 00 01 10 11
+ // v1 = m11 m12 m13 m14 m21 m22 m23 m24
+ // v2 = m11 m12 m13 m14 m21 m22 m23 m24
+
+ // shuffled with 00 00 00 00
+ // v1[0] v1[0] v2[0] v2[0] v1[0] v1[0] v2[0] v2[0]
+ // -> m11 m11 m11 m11 m21 m21 m21 m21
+
+ // Broadcasting: (Latency 1)
+ // -> n11 n12 n13 n14 broadcasted
+ // n11 n12 n13 n14 n11 n12 n13 n14
+
+ // Multiplying (Latency 5):
+ // m11 m11 m11 m11 m21 m21 m21 m21 * n11 n12 n13 n14 n11 n12 n13 n14
+
+ // -> m11 n11, m11 n12, m11 n13, m11 n14
+ // m21 n11, m21 n12, m21 n13, m21 n14
+
+ // 00 01 10 11, 00 01 10 11
+ // v1 = m11 m12 m13 m14 m21 m22 m23 m24
+ // v2 = m11 m12 m13 m14 m21 m22 m23 m24
+ const __m256 otherCol12 = other.m_col12;
+ const __m256 otherCol34 = other.m_col34;
+ const __m128 col1 = _mm256_extractf128_ps(m_col12, 0);
+ const __m128 col2 = _mm256_extractf128_ps(m_col12, 1);
+ const __m128 col3 = _mm256_extractf128_ps(m_col34, 0);
+ const __m128 col4 = _mm256_extractf128_ps(m_col34, 1);
+
+ // const __m256 col12 = _mm256_load_ps(m);
+ // const __m256 col34 = _mm256_load_ps(m + 8);
+ // const __m128 otherCol1 = _mm_load_ps(other.m);
+ // const __m128 otherCol2 = _mm_load_ps(other.m + 4);
+ // const __m128 otherCol3 = _mm_load_ps(other.m + 8);
+ // const __m128 otherCol4 = _mm_load_ps(other.m + 12);
+
+ __m256 tmp = _mm256_mul_ps(_mm256_shuffle_ps(otherCol12, otherCol12, 0x00), _mm256_broadcast_ps(&col1));
+
+ // shuffled with 01 01 01 01
+ // v1[1] v1[1] v2[1] v2[1] v1[1] v1[1] v2[1] v2[1]
+ // -> m12 m12 m12 m12 m22 m22 m22 m22
+
+
+ // 00 01 10 11, 00 01 10 11
+ // m11 m12 m13 m14, m21 m22 m23 m24 shuffled with 01 01 01 01
+ // -> m12 m12 m12 m12 m22 m22 m22 m22 x n21 n22 n23 n24 n21 n22 n23 n24
+
+ // -> m12 n21, m12 n22, m12 n23, m12 n24,
+ // -> m22 n21, m22 n22, m22 n23, m22 n24
+ tmp = _mm256_add_ps(_mm256_mul_ps(_mm256_shuffle_ps(otherCol12, otherCol12, 0x55), _mm256_broadcast_ps(&col2)), tmp);
+
+ // m11 m12 m13 m14 m11 m12 m13 m14 shuffled with 10 10 10 10
+ // m13 m13 m13 m13, m23 m23 m23 m23
+
+ // Multiplying with other.col3
+ // -> m13 n31, m13 n32, m13 n33, m13 n34
+ // -> m23 n31, m23 n32, m23 n33, m23 n34
+ tmp = _mm256_add_ps(_mm256_mul_ps(_mm256_shuffle_ps(otherCol12, otherCol12, 0xaa), _mm256_broadcast_ps(&col3)), tmp);
+
+ // m11 m12 m13 m14 m11 m12 m13 m14 shuffled with 11 11 11 11
+ // m14 m14 m14 m14 m24 m24 m24 m24
+
+ // -> m14 n41, m14 n42, m14 n43, m14 n44
+ // -> m24 n41, m24 n42, m24 n43, m24 n44
+ tmp = _mm256_add_ps(_mm256_mul_ps(_mm256_shuffle_ps(otherCol12, otherCol12, 0xff), _mm256_broadcast_ps(&col4)), tmp);
+
+ // Which finally gives
+ // c11 -> m11 n11 + m12 n21 + m13 n31 + m14 n41,
+ // c12 -> m11 n12 + m12 n22 + m13 n32 + m14 n42
+ // c13 -> m11 n13 + m12 n23 + m13 n33 + m14 n43
+ // c14 -> m11 n14 + m12 n24 + m13 n34 + m14 n44
+
+ // c21 -> m21 n11 + m22 n21 + m23 n31 + m24 n41,
+ // c12 -> m21 n12 + m22 n22 + m23 n32 + m24 n42
+ // c13 -> m21 n13 + m22 n23 + m23 n33 + m24 n43
+ // c14 -> m21 n14 + m22 n24 + m23 n34 + m24 n44
+
+ __m256 tmp2 = _mm256_mul_ps(_mm256_shuffle_ps(otherCol34, otherCol34, 0x00), _mm256_broadcast_ps(&col1));
+ tmp2 = _mm256_add_ps(_mm256_mul_ps(_mm256_shuffle_ps(otherCol34, otherCol34, 0x55), _mm256_broadcast_ps(&col2)), tmp2);
+ tmp2 = _mm256_add_ps(_mm256_mul_ps(_mm256_shuffle_ps(otherCol34, otherCol34, 0xaa), _mm256_broadcast_ps(&col3)), tmp2);
+ tmp2 = _mm256_add_ps(_mm256_mul_ps(_mm256_shuffle_ps(otherCol34, otherCol34, 0xff), _mm256_broadcast_ps(&col4)), tmp2);
+
+ Matrix4x4_AVX2 c(Qt::Uninitialized);
+ c.m_col12 = tmp;
+ c.m_col34 = tmp2;
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 operator-(const Matrix4x4_AVX2 &other) const
+ {
+ Matrix4x4_AVX2 c(Qt::Uninitialized);
+
+ c.m_col12 = _mm256_sub_ps(m_col12, other.m_col12);
+ c.m_col34 = _mm256_sub_ps(m_col34, other.m_col34);
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 operator+(const Matrix4x4_AVX2 &other) const
+ {
+ Matrix4x4_AVX2 c(Qt::Uninitialized);
+
+ c.m_col12 = _mm256_add_ps(m_col12, other.m_col12);
+ c.m_col34 = _mm256_add_ps(m_col34, other.m_col34);
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 &operator*=(const Matrix4x4_AVX2 &other)
+ {
+ *this = *this * other;
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 &operator-=(const Matrix4x4_AVX2 &other)
+ {
+ *this = *this - other;
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 &operator+=(const Matrix4x4_AVX2 &other)
+ {
+ *this = *this + other;
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 transposed() const
+ {
+ Matrix4x4_AVX2 c(Qt::Uninitialized);
+ const __m128 col1 = _mm256_extractf128_ps(m_col12, 0);
+ const __m128 col2 = _mm256_extractf128_ps(m_col12, 1);
+ const __m128 col3 = _mm256_extractf128_ps(m_col34, 0);
+ const __m128 col4 = _mm256_extractf128_ps(m_col34, 1);
+
+ // ~117 instructions
+ // Matrix4x4_AVX2 c = *this;
+ // _MM_TRANSPOSE4_PS(c.m_col1, c.m_col2, c.m_col3, c.m_col4);
+
+ // ~131 instructions - AVX2
+ // const __m256i indexes = _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0);
+ // c.m_col12 = _mm256_permutevar8x32_ps(_mm256_unpacklo_ps(m_col12, m_col34), indexes);
+ // c.m_col34 = _mm256_permutevar8x32_ps(_mm256_unpackhi_ps(m_col12, m_col34), indexes);
+
+ // ~193 instructions
+ // c.m_col12 = _mm256_setr_ps(m_m11, m_m21, m_m31, m_m41, m_m12, m_m22, m_m32, m_m42);
+ // c.m_col34 = _mm256_setr_ps(m_m13, m_m23, m_m33, m_m43, m_m14, m_m24, m_m34, m_m44);
+
+ // ~113 instructions
+ // union {
+ // struct
+ // {
+ // __m256 twin;
+ // };
+ // struct
+ // {
+ // __m128 col1;
+ // __m128 col2;
+ // };
+ // } u;
+
+ // u.twin = _mm256_shuffle_ps(m_col12, m_col34, 0b01000100);
+ // c.m_col1 = _mm_permute_ps(_mm_shuffle_ps(u.col1, u.col2, 0b10001000), 0b11011000);
+ // c.m_col2 = _mm_permute_ps(_mm_shuffle_ps(u.col1, u.col2, 0b11011101), 0b11011000);
+
+ // u.twin = _mm256_shuffle_ps(m_col12, m_col34, 0b11101110);
+ // c.m_col3 = _mm_permute_ps(_mm_shuffle_ps(u.col1, u.col2, 0b10001000), 0b11011000);
+ // c.m_col4 = _mm_permute_ps(_mm_shuffle_ps(u.col1, u.col2, 0b11011101), 0b11011000);
+
+ // ~113 instructions
+ // 0b11011101 == 0xdd
+ // 0b10001000 == 0x88
+ const __m128 tmp1 = _mm_shuffle_ps(col1, col2, 0xdd);
+ const __m128 tmp2 = _mm_shuffle_ps(col1, col2, 0x88);
+ const __m128 tmp3 = _mm_shuffle_ps(col3, col4, 0xdd);
+ const __m128 tmp4 = _mm_shuffle_ps(col3, col4, 0x88);
+ c.m_col12 = _mm256_set_m128(_mm_shuffle_ps(tmp1, tmp3, 0x88), _mm_shuffle_ps(tmp2, tmp4, 0x88));
+ c.m_col34 = _mm256_set_m128(_mm_shuffle_ps(tmp1, tmp3, 0xdd), _mm_shuffle_ps(tmp2, tmp4, 0xdd));
+
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_AVX2 inverted() const
+ {
+ // TO DO: Optimize
+ const QMatrix4x4 mat = toQMatrix4x4();
+ return Matrix4x4_AVX2(mat.inverted());
+ }
+
+ Q_ALWAYS_INLINE bool operator==(const Matrix4x4_AVX2 &other) const
+ {
+ // cmp returns (-1, -1, -1, -1, -1, -1, -1, -1) if the two m256 are equals
+ // movemask takes the most significant bits (8x 1 in this case) which equals 0xff
+ return (_mm256_movemask_ps(_mm256_cmp_ps(m_col12, other.m_col12, _CMP_EQ_OQ)) == 0xff &&
+ _mm256_movemask_ps(_mm256_cmp_ps(m_col34, other.m_col34, _CMP_EQ_OQ)) == 0xff);
+
+ }
+
+ Q_ALWAYS_INLINE bool operator!=(const Matrix4x4_AVX2 &other) const
+ {
+ return !(*this == other);
+ }
+
+ // For some reason _mm256_cvtss_f32 doesn't seem to be defined
+ Q_ALWAYS_INLINE float m11() const { return _mm_cvtss_f32(_mm256_extractf128_ps(m_col12, 0)); }
+ Q_ALWAYS_INLINE float m12() const { return _mm_cvtss_f32(_mm256_extractf128_ps(m_col12, 1)); }
+ Q_ALWAYS_INLINE float m13() const { return _mm_cvtss_f32(_mm256_extractf128_ps(m_col34, 0)); }
+ Q_ALWAYS_INLINE float m14() const { return _mm_cvtss_f32(_mm256_extractf128_ps(m_col34, 1)); }
+
+ Q_ALWAYS_INLINE float m21() const
+ {
+ // 0b01010101 = 0x55
+ const __m128 v = _mm256_extractf128_ps(m_col12, 0);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0x55));
+ }
+ Q_ALWAYS_INLINE float m22() const
+ {
+ // 0b01010101 = 0x55
+ const __m128 v = _mm256_extractf128_ps(m_col12, 1);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0x55));
+ }
+ Q_ALWAYS_INLINE float m23() const
+ {
+ // 0b01010101 = 0x55
+ const __m128 v = _mm256_extractf128_ps(m_col34, 0);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0x55));
+ }
+ Q_ALWAYS_INLINE float m24() const
+ {
+ // 0b01010101 = 0x55
+ const __m128 v = _mm256_extractf128_ps(m_col34, 1);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0x55));
+ }
+
+ Q_ALWAYS_INLINE float m31() const
+ {
+ // 0b10101010 = 0xaa
+ const __m128 v = _mm256_extractf128_ps(m_col12, 0);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xaa));
+ }
+ Q_ALWAYS_INLINE float m32() const
+ {
+ // 0b10101010 = 0xaa
+ const __m128 v = _mm256_extractf128_ps(m_col12, 1);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xaa));
+ }
+ Q_ALWAYS_INLINE float m33() const
+ {
+ // 0b10101010 = 0xaa
+ const __m128 v = _mm256_extractf128_ps(m_col34, 0);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xaa));
+ }
+ Q_ALWAYS_INLINE float m34() const
+ {
+ // 0b10101010 = 0xaa
+ const __m128 v = _mm256_extractf128_ps(m_col34, 1);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xaa));
+ }
+
+ Q_ALWAYS_INLINE float m41() const
+ {
+ // 0b11111111 = 0xff
+ const __m128 v = _mm256_extractf128_ps(m_col12, 0);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xff));
+ }
+ Q_ALWAYS_INLINE float m42() const
+ {
+ // 0b11111111 = 0xff
+ const __m128 v = _mm256_extractf128_ps(m_col12, 1);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xff));
+ }
+ Q_ALWAYS_INLINE float m43() const
+ {
+ // 0b11111111 = 0xff
+ const __m128 v = _mm256_extractf128_ps(m_col34, 0);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xff));
+ }
+ Q_ALWAYS_INLINE float m44() const
+ {
+ // 0b11111111 = 0xff
+ const __m128 v = _mm256_extractf128_ps(m_col34, 1);
+ return _mm_cvtss_f32(_mm_shuffle_ps(v, v, 0xff));
+ }
+ Q_ALWAYS_INLINE QMatrix4x4 toQMatrix4x4() const { return QMatrix4x4(m11(), m12(), m13(), m14(),
+ m21(), m22(), m23(), m24(),
+ m31(), m32(), m33(), m34(),
+ m41(), m42(), m43(), m44()); }
+
+ Q_ALWAYS_INLINE Vector4D row(int index) const
+ {
+ switch (index) {
+ case 0:
+ return Vector4D(m11(), m12(), m13(), m14());
+ case 1:
+ return Vector4D(m21(), m22(), m23(), m24());
+ case 2:
+ return Vector4D(m31(), m32(), m33(), m34());
+ case 3:
+ return Vector4D(m41(), m42(), m43(), m44());
+ default:
+ Q_UNREACHABLE();
+ return Vector4D();
+ }
+ }
+
+ Q_ALWAYS_INLINE Vector4D column(int index) const
+ {
+ Vector4D c(Qt::Uninitialized);
+ switch (index) {
+ case 0:
+ c.m_xyzw = _mm256_extractf128_ps(m_col12, 0);
+ break;
+ case 1:
+ c.m_xyzw = _mm256_extractf128_ps(m_col12, 1);
+ break;
+ case 2:
+ c.m_xyzw = _mm256_extractf128_ps(m_col34, 0);
+ break;
+ case 3:
+ c.m_xyzw = _mm256_extractf128_ps(m_col34, 1);
+ break;
+ default:
+ Q_UNREACHABLE();
+ return Vector4D();
+ }
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE map(const Vector3D_SSE &point) const
+ {
+ return *this * point;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE map(const Vector4D_SSE &point) const
+ {
+ return *this * point;
+ }
+
+ Vector3D_SSE mapVector(const Vector3D_SSE &vector) const
+ {
+ const __m128 row1 = _mm_set_ps(0.0f, m13(), m12(), m11());
+ const __m128 row2 = _mm_set_ps(0.0f, m23(), m22(), m21());
+ const __m128 row3 = _mm_set_ps(0.0f, m33(), m32(), m31());
+
+ const __m128 tmp = _mm_add_ps(_mm_mul_ps(vector.m_xyzw, row1), _mm_mul_ps(vector.m_xyzw, row2));
+
+ Vector3D_SSE v(Qt::Uninitialized);
+ v.m_xyzw = _mm_add_ps(tmp, _mm_mul_ps(vector.m_xyzw, row3));
+ return v;
+ }
+
+ friend Vector4D operator*(const Vector4D &vector, const Matrix4x4_AVX2 &matrix);
+ friend Vector4D operator*(const Matrix4x4_AVX2 &matrix, const Vector4D &vector);
+
+ friend Vector3D operator*(const Vector3D &vector, const Matrix4x4_AVX2 &matrix);
+ friend Vector3D operator*(const Matrix4x4_AVX2 &matrix, const Vector3D &vector);
+
+ friend QT3DCORE_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Matrix4x4_AVX2 &m);
+private:
+ // column major order
+ // aligned on 32 bytes boundaries for AVX, compatible with 16 bytes boundary for SSE
+ // union Q_DECL_ALIGN(32)
+ // {
+ // float m[16];
+ // struct
+ // {
+ // float m_m11, m_m21, m_m31, m_m41;
+ // float m_m12, m_m22, m_m32, m_m42;
+ // float m_m13, m_m23, m_m33, m_m43;
+ // float m_m14, m_m24, m_m34, m_m44;
+ // };
+ // };
+ __m256 m_col12;
+ __m256 m_col34;
+};
+
+Q_ALWAYS_INLINE Vector4D operator*(const Vector4D &vector, const Matrix4x4_AVX2 &matrix)
+{
+ const __m256 vecMultiplier = _mm256_broadcast_ps(&vector.m_xyzw);
+ // a1 a2 a3 a4 b1 b2 b3 b4, c1 c2 c3 c4 d1 d2 d3 d4
+ // a1 + a2, a3 + a4, c1 + c2, c3 + c4
+ // b1 + b2, b3 + b3, d1 + d2, d3 + d4
+
+ const __m256 partialSum = _mm256_hadd_ps(_mm256_mul_ps(matrix.m_col12, vecMultiplier),
+ _mm256_mul_ps(matrix.m_col34, vecMultiplier));
+
+ Vector4D v(Qt::Uninitialized);
+ // a12 + a34, b12 + b34, c12 + c34, d12 + d34
+ // _mm256_permute4x64_pd is AVX2
+ // 0b11011000 == 0xd8
+ const __m256 shuffledSum = _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(partialSum), 0xd8));
+ v.m_xyzw = _mm_hadd_ps(_mm256_extractf128_ps(shuffledSum, 0), _mm256_extractf128_ps(shuffledSum, 1));
+ return v;
+}
+
+Q_ALWAYS_INLINE Vector4D operator*(const Matrix4x4_AVX2 &matrix, const Vector4D &vector)
+{
+ const Matrix4x4_AVX2 transposed = matrix.transposed();
+ return vector * transposed;
+}
+
+Q_ALWAYS_INLINE Vector3D operator*(const Vector3D &vector, const Matrix4x4_AVX2 &matrix)
+{
+ const __m128 vec4 = _mm_set_ps(1.0f, vector.z(), vector.y(), vector.x());
+ const __m256 vecMultiplier = _mm256_broadcast_ps(&vec4);
+ // a1 a2 a3 a4 b1 b2 b3 b4, c1 c2 c3 c4 d1 d2 d3 d4
+ // a1 + a2, a3 + a4, c1 + c2, c3 + c4
+ // b1 + b2, b3 + b3, d1 + d2, d3 + d4
+ const __m256 partialSum = _mm256_hadd_ps(_mm256_mul_ps(matrix.m_col12, vecMultiplier),
+ _mm256_mul_ps(matrix.m_col34, vecMultiplier));
+
+ // _mm256_permute4x64_pd is AVX2
+ // 0b11011000 == 0xd8
+ const __m256 shuffledSum = _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(partialSum), 0xd8));
+ // a12 + a34, b12 + b34, c12 + c34, d12 + d34
+ const __m128 result = _mm_hadd_ps(_mm256_extractf128_ps(shuffledSum, 0), _mm256_extractf128_ps(shuffledSum, 1));
+ // 0b11111111 = 0xff
+ const __m128 divisor = _mm_shuffle_ps(result, result, 0xff);
+
+ Vector3D v(Qt::Uninitialized);
+ v.m_xyzw = _mm_div_ps(result, divisor);;
+ return v;
+}
+
+Q_ALWAYS_INLINE Vector3D operator*(const Matrix4x4_AVX2 &matrix, const Vector3D &vector)
+{
+ const Matrix4x4_AVX2 transposed = matrix.transposed();
+ return vector * transposed;
+}
+
+} // Qt3DCore
+
+Q_DECLARE_TYPEINFO(Qt3DCore::Matrix4x4_AVX2, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DCore::Matrix4x4_AVX2)
+
+#endif // QT_COMPILER_SUPPORTS_AVX
+
+#endif // QT3DCORE_MATRIX4X4_AVX2_P_H
diff --git a/src/core/transforms/matrix4x4_p.h b/src/core/transforms/matrix4x4_p.h
new file mode 100644
index 000000000..1aded0f9c
--- /dev/null
+++ b/src/core/transforms/matrix4x4_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_MATRIX4X4_P_H
+#define QT3DCORE_MATRIX4X4_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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 <private/qsimd_p.h>
+
+#if defined(__AVX2__) && defined(QT_COMPILER_SUPPORTS_AVX2)
+
+#include <Qt3DCore/private/matrix4x4_avx2_p.h>
+
+QT_BEGIN_NAMESPACE
+using Matrix4x4 = Qt3DCore::Matrix4x4_AVX2;
+QT_END_NAMESPACE
+
+#elif defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSE2)
+
+#include <Qt3DCore/private/matrix4x4_sse_p.h>
+
+QT_BEGIN_NAMESPACE
+using Matrix4x4 = Qt3DCore::Matrix4x4_SSE;
+QT_END_NAMESPACE
+
+#else
+
+#include <QMatrix4x4>
+
+QT_BEGIN_NAMESPACE
+using Matrix4x4 = QMatrix4x4;
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QT3DCORE_MATRIX4X4_P_H
diff --git a/src/core/transforms/matrix4x4_sse.cpp b/src/core/transforms/matrix4x4_sse.cpp
new file mode 100644
index 000000000..d35cc2e35
--- /dev/null
+++ b/src/core/transforms/matrix4x4_sse.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "matrix4x4_sse_p.h"
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QDebug operator<<(QDebug dbg, const Matrix4x4_SSE &m)
+{
+ dbg.nospace() << "Matrix4x4_SSE(" << endl
+ << qSetFieldWidth(10)
+ << m.m11() << m.m12() << m.m13() << m.m14() << endl
+ << m.m21() << m.m22() << m.m23() << m.m24() << endl
+ << m.m31() << m.m32() << m.m33() << m.m34() << endl
+ << m.m41() << m.m42() << m.m43() << m.m44() << endl
+ << qSetFieldWidth(0) << ')';
+ return dbg;
+}
+
+} // Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT_COMPILER_SUPPORTS_SSE2
diff --git a/src/core/transforms/matrix4x4_sse_p.h b/src/core/transforms/matrix4x4_sse_p.h
new file mode 100644
index 000000000..be314ca4d
--- /dev/null
+++ b/src/core/transforms/matrix4x4_sse_p.h
@@ -0,0 +1,504 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_MATRIX4X4_SSE_P_H
+#define QT3DCORE_MATRIX4X4_SSE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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/private/vector4d_p.h>
+#include <Qt3DCore/private/vector3d_p.h>
+#include <private/qsimd_p.h>
+#include <QMatrix4x4>
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class Matrix4x4_SSE
+{
+public:
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE() { setToIdentity(); }
+ explicit Q_ALWAYS_INLINE Matrix4x4_SSE(Qt::Initialization) {}
+
+ // QMatrix4x4::constData returns in column major order
+ explicit Q_ALWAYS_INLINE Matrix4x4_SSE(const QMatrix4x4 &mat)
+ {
+ // data may not be properly aligned, using unaligned loads
+ const float *data = mat.constData();
+ m_col1 = _mm_loadu_ps(data);
+ m_col2 = _mm_loadu_ps(data + 4);
+ m_col3 = _mm_loadu_ps(data + 8);
+ m_col4 = _mm_loadu_ps(data + 12);
+ }
+
+ // Assumes data is 16 bytes aligned (and in column major order)
+ explicit Q_ALWAYS_INLINE Matrix4x4_SSE(float *data)
+ {
+ m_col1 = _mm_load_ps(data);
+ m_col2 = _mm_load_ps(data + 4);
+ m_col3 = _mm_load_ps(data + 8);
+ m_col4 = _mm_load_ps(data + 12);
+ }
+
+ // In (row major) but we store in column major order
+ explicit Q_ALWAYS_INLINE Matrix4x4_SSE(float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44)
+ {
+ m_col1 = _mm_set_ps(m41, m31, m21, m11);
+ m_col2 = _mm_set_ps(m42, m32, m22, m12);
+ m_col3 = _mm_set_ps(m43, m33, m23, m13);
+ m_col4 = _mm_set_ps(m44, m34, m24, m14);
+ }
+
+ Q_ALWAYS_INLINE void setToIdentity()
+ {
+ m_col1 = _mm_set_ss(1.0f);
+ m_col2 = _mm_set_ps(0.0f, 0.0f, 1.0f, 0.0f);
+ m_col3 = _mm_set_ps(0.0f, 1.0f, 0.0f, 0.0f);
+ m_col4 = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE operator*(const Matrix4x4_SSE &other) const
+ {
+ Matrix4x4_SSE c(Qt::Uninitialized);
+
+ const __m128 c1 = m_col1;
+ const __m128 c2 = m_col2;
+ const __m128 c3 = m_col3;
+ const __m128 c4 = m_col4;
+
+ // c11, c21, c31, c41
+ // 1) (m11 x n11), (m11 x n21), (m11 x n31), (m11 x n41)
+ // 2) (m11 x n11) + (m21 x n12), (m11 x n21) + (m21 x n22), (m11 x n31) + (m21 x n32), (m11 x n41) + (m21 x n42)
+ // 3) (m11 x n11) + (m21 x n21) + (m31 x n13), (m11 x n21) + (m21 x n22) + (m31 x n 23), (m11 x n31) + (m21 x n32) + (m31 x n33), (m11 x n41) + (m21 x n42) (m31 x n43)
+ // 4) (m11 x n11) + (m21 x n21) + (m31 x n13) + (m41 x n14), (m11 x n21) + (m21 x n22) + (m31 x n 23) + (m41 x n24), (m11 x n31) + (m21 x n32) + (m31 x n33) + (m41 x n34), (m11 x n41) + (m21 x n42) (m31 x n43) + (m41 x n44)
+ __m128 tmp = _mm_mul_ps(_mm_set1_ps(other.m11()), c1);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m21()), c2), tmp);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m31()), c3), tmp);
+ c.m_col1 = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m41()), c4), tmp);
+
+ // c21, c22, c23, c24
+ tmp = _mm_mul_ps(_mm_set1_ps(other.m12()), c1);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m22()), c2), tmp);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m32()), c3), tmp);
+ c.m_col2 = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m42()), c4), tmp);
+
+ // c31, c32, c33, c34
+ tmp = _mm_mul_ps(_mm_set1_ps(other.m13()), c1);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m23()), c2), tmp);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m33()), c3), tmp);
+ c.m_col3 = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m43()), c4), tmp);
+
+ // c41, c42, c43, c44
+ tmp = _mm_mul_ps(_mm_set1_ps(other.m14()), c1);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m24()), c2), tmp);
+ tmp = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m34()), c3), tmp);
+ c.m_col4 = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(other.m44()), c4), tmp);
+
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE operator-(const Matrix4x4_SSE &other) const
+ {
+ Matrix4x4_SSE c(Qt::Uninitialized);
+
+ c.m_col1 = _mm_sub_ps(m_col1, other.m_col1);
+ c.m_col2 = _mm_sub_ps(m_col2, other.m_col2);
+ c.m_col3 = _mm_sub_ps(m_col3, other.m_col3);
+ c.m_col4 = _mm_sub_ps(m_col4, other.m_col4);
+
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE operator+(const Matrix4x4_SSE &other) const
+ {
+ Matrix4x4_SSE c(Qt::Uninitialized);
+
+ c.m_col1 = _mm_add_ps(m_col1, other.m_col1);
+ c.m_col2 = _mm_add_ps(m_col2, other.m_col2);
+ c.m_col3 = _mm_add_ps(m_col3, other.m_col3);
+ c.m_col4 = _mm_add_ps(m_col4, other.m_col4);
+
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE &operator*=(const Matrix4x4_SSE &other)
+ {
+ *this = *this * other;
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE &operator-=(const Matrix4x4_SSE &other)
+ {
+ *this = *this - other;
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE &operator+=(const Matrix4x4_SSE &other)
+ {
+ *this = *this + other;
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE transposed() const
+ {
+ Matrix4x4_SSE c(Qt::Uninitialized);
+
+ // ~113 instructions
+ // 0b11011101 == 0xdd
+ // 0b10001000 == 0x88
+ const __m128 tmp1 = _mm_shuffle_ps(m_col1, m_col2, 0xdd);
+ const __m128 tmp2 = _mm_shuffle_ps(m_col1, m_col2, 0x88);
+ const __m128 tmp3 = _mm_shuffle_ps(m_col3, m_col4, 0xdd);
+ const __m128 tmp4 = _mm_shuffle_ps(m_col3, m_col4, 0x88);
+ c.m_col1 = _mm_shuffle_ps(tmp2, tmp4, 0x88);
+ c.m_col2 = _mm_shuffle_ps(tmp1, tmp3, 0x88);
+ c.m_col3 = _mm_shuffle_ps(tmp2, tmp4, 0xdd);
+ c.m_col4 = _mm_shuffle_ps(tmp1, tmp3, 0xdd);
+
+ return c;
+ }
+
+ Q_ALWAYS_INLINE Matrix4x4_SSE inverted() const
+ {
+ // TO DO: Optimize
+ const QMatrix4x4 mat = toQMatrix4x4();
+ return Matrix4x4_SSE(mat.inverted());
+ }
+
+ Q_ALWAYS_INLINE bool operator==(const Matrix4x4_SSE &other) const
+ {
+ // 0b1111 == 0xf
+ return (_mm_movemask_ps(_mm_cmpeq_ps(m_col1, other.m_col1)) == 0xf &&
+ _mm_movemask_ps(_mm_cmpeq_ps(m_col2, other.m_col2)) == 0xf &&
+ _mm_movemask_ps(_mm_cmpeq_ps(m_col3, other.m_col3)) == 0xf &&
+ _mm_movemask_ps(_mm_cmpeq_ps(m_col4, other.m_col4)) == 0xf);
+ }
+
+ Q_ALWAYS_INLINE bool operator!=(const Matrix4x4_SSE &other) const
+ {
+ return !(*this == other);
+ }
+
+ Q_ALWAYS_INLINE float m11() const { return _mm_cvtss_f32(m_col1); }
+ Q_ALWAYS_INLINE float m12() const { return _mm_cvtss_f32(m_col2); }
+ Q_ALWAYS_INLINE float m13() const { return _mm_cvtss_f32(m_col3); }
+ Q_ALWAYS_INLINE float m14() const { return _mm_cvtss_f32(m_col4); }
+
+ Q_ALWAYS_INLINE float m21() const
+ {
+ // 0b01010101 = 0x55
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col1, m_col1, 0x55));
+ }
+ Q_ALWAYS_INLINE float m22() const
+ {
+ // 0b01010101 = 0x55
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col2, m_col2, 0x55));
+ }
+ Q_ALWAYS_INLINE float m23() const
+ {
+ // 0b01010101 = 0x55
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col3, m_col3, 0x55));
+ }
+ Q_ALWAYS_INLINE float m24() const
+ {
+ // 0b01010101 = 0x55
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col4, m_col4, 0x55));
+ }
+
+ Q_ALWAYS_INLINE float m31() const
+ {
+ // 0b10101010 = 0xaa
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col1, m_col1, 0xaa));
+ }
+ Q_ALWAYS_INLINE float m32() const
+ {
+ // 0b10101010 = 0xaa
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col2, m_col2, 0xaa));
+ }
+ Q_ALWAYS_INLINE float m33() const
+ {
+ // 0b10101010 = 0xaa
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col3, m_col3, 0xaa));
+ }
+ Q_ALWAYS_INLINE float m34() const
+ {
+ // 0b10101010 = 0xaa
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col4, m_col4, 0xaa));
+ }
+
+ Q_ALWAYS_INLINE float m41() const
+ {
+ // 0b11111111 = 0xff
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col1, m_col1, 0xff));
+ }
+ Q_ALWAYS_INLINE float m42() const
+ {
+ // 0b11111111 = 0xff
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col2, m_col2, 0xff));
+ }
+ Q_ALWAYS_INLINE float m43() const
+ {
+ // 0b11111111 = 0xff
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col3, m_col3, 0xff));
+ }
+ Q_ALWAYS_INLINE float m44() const
+ {
+ // 0b11111111 = 0xff
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_col4, m_col4, 0xff));
+ }
+
+ Q_ALWAYS_INLINE Vector4D row(int index) const
+ {
+ switch (index) {
+ case 0:
+ return Vector4D(m11(), m12(), m13(), m14());
+ case 1:
+ return Vector4D(m21(), m22(), m23(), m24());
+ case 2:
+ return Vector4D(m31(), m32(), m33(), m34());
+ case 3:
+ return Vector4D(m41(), m42(), m43(), m44());
+ default:
+ Q_UNREACHABLE();
+ return Vector4D();
+ }
+ }
+
+ Q_ALWAYS_INLINE Vector4D column(int index) const
+ {
+ Vector4D c(Qt::Uninitialized);
+ switch (index) {
+ case 0:
+ c.m_xyzw = m_col1;
+ break;
+ case 1:
+ c.m_xyzw = m_col2;
+ break;
+ case 2:
+ c.m_xyzw = m_col3;
+ break;
+ case 3:
+ c.m_xyzw = m_col4;
+ break;
+ default:
+ Q_UNREACHABLE();
+ return Vector4D();
+ }
+ return c;
+ }
+
+ Q_ALWAYS_INLINE QMatrix4x4 toQMatrix4x4() const { return QMatrix4x4(m11(), m12(), m13(), m14(),
+ m21(), m22(), m23(), m24(),
+ m31(), m32(), m33(), m34(),
+ m41(), m42(), m43(), m44()); }
+
+ Q_ALWAYS_INLINE Vector3D_SSE map(const Vector3D_SSE &point) const
+ {
+ return *this * point;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE map(const Vector4D_SSE &point) const
+ {
+ return *this * point;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE mapVector(const Vector3D_SSE &vector) const
+ {
+ const __m128 row1 = _mm_set_ps(0.0f, m13(), m12(), m11());
+ const __m128 row2 = _mm_set_ps(0.0f, m23(), m22(), m21());
+ const __m128 row3 = _mm_set_ps(0.0f, m33(), m32(), m31());
+
+ const __m128 tmp = _mm_add_ps(_mm_mul_ps(vector.m_xyzw, row1), _mm_mul_ps(vector.m_xyzw, row2));
+
+ Vector3D_SSE v(Qt::Uninitialized);
+ v.m_xyzw = _mm_add_ps(tmp, _mm_mul_ps(vector.m_xyzw, row3));
+ return v;
+ }
+
+ friend Q_ALWAYS_INLINE Vector4D operator*(const Vector4D &vector, const Matrix4x4_SSE &matrix);
+ friend Q_ALWAYS_INLINE Vector4D operator*(const Matrix4x4_SSE &matrix, const Vector4D &vector);
+
+ friend Q_ALWAYS_INLINE Vector3D operator*(const Vector3D &vector, const Matrix4x4_SSE &matrix);
+ friend Q_ALWAYS_INLINE Vector3D operator*(const Matrix4x4_SSE &matrix, const Vector3D &vector);
+
+ friend QT3DCORE_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Matrix4x4_SSE &m);
+private:
+ // Internally we will store the matrix as indicated below
+ // Q_DECL_ALIGN(16) // aligned on 16 bytes boundary for SSE (column major)
+ // struct
+ // {
+ // float m_m11, m_m21, m_m31, m_m41;
+ // float m_m12, m_m22, m_m32, m_m42;
+ // float m_m13, m_m23, m_m33, m_m43;
+ // float m_m14, m_m24, m_m34, m_m44;
+ // };
+ // struct
+ // {
+ // float m[16];
+ // };
+ __m128 m_col1;
+ __m128 m_col2;
+ __m128 m_col3;
+ __m128 m_col4;
+};
+
+Q_ALWAYS_INLINE Vector4D operator*(const Vector4D &vector, const Matrix4x4_SSE &matrix)
+{
+ const __m128 vCol1 = _mm_mul_ps(matrix.m_col1, vector.m_xyzw);
+ const __m128 vCol2 = _mm_mul_ps(matrix.m_col2, vector.m_xyzw);
+ const __m128 vCol3 = _mm_mul_ps(matrix.m_col3, vector.m_xyzw);
+ const __m128 vCol4 = _mm_mul_ps(matrix.m_col4, vector.m_xyzw);
+
+
+ // 0b01000100 == 0x44
+ // 0b11101110 == 0xee
+
+ // vCol1.x, vCol1.y, vCol2.x, vCol2.y
+ __m128 tmp1 = _mm_shuffle_ps(vCol1, vCol2, 0x44);
+ // vCol1.z, vCol1.w, vCol2.z, vCol2.w
+ __m128 tmp2 = _mm_shuffle_ps(vCol1, vCol2, 0xee);
+
+ // vCol1.x + vCol1.z, vCol1.y + vCol1.w, vCol2.x + vCol2.z, vCol2.y + vCol2.w,
+ const __m128 tmpSum01 = _mm_add_ps(tmp1, tmp2);
+
+ // vCol3.x, vCol3.y, vCol4.x, vCol4.y
+ tmp1 = _mm_shuffle_ps(vCol3, vCol4, 0x44);
+ // vCol3.z, vCol3.w, vCol4.z, vCol4.w
+ tmp2 = _mm_shuffle_ps(vCol3, vCol4, 0xee);
+
+ // vCol3.x + vCol3.z, vCol3.y + vCol3.w, vCol4.x + vCol4.z, vCol4.y + vCol4.w,
+ const __m128 tmpSum02 = _mm_add_ps(tmp1, tmp2);
+
+ // 0b10001000 == 0x88
+ // 0b11011101 == 0xdd
+
+ // vCol1.x + vCol1.z, vCol2.x + vCol2.z, vCol3.x + vCol3.z, vCol4.x + vCol4.z,
+ tmp1 = _mm_shuffle_ps(tmpSum01, tmpSum02, 0x88);
+ // vCol1.y + vCol1.w, vCol2.y + vCol2.w, vCol3.y + vCol3.w, vCol4.y + vCol4.w,
+ tmp2 = _mm_shuffle_ps(tmpSum01, tmpSum02, 0xdd);
+
+ Vector4D v(Qt::Uninitialized);
+ v.m_xyzw = _mm_add_ps(tmp1, tmp2);
+ return v;
+}
+
+Q_ALWAYS_INLINE Vector4D operator*(const Matrix4x4_SSE &matrix, const Vector4D &vector)
+{
+ const Matrix4x4_SSE transposed = matrix.transposed();
+ return vector * transposed;
+}
+
+Q_ALWAYS_INLINE Vector3D operator*(const Vector3D &vector, const Matrix4x4_SSE &matrix)
+{
+ const __m128 vec4 = _mm_set_ps(1.0f, vector.z(), vector.y(), vector.x());
+
+ const __m128 vCol1 = _mm_mul_ps(matrix.m_col1, vec4);
+ const __m128 vCol2 = _mm_mul_ps(matrix.m_col2, vec4);
+ const __m128 vCol3 = _mm_mul_ps(matrix.m_col3, vec4);
+ const __m128 vCol4 = _mm_mul_ps(matrix.m_col4, vec4);
+
+ // 0b01000100 == 0x44
+ // 0b11101110 == 0xee
+
+ // vCol1.x, vCol1.y, vCol2.x, vCol2.y
+ __m128 tmp1 = _mm_shuffle_ps(vCol1, vCol2, 0x44);
+ // vCol1.z, vCol1.w, vCol2.z, vCol2.w
+ __m128 tmp2 = _mm_shuffle_ps(vCol1, vCol2, 0xee);
+
+ // vCol1.x + vCol1.z, vCol1.y + vCol1.w, vCol2.x + vCol2.z, vCol2.y + vCol2.w,
+ const __m128 tmpSum01 = _mm_add_ps(tmp1, tmp2);
+
+ // vCol3.x, vCol3.y, vCol4.x, vCol4.y
+ tmp1 = _mm_shuffle_ps(vCol3, vCol4, 0x44);
+ // vCol3.z, vCol3.w, vCol4.z, vCol4.w
+ tmp2 = _mm_shuffle_ps(vCol3, vCol4, 0xee);
+
+ // vCol3.x + vCol3.z, vCol3.y + vCol3.w, vCol4.x + vCol4.z, vCol4.y + vCol4.w,
+ const __m128 tmpSum02 = _mm_add_ps(tmp1, tmp2);
+
+ // 0b10001000 == 0x88
+ // 0b11011101 == 0xdd
+
+ // vCol1.x + vCol1.z, vCol2.x + vCol2.z, vCol3.x + vCol3.z, vCol4.x + vCol4.z,
+ tmp1 = _mm_shuffle_ps(tmpSum01, tmpSum02, 0x88);
+ // vCol1.y + vCol1.w, vCol2.y + vCol2.w, vCol3.y + vCol3.w, vCol4.y + vCol4.w,
+ tmp2 = _mm_shuffle_ps(tmpSum01, tmpSum02, 0xdd);
+
+ const __m128 result = _mm_add_ps(tmp1, tmp2);
+ // 0b11111111 = 0xff
+ const __m128 divisor = _mm_shuffle_ps(result, result, 0xff);
+ Vector3D v(Qt::Uninitialized);
+ v.m_xyzw = _mm_div_ps(result, divisor);
+ return v;
+}
+
+QT3DCORE_PRIVATE_EXPORT Q_ALWAYS_INLINE Vector3D operator*(const Matrix4x4_SSE &matrix, const Vector3D &vector)
+{
+ const Matrix4x4_SSE transposed = matrix.transposed();
+ return vector * transposed;
+}
+
+} // Qt3DCore
+
+
+Q_DECLARE_TYPEINFO(Qt3DCore::Matrix4x4_SSE, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DCore::Matrix4x4_SSE)
+
+#endif // QT_COMPILER_SUPPORTS_SSE2
+
+#endif // QT3DCORE_MATRIX4X4_SSE_P_H
diff --git a/src/core/transforms/qabstractskeleton.cpp b/src/core/transforms/qabstractskeleton.cpp
new file mode 100644
index 000000000..d780987ee
--- /dev/null
+++ b/src/core/transforms/qabstractskeleton.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qabstractskeleton.h"
+#include "qabstractskeleton_p.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QAbstractSkeletonPrivate::QAbstractSkeletonPrivate()
+ : Qt3DCore::QNodePrivate()
+ , m_jointCount(0)
+{
+}
+
+/*!
+ \internal
+ */
+const QAbstractSkeletonPrivate *QAbstractSkeletonPrivate::get(const QAbstractSkeleton *q)
+{
+ return q->d_func();
+}
+
+/*!
+ \qmltype AbstractSkeleton
+ \inqmlmodule Qt3D.Core
+ \inherits Node
+ \instantiates Qt3DCore::QAbstractSkeleton
+ \since 5.10
+ \brief A skeleton contains the joints for a skinned mesh
+
+ Do not use this class directly. You should use SkeletonLoader if loading
+ skeleton data from a file (most likely) or Skeleton if creating the
+ skeleton and skinned mesh data yourself (mainly for people creating
+ editors or tooling).
+*/
+
+/*!
+ \class Qt3DCore::QAbstractSkeleton
+ \inmodule Qt3DCore
+ \inherits Qt3DCore::QNode
+ \since 5.10
+ \brief A skeleton contains the joints for a skinned mesh
+
+ Do not use this class directly. You should use QSkeletonLoader if loading
+ skeleton data from a file (most likely) or QSkeleton if creating the
+ skeleton and skinned mesh data yourself (mainly for people creating
+ editors or tooling).
+*/
+
+/*! \internal */
+QAbstractSkeleton::QAbstractSkeleton(QAbstractSkeletonPrivate &dd, Qt3DCore::QNode *parent)
+ : Qt3DCore::QNode(dd, parent)
+{
+}
+
+/*! \internal */
+QAbstractSkeleton::~QAbstractSkeleton()
+{
+}
+
+/*!
+ \property Qt3DCore::QAbstractSkeleton::jointCount
+
+ Holds the number of joints contained in the skeleton
+*/
+int QAbstractSkeleton::jointCount() const
+{
+ Q_D(const QAbstractSkeleton);
+ return d->m_jointCount;
+}
+
+void QAbstractSkeletonPrivate::setJointCount(int jointCount)
+{
+ Q_Q(QAbstractSkeleton);
+ if (m_jointCount == jointCount)
+ return;
+ m_jointCount = jointCount;
+ const bool block = q->blockNotifications(true);
+ emit q->jointCountChanged(jointCount);
+ q->blockNotifications(block);
+}
+
+void QAbstractSkeleton::sceneChangeEvent(const QSceneChangePtr &change)
+{
+ Q_D(QAbstractSkeleton);
+ if (change->type() == Qt3DCore::PropertyUpdated) {
+ const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (e->propertyName() == QByteArrayLiteral("jointCount"))
+ d->setJointCount(e->value().toInt());
+ }
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/transforms/qabstractskeleton.h b/src/core/transforms/qabstractskeleton.h
new file mode 100644
index 000000000..3fc13fb70
--- /dev/null
+++ b/src/core/transforms/qabstractskeleton.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QABSTRACTSKELETON_H
+#define QT3DCORE_QABSTRACTSKELETON_H
+
+#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/qt3dcore_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QAbstractSkeletonPrivate;
+
+class QT3DCORESHARED_EXPORT QAbstractSkeleton : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(int jointCount READ jointCount NOTIFY jointCountChanged)
+
+public:
+ ~QAbstractSkeleton();
+
+ int jointCount() const;
+
+Q_SIGNALS:
+ void jointCountChanged(int jointCount);
+
+protected:
+ QAbstractSkeleton(QAbstractSkeletonPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const QSceneChangePtr &change) override;
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractSkeleton)
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QABSTRACTSKELETON_H
diff --git a/src/core/transforms/qabstractskeleton_p.h b/src/core/transforms/qabstractskeleton_p.h
new file mode 100644
index 000000000..51d57f8c4
--- /dev/null
+++ b/src/core/transforms/qabstractskeleton_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QABSTRACTSKELETON_P_H
+#define QT3DCORE_QABSTRACTSKELETON_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/private/qnode_p.h>
+#include <Qt3DCore/private/qskeletoncreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QAbstractSkeletonPrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QAbstractSkeletonPrivate();
+
+ void setJointCount(int jointCount);
+
+ Q_DECLARE_PUBLIC(QAbstractSkeleton)
+ static const QAbstractSkeletonPrivate *get(const QAbstractSkeleton *q);
+
+ QSkeletonCreatedChangeBase::SkeletonType m_type;
+
+ int m_jointCount;
+};
+
+} // namespace Qt3DCore
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QABSTRACTSKELETON_P_H
diff --git a/src/core/transforms/qarmature.cpp b/src/core/transforms/qarmature.cpp
new file mode 100644
index 000000000..65a13b262
--- /dev/null
+++ b/src/core/transforms/qarmature.cpp
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qarmature.h"
+#include "qarmature_p.h"
+#include <Qt3DCore/qabstractskeleton.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QArmaturePrivate::QArmaturePrivate()
+ : Qt3DCore::QComponentPrivate()
+ , m_skeleton(nullptr)
+{
+}
+
+/*!
+ \qmltype Armature
+ \inqmlmodule Qt3D.Core
+ \inherits Component3D
+ \instantiates Qt3DCore::QArmature
+ \since 5.10
+ \brief Used to calculate skinning transform matrices and set them on shaders
+
+ The Armature component is aggregated by entities to give them the ability to
+ calculate the palette of skinning transform matrices needed to properly
+ render skinned meshes.
+
+ Each vertex in a skinned mesh is associated (bound) to up to 4 joints in a
+ skeleton. For each joint affecting a vertex the mesh also provides a weight
+ which determines the level of influence of the corresponding joint. The
+ skinning palette used for performing the transformation of skinned vertices
+ is provided by the Armature and is calculated from the joints contained in
+ the referenced skeleton.
+
+ Updating the local transform of a joint results in the skinning matrices
+ being recalculated and the skinned mesh vertices bound to that joint moving
+ accordingly.
+*/
+
+/*!
+ \qmlproperty AbstractSkeleton Armature::skeleton
+
+ Holds the skeleton used to calculate the skinning transform matrix palette.
+*/
+
+/*!
+ \class Qt3DCore::QArmature
+ \inmodule Qt3DCore
+ \inherits Qt3DCore::QComponent
+ \since 5.10
+ \brief Used to calculate skinning transform matrices and set them on shaders
+
+ The Armature component is aggregated by entities to give them the ability to
+ calculate the palette of skinning transform matrices needed to properly
+ render skinned meshes.
+
+ Each vertex in a skinned mesh is associated (bound) to up to 4 joints in a
+ skeleton. For each joint affecting a vertex the mesh also provides a weight
+ which determines the level of influence of the corresponding joint. The
+ skinning palette used for performing the transformation of skinned vertices
+ is provided by the Armature and is calculated from the joints contained in
+ the referenced skeleton.
+
+ Updating the local transform of a joint results in the skinning matrices
+ being recalculated and the skinned mesh vertices bound to that joint moving
+ accordingly.
+*/
+
+/*!
+ Constructs a new QArmature with \a parent.
+*/
+QArmature::QArmature(Qt3DCore::QNode *parent)
+ : Qt3DCore::QComponent(*new QArmaturePrivate, parent)
+{
+}
+
+/*! \internal */
+QArmature::QArmature(QArmaturePrivate &dd, Qt3DCore::QNode *parent)
+ : Qt3DCore::QComponent(dd, parent)
+{
+}
+
+/*! \internal */
+QArmature::~QArmature()
+{
+}
+
+/*!
+ \property Qt3DCore::QArmature::skeleton
+
+ Holds the skeleton used to calculate the skinning transform matrix palette.
+*/
+Qt3DCore::QAbstractSkeleton *QArmature::skeleton() const
+{
+ Q_D(const QArmature);
+ return d->m_skeleton;
+}
+
+void QArmature::setSkeleton(Qt3DCore::QAbstractSkeleton *skeleton)
+{
+ Q_D(QArmature);
+ if (d->m_skeleton != skeleton) {
+ if (d->m_skeleton)
+ d->unregisterDestructionHelper(d->m_skeleton);
+
+ // We need to add it as a child of the current node if it has been declared inline
+ // Or not previously added as a child of the current node so that
+ // 1) The backend gets notified about it's creation
+ // 2) When the current node is destroyed, it gets destroyed as well
+ if (skeleton && !skeleton->parent())
+ skeleton->setParent(this);
+ d->m_skeleton = skeleton;
+
+ // Ensures proper bookkeeping
+ if (d->m_skeleton)
+ d->registerDestructionHelper(d->m_skeleton, &QArmature::setSkeleton, d->m_skeleton);
+
+ emit skeletonChanged(skeleton);
+ }
+}
+
+/*! \internal */
+Qt3DCore::QNodeCreatedChangeBasePtr QArmature::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QArmatureData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QArmature);
+ data.skeletonId = qIdForNode(d->m_skeleton);
+ return creationChange;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/transforms/qarmature.h b/src/core/transforms/qarmature.h
new file mode 100644
index 000000000..a5ccc9d28
--- /dev/null
+++ b/src/core/transforms/qarmature.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QARMATURE_H
+#define QT3DCORE_QARMATURE_H
+
+#include <Qt3DCore/qcomponent.h>
+#include <Qt3DCore/qt3dcore_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QArmaturePrivate;
+class QAbstractSkeleton;
+
+class QT3DCORESHARED_EXPORT QArmature : public Qt3DCore::QComponent
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DCore::QAbstractSkeleton* skeleton READ skeleton WRITE setSkeleton NOTIFY skeletonChanged)
+
+public:
+ explicit QArmature(Qt3DCore::QNode *parent = nullptr);
+ ~QArmature();
+
+ QAbstractSkeleton* skeleton() const;
+
+public Q_SLOTS:
+ void setSkeleton(Qt3DCore::QAbstractSkeleton* skeleton);
+
+Q_SIGNALS:
+ void skeletonChanged(Qt3DCore::QAbstractSkeleton* skeleton);
+
+protected:
+ QArmature(QArmaturePrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QArmature)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QARMATURE_H
diff --git a/src/core/transforms/qarmature_p.h b/src/core/transforms/qarmature_p.h
new file mode 100644
index 000000000..1fc241dc2
--- /dev/null
+++ b/src/core/transforms/qarmature_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QARMATURE_P_H
+#define QT3DCORE_QARMATURE_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/private/qcomponent_p.h>
+#include <Qt3DCore/qarmature.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QAbstractSkeleton;
+
+class QArmaturePrivate : public Qt3DCore::QComponentPrivate
+{
+public:
+ QArmaturePrivate();
+
+ Q_DECLARE_PUBLIC(QArmature)
+
+ QAbstractSkeleton *m_skeleton;
+};
+
+struct QArmatureData
+{
+ QNodeId skeletonId;
+};
+
+} // namespace Qt3DCore
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QARMATURE_P_H
diff --git a/src/core/transforms/qjoint.cpp b/src/core/transforms/qjoint.cpp
new file mode 100644
index 000000000..3f631ec98
--- /dev/null
+++ b/src/core/transforms/qjoint.cpp
@@ -0,0 +1,414 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qjoint.h"
+#include "qjoint_p.h"
+
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QJointPrivate::QJointPrivate()
+ : QNodePrivate()
+ , m_inverseBindMatrix()
+ , m_rotation()
+ , m_translation()
+ , m_scale(1.0f, 1.0f, 1.0f)
+{
+}
+
+/*!
+ \qmltype Joint
+ \inqmlmodule Qt3D.Core
+ \inherits Node
+ \instantiates Qt3DCore::QJoint
+ \since 5.10
+ \brief Used to transforms parts of skinned meshes
+
+ The Joint node is used to build skeletons as part of the skinned mesh
+ support in Qt 3D. A joint can be transformed by way of its scale, rotation
+ and translation properties. Any mesh vertices that are bound to the joint
+ will have their transformations updated accordingly.
+*/
+
+/*!
+ \qmlproperty vector3d Joint::scale
+
+ Holds the uniform scale of the joint.
+*/
+
+/*!
+ \qmlproperty quaternion Joint::rotation
+
+ Holds the rotation of the joint as quaternion.
+*/
+
+/*!
+ \qmlproperty vector3d Joint::translation
+
+ Holds the translation of the joint as vector3d.
+*/
+
+/*!
+ \qmlproperty real Joint::rotationX
+
+ Holds the x rotation of the joint as an Euler angle.
+*/
+
+/*!
+ \qmlproperty real Joint::rotationY
+
+ Holds the y rotation of the joint as an Euler angle.
+*/
+
+/*!
+ \qmlproperty real Joint::rotationZ
+
+ Holds the z rotation of the joint as an Euler angle.
+*/
+
+/*!
+ \qmlproperty matrix4x4 inverseBindMatrix
+
+ Holds the inverse bind matrix of the joint. This is used to transform
+ vertices from model space into the space of this joint so they can
+ subsequently be multiplied by the joint's global transform to perform
+ the skinning operation.
+*/
+
+/*!
+ \class Qt3DCore::QJoint
+ \inmodule Qt3DCore
+ \inherits Qt3DCore::QNode
+ \since 5.10
+ \brief Used to transforms parts of skinned meshes
+
+ The QJoint node is used to build skeletons as part of the skinned mesh
+ support in Qt 3D. A joint can be transformed by way of its scale, rotation
+ and translation properties. Any mesh vertices that are bound to the joint
+ will have their transformations updated accordingly.
+*/
+
+/*!
+ Constructs a new QJoint with \a parent.
+*/
+QJoint::QJoint(Qt3DCore::QNode *parent)
+ : QNode(*new QJointPrivate, parent)
+{
+}
+
+/*! \internal */
+QJoint::~QJoint()
+{
+}
+
+/*!
+ \property Qt3DCore::QJoint::scale
+
+ Holds the scale of the joint.
+*/
+QVector3D QJoint::scale() const
+{
+ Q_D(const QJoint);
+ return d->m_scale;
+}
+
+/*!
+ \property Qt3DCore::QJoint::rotation
+
+ Holds the rotation of the joint as QQuaternion.
+*/
+QQuaternion QJoint::rotation() const
+{
+ Q_D(const QJoint);
+ return d->m_rotation;
+}
+
+/*!
+ \property Qt3DCore::QJoint::translation
+
+ Holds the translation of the joint as QVector3D.
+*/
+QVector3D QJoint::translation() const
+{
+ Q_D(const QJoint);
+ return d->m_translation;
+}
+
+/*!
+ \property Qt3DCore::QJoint::inverseBindMatrix
+
+ Holds the inverse bind matrix of the joint. This is used to transform
+ vertices from model space into the space of this joint so they can
+ subsequently be multiplied by the joint's global transform to perform
+ the skinning operation.
+*/
+QMatrix4x4 QJoint::inverseBindMatrix() const
+{
+ Q_D(const QJoint);
+ return d->m_inverseBindMatrix;
+}
+
+/*!
+ \property Qt3DCore::QJoint::rotationX
+
+ Holds the x rotation of the joint as an Euler angle.
+*/
+float QJoint::rotationX() const
+{
+ Q_D(const QJoint);
+ return d->m_eulerRotationAngles.x();
+}
+
+/*!
+ \property Qt3DCore::QJoint::rotationY
+
+ Holds the y rotation of the joint as an Euler angle.
+*/
+float QJoint::rotationY() const
+{
+ Q_D(const QJoint);
+ return d->m_eulerRotationAngles.y();
+}
+
+/*!
+ \property Qt3DCore::QJoint::rotationZ
+
+ Holds the z rotation of the joint as an Euler angle.
+*/
+float QJoint::rotationZ() const
+{
+ Q_D(const QJoint);
+ return d->m_eulerRotationAngles.z();
+}
+
+void QJoint::setScale(const QVector3D &scale)
+{
+ Q_D(QJoint);
+ if (scale == d->m_scale)
+ return;
+
+ d->m_scale = scale;
+ emit scaleChanged(scale);
+}
+
+void QJoint::setRotation(const QQuaternion &rotation)
+{
+ Q_D(QJoint);
+ if (rotation == d->m_rotation)
+ return;
+
+ d->m_rotation = rotation;
+ const QVector3D oldRotation = d->m_eulerRotationAngles;
+ d->m_eulerRotationAngles = d->m_rotation.toEulerAngles();
+ emit rotationChanged(rotation);
+
+ const bool wasBlocked = blockNotifications(true);
+ if (!qFuzzyCompare(d->m_eulerRotationAngles.x(), oldRotation.x()))
+ emit rotationXChanged(d->m_eulerRotationAngles.x());
+ if (!qFuzzyCompare(d->m_eulerRotationAngles.y(), oldRotation.y()))
+ emit rotationYChanged(d->m_eulerRotationAngles.y());
+ if (!qFuzzyCompare(d->m_eulerRotationAngles.z(), oldRotation.z()))
+ emit rotationZChanged(d->m_eulerRotationAngles.z());
+ blockNotifications(wasBlocked);
+}
+
+void QJoint::setTranslation(const QVector3D &translation)
+{
+ Q_D(QJoint);
+ if (translation == d->m_translation)
+ return;
+
+ d->m_translation = translation;
+ emit translationChanged(translation);
+}
+
+void QJoint::setInverseBindMatrix(const QMatrix4x4 &inverseBindMatrix)
+{
+ Q_D(QJoint);
+ if (d->m_inverseBindMatrix == inverseBindMatrix)
+ return;
+
+ d->m_inverseBindMatrix = inverseBindMatrix;
+ emit inverseBindMatrixChanged(inverseBindMatrix);
+}
+
+void QJoint::setRotationX(float rotationX)
+{
+ Q_D(QJoint);
+
+ if (qFuzzyCompare(d->m_eulerRotationAngles.x(), rotationX))
+ return;
+
+ const auto eulers = QVector3D(rotationX,
+ d->m_eulerRotationAngles.y(),
+ d->m_eulerRotationAngles.z());
+ const QQuaternion r = QQuaternion::fromEulerAngles(eulers);
+ setRotation(r);
+}
+
+void QJoint::setRotationY(float rotationY)
+{
+ Q_D(QJoint);
+
+ if (qFuzzyCompare(d->m_eulerRotationAngles.y(), rotationY))
+ return;
+
+ const auto eulers = QVector3D(d->m_eulerRotationAngles.x(),
+ rotationY,
+ d->m_eulerRotationAngles.z());
+ const QQuaternion r = QQuaternion::fromEulerAngles(eulers);
+ setRotation(r);
+}
+
+void QJoint::setRotationZ(float rotationZ)
+{
+ Q_D(QJoint);
+ if (qFuzzyCompare(d->m_eulerRotationAngles.z(), rotationZ))
+ return;
+
+ const auto eulers = QVector3D(d->m_eulerRotationAngles.x(),
+ d->m_eulerRotationAngles.y(),
+ rotationZ);
+ const QQuaternion r = QQuaternion::fromEulerAngles(eulers);
+ setRotation(r);
+}
+
+void QJoint::setName(const QString &name)
+{
+ Q_D(QJoint);
+ if (d->m_name == name)
+ return;
+
+ d->m_name = name;
+ emit nameChanged(name);
+}
+
+void QJoint::setToIdentity()
+{
+ setScale(QVector3D(1.0f, 1.0f, 1.0f));
+ setRotation(QQuaternion());
+ setTranslation(QVector3D());
+}
+
+/*!
+ Adds \a joint as a child of this joint. If \a joint has no parent, then
+ this joint takes ownership of it. Child joints are in the coordinate system
+ of their parent joint.
+*/
+void QJoint::addChildJoint(QJoint *joint)
+{
+ Q_D(QJoint);
+ if (!d->m_childJoints.contains(joint)) {
+ d->m_childJoints.push_back(joint);
+ // Force creation in backend by setting parent
+ if (!joint->parent())
+ joint->setParent(this);
+
+ // Ensures proper bookkeeping
+ d->registerDestructionHelper(joint, &QJoint::removeChildJoint, d->m_childJoints);
+
+ if (d->m_changeArbiter != nullptr) {
+ const auto change = QPropertyNodeAddedChangePtr::create(id(), joint);
+ change->setPropertyName("childJoint");
+ d->notifyObservers(change);
+ }
+ }
+}
+
+/*!
+ Removes \a joint from this joint's list of children. The child joint is not
+ destroyed.
+*/
+void QJoint::removeChildJoint(QJoint *joint)
+{
+ Q_D(QJoint);
+ if (d->m_childJoints.contains(joint)) {
+
+ if (d->m_changeArbiter != nullptr) {
+ const auto change = QPropertyNodeRemovedChangePtr::create(id(), joint);
+ change->setPropertyName("childJoint");
+ d->notifyObservers(change);
+ }
+
+ d->m_childJoints.removeOne(joint);
+
+ // Remove bookkeeping connection
+ d->unregisterDestructionHelper(joint);
+ }
+}
+
+/*!
+ The vector of joints this joint has as children.
+*/
+QVector<QJoint *> QJoint::childJoints() const
+{
+ Q_D(const QJoint);
+ return d->m_childJoints;
+}
+
+QString QJoint::name() const
+{
+ Q_D(const QJoint);
+ return d->m_name;
+}
+
+/*! \internal */
+Qt3DCore::QNodeCreatedChangeBasePtr QJoint::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QJointData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QJoint);
+ data.inverseBindMatrix = d->m_inverseBindMatrix;
+ data.childJointIds = qIdsForNodes(d->m_childJoints);
+ data.rotation = d->m_rotation;
+ data.scale = d->m_scale;
+ data.translation = d->m_translation;
+ data.name = d->m_name;
+ return creationChange;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/transforms/qjoint.h b/src/core/transforms/qjoint.h
new file mode 100644
index 000000000..fdc3d51a3
--- /dev/null
+++ b/src/core/transforms/qjoint.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QJOINT_H
+#define QT3DCORE_QJOINT_H
+
+#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/qt3dcore_global.h>
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qquaternion.h>
+#include <QtGui/qvector3d.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QJointPrivate;
+
+class QT3DCORESHARED_EXPORT QJoint : public QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector3D scale READ scale WRITE setScale NOTIFY scaleChanged)
+ Q_PROPERTY(QQuaternion rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(QVector3D translation READ translation WRITE setTranslation NOTIFY translationChanged)
+ Q_PROPERTY(QMatrix4x4 inverseBindMatrix READ inverseBindMatrix WRITE setInverseBindMatrix NOTIFY inverseBindMatrixChanged)
+ Q_PROPERTY(float rotationX READ rotationX WRITE setRotationX NOTIFY rotationXChanged)
+ Q_PROPERTY(float rotationY READ rotationY WRITE setRotationY NOTIFY rotationYChanged)
+ Q_PROPERTY(float rotationZ READ rotationZ WRITE setRotationZ NOTIFY rotationZChanged)
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+
+public:
+ explicit QJoint(Qt3DCore::QNode *parent = nullptr);
+ ~QJoint();
+
+ QVector3D scale() const;
+ QQuaternion rotation() const;
+ QVector3D translation() const;
+ QMatrix4x4 inverseBindMatrix() const;
+ float rotationX() const;
+ float rotationY() const;
+ float rotationZ() const;
+ QString name() const;
+
+ void addChildJoint(QJoint *joint);
+ void removeChildJoint(QJoint *joint);
+ QVector<QJoint *> childJoints() const;
+
+public Q_SLOTS:
+ void setScale(const QVector3D &scale);
+ void setRotation(const QQuaternion &rotation);
+ void setTranslation(const QVector3D &translation);
+ void setInverseBindMatrix(const QMatrix4x4 &inverseBindMatrix);
+ void setRotationX(float rotationX);
+ void setRotationY(float rotationY);
+ void setRotationZ(float rotationZ);
+ void setName(const QString &name);
+ void setToIdentity();
+
+Q_SIGNALS:
+ void scaleChanged(const QVector3D &scale);
+ void rotationChanged(const QQuaternion &rotation);
+ void translationChanged(const QVector3D &translation);
+ void inverseBindMatrixChanged(const QMatrix4x4 &inverseBindMatrix);
+ void rotationXChanged(float rotationX);
+ void rotationYChanged(float rotationY);
+ void rotationZChanged(float rotationZ);
+ void nameChanged(const QString &name);
+
+private:
+ Q_DECLARE_PRIVATE(QJoint)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QJOINT_H
diff --git a/src/core/transforms/qjoint_p.h b/src/core/transforms/qjoint_p.h
new file mode 100644
index 000000000..82439d55a
--- /dev/null
+++ b/src/core/transforms/qjoint_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QJOINT_P_H
+#define QT3DCORE_QJOINT_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/private/qnode_p.h>
+#include <Qt3DCore/qjoint.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QJoint;
+
+class QJointPrivate : public QNodePrivate
+{
+public:
+ QJointPrivate();
+
+ Q_DECLARE_PUBLIC(QJoint)
+
+ QMatrix4x4 m_inverseBindMatrix;
+ QVector<QJoint *> m_childJoints;
+ QQuaternion m_rotation;
+ QVector3D m_translation;
+ QVector3D m_scale;
+ QString m_name;
+
+ // Not sent to backend. Purely internal convenience
+ QVector3D m_eulerRotationAngles;
+};
+
+struct QJointData
+{
+ QMatrix4x4 inverseBindMatrix;
+ QNodeIdVector childJointIds;
+ QQuaternion rotation;
+ QVector3D translation;
+ QVector3D scale;
+ QString name;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QJOINT_P_H
diff --git a/src/core/transforms/qmath3d_p.h b/src/core/transforms/qmath3d_p.h
index 8c2afac31..a4f33f0b6 100644
--- a/src/core/transforms/qmath3d_p.h
+++ b/src/core/transforms/qmath3d_p.h
@@ -53,6 +53,7 @@
#include <QtGui/qmatrix4x4.h>
#include <QtGui/qquaternion.h>
#include <QtGui/qvector3d.h>
+#include <Qt3DCore/private/sqt_p.h>
#include <cmath>
@@ -189,6 +190,24 @@ inline void decomposeQMatrix4x4(const QMatrix4x4 &m, QVector3D &position, QQuate
position = QVector3D(m(0, 3), m(1, 3), m(2, 3));
}
+inline void decomposeQMatrix4x4(const QMatrix4x4 &m, Qt3DCore::Sqt &sqt)
+{
+ Q_ASSERT(m.isAffine());
+
+ const QMatrix3x3 m3x3(m.toGenericMatrix<3, 3>());
+
+ QMatrix3x3 rot3x3(Qt::Uninitialized);
+ if (hasScale(m)) {
+ decomposeQMatrix3x3(m3x3, rot3x3, sqt.scale, sqt.translation);
+ } else {
+ // we know there is no scaling part; no need for QDU decomposition
+ sqt.scale = QVector3D(1.0f, 1.0f, 1.0f);
+ rot3x3 = m3x3;
+ }
+ sqt.rotation = QQuaternion::fromRotationMatrix(rot3x3);
+ sqt.translation = QVector3D(m(0, 3), m(1, 3), m(2, 3));
+}
+
QT_END_NAMESPACE
#endif // QT3DCORE_QMATH3D_P_H
diff --git a/src/core/transforms/qskeleton.cpp b/src/core/transforms/qskeleton.cpp
new file mode 100644
index 000000000..c58bc0f8c
--- /dev/null
+++ b/src/core/transforms/qskeleton.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qskeleton.h"
+#include "qskeleton_p.h"
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/private/qskeletoncreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QSkeletonPrivate::QSkeletonPrivate()
+ : QAbstractSkeletonPrivate()
+ , m_rootJoint(nullptr)
+{
+ m_type = QSkeletonCreatedChangeBase::Skeleton;
+}
+
+/*!
+ \qmltype Skeleton
+ \inqmlmodule Qt3D.Core
+ \inherits AbstractSkeleton
+ \instantiates Qt3DCore::QSkeleton
+ \since 5.10
+ \brief Holds the data for a skeleton to be used with skinned meshes
+
+ Use Skeleton if you wish to manually create the joints of a skeleton for
+ use with skinned meshes. This is mainly of use to people creating editors,
+ tooling, or dynamic skeletons. It is more common that a Qt 3D application
+ would simply consume an existing skeleton and skinned mesh as created in
+ a digital content creation tool such as Blender. For this use case, please
+ see SkeletonLoader.
+*/
+
+/*!
+ \qmlproperty Joint Skeleton::rootJoint
+
+ Holds the root joint of the hierarchy of joints forming the skeleton.
+*/
+
+/*!
+ \class Qt3DCore::QSkeleton
+ \inmodule Qt3DCore
+ \inherits Qt3DCore::QAbstractSkeleton
+ \since 5.10
+ \brief Holds the data for a skeleton to be used with skinned meshes
+
+ Use QSkeleton if you wish to manually create the joints of a skeleton for
+ use with skinned meshes. This is mainly of use to people creating editors,
+ tooling, or dynamic skeletons. It is more common that a Qt 3D application
+ would simply consume an existing skeleton and skinned mesh as created in
+ a digital content creation tool such as Blender. For this use case, please
+ see QSkeletonLoader.
+*/
+
+/*!
+ Constructs a new QSkeleton with \a parent.
+*/
+QSkeleton::QSkeleton(Qt3DCore::QNode *parent)
+ : QAbstractSkeleton(*new QSkeletonPrivate, parent)
+{
+}
+
+/*! \internal */
+QSkeleton::~QSkeleton()
+{
+}
+
+/*!
+ \property Qt3DCore::QSkeleton::rootJoint
+
+ Holds the root joint of the hierarchy of joints forming the skeleton.
+*/
+Qt3DCore::QJoint *QSkeleton::rootJoint() const
+{
+ Q_D(const QSkeleton);
+ return d->m_rootJoint;
+}
+
+void QSkeleton::setRootJoint(Qt3DCore::QJoint *rootJoint)
+{
+ Q_D(QSkeleton);
+ if (d->m_rootJoint != rootJoint) {
+ if (d->m_rootJoint)
+ d->unregisterDestructionHelper(d->m_rootJoint);
+
+ // We need to add it as a child of the current node if it has been declared inline
+ // Or not previously added as a child of the current node so that
+ // 1) The backend gets notified about it's creation
+ // 2) When the current node is destroyed, it gets destroyed as well
+ if (rootJoint && !rootJoint->parent())
+ rootJoint->setParent(this);
+ d->m_rootJoint = rootJoint;
+
+ // Ensures proper bookkeeping
+ if (d->m_rootJoint)
+ d->registerDestructionHelper(d->m_rootJoint, &QSkeleton::setRootJoint, d->m_rootJoint);
+
+ emit rootJointChanged(rootJoint);
+ }
+}
+
+/*! \internal */
+Qt3DCore::QNodeCreatedChangeBasePtr QSkeleton::createNodeCreationChange() const
+{
+ auto creationChange = QSkeletonCreatedChangePtr<QSkeletonData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QSkeleton);
+ data.rootJointId = qIdForNode(d->m_rootJoint);
+ return creationChange;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/transforms/qskeleton.h b/src/core/transforms/qskeleton.h
new file mode 100644
index 000000000..e3c0c9194
--- /dev/null
+++ b/src/core/transforms/qskeleton.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QSKELETON_H
+#define QT3DCORE_QSKELETON_H
+
+#include <Qt3DCore/qabstractskeleton.h>
+#include <Qt3DCore/qt3dcore_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QJoint;
+class QSkeletonPrivate;
+
+class QT3DCORESHARED_EXPORT QSkeleton : public QAbstractSkeleton
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DCore::QJoint* rootJoint READ rootJoint WRITE setRootJoint NOTIFY rootJointChanged)
+
+public:
+ QSkeleton(Qt3DCore::QNode *parent = nullptr);
+ ~QSkeleton();
+
+ Qt3DCore::QJoint *rootJoint() const;
+
+public Q_SLOTS:
+ void setRootJoint(Qt3DCore::QJoint *rootJoint);
+
+Q_SIGNALS:
+ void rootJointChanged(Qt3DCore::QJoint *rootJoint);
+
+private:
+ Q_DECLARE_PRIVATE(QSkeleton)
+ QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QSKELETON_H
diff --git a/src/core/transforms/qskeleton_p.h b/src/core/transforms/qskeleton_p.h
new file mode 100644
index 000000000..c8b6554f9
--- /dev/null
+++ b/src/core/transforms/qskeleton_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QSKELETON_P_H
+#define QT3DCORE_QSKELETON_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/private/qabstractskeleton_p.h>
+#include <Qt3DCore/qskeleton.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QJoint;
+
+class QSkeletonPrivate : public QAbstractSkeletonPrivate
+{
+public:
+ QSkeletonPrivate();
+
+ Q_DECLARE_PUBLIC(QSkeleton)
+
+ QJoint *m_rootJoint;
+};
+
+struct QSkeletonData
+{
+ QNodeId rootJointId;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QSKELETON_P_H
diff --git a/src/core/transforms/qskeletonloader.cpp b/src/core/transforms/qskeletonloader.cpp
new file mode 100644
index 000000000..9e0fdae5c
--- /dev/null
+++ b/src/core/transforms/qskeletonloader.cpp
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qskeletonloader.h"
+#include "qskeletonloader_p.h"
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qskeletoncreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QSkeletonLoaderPrivate::QSkeletonLoaderPrivate()
+ : QAbstractSkeletonPrivate()
+ , m_source()
+ , m_createJoints(false)
+ , m_status(QSkeletonLoader::NotReady)
+ , m_rootJoint(nullptr)
+{
+ m_type = QSkeletonCreatedChangeBase::SkeletonLoader;
+}
+
+void QSkeletonLoaderPrivate::setStatus(QSkeletonLoader::Status status)
+{
+ Q_Q(QSkeletonLoader);
+ if (status != m_status) {
+ m_status = status;
+ const bool blocked = q->blockNotifications(true);
+ emit q->statusChanged(m_status);
+ q->blockNotifications(blocked);
+ }
+}
+
+/*!
+ \qmltype SkeletonLoader
+ \inqmlmodule Qt3D.Core
+ \inherits AbstractSkeleton
+ \instantiates Qt3DCore::QSkeletonLoader
+ \since 5.10
+ \brief Used to load a skeleton of joints from file
+
+ Use SkeletonLoader if you wish to load a whole skeleton from file rather
+ than creating the joints yourself using Skeleton and Joints. Creating a
+ skeleton and binding the vertices of a mesh to the skeleton is most easily
+ performed in a 3D digital content creation tool such as Blender. The
+ resulting skeleton and mesh can then be exported in a suitable format such
+ as glTF 2 for consumption by Qt 3D.
+*/
+
+/*!
+ \qmlproperty url SkeletonLoader::source
+
+ Holds the source url from which to load the skeleton.
+*/
+
+/*!
+ \qmlproperty SkeletonLoader.Status SkeletonLoader::status
+
+ Holds the current status of skeleton loading.
+*/
+
+/*!
+ \class Qt3DCore::QSkeletonLoader
+ \inmodule Qt3DCore
+ \inherits Qt3DCore::QAbstractSkeleton
+ \since 5.10
+ \brief Used to load a skeleton of joints from file
+
+ Use SkeletonLoader if you wish to load a whole skeleton from file rather
+ than creating the joints yourself using Skeleton and Joints. Creating a
+ skeleton and binding the vertices of a mesh to the skeleton is most easily
+ performed in a 3D digital content creation tool such as Blender. The
+ resulting skeleton and mesh can then be exported in a suitable format such
+ as glTF 2 for consumption by Qt 3D.
+*/
+
+/*!
+ \enum QSkeletonLoader::Status
+
+ This enum identifies the status of skeleton.
+
+ \value NotReady The skeleton has not been loaded yet
+ \value Ready The skeleton was successfully loaded
+ \value Error An error occurred while loading the skeleton
+*/
+
+/*!
+ Constructs a new QSkeletonLoader with \a parent.
+*/
+QSkeletonLoader::QSkeletonLoader(Qt3DCore::QNode *parent)
+ : QAbstractSkeleton(*new QSkeletonLoaderPrivate, parent)
+{
+}
+
+/*!
+ Constructs a new QSkeletonLoader with \a parent and sets the \a source.
+*/
+QSkeletonLoader::QSkeletonLoader(const QUrl &source, QNode *parent)
+ : QAbstractSkeleton(*new QSkeletonLoaderPrivate, parent)
+{
+ setSource(source);
+}
+
+/*! \internal */
+QSkeletonLoader::QSkeletonLoader(QSkeletonLoaderPrivate &dd, Qt3DCore::QNode *parent)
+ : QAbstractSkeleton(dd, parent)
+{
+}
+
+/*! \internal */
+QSkeletonLoader::~QSkeletonLoader()
+{
+}
+
+/*!
+ \property Qt3DCore::QSkeletonLoader::source
+
+ Holds the source url from which to load the skeleton.
+*/
+QUrl QSkeletonLoader::source() const
+{
+ Q_D(const QSkeletonLoader);
+ return d->m_source;
+}
+
+/*!
+ \property Qt3DCore::QSkeletonLoader::status
+
+ Holds the current status of skeleton loading.
+*/
+QSkeletonLoader::Status QSkeletonLoader::status() const
+{
+ Q_D(const QSkeletonLoader);
+ return d->m_status;
+}
+
+bool QSkeletonLoader::isCreateJointsEnabled() const
+{
+ Q_D(const QSkeletonLoader);
+ return d->m_createJoints;
+}
+
+Qt3DCore::QJoint *QSkeletonLoader::rootJoint() const
+{
+ Q_D(const QSkeletonLoader);
+ return d->m_rootJoint;
+}
+
+void QSkeletonLoader::setSource(const QUrl &source)
+{
+ Q_D(QSkeletonLoader);
+ if (d->m_source == source)
+ return;
+
+ d->m_source = source;
+ emit sourceChanged(source);
+}
+
+void QSkeletonLoader::setCreateJointsEnabled(bool createJoints)
+{
+ Q_D(QSkeletonLoader);
+ if (d->m_createJoints == createJoints)
+ return;
+
+ d->m_createJoints = createJoints;
+ emit createJointsEnabledChanged(createJoints);
+}
+
+void QSkeletonLoader::setRootJoint(QJoint *rootJoint)
+{
+ Q_D(QSkeletonLoader);
+ if (rootJoint == d->m_rootJoint)
+ return;
+
+ if (d->m_rootJoint)
+ d->unregisterDestructionHelper(d->m_rootJoint);
+
+ if (rootJoint && !rootJoint->parent())
+ rootJoint->setParent(this);
+
+ d->m_rootJoint = rootJoint;
+
+ // Ensures proper bookkeeping
+ if (d->m_rootJoint)
+ d->registerDestructionHelper(d->m_rootJoint, &QSkeletonLoader::setRootJoint, d->m_rootJoint);
+
+ emit rootJointChanged(d->m_rootJoint);
+}
+
+/*! \internal */
+void QSkeletonLoader::sceneChangeEvent(const QSceneChangePtr &change)
+{
+ Q_D(QSkeletonLoader);
+ if (change->type() == Qt3DCore::PropertyUpdated) {
+ auto propertyChange = qSharedPointerCast<QStaticPropertyUpdatedChangeBase>(change);
+ if (propertyChange->propertyName() == QByteArrayLiteral("status")) {
+ const auto e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ d->setStatus(static_cast<QSkeletonLoader::Status>(e->value().toInt()));
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("rootJoint")) {
+ auto typedChange = qSharedPointerCast<QJointChange>(propertyChange);
+ auto rootJoint = std::move(typedChange->data);
+ setRootJoint(rootJoint.release());
+ }
+ }
+ QAbstractSkeleton::sceneChangeEvent(change);
+}
+
+/*! \internal */
+Qt3DCore::QNodeCreatedChangeBasePtr QSkeletonLoader::createNodeCreationChange() const
+{
+ auto creationChange = QSkeletonCreatedChangePtr<QSkeletonLoaderData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QSkeletonLoader);
+ data.source = d->m_source;
+ data.createJoints = d->m_createJoints;
+ return creationChange;
+}
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/core/transforms/qskeletonloader.h b/src/core/transforms/qskeletonloader.h
new file mode 100644
index 000000000..1185ba6c7
--- /dev/null
+++ b/src/core/transforms/qskeletonloader.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QSKELETONLOADER_H
+#define QT3DCORE_QSKELETONLOADER_H
+
+#include <Qt3DCore/qabstractskeleton.h>
+#include <Qt3DCore/qt3dcore_global.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QJoint;
+class QSkeletonLoaderPrivate;
+
+class QT3DCORESHARED_EXPORT QSkeletonLoader : public QAbstractSkeleton
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(bool createJointsEnabled READ isCreateJointsEnabled WRITE setCreateJointsEnabled NOTIFY createJointsEnabledChanged)
+ Q_PROPERTY(Qt3DCore::QJoint* rootJoint READ rootJoint NOTIFY rootJointChanged)
+
+public:
+ explicit QSkeletonLoader(Qt3DCore::QNode *parent = nullptr);
+ explicit QSkeletonLoader(const QUrl &source,
+ Qt3DCore::QNode *parent = nullptr);
+ ~QSkeletonLoader();
+
+ enum Status {
+ NotReady = 0,
+ Ready,
+ Error
+ };
+ Q_ENUM(Status) // LCOV_EXCL_LINE
+
+ QUrl source() const;
+ Status status() const;
+ bool isCreateJointsEnabled() const;
+ Qt3DCore::QJoint* rootJoint() const;
+
+public Q_SLOTS:
+ void setSource(const QUrl &source);
+ void setCreateJointsEnabled(bool enabled);
+
+Q_SIGNALS:
+ void sourceChanged(const QUrl &source);
+ void statusChanged(Status status);
+ void createJointsEnabledChanged(bool createJointsEnabled);
+ void rootJointChanged(Qt3DCore::QJoint* rootJoint);
+
+protected:
+ explicit QSkeletonLoader(QSkeletonLoaderPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
+
+private:
+ Q_DECLARE_PRIVATE(QSkeletonLoader)
+ QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
+ void setRootJoint(QJoint *rootJoint); // Needed for lifetime management of created joints
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QSKELETONLOADER_H
diff --git a/src/core/transforms/qskeletonloader_p.h b/src/core/transforms/qskeletonloader_p.h
new file mode 100644
index 000000000..ab0babe00
--- /dev/null
+++ b/src/core/transforms/qskeletonloader_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QSKELETONLOADER_P_H
+#define QT3DCORE_QSKELETONLOADER_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/private/qabstractskeleton_p.h>
+#include "qskeletonloader.h"
+
+#include <Qt3DCore/private/qtypedpropertyupdatechange_p.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class QJoint;
+
+class QSkeletonLoaderPrivate : public QAbstractSkeletonPrivate
+{
+public:
+ QSkeletonLoaderPrivate();
+
+ void setStatus(QSkeletonLoader::Status status);
+
+ Q_DECLARE_PUBLIC(QSkeletonLoader)
+
+ QUrl m_source;
+ bool m_createJoints;
+
+ // Set by the backend
+ QSkeletonLoader::Status m_status;
+ Qt3DCore::QJoint* m_rootJoint;
+};
+
+struct QSkeletonLoaderData
+{
+ QUrl source;
+ bool createJoints;
+};
+
+class QJoint;
+typedef QTypedPropertyUpdatedChange<std::unique_ptr<QJoint>> QJointChange;
+typedef QTypedPropertyUpdatedChangePtr<std::unique_ptr<QJoint>> QJointChangePtr;
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QSKELETONLOADER_P_H
diff --git a/src/core/transforms/sqt_p.h b/src/core/transforms/sqt_p.h
new file mode 100644
index 000000000..5fdefccc8
--- /dev/null
+++ b/src/core/transforms/sqt_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_SQT_P_H
+#define QT3DCORE_SQT_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 <QtGui/qmatrix4x4.h>
+#include <QtGui/qquaternion.h>
+#include <QtGui/qvector3d.h>
+#include <QtCore/qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+struct Sqt
+{
+ QQuaternion rotation;
+ QVector3D scale;
+ float pad1;
+ QVector3D translation;
+ float pad2;
+
+ Sqt()
+ : rotation()
+ , scale(1.0f, 1.0f, 1.0f)
+ , translation()
+ {}
+
+ inline QMatrix4x4 toMatrix() const
+ {
+ QMatrix4x4 m;
+ m.translate(translation);
+ m.rotate(rotation);
+ m.scale(scale);
+ return m;
+ }
+
+ bool operator == (const Sqt &rhs) const
+ {
+ return rotation == rhs.rotation
+ && scale == rhs.scale
+ && translation == rhs.translation;
+ }
+};
+
+struct JointNamesAndLocalPoses
+{
+ QVector<QString> names;
+ QVector<Sqt> localPoses;
+};
+
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QVector<Qt3DCore::Sqt>)
+Q_DECLARE_METATYPE(Qt3DCore::JointNamesAndLocalPoses)
+
+#endif // QT3DCORE_SQT_P_H
diff --git a/src/core/transforms/transforms.pri b/src/core/transforms/transforms.pri
index 75ae7c7a9..f83c37a0b 100644
--- a/src/core/transforms/transforms.pri
+++ b/src/core/transforms/transforms.pri
@@ -1,10 +1,58 @@
-
SOURCES += \
- $$PWD/qtransform.cpp
+ $$PWD/qtransform.cpp \
+ $$PWD/qjoint.cpp \
+ $$PWD/qabstractskeleton.cpp \
+ $$PWD/qskeleton.cpp \
+ $$PWD/qskeletonloader.cpp \
+ $$PWD/qarmature.cpp
HEADERS += \
- $$PWD/qtransform.h \
- $$PWD/qtransform_p.h \
- $$PWD/qmath3d_p.h
+ $$PWD/qtransform.h \
+ $$PWD/qtransform_p.h \
+ $$PWD/qmath3d_p.h \
+ $$PWD/qjoint.h \
+ $$PWD/qjoint_p.h \
+ $$PWD/qabstractskeleton.h \
+ $$PWD/qabstractskeleton_p.h \
+ $$PWD/qskeleton.h \
+ $$PWD/qskeleton_p.h \
+ $$PWD/qskeletonloader.h \
+ $$PWD/qskeletonloader_p.h \
+ $$PWD/qarmature.h \
+ $$PWD/qarmature_p.h \
+ $$PWD/vector4d_p.h \
+ $$PWD/vector3d_p.h \
+ $$PWD/matrix4x4_p.h \
+ $$PWD/sqt_p.h
INCLUDEPATH += $$PWD
+
+qtConfig(qt3d-simd-sse2) {
+ CONFIG += simd
+
+ SSE2_HEADERS += \
+ $$PWD/vector4d_sse_p.h \
+ $$PWD/vector3d_sse_p.h \
+ $$PWD/matrix4x4_sse_p.h
+
+ SSE2_SOURCES += \
+ $$PWD/matrix4x4_sse.cpp
+
+ # These files contain AVX2 code, only add them to SSE2 if AVX2 not available
+ !qtConfig(qt3d-simd-avx2) {
+ SSE2_SOURCES += \
+ $$PWD/vector4d_sse.cpp \
+ $$PWD/vector3d_sse.cpp
+ }
+}
+
+qtConfig(qt3d-simd-avx2) {
+ CONFIG += simd
+
+ AVX2_HEADERS += \
+ $$PWD/matrix4x4_avx2_p.h
+ AVX2_SOURCES += \
+ $$PWD/matrix4x4_avx2.cpp \
+ $$PWD/vector4d_sse.cpp \
+ $$PWD/vector3d_sse.cpp
+}
diff --git a/src/core/transforms/vector3d_p.h b/src/core/transforms/vector3d_p.h
new file mode 100644
index 000000000..fa72c9f2f
--- /dev/null
+++ b/src/core/transforms/vector3d_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_VECTOR3D_P_H
+#define QT3DCORE_VECTOR3D_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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 <private/qsimd_p.h>
+
+#if (defined(__AVX2__) || defined(__SSE2__)) && defined(QT_COMPILER_SUPPORTS_SSE2)
+
+#include <Qt3DCore/private/vector3d_sse_p.h>
+
+QT_BEGIN_NAMESPACE
+using Vector3D = Qt3DCore::Vector3D_SSE;
+QT_END_NAMESPACE
+
+#else
+
+#include <QVector3D>
+
+QT_BEGIN_NAMESPACE
+using Vector3D = QVector3D;
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QT3DCORE_VECTOR3D_P_H
diff --git a/src/core/transforms/vector3d_sse.cpp b/src/core/transforms/vector3d_sse.cpp
new file mode 100644
index 000000000..151cbb959
--- /dev/null
+++ b/src/core/transforms/vector3d_sse.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <private/qsimd_p.h>
+
+#ifdef __AVX2__
+#include "matrix4x4_avx2_p.h"
+#else
+#include "matrix4x4_sse_p.h"
+#endif
+
+#include "vector3d_sse_p.h"
+#include "vector4d_sse_p.h"
+#include <QDebug>
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QDebug operator<<(QDebug dbg, const Vector3D_SSE &v)
+{
+ dbg.nospace() << "Vector3D_SSE(" << v.x() << ", " << v.y() << ", " << v.z() << ") ";
+ return dbg;
+}
+
+Vector3D_SSE::Vector3D_SSE(const Vector4D_SSE &v)
+{
+ m_xyzw = _mm_mul_ps(v.m_xyzw, _mm_set_ps(0.0f, 1.0f, 1.0f, 1.0f));
+}
+
+#ifdef __AVX2__
+
+Vector3D_SSE Vector3D_SSE::unproject(const Matrix4x4_AVX2 &modelView, const Matrix4x4_AVX2 &projection, const QRect &viewport) const
+{
+ const Matrix4x4_AVX2 inverse = (projection * modelView).inverted();
+
+ Vector4D_SSE tmp(*this, 1.0f);
+ tmp.setX((tmp.x() - float(viewport.x())) / float(viewport.width()));
+ tmp.setY((tmp.y() - float(viewport.y())) / float(viewport.height()));
+ tmp = tmp * 2.0f - Vector4D_SSE(1.0f, 1.0f, 1.0f, 1.0f);
+
+ Vector4D_SSE obj = inverse * tmp;
+ if (qFuzzyIsNull(obj.w()))
+ obj.setW(1.0f);
+ obj /= obj.w();
+ return Vector3D_SSE(obj);
+}
+
+Vector3D_SSE Vector3D_SSE::project(const Matrix4x4_AVX2 &modelView, const Matrix4x4_AVX2 &projection, const QRect &viewport) const
+{
+ Vector4D_SSE tmp(*this, 1.0f);
+ tmp = projection * modelView * tmp;
+ if (qFuzzyIsNull(tmp.w()))
+ tmp.setW(1.0f);
+ tmp /= tmp.w();
+
+ tmp = tmp * 0.5f + Vector4D_SSE(0.5f, 0.5f, 0.5f, 0.5f);
+ tmp.setX(tmp.x() * viewport.width() + viewport.x());
+ tmp.setY(tmp.y() * viewport.height() + viewport.y());
+
+ return Vector3D_SSE(tmp);
+}
+
+#else
+
+Vector3D_SSE Vector3D_SSE::unproject(const Matrix4x4_SSE &modelView, const Matrix4x4_SSE &projection, const QRect &viewport) const
+{
+ const Matrix4x4_SSE inverse = (projection * modelView).inverted();
+
+ Vector4D_SSE tmp(*this, 1.0f);
+ tmp.setX((tmp.x() - float(viewport.x())) / float(viewport.width()));
+ tmp.setY((tmp.y() - float(viewport.y())) / float(viewport.height()));
+ tmp = tmp * 2.0f - Vector4D_SSE(1.0f, 1.0f, 1.0f, 1.0f);
+
+ Vector4D_SSE obj = inverse * tmp;
+ if (qFuzzyIsNull(obj.w()))
+ obj.setW(1.0f);
+ obj /= obj.w();
+ return Vector3D_SSE(obj);
+}
+
+Vector3D_SSE Vector3D_SSE::project(const Matrix4x4_SSE &modelView, const Matrix4x4_SSE &projection, const QRect &viewport) const
+{
+ Vector4D_SSE tmp(*this, 1.0f);
+ tmp = projection * modelView * tmp;
+ if (qFuzzyIsNull(tmp.w()))
+ tmp.setW(1.0f);
+ tmp /= tmp.w();
+
+ tmp = tmp * 0.5f + Vector4D_SSE(0.5f, 0.5f, 0.5f, 0.5f);
+ tmp.setX(tmp.x() * viewport.width() + viewport.x());
+ tmp.setY(tmp.y() * viewport.height() + viewport.y());
+
+ return Vector3D_SSE(tmp);
+}
+
+#endif
+
+} // Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT_COMPILER_SUPPORTS_SSE2
diff --git a/src/core/transforms/vector3d_sse_p.h b/src/core/transforms/vector3d_sse_p.h
new file mode 100644
index 000000000..a299d1db9
--- /dev/null
+++ b/src/core/transforms/vector3d_sse_p.h
@@ -0,0 +1,399 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_VECTOR3D_SSE_P_H
+#define QT3DCORE_VECTOR3D_SSE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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/private/qt3dcore_global_p.h>
+#include <QtCore/private/qsimd_p.h>
+#include <QtCore/QtGlobal>
+#include <QtGui/qvector3d.h>
+#include <QDebug>
+#include <math.h>
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class Matrix4x4_SSE;
+class Matrix4x4_AVX2;
+class Vector4D_SSE;
+
+class Vector3D_SSE
+{
+public:
+
+ Q_ALWAYS_INLINE Vector3D_SSE()
+ : m_xyzw(_mm_setzero_ps())
+ {
+ }
+
+ explicit Q_ALWAYS_INLINE Vector3D_SSE(Qt::Initialization) {}
+
+ explicit Q_ALWAYS_INLINE Vector3D_SSE(float x, float y, float z)
+ : m_xyzw(_mm_set_ps(0.0f, z, y, x))
+ {
+ }
+
+ explicit Q_ALWAYS_INLINE Vector3D_SSE(QVector3D v)
+ : m_xyzw(_mm_set_ps(0.0f, v.z(), v.y(), v.x()))
+ {
+ }
+
+ explicit QT3DCORE_PRIVATE_EXPORT Vector3D_SSE(const Vector4D_SSE &v);
+
+ Q_ALWAYS_INLINE Vector3D_SSE &operator+=(Vector3D_SSE vector)
+ {
+ m_xyzw = _mm_add_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE &operator-=(Vector3D_SSE vector)
+ {
+ m_xyzw = _mm_sub_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE &operator*=(Vector3D_SSE vector)
+ {
+ m_xyzw = _mm_mul_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE &operator/=(Vector3D_SSE vector)
+ {
+ m_xyzw = _mm_div_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE &operator*=(float factor)
+ {
+ m_xyzw = _mm_mul_ps(m_xyzw, _mm_set1_ps(factor));
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE &operator/=(float factor)
+ {
+ m_xyzw = _mm_div_ps(m_xyzw, _mm_set1_ps(factor));
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE bool operator==(Vector3D_SSE other) const
+ {
+ // 0b111 == 0x7
+ return ((_mm_movemask_ps(_mm_cmpeq_ps(m_xyzw, other.m_xyzw)) & 0x7) == 0x7);
+ }
+
+ Q_ALWAYS_INLINE bool operator!=(Vector3D_SSE other) const
+ {
+ return !(*this == other);
+ }
+
+ Q_ALWAYS_INLINE QVector3D toQVector3D() const
+ {
+ return QVector3D(x(), y(), z());
+ }
+
+ Q_ALWAYS_INLINE float lengthSquared() const
+ {
+ return Qt3DCore::Vector3D_SSE::dotProduct(*this, *this);
+ }
+
+ Q_ALWAYS_INLINE float length() const
+ {
+ return sqrt(Qt3DCore::Vector3D_SSE::dotProduct(*this, *this));
+ }
+
+ Q_ALWAYS_INLINE float distanceToPoint(const Vector3D_SSE &point) const
+ {
+ return (*this - point).length();
+ }
+
+ Q_ALWAYS_INLINE void normalize()
+ {
+ const float len = length();
+ m_xyzw = _mm_div_ps(m_xyzw, _mm_set_ps1(len));
+ }
+
+ Q_ALWAYS_INLINE Vector3D_SSE normalized() const
+ {
+ Vector3D_SSE v = *this;
+ v.normalize();
+ return v;
+ }
+
+ Q_ALWAYS_INLINE bool isNull() const
+ {
+ // Ignore last bit
+ // 0b111 = 0x7
+ return ((_mm_movemask_ps(_mm_cmpeq_ps(m_xyzw, _mm_set_ps1(0.0f))) & 0x7) == 0x7);
+ }
+
+#ifdef __AVX2__
+ QT3DCORE_PRIVATE_EXPORT Vector3D_SSE unproject(const Matrix4x4_AVX2 &modelView, const Matrix4x4_AVX2 &projection, const QRect &viewport) const;
+ QT3DCORE_PRIVATE_EXPORT Vector3D_SSE project(const Matrix4x4_AVX2 &modelView, const Matrix4x4_AVX2 &projection, const QRect &viewport) const;
+#else
+ QT3DCORE_PRIVATE_EXPORT Vector3D_SSE unproject(const Matrix4x4_SSE &modelView, const Matrix4x4_SSE &projection, const QRect &viewport) const;
+ QT3DCORE_PRIVATE_EXPORT Vector3D_SSE project(const Matrix4x4_SSE &modelView, const Matrix4x4_SSE &projection, const QRect &viewport) const;
+#endif
+
+ Q_ALWAYS_INLINE float x() const { return _mm_cvtss_f32(m_xyzw); }
+
+ Q_ALWAYS_INLINE float y() const
+ {
+ // 0b01010101 = 0x55
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_xyzw, m_xyzw, 0x55));
+ }
+
+ Q_ALWAYS_INLINE float z() const
+ {
+ // 0b10101010 = 0xaa
+ return _mm_cvtss_f32(_mm_unpackhi_ps(m_xyzw, m_xyzw));
+ }
+
+ Q_ALWAYS_INLINE void setX(float x)
+ {
+ m_xyzw = _mm_move_ss(m_xyzw, _mm_set_ss(x));
+ }
+
+ Q_ALWAYS_INLINE void setY(float y)
+ {
+ // m_xyzw = a, b, c, d
+
+ // y, y, y, y
+ const __m128 yVec = _mm_set_ps1(y);
+
+ // y, y, a, a
+ // 0b00000000 == 0x0
+ const __m128 yaVec = _mm_shuffle_ps(yVec, m_xyzw, 0x0);
+
+ // a, y, c, d
+ // 0b11100010 == 0xe2
+ m_xyzw = _mm_shuffle_ps(yaVec, m_xyzw, 0xe2);
+ }
+
+ Q_ALWAYS_INLINE void setZ(float z)
+ {
+ // m_xyzw = a, b, c, d
+
+ // z, z, z, z
+ const __m128 zVec = _mm_set_ps1(z);
+
+ // z, z, d, d
+ // 0b11110000 == 0xf0
+ const __m128 zdVec = _mm_shuffle_ps(zVec, m_xyzw, 0xf0);
+
+ // a, b, z, d
+ // 0b10000100 == 0x84
+ m_xyzw = _mm_shuffle_ps(m_xyzw, zdVec, 0x84);
+ }
+
+ Q_ALWAYS_INLINE float operator[](int idx) const
+ {
+ switch (idx) {
+ case 0:
+ return x();
+ case 1:
+ return y();
+ case 2:
+ return z();
+ default:
+ Q_UNREACHABLE();
+ return 0.0f;
+ }
+ }
+
+ struct DigitWrapper
+ {
+ explicit DigitWrapper(int idx, Vector3D_SSE *vec)
+ : m_vec(vec)
+ , m_idx(idx)
+ {}
+
+ operator float() const
+ {
+ switch (m_idx) {
+ case 0:
+ return m_vec->x();
+ case 1:
+ return m_vec->y();
+ case 2:
+ return m_vec->z();
+ default:
+ Q_UNREACHABLE();
+ return 0.0f;
+ }
+ }
+
+ void operator =(float value)
+ {
+ switch (m_idx) {
+ case 0:
+ m_vec->setX(value);
+ break;
+ case 1:
+ m_vec->setY(value);
+ break;
+ case 2:
+ m_vec->setZ(value);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ private:
+ Vector3D_SSE *m_vec;
+ const int m_idx;
+ };
+
+ Q_ALWAYS_INLINE DigitWrapper operator[](int idx)
+ {
+ return DigitWrapper(idx, this);
+ }
+
+ static Q_ALWAYS_INLINE float dotProduct(Vector3D_SSE a, Vector3D_SSE b)
+ {
+#if defined(__SSE4_1__)
+ // 0b01111111 = 0x7f
+ return _mm_cvtss_f32(_mm_dp_ps(a.m_xyzw, b.m_xyzw, 0x7f));
+#elif defined(__SSE3__)
+ const __m128 mult = _mm_mul_ps(a.m_xyzw, b.m_xyzw);
+ // a + b, c + d, a + d, c + d
+ const __m128 partialSum = _mm_hadd_ps(mult, mult);
+ // c + d, ......
+ // 0x00000001 =
+ const __m128 partialSumShuffle = _mm_shuffle_ps(partialSum, partialSum, 0x1);
+ return _mm_cvtss_f32(_mm_hadd_ps(partialSum, partialSumShuffle));
+#else
+ const __m128 mult = _mm_mul_ps(a.m_xyzw, b.m_xyzw);
+
+ // (multX, 0, 0, 0) + (multY, 0, 0, 0) -> (multX + multY, 0, 0, 0)
+ // 0b11111101 == 0xfd
+ const __m128 shuffled = _mm_shuffle_ps(mult, mult, 0xfd);
+ // (multX + multY, 0, 0, 0) + (multZ, 0, 0, 0);
+ // 0b11111110 == 0xfe
+ const __m128 shuffled2 = _mm_shuffle_ps(mult, mult, 0xfe);
+ const __m128 result = _mm_add_ps(_mm_add_ps(shuffled, mult), shuffled2);
+ return _mm_cvtss_f32(result);
+#endif
+ }
+
+ static Q_ALWAYS_INLINE Vector3D_SSE crossProduct(Vector3D_SSE a, Vector3D_SSE b)
+ {
+ // a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x
+ // (a.y, a.z, a.z, a.x, a.x, a.y) (b.z, b.y, b.x, b.z, b.y, b.x)
+ // (a.y, a.z, a.x) * (b.z, b.x, b.y) - (a.z, a.x, a.y) (b.y, b.z, b.x)
+
+ // 0b11001001 == 0xc9
+ const __m128 a1 = _mm_shuffle_ps(a.m_xyzw, a.m_xyzw, 0xc9);
+ const __m128 b2 = _mm_shuffle_ps(b.m_xyzw, b.m_xyzw, 0xc9);
+ // 0b11010010 == 0xd2
+ const __m128 a2 = _mm_shuffle_ps(a.m_xyzw, a.m_xyzw, 0xd2);
+ const __m128 b1 = _mm_shuffle_ps(b.m_xyzw, b.m_xyzw, 0xd2);
+
+ Vector3D_SSE v(Qt::Uninitialized);
+ v.m_xyzw = _mm_sub_ps(_mm_mul_ps(a1, b1), _mm_mul_ps(a2, b2));
+ return v;
+ }
+
+ friend class Matrix4x4_AVX2;
+ friend class Matrix4x4_SSE;
+ friend class Vector4D_SSE;
+
+ friend QT3DCORE_PRIVATE_EXPORT Vector3D_SSE operator*(const Vector3D_SSE &vector, const Matrix4x4_SSE &matrix);
+ friend QT3DCORE_PRIVATE_EXPORT Vector3D_SSE operator*(const Matrix4x4_SSE &matrix, const Vector3D_SSE &vector);
+
+ friend QT3DCORE_PRIVATE_EXPORT Vector3D_SSE operator*(const Vector3D_SSE &vector, const Matrix4x4_AVX2 &matrix);
+ friend QT3DCORE_PRIVATE_EXPORT Vector3D_SSE operator*(const Matrix4x4_AVX2 &matrix, const Vector3D_SSE &vector);
+
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator+(Vector3D_SSE v1, Vector3D_SSE v2) { return v1 += v2; }
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator-(Vector3D_SSE v1, Vector3D_SSE v2) { return v1 -= v2; }
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator*(float factor, Vector3D_SSE vector) { return vector *= factor; }
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator*(Vector3D_SSE vector, float factor) { return vector *= factor; }
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator*(Vector3D_SSE v1, Vector3D_SSE v2) { return v1 *= v2; }
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator-(Vector3D_SSE vector)
+ {
+ Vector3D_SSE c(Qt::Uninitialized);
+
+ c.m_xyzw = _mm_xor_ps(vector.m_xyzw, _mm_set1_ps(-0.0f));
+
+ return c;
+ }
+
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator/(Vector3D_SSE vector, float divisor) { return vector /= divisor; }
+ friend Q_ALWAYS_INLINE const Vector3D_SSE operator/(Vector3D_SSE vector, Vector3D_SSE divisor) { return vector /= divisor; }
+
+ friend QT3DCORE_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Vector3D_SSE &v);
+ friend Q_ALWAYS_INLINE bool qFuzzyCompare(const Vector3D_SSE& v1, const Vector3D_SSE& v2)
+ {
+ return ::qFuzzyCompare(v1.x(), v2.x()) &&
+ ::qFuzzyCompare(v1.y(), v2.y()) &&
+ ::qFuzzyCompare(v1.z(), v2.z());
+ }
+
+private:
+ // Q_DECL_ALIGN(16) float m[4];// for SSE support
+ __m128 m_xyzw;
+};
+
+} // Qt3DCore
+
+Q_DECLARE_TYPEINFO(Qt3DCore::Vector3D_SSE, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DCore::Vector3D_SSE)
+
+#endif // QT_COMPILER_SUPPORTS_SSE2
+
+#endif // QT3DCORE_VECTOR3D_SSE_P_H
diff --git a/src/core/transforms/vector4d_p.h b/src/core/transforms/vector4d_p.h
new file mode 100644
index 000000000..584eb470b
--- /dev/null
+++ b/src/core/transforms/vector4d_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_VECTOR4D_P_H
+#define QT3DCORE_VECTOR4D_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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 <private/qsimd_p.h>
+
+#if (defined(__AVX2__) || defined(__SSE2__)) && defined(QT_COMPILER_SUPPORTS_SSE2)
+
+#include <Qt3DCore/private/vector4d_sse_p.h>
+
+QT_BEGIN_NAMESPACE
+using Vector4D = Qt3DCore::Vector4D_SSE;
+QT_END_NAMESPACE
+
+#else
+
+#include <QVector4D>
+
+QT_BEGIN_NAMESPACE
+using Vector4D = QVector4D;
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QT3DCORE_VECTOR4D_P_H
diff --git a/src/core/transforms/vector4d_sse.cpp b/src/core/transforms/vector4d_sse.cpp
new file mode 100644
index 000000000..c7c76a694
--- /dev/null
+++ b/src/core/transforms/vector4d_sse.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "vector4d_sse_p.h"
+#include <QDebug>
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+QDebug operator<<(QDebug dbg, const Vector4D_SSE &v)
+{
+ dbg.nospace() << "Vector4D_SSE(" << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << ") ";
+ return dbg;
+}
+
+} // Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT_COMPILER_SUPPORTS_SSE2
diff --git a/src/core/transforms/vector4d_sse_p.h b/src/core/transforms/vector4d_sse_p.h
new file mode 100644
index 000000000..ffeca0946
--- /dev/null
+++ b/src/core/transforms/vector4d_sse_p.h
@@ -0,0 +1,396 @@
+/****************************************************************************
+**
+** 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: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 QT3DCORE_VECTOR4D_SSE_P_H
+#define QT3DCORE_VECTOR4D_SSE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt3D 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/private/vector3d_p.h>
+#include <QtGui/qvector4d.h>
+
+#ifdef QT_COMPILER_SUPPORTS_SSE2
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+
+class Matrix4x4_SSE;
+class Matrix4x4_AVX2;
+
+class Vector4D_SSE
+{
+public:
+ Q_ALWAYS_INLINE Vector4D_SSE()
+ : m_xyzw(_mm_setzero_ps())
+ {
+ }
+
+ explicit Q_ALWAYS_INLINE Vector4D_SSE(Qt::Initialization) {}
+
+ explicit Q_ALWAYS_INLINE Vector4D_SSE(float x, float y, float z, float w)
+ : m_xyzw(_mm_set_ps(w, z, y, x))
+ {
+ }
+
+ explicit Q_ALWAYS_INLINE Vector4D_SSE(QVector4D v)
+ : m_xyzw(_mm_set_ps(v.w(), v.z(), v.y(), v.x()))
+ {
+ }
+
+ explicit Q_ALWAYS_INLINE Vector4D_SSE(const Vector3D_SSE &vec3, float w = 0.0f)
+ : m_xyzw(vec3.m_xyzw)
+ {
+ setW(w);
+ }
+
+ explicit Q_ALWAYS_INLINE Vector4D_SSE(QVector3D v, float w = 0.0f)
+ : m_xyzw(_mm_set_ps(w, v.z(), v.y(), v.x()))
+ {
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE &operator+=(Vector4D_SSE vector)
+ {
+ m_xyzw = _mm_add_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE &operator-=(Vector4D_SSE vector)
+ {
+ m_xyzw = _mm_sub_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE &operator*=(Vector4D_SSE vector)
+ {
+ m_xyzw = _mm_mul_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE &operator/=(Vector4D_SSE vector)
+ {
+ m_xyzw = _mm_div_ps(m_xyzw, vector.m_xyzw);
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE &operator*=(float factor)
+ {
+ m_xyzw = _mm_mul_ps(m_xyzw, _mm_set1_ps(factor));
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE &operator/=(float factor)
+ {
+ m_xyzw = _mm_div_ps(m_xyzw, _mm_set1_ps(factor));
+ return *this;
+ }
+
+ Q_ALWAYS_INLINE bool operator==(Vector4D_SSE other) const
+ {
+ // 0b1111 == 0xf
+ return (_mm_movemask_ps(_mm_cmpeq_ps(m_xyzw, other.m_xyzw)) == 0xf);
+ }
+
+ Q_ALWAYS_INLINE bool operator!=(Vector4D_SSE other) const
+ {
+ return !(*this == other);
+ }
+
+ Q_ALWAYS_INLINE QVector4D toQVector4D() const
+ {
+ return QVector4D(x(), y(), z(), w());
+ }
+
+ // TODO: Uncomment when we introduce Vector3D_SSE
+ //Q_ALWAYS_INLINE Vector3D_SSE toVector3D() const { return Vector3D_SSE(*this); }
+
+ Q_ALWAYS_INLINE float lengthSquared() const
+ {
+ return dotProduct(*this, *this);
+ }
+
+ Q_ALWAYS_INLINE float length() const
+ {
+ return sqrt(dotProduct(*this, *this));
+ }
+
+ Q_ALWAYS_INLINE void normalize()
+ {
+ const float len = length();
+ m_xyzw = _mm_div_ps(m_xyzw, _mm_set_ps1(len));
+ }
+
+ Q_ALWAYS_INLINE Vector4D_SSE normalized() const
+ {
+ Vector4D_SSE v = *this;
+ v.normalize();
+ return v;
+ }
+
+ Q_ALWAYS_INLINE bool isNull() const
+ {
+ // 0b1111 == 0xf
+ return _mm_movemask_ps(_mm_cmpeq_ps(m_xyzw, _mm_setzero_ps())) == 0xf;
+ }
+
+ Q_ALWAYS_INLINE float x() const { return _mm_cvtss_f32(m_xyzw); }
+
+ Q_ALWAYS_INLINE float y() const
+ {
+ // 0b01010101 = 0x55
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_xyzw, m_xyzw, 0x55));
+ }
+
+ Q_ALWAYS_INLINE float z() const
+ {
+ // 0b10101010 = 0xaa
+ return _mm_cvtss_f32(_mm_unpackhi_ps(m_xyzw, m_xyzw));
+ }
+
+ Q_ALWAYS_INLINE float w() const
+ {
+ // 0b11111111 = 0xff
+ return _mm_cvtss_f32(_mm_shuffle_ps(m_xyzw, m_xyzw, 0xff));
+ }
+
+ Q_ALWAYS_INLINE void setX(float x)
+ {
+ m_xyzw = _mm_move_ss(m_xyzw, _mm_set_ss(x));
+ }
+
+ Q_ALWAYS_INLINE void setY(float y)
+ {
+ // m_xyzw = a, b, c, d
+
+ // y, y, y, y
+ const __m128 yVec = _mm_set_ps1(y);
+
+ // y, y, a, a
+ // 0b00000000 == 0x0
+ const __m128 yaVec = _mm_shuffle_ps(yVec, m_xyzw, 0x0);
+
+ // a, y, c, d
+ // 0b11100010 == 0xe2
+ m_xyzw = _mm_shuffle_ps(yaVec, m_xyzw, 0xe2);
+ }
+
+ Q_ALWAYS_INLINE void setZ(float z)
+ {
+ // m_xyzw = a, b, c, d
+
+ // z, z, z, z
+ const __m128 zVec = _mm_set_ps1(z);
+
+ // z, z, d, d
+ // 0b11110000 == 0xf0
+ const __m128 zdVec = _mm_shuffle_ps(zVec, m_xyzw, 0xf0);
+
+ // a, b, z, d
+ // 0b10000100 == 0x84
+ m_xyzw = _mm_shuffle_ps(m_xyzw, zdVec, 0x84);
+ }
+
+ Q_ALWAYS_INLINE void setW(float w)
+ {
+#ifdef __SSE4_1__
+ const __m128 wVec = _mm_set_ss(w);
+ // insert element 0 of wVec into position 3 in vec3, don't zero anything
+ m_xyzw = _mm_insert_ps(m_xyzw, wVec, 0x30);
+#else
+ // m_xyzw = a, b, c, d
+
+ // w, w, w, w
+ const __m128 wVec = _mm_set_ps1(w);
+
+ // c, c, w, w
+ const __m128 cwVec = _mm_shuffle_ps(m_xyzw, wVec, _MM_SHUFFLE(0, 0, 2, 2));
+
+ // a, b, c, w
+ m_xyzw = _mm_shuffle_ps(m_xyzw, cwVec, _MM_SHUFFLE(2, 0, 1, 0));
+#endif
+ }
+
+ Q_ALWAYS_INLINE float operator[](int idx) const
+ {
+ Q_DECL_ALIGN(16) float vec[4];
+ _mm_store_ps(vec, m_xyzw);
+ return vec[idx];
+ }
+
+ struct DigitWrapper
+ {
+ explicit DigitWrapper(int idx, Vector4D_SSE *vec)
+ : m_vec(vec)
+ , m_idx(idx)
+ {}
+
+ operator float() const
+ {
+ switch (m_idx) {
+ case 0:
+ return m_vec->x();
+ case 1:
+ return m_vec->y();
+ case 2:
+ return m_vec->z();
+ case 3:
+ return m_vec->w();
+ default:
+ Q_UNREACHABLE();
+ return 0.0f;
+ }
+ }
+ void operator =(float value)
+ {
+ switch (m_idx) {
+ case 0:
+ m_vec->setX(value);
+ break;
+ case 1:
+ m_vec->setY(value);
+ break;
+ case 2:
+ m_vec->setZ(value);
+ break;
+ case 3:
+ m_vec->setW(value);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ private:
+ Vector4D_SSE *m_vec;
+ const int m_idx;
+ };
+
+ Q_ALWAYS_INLINE DigitWrapper operator[](int idx)
+ {
+ return DigitWrapper(idx, this);
+ }
+
+ static Q_ALWAYS_INLINE float dotProduct(Vector4D_SSE a, Vector4D_SSE b)
+ {
+#if defined(__SSE4_1__)
+ // 0b11111111 = 0xff
+ return _mm_cvtss_f32(_mm_dp_ps(a.m_xyzw, b.m_xyzw, 0xff));
+#elif defined(__SSE3__)
+ const __m128 mult = _mm_mul_ps(a.m_xyzw, b.m_xyzw);
+ // a + b, c + d, a + d, c + d
+ const __m128 partialSum = _mm_hadd_ps(mult, mult);
+ // c + d, ......
+ // 0x00000001 =
+ const __m128 partialSumShuffle = _mm_shuffle_ps(partialSum, partialSum, 0x1);
+ return _mm_cvtss_f32(_mm_hadd_ps(partialSum, partialSumShuffle));
+#else
+ const __m128 mult = _mm_mul_ps(a.m_xyzw, b.m_xyzw);
+ // (multX, multY, 0, 0) + (multZ, multW, 0, 0) -> (multX + multZ, multY + multW, 0, 0)
+ // 0b00001110 == 0xe
+ const __m128 shuffled = _mm_shuffle_ps(mult, mult, 0xe);
+ __m128 result = _mm_add_ps(shuffled, mult);
+ // (multX + multZ, 0, 0, 0) + (multY + multW, 0, 0, 0);
+ // 0b00000001 == 0x1
+ const __m128 shuffled2 = _mm_shuffle_ps(result, result, 0x1);
+ result = _mm_add_ps(result, shuffled2);
+ return _mm_cvtss_f32(result);
+#endif
+ }
+
+ friend class Matrix4x4_AVX2;
+ friend class Matrix4x4_SSE;
+ friend class Vector3D_SSE;
+
+ friend Vector4D_SSE operator*(const Vector4D_SSE &vector, const Matrix4x4_SSE &matrix);
+ friend Vector4D_SSE operator*(const Matrix4x4_SSE &matrix, const Vector4D_SSE &vector);
+
+ friend Vector4D_SSE operator*(const Vector4D_SSE &vector, const Matrix4x4_AVX2 &matrix);
+ friend Vector4D_SSE operator*(const Matrix4x4_AVX2 &matrix, const Vector4D_SSE &vector);
+
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator+(Vector4D_SSE v1, Vector4D_SSE v2) { return v1 += v2; }
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator-(Vector4D_SSE v1, Vector4D_SSE v2) { return v1 -= v2; }
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator*(float factor, Vector4D_SSE vector) { return vector *= factor; }
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator*(Vector4D_SSE vector, float factor) { return vector *= factor; }
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator*(Vector4D_SSE v1, Vector4D_SSE v2) { return v1 *= v2; }
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator-(Vector4D_SSE vector)
+ {
+ Vector4D_SSE c(Qt::Uninitialized);
+
+ c.m_xyzw = _mm_xor_ps(vector.m_xyzw, _mm_set1_ps(-0.0f));
+
+ return c;
+ }
+
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator/(Vector4D_SSE vector, float divisor) { return vector /= divisor; }
+ friend Q_ALWAYS_INLINE const Vector4D_SSE operator/(Vector4D_SSE vector, Vector4D_SSE divisor) { return vector /= divisor; }
+
+ friend QT3DCORE_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Vector4D_SSE &v);
+ friend Q_ALWAYS_INLINE bool qFuzzyCompare(const Vector4D_SSE& v1, const Vector4D_SSE& v2)
+ {
+ return ::qFuzzyCompare(v1.x(), v2.x()) &&
+ ::qFuzzyCompare(v1.y(), v2.y()) &&
+ ::qFuzzyCompare(v1.z(), v2.z()) &&
+ ::qFuzzyCompare(v1.w(), v2.w());
+ }
+
+private:
+ // Q_DECL_ALIGN(16) float m[4];// for SSE support
+ __m128 m_xyzw;
+};
+
+} // Qt3DCore
+
+Q_DECLARE_TYPEINFO(Qt3DCore::Vector4D_SSE, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Qt3DCore::Vector4D_SSE)
+
+#endif // QT_COMPILER_SUPPORTS_SSE2
+
+#endif // QT3DCORE_VECTOR4D_SSE_P_H
diff --git a/src/extras/3dtext/qextrudedtextgeometry.cpp b/src/extras/3dtext/qextrudedtextgeometry.cpp
index c4c4ba77f..4a81ae44a 100644
--- a/src/extras/3dtext/qextrudedtextgeometry.cpp
+++ b/src/extras/3dtext/qextrudedtextgeometry.cpp
@@ -166,8 +166,8 @@ void QExtrudedTextGeometryPrivate::init()
m_positionAttribute = new Qt3DRender::QAttribute(q);
m_normalAttribute = new Qt3DRender::QAttribute(q);
m_indexAttribute = new Qt3DRender::QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
const quint32 elementSize = 3 + 3;
const quint32 stride = elementSize * sizeof(float);
diff --git a/src/extras/defaults/defaults.pri b/src/extras/defaults/defaults.pri
index 8a18fb6e9..db4db24db 100644
--- a/src/extras/defaults/defaults.pri
+++ b/src/extras/defaults/defaults.pri
@@ -1,6 +1,8 @@
INCLUDEPATH += $$PWD
HEADERS += \
+ $$PWD/qdiffusespecularmaterial.h \
+ $$PWD/qdiffusespecularmaterial_p.h \
$$PWD/qphongmaterial.h \
$$PWD/qphongmaterial_p.h \
$$PWD/qdiffusemapmaterial_p.h \
@@ -25,20 +27,29 @@ HEADERS += \
$$PWD/qphongalphamaterial_p.h \
$$PWD/qt3dwindow.h \
$$PWD/qt3dwindow_p.h \
+ $$PWD/qabstractcameracontroller.h \
+ $$PWD/qabstractcameracontroller_p.h \
$$PWD/qfirstpersoncameracontroller.h \
- $$PWD/qfirstpersoncameracontroller_p.h \
$$PWD/qorbitcameracontroller.h \
$$PWD/qorbitcameracontroller_p.h \
+ $$PWD/qabstractspritesheet.h \
+ $$PWD/qabstractspritesheet_p.h \
+ $$PWD/qspritegrid.h \
+ $$PWD/qspritegrid_p.h \
+ $$PWD/qspritesheet.h \
+ $$PWD/qspritesheet_p.h \
+ $$PWD/qspritesheetitem.h \
+ $$PWD/qspritesheetitem_p.h \
$$PWD/qtexturematerial.h \
$$PWD/qtexturematerial_p.h \
$$PWD/qmetalroughmaterial.h \
$$PWD/qmetalroughmaterial_p.h \
$$PWD/qtexturedmetalroughmaterial.h \
- $$PWD/qtexturedmetalroughmaterial_p.h \
$$PWD/qmorphphongmaterial.h \
$$PWD/qmorphphongmaterial_p.h
SOURCES += \
+ $$PWD/qdiffusespecularmaterial.cpp \
$$PWD/qphongmaterial.cpp \
$$PWD/qdiffusemapmaterial.cpp \
$$PWD/qnormaldiffusespecularmapmaterial.cpp \
@@ -51,8 +62,13 @@ SOURCES += \
$$PWD/qgoochmaterial.cpp \
$$PWD/qphongalphamaterial.cpp \
$$PWD/qt3dwindow.cpp \
+ $$PWD/qabstractcameracontroller.cpp \
$$PWD/qfirstpersoncameracontroller.cpp \
$$PWD/qorbitcameracontroller.cpp \
+ $$PWD/qabstractspritesheet.cpp \
+ $$PWD/qspritegrid.cpp \
+ $$PWD/qspritesheet.cpp \
+ $$PWD/qspritesheetitem.cpp \
$$PWD/qtexturematerial.cpp \
$$PWD/qmetalroughmaterial.cpp \
$$PWD/qtexturedmetalroughmaterial.cpp \
diff --git a/src/extras/defaults/qabstractcameracontroller.cpp b/src/extras/defaults/qabstractcameracontroller.cpp
new file mode 100644
index 000000000..2ebf187aa
--- /dev/null
+++ b/src/extras/defaults/qabstractcameracontroller.cpp
@@ -0,0 +1,436 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "qabstractcameracontroller.h"
+#include "qabstractcameracontroller_p.h"
+
+#include <Qt3DRender/QCamera>
+#include <Qt3DInput/QAxis>
+#include <Qt3DInput/QAnalogAxisInput>
+#include <Qt3DInput/QButtonAxisInput>
+#include <Qt3DInput/QAction>
+#include <Qt3DInput/QActionInput>
+#include <Qt3DInput/QLogicalDevice>
+#include <Qt3DInput/QKeyboardDevice>
+#include <Qt3DInput/QMouseDevice>
+#include <Qt3DInput/QMouseEvent>
+#include <Qt3DLogic/QFrameAction>
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+QAbstractCameraControllerPrivate::QAbstractCameraControllerPrivate()
+ : Qt3DCore::QEntityPrivate()
+ , m_camera(nullptr)
+ , m_leftMouseButtonAction(new Qt3DInput::QAction())
+ , m_middleMouseButtonAction(new Qt3DInput::QAction())
+ , m_rightMouseButtonAction(new Qt3DInput::QAction())
+ , m_altButtonAction(new Qt3DInput::QAction())
+ , m_shiftButtonAction(new Qt3DInput::QAction())
+ , m_rxAxis(new Qt3DInput::QAxis())
+ , m_ryAxis(new Qt3DInput::QAxis())
+ , m_txAxis(new Qt3DInput::QAxis())
+ , m_tyAxis(new Qt3DInput::QAxis())
+ , m_tzAxis(new Qt3DInput::QAxis())
+ , m_leftMouseButtonInput(new Qt3DInput::QActionInput())
+ , m_middleMouseButtonInput(new Qt3DInput::QActionInput())
+ , m_rightMouseButtonInput(new Qt3DInput::QActionInput())
+ , m_altButtonInput(new Qt3DInput::QActionInput())
+ , m_shiftButtonInput(new Qt3DInput::QActionInput())
+ , m_mouseRxInput(new Qt3DInput::QAnalogAxisInput())
+ , m_mouseRyInput(new Qt3DInput::QAnalogAxisInput())
+ , m_mouseTzXInput(new Qt3DInput::QAnalogAxisInput())
+ , m_mouseTzYInput(new Qt3DInput::QAnalogAxisInput())
+ , m_keyboardTxPosInput(new Qt3DInput::QButtonAxisInput())
+ , m_keyboardTyPosInput(new Qt3DInput::QButtonAxisInput())
+ , m_keyboardTzPosInput(new Qt3DInput::QButtonAxisInput())
+ , m_keyboardTxNegInput(new Qt3DInput::QButtonAxisInput())
+ , m_keyboardTyNegInput(new Qt3DInput::QButtonAxisInput())
+ , m_keyboardTzNegInput(new Qt3DInput::QButtonAxisInput())
+ , m_keyboardDevice(new Qt3DInput::QKeyboardDevice())
+ , m_mouseDevice(new Qt3DInput::QMouseDevice())
+ , m_logicalDevice(new Qt3DInput::QLogicalDevice())
+ , m_frameAction(new Qt3DLogic::QFrameAction())
+ , m_linearSpeed(10.0f)
+ , m_lookSpeed(180.0f)
+ , m_acceleration(-1.0f)
+ , m_deceleration(-1.0f)
+ , m_sceneUp(0.0f, 1.0f, 0.0f)
+{}
+
+void QAbstractCameraControllerPrivate::init()
+{
+ //// Actions
+
+ // Left Mouse Button Action
+ m_leftMouseButtonInput->setButtons(QVector<int>() << Qt::LeftButton);
+ m_leftMouseButtonInput->setSourceDevice(m_mouseDevice);
+ m_leftMouseButtonAction->addInput(m_leftMouseButtonInput);
+
+ // Middle Mouse Button Action
+ m_middleMouseButtonInput->setButtons(QVector<int>() << Qt::MiddleButton);
+ m_middleMouseButtonInput->setSourceDevice(m_mouseDevice);
+ m_middleMouseButtonAction->addInput(m_middleMouseButtonInput);
+
+ // Right Mouse Button Action
+ m_rightMouseButtonInput->setButtons(QVector<int>() << Qt::RightButton);
+ m_rightMouseButtonInput->setSourceDevice(m_mouseDevice);
+ m_rightMouseButtonAction->addInput(m_rightMouseButtonInput);
+
+ // Alt Button Action
+ m_altButtonInput->setButtons(QVector<int>() << Qt::Key_Alt);
+ m_altButtonInput->setSourceDevice(m_keyboardDevice);
+ m_altButtonAction->addInput(m_altButtonInput);
+
+ // Shift Button Action
+ m_shiftButtonInput->setButtons(QVector<int>() << Qt::Key_Shift);
+ m_shiftButtonInput->setSourceDevice(m_keyboardDevice);
+ m_shiftButtonAction->addInput(m_shiftButtonInput);
+
+ //// Axes
+
+ // Mouse X
+ m_mouseRxInput->setAxis(Qt3DInput::QMouseDevice::X);
+ m_mouseRxInput->setSourceDevice(m_mouseDevice);
+ m_rxAxis->addInput(m_mouseRxInput);
+
+ // Mouse Y
+ m_mouseRyInput->setAxis(Qt3DInput::QMouseDevice::Y);
+ m_mouseRyInput->setSourceDevice(m_mouseDevice);
+ m_ryAxis->addInput(m_mouseRyInput);
+
+ // Mouse Wheel X
+ m_mouseTzXInput->setAxis(Qt3DInput::QMouseDevice::WheelX);
+ m_mouseTzXInput->setSourceDevice(m_mouseDevice);
+ m_tzAxis->addInput(m_mouseTzXInput);
+
+ // Mouse Wheel Y
+ m_mouseTzYInput->setAxis(Qt3DInput::QMouseDevice::WheelY);
+ m_mouseTzYInput->setSourceDevice(m_mouseDevice);
+ m_tzAxis->addInput(m_mouseTzYInput);
+
+ // Keyboard Pos Tx
+ m_keyboardTxPosInput->setButtons(QVector<int>() << Qt::Key_Right);
+ m_keyboardTxPosInput->setScale(1.0f);
+ m_keyboardTxPosInput->setSourceDevice(m_keyboardDevice);
+ m_txAxis->addInput(m_keyboardTxPosInput);
+
+ // Keyboard Pos Tz
+ m_keyboardTzPosInput->setButtons(QVector<int>() << Qt::Key_PageUp);
+ m_keyboardTzPosInput->setScale(1.0f);
+ m_keyboardTzPosInput->setSourceDevice(m_keyboardDevice);
+ m_tzAxis->addInput(m_keyboardTzPosInput);
+
+ // Keyboard Pos Ty
+ m_keyboardTyPosInput->setButtons(QVector<int>() << Qt::Key_Up);
+ m_keyboardTyPosInput->setScale(1.0f);
+ m_keyboardTyPosInput->setSourceDevice(m_keyboardDevice);
+ m_tyAxis->addInput(m_keyboardTyPosInput);
+
+ // Keyboard Neg Tx
+ m_keyboardTxNegInput->setButtons(QVector<int>() << Qt::Key_Left);
+ m_keyboardTxNegInput->setScale(-1.0f);
+ m_keyboardTxNegInput->setSourceDevice(m_keyboardDevice);
+ m_txAxis->addInput(m_keyboardTxNegInput);
+
+ // Keyboard Neg Tz
+ m_keyboardTzNegInput->setButtons(QVector<int>() << Qt::Key_PageDown);
+ m_keyboardTzNegInput->setScale(-1.0f);
+ m_keyboardTzNegInput->setSourceDevice(m_keyboardDevice);
+ m_tzAxis->addInput(m_keyboardTzNegInput);
+
+ // Keyboard Neg Ty
+ m_keyboardTyNegInput->setButtons(QVector<int>() << Qt::Key_Down);
+ m_keyboardTyNegInput->setScale(-1.0f);
+ m_keyboardTyNegInput->setSourceDevice(m_keyboardDevice);
+ m_tyAxis->addInput(m_keyboardTyNegInput);
+
+ //// Logical Device
+
+ m_logicalDevice->addAction(m_leftMouseButtonAction);
+ m_logicalDevice->addAction(m_middleMouseButtonAction);
+ m_logicalDevice->addAction(m_rightMouseButtonAction);
+ m_logicalDevice->addAction(m_altButtonAction);
+ m_logicalDevice->addAction(m_shiftButtonAction);
+ m_logicalDevice->addAxis(m_rxAxis);
+ m_logicalDevice->addAxis(m_ryAxis);
+ m_logicalDevice->addAxis(m_txAxis);
+ m_logicalDevice->addAxis(m_tyAxis);
+ m_logicalDevice->addAxis(m_tzAxis);
+
+ applyInputAccelerations();
+
+ Q_Q(QAbstractCameraController);
+ //// FrameAction
+
+ // Disable the logical device when the entity is disabled
+ QObject::connect(q, &Qt3DCore::QEntity::enabledChanged,
+ m_logicalDevice, &Qt3DInput::QLogicalDevice::setEnabled);
+
+ q->addComponent(m_frameAction);
+ q->addComponent(m_logicalDevice);
+}
+
+void QAbstractCameraControllerPrivate::applyInputAccelerations()
+{
+ const auto inputs = {
+ m_keyboardTxPosInput,
+ m_keyboardTyPosInput,
+ m_keyboardTzPosInput,
+ m_keyboardTxNegInput,
+ m_keyboardTyNegInput,
+ m_keyboardTzNegInput
+ };
+
+ for (auto input : inputs) {
+ input->setAcceleration(m_acceleration);
+ input->setDeceleration(m_deceleration);
+ }
+}
+
+/*!
+ \class Qt3DExtras::QAbstractCameraController
+
+ \brief The QAbstractCameraController class provides basic
+ functionality for camera controllers.
+
+ \inmodule Qt3DExtras
+ \since 5.10
+
+ QAbstractCameraController sets up and handles input from keyboard,
+ mouse, and other devices. QAbstractCameraController is an abstract
+ class and cannot itself be instantiated. It provides a standard
+ interface for camera controllers.
+
+ Derived classes need only implement the frameActionTriggered()
+ method to move the camera.
+*/
+
+/*!
+ \fn void QAbstractCameraController::moveCamera(const InputState &state, float dt) = 0
+
+ This method is called whenever a frame action is triggered. Derived
+ classes must override this method to implement the camera movement
+ specific to the controller.
+
+ In the base class this is a pure virtual function.
+*/
+
+QAbstractCameraController::QAbstractCameraController(Qt3DCore::QNode *parent)
+ : QAbstractCameraController(*new QAbstractCameraControllerPrivate, parent)
+{
+}
+
+/*! \internal
+ */
+QAbstractCameraController::QAbstractCameraController(QAbstractCameraControllerPrivate &dd, Qt3DCore::QNode *parent)
+ : Qt3DCore::QEntity(dd, parent)
+{
+ Q_D(QAbstractCameraController);
+ d->init();
+
+ QObject::connect(d->m_frameAction, &Qt3DLogic::QFrameAction::triggered,
+ this, [=] (float dt) {
+ InputState state;
+
+ state.rxAxisValue = d->m_rxAxis->value();
+ state.ryAxisValue = d->m_ryAxis->value();
+ state.txAxisValue = d->m_txAxis->value();
+ state.tyAxisValue = d->m_tyAxis->value();
+ state.tzAxisValue = d->m_tzAxis->value();
+
+ state.leftMouseButtonActive = d->m_leftMouseButtonAction->isActive();
+ state.middleMouseButtonActive = d->m_middleMouseButtonAction->isActive();
+ state.rightMouseButtonActive = d->m_rightMouseButtonAction->isActive();
+
+ state.altKeyActive = d->m_altButtonAction->isActive();
+ state.shiftKeyActive = d->m_shiftButtonAction->isActive();
+
+ moveCamera(state, dt);
+ });
+}
+
+QAbstractCameraController::~QAbstractCameraController()
+{
+}
+
+/*!
+ \property QAbstractCameraController::camera
+
+ Holds the currently controlled camera.
+*/
+Qt3DRender::QCamera *QAbstractCameraController::camera() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_camera;
+}
+
+/*!
+ \property QAbstractCameraController::linearSpeed
+
+ Holds the current linear speed of the camera controller. Linear speed determines the
+ movement speed of the camera.
+
+ The default is 10.0.
+*/
+float QAbstractCameraController::linearSpeed() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_linearSpeed;
+}
+
+/*!
+ \property QAbstractCameraController::lookSpeed
+
+ Holds the current look speed of the camera controller. The look speed determines the turn rate
+ of the camera pan and tilt.
+
+ The default is 180.0.
+*/
+float QAbstractCameraController::lookSpeed() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_lookSpeed;
+}
+
+/*!
+ \property QAbstractCameraController::acceleration
+
+ Holds the current acceleration of the camera controller.
+*/
+float QAbstractCameraController::acceleration() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_acceleration;
+}
+
+/*!
+ \property QAbstractCameraController::deceleration
+
+ Holds the current deceleration of the camera controller.
+*/
+float QAbstractCameraController::deceleration() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_deceleration;
+}
+
+void QAbstractCameraController::setCamera(Qt3DRender::QCamera *camera)
+{
+ Q_D(QAbstractCameraController);
+ 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, &QAbstractCameraController::setCamera, d->m_camera);
+
+ emit cameraChanged();
+ }
+}
+
+void QAbstractCameraController::setLinearSpeed(float linearSpeed)
+{
+ Q_D(QAbstractCameraController);
+ if (d->m_linearSpeed != linearSpeed) {
+ d->m_linearSpeed = linearSpeed;
+ emit linearSpeedChanged();
+ }
+}
+
+void QAbstractCameraController::setLookSpeed(float lookSpeed)
+{
+ Q_D(QAbstractCameraController);
+ if (d->m_lookSpeed != lookSpeed) {
+ d->m_lookSpeed = lookSpeed;
+ emit lookSpeedChanged();
+ }
+}
+
+void QAbstractCameraController::setAcceleration(float acceleration)
+{
+ Q_D(QAbstractCameraController);
+ if (d->m_acceleration != acceleration) {
+ d->m_acceleration = acceleration;
+ d->applyInputAccelerations();
+ emit accelerationChanged(acceleration);
+ }
+}
+
+void QAbstractCameraController::setDeceleration(float deceleration)
+{
+ Q_D(QAbstractCameraController);
+ if (d->m_deceleration != deceleration) {
+ d->m_deceleration = deceleration;
+ d->applyInputAccelerations();
+ emit decelerationChanged(deceleration);
+ }
+}
+
+/*!
+ Provides access to the keyboard device.
+*/
+
+Qt3DInput::QKeyboardDevice *QAbstractCameraController::keyboardDevice() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_keyboardDevice;
+}
+
+/*!
+ Provides access to the mouse device.
+*/
+
+Qt3DInput::QMouseDevice *QAbstractCameraController::mouseDevice() const
+{
+ Q_D(const QAbstractCameraController);
+ return d->m_mouseDevice;
+}
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractcameracontroller.cpp"
diff --git a/src/extras/defaults/qabstractcameracontroller.h b/src/extras/defaults/qabstractcameracontroller.h
new file mode 100644
index 000000000..f13079f5f
--- /dev/null
+++ b/src/extras/defaults/qabstractcameracontroller.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DEXTRAS_QABSTRACTCAMERACONTROLLER_H
+#define QT3DEXTRAS_QABSTRACTCAMERACONTROLLER_H
+
+#include <Qt3DCore/QEntity>
+#include <Qt3DExtras/qt3dextras_global.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DInput {
+class QKeyboardDevice;
+class QMouseDevice;
+}
+
+namespace Qt3DRender {
+class QCamera;
+}
+
+namespace Qt3DExtras {
+
+class QAbstractCameraControllerPrivate;
+
+class QT3DEXTRASSHARED_EXPORT QAbstractCameraController : public Qt3DCore::QEntity
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged)
+ Q_PROPERTY(float linearSpeed READ linearSpeed WRITE setLinearSpeed NOTIFY linearSpeedChanged)
+ Q_PROPERTY(float lookSpeed READ lookSpeed WRITE setLookSpeed NOTIFY lookSpeedChanged)
+ Q_PROPERTY(float acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+ Q_PROPERTY(float deceleration READ deceleration WRITE setDeceleration NOTIFY decelerationChanged)
+
+public:
+ ~QAbstractCameraController();
+
+ Qt3DRender::QCamera *camera() const;
+ float linearSpeed() const;
+ float lookSpeed() const;
+
+ float acceleration() const;
+ float deceleration() const;
+
+ void setCamera(Qt3DRender::QCamera *camera);
+ void setLinearSpeed(float linearSpeed);
+ void setLookSpeed(float lookSpeed);
+
+ void setAcceleration(float acceleration);
+ void setDeceleration(float deceleration);
+
+Q_SIGNALS:
+ void cameraChanged();
+ void linearSpeedChanged();
+ void lookSpeedChanged();
+
+ void accelerationChanged(float acceleration);
+ void decelerationChanged(float deceleration);
+
+protected:
+ explicit QAbstractCameraController(Qt3DCore::QNode *parent = nullptr);
+ QAbstractCameraController(QAbstractCameraControllerPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+ Qt3DInput::QKeyboardDevice *keyboardDevice() const;
+ Qt3DInput::QMouseDevice *mouseDevice() const;
+
+ struct InputState
+ {
+ float rxAxisValue;
+ float ryAxisValue;
+ float txAxisValue;
+ float tyAxisValue;
+ float tzAxisValue;
+
+ bool leftMouseButtonActive;
+ bool middleMouseButtonActive;
+ bool rightMouseButtonActive;
+
+ bool altKeyActive;
+ bool shiftKeyActive;
+ };
+
+private:
+ virtual void moveCamera(const InputState &state, float dt) = 0;
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractCameraController)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QABSTRACTCAMERACONTROLLER_H
diff --git a/src/extras/defaults/qabstractcameracontroller_p.h b/src/extras/defaults/qabstractcameracontroller_p.h
new file mode 100644
index 000000000..00424a55b
--- /dev/null
+++ b/src/extras/defaults/qabstractcameracontroller_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DEXTRAS_QABSTRACTCAMERACONTROLLER_P_H
+#define QT3DEXTRAS_QABSTRACTCAMERACONTROLLER_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 <Qt3DExtras/qabstractcameracontroller.h>
+#include <QtGui/QVector3D>
+
+#include <Qt3DCore/private/qentity_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+class QCamera;
+}
+
+namespace Qt3DLogic {
+class QFrameAction;
+}
+
+namespace Qt3DInput {
+class QKeyboardDevice;
+class QMouseDevice;
+class QLogicalDevice;
+class QAction;
+class QActionInput;
+class QAxis;
+class QAnalogAxisInput;
+class QButtonAxisInput;
+class QAxisActionHandler;
+}
+
+namespace Qt3DExtras {
+
+class QAbstractCameraControllerPrivate : public Qt3DCore::QEntityPrivate
+{
+public:
+ QAbstractCameraControllerPrivate();
+
+ void init();
+ void applyInputAccelerations();
+
+ Qt3DRender::QCamera *m_camera;
+
+ Qt3DInput::QAction *m_leftMouseButtonAction;
+ Qt3DInput::QAction *m_middleMouseButtonAction;
+ Qt3DInput::QAction *m_rightMouseButtonAction;
+ Qt3DInput::QAction *m_altButtonAction;
+ Qt3DInput::QAction *m_shiftButtonAction;
+
+ Qt3DInput::QAxis *m_rxAxis;
+ Qt3DInput::QAxis *m_ryAxis;
+ Qt3DInput::QAxis *m_txAxis;
+ Qt3DInput::QAxis *m_tyAxis;
+ Qt3DInput::QAxis *m_tzAxis;
+
+ Qt3DInput::QActionInput *m_leftMouseButtonInput;
+ Qt3DInput::QActionInput *m_middleMouseButtonInput;
+ Qt3DInput::QActionInput *m_rightMouseButtonInput;
+ Qt3DInput::QActionInput *m_altButtonInput;
+ Qt3DInput::QActionInput *m_shiftButtonInput;
+
+ Qt3DInput::QAnalogAxisInput *m_mouseRxInput;
+ Qt3DInput::QAnalogAxisInput *m_mouseRyInput;
+ Qt3DInput::QAnalogAxisInput *m_mouseTzXInput;
+ Qt3DInput::QAnalogAxisInput *m_mouseTzYInput;
+ Qt3DInput::QButtonAxisInput *m_keyboardTxPosInput;
+ Qt3DInput::QButtonAxisInput *m_keyboardTyPosInput;
+ Qt3DInput::QButtonAxisInput *m_keyboardTzPosInput;
+ Qt3DInput::QButtonAxisInput *m_keyboardTxNegInput;
+ Qt3DInput::QButtonAxisInput *m_keyboardTyNegInput;
+ Qt3DInput::QButtonAxisInput *m_keyboardTzNegInput;
+
+ Qt3DInput::QKeyboardDevice *m_keyboardDevice;
+ Qt3DInput::QMouseDevice *m_mouseDevice;
+
+ Qt3DInput::QLogicalDevice *m_logicalDevice;
+
+ Qt3DLogic::QFrameAction *m_frameAction;
+
+ float m_linearSpeed;
+ float m_lookSpeed;
+
+ float m_acceleration;
+ float m_deceleration;
+
+ QVector3D m_sceneUp;
+
+ Q_DECLARE_PUBLIC(QAbstractCameraController)
+};
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QABSTRACTCAMERACONTROLLER_P_H
diff --git a/src/extras/defaults/qabstractspritesheet.cpp b/src/extras/defaults/qabstractspritesheet.cpp
new file mode 100644
index 000000000..640e600c7
--- /dev/null
+++ b/src/extras/defaults/qabstractspritesheet.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qabstractspritesheet.h"
+#include "qabstractspritesheet_p.h"
+
+#include <Qt3DRender/qabstracttexture.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DExtras {
+
+QAbstractSpriteSheetPrivate::QAbstractSpriteSheetPrivate()
+ : QNodePrivate()
+ , m_texture(nullptr)
+ , m_currentIndex(-1)
+{
+}
+
+void QAbstractSpriteSheetPrivate::init()
+{
+ m_textureTransform.setToIdentity();
+}
+
+void QAbstractSpriteSheetPrivate::updateTexture(Qt3DRender::QAbstractTexture *texture)
+{
+ if (m_texture) {
+ disconnect(m_texture, &Qt3DRender::QAbstractTexture::widthChanged,
+ this, &QAbstractSpriteSheetPrivate::updateSizes);
+ disconnect(m_texture, &Qt3DRender::QAbstractTexture::heightChanged,
+ this, &QAbstractSpriteSheetPrivate::updateSizes);
+ }
+ m_texture = texture;
+ if (m_texture) {
+ connect(m_texture, &Qt3DRender::QAbstractTexture::widthChanged,
+ this, &QAbstractSpriteSheetPrivate::updateSizes);
+ connect(m_texture, &Qt3DRender::QAbstractTexture::heightChanged,
+ this, &QAbstractSpriteSheetPrivate::updateSizes);
+ }
+}
+
+void QAbstractSpriteSheetPrivate::updateIndex(int newIndex)
+{
+ Q_Q(QAbstractSpriteSheet);
+ if (newIndex > maxIndex())
+ newIndex = 0;
+
+ m_currentIndex = newIndex;
+ emit q->currentIndexChanged(newIndex);
+ updateTransform();
+}
+
+QAbstractSpriteSheet::QAbstractSpriteSheet(QAbstractSpriteSheetPrivate &dd, QNode *parent)
+ : Qt3DCore::QNode(dd, parent)
+{
+ Q_D(QAbstractSpriteSheet);
+ d->init();
+}
+
+QAbstractSpriteSheet::~QAbstractSpriteSheet()
+{
+}
+
+/*!
+ \property QAbstractSpriteSheet::texture
+
+ Holds the current texture used by the material.
+*/
+Qt3DRender::QAbstractTexture *QAbstractSpriteSheet::texture() const
+{
+ Q_D(const QAbstractSpriteSheet);
+ return d->m_texture;
+}
+
+void QAbstractSpriteSheet::setTexture(Qt3DRender::QAbstractTexture *texture)
+{
+ Q_D(QAbstractSpriteSheet);
+ if (d->m_texture != texture) {
+ d->updateTexture(texture);
+ d->updateSizes();
+ emit textureChanged(d->m_texture);
+ }
+}
+
+QMatrix3x3 QAbstractSpriteSheet::textureTransform() const
+{
+ Q_D(const QAbstractSpriteSheet);
+ return d->m_textureTransform;
+}
+
+int QAbstractSpriteSheet::currentIndex() const
+{
+ Q_D(const QAbstractSpriteSheet);
+ return d->m_currentIndex;
+}
+
+void QAbstractSpriteSheet::setCurrentIndex(int currentIndex)
+{
+ Q_D(QAbstractSpriteSheet);
+ d->updateIndex(currentIndex);
+}
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/extras/defaults/qabstractspritesheet.h b/src/extras/defaults/qabstractspritesheet.h
new file mode 100644
index 000000000..cb8b70fd9
--- /dev/null
+++ b/src/extras/defaults/qabstractspritesheet.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QABSTRACTSPRITESHEET_H
+#define QT3DEXTRAS_QABSTRACTSPRITESHEET_H
+
+#include <Qt3DExtras/qt3dextras_global.h>
+#include <Qt3DCore/QNode>
+#include <QVector2D>
+#include <QMatrix3x3>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+
+} // namespace Qt3DRender
+
+namespace Qt3DExtras {
+
+class QAbstractSpriteSheetPrivate;
+
+class QT3DEXTRASSHARED_EXPORT QAbstractSpriteSheet : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged)
+ Q_PROPERTY(QMatrix3x3 textureTransform READ textureTransform NOTIFY textureTransformChanged)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+public:
+ ~QAbstractSpriteSheet();
+
+ Qt3DRender::QAbstractTexture *texture() const;
+ QMatrix3x3 textureTransform() const;
+ int currentIndex() const;
+
+public Q_SLOTS:
+ void setTexture(Qt3DRender::QAbstractTexture *texture);
+ void setCurrentIndex(int currentIndex);
+
+Q_SIGNALS:
+ void textureChanged(Qt3DRender::QAbstractTexture *texture);
+ void textureTransformChanged(const QMatrix3x3 &textureTransform);
+ void currentIndexChanged(int currentIndex);
+
+protected:
+ explicit QAbstractSpriteSheet(QAbstractSpriteSheetPrivate &d, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QAbstractSpriteSheet)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QABSTRACTSPRITESHEET_H
diff --git a/src/extras/defaults/qabstractspritesheet_p.h b/src/extras/defaults/qabstractspritesheet_p.h
new file mode 100644
index 000000000..604fc3c62
--- /dev/null
+++ b/src/extras/defaults/qabstractspritesheet_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QABSTRACTSPRITESHEET_P_H
+#define QT3DEXTRAS_QABSTRACTSPRITESHEET_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/private/qnode_p.h>
+#include <QMatrix3x3>
+#include <QSize>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QFilterKey;
+class QEffect;
+class QAbstractTexture;
+class QTechnique;
+class QParameter;
+class QShaderProgram;
+class QRenderPass;
+
+} // namespace Qt3DRender
+
+namespace Qt3DExtras {
+
+class QAbstractSpriteSheet;
+
+class QAbstractSpriteSheetPrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QAbstractSpriteSheetPrivate();
+
+ virtual void init();
+ void updateTexture(Qt3DRender::QAbstractTexture *texture);
+ void updateIndex(int newIndex);
+ virtual int maxIndex() const = 0;
+ virtual void updateSizes() = 0;
+ virtual void updateTransform() = 0;
+
+ Qt3DRender::QAbstractTexture *m_texture;
+ QMatrix3x3 m_textureTransform;
+ QSize m_textureSize;
+ int m_currentIndex;
+
+ Q_DECLARE_PUBLIC(QAbstractSpriteSheet)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QABSTRACTSPRITESHEET_P_H
+
diff --git a/src/extras/defaults/qdiffusemapmaterial.cpp b/src/extras/defaults/qdiffusemapmaterial.cpp
index a6da98a2e..26fb99c2c 100644
--- a/src/extras/defaults/qdiffusemapmaterial.cpp
+++ b/src/extras/defaults/qdiffusemapmaterial.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
@@ -75,7 +76,9 @@ QDiffuseMapMaterialPrivate::QDiffuseMapMaterialPrivate()
, m_diffuseMapGL2RenderPass(new QRenderPass())
, m_diffuseMapES2RenderPass(new QRenderPass())
, m_diffuseMapGL3Shader(new QShaderProgram())
+ , m_diffuseMapGL3ShaderBuilder(new QShaderProgramBuilder())
, m_diffuseMapGL2ES2Shader(new QShaderProgram())
+ , m_diffuseMapGL2ES2ShaderBuilder(new QShaderProgramBuilder())
, m_filterKey(new QFilterKey)
{
m_diffuseTexture->setMagnificationFilter(QAbstractTexture::Linear);
@@ -87,6 +90,8 @@ QDiffuseMapMaterialPrivate::QDiffuseMapMaterialPrivate()
void QDiffuseMapMaterialPrivate::init()
{
+ Q_Q(QDiffuseMapMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QDiffuseMapMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -98,10 +103,21 @@ void QDiffuseMapMaterialPrivate::init()
connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
this, &QDiffuseMapMaterialPrivate::handleTextureScaleChanged);
- m_diffuseMapGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/diffusemap.vert"))));
- m_diffuseMapGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/diffusemap.frag"))));
- m_diffuseMapGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/diffusemap.vert"))));
- m_diffuseMapGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/diffusemap.frag"))));
+ m_diffuseMapGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_diffuseMapGL3ShaderBuilder->setParent(q);
+ m_diffuseMapGL3ShaderBuilder->setShaderProgram(m_diffuseMapGL3Shader);
+ m_diffuseMapGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_diffuseMapGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
+
+ m_diffuseMapGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_diffuseMapGL2ES2ShaderBuilder->setParent(q);
+ m_diffuseMapGL2ES2ShaderBuilder->setShaderProgram(m_diffuseMapGL2ES2Shader);
+ m_diffuseMapGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_diffuseMapGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
m_diffuseMapGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_diffuseMapGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -118,7 +134,6 @@ void QDiffuseMapMaterialPrivate::init()
m_diffuseMapES2Technique->graphicsApiFilter()->setMinorVersion(0);
m_diffuseMapES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
- Q_Q(QDiffuseMapMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -186,6 +201,9 @@ void QDiffuseMapMaterialPrivate::handleTextureScaleChanged(const QVariant &var)
\since 5.7
\inherits Qt3DRender::QMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The specular lighting effect is based on the combination of 3 lighting components ambient,
diffuse and specular. The relative strengths of these components are controlled by means of
their reflectivity coefficients which are modelled as RGB triplets:
diff --git a/src/extras/defaults/qdiffusemapmaterial_p.h b/src/extras/defaults/qdiffusemapmaterial_p.h
index c0bcc01eb..cef75a3f0 100644
--- a/src/extras/defaults/qdiffusemapmaterial_p.h
+++ b/src/extras/defaults/qdiffusemapmaterial_p.h
@@ -63,6 +63,7 @@ class QAbstractTexture;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
} // namespace Qt3DRender
@@ -97,7 +98,9 @@ class QDiffuseMapMaterialPrivate : public Qt3DRender::QMaterialPrivate
Qt3DRender::QRenderPass *m_diffuseMapGL2RenderPass;
Qt3DRender::QRenderPass *m_diffuseMapES2RenderPass;
Qt3DRender::QShaderProgram *m_diffuseMapGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_diffuseMapGL3ShaderBuilder;
Qt3DRender::QShaderProgram *m_diffuseMapGL2ES2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_diffuseMapGL2ES2ShaderBuilder;
Qt3DRender::QFilterKey *m_filterKey;
Q_DECLARE_PUBLIC(QDiffuseMapMaterial)
diff --git a/src/extras/defaults/qdiffusespecularmapmaterial.cpp b/src/extras/defaults/qdiffusespecularmapmaterial.cpp
index 615ee6305..727eaed27 100644
--- a/src/extras/defaults/qdiffusespecularmapmaterial.cpp
+++ b/src/extras/defaults/qdiffusespecularmapmaterial.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
@@ -76,7 +77,9 @@ QDiffuseSpecularMapMaterialPrivate::QDiffuseSpecularMapMaterialPrivate()
, m_diffuseSpecularMapGL2RenderPass(new QRenderPass())
, m_diffuseSpecularMapES2RenderPass(new QRenderPass())
, m_diffuseSpecularMapGL3Shader(new QShaderProgram())
+ , m_diffuseSpecularMapGL3ShaderBuilder(new QShaderProgramBuilder())
, m_diffuseSpecularMapGL2ES2Shader(new QShaderProgram())
+ , m_diffuseSpecularMapGL2ES2ShaderBuilder(new QShaderProgramBuilder())
, m_filterKey(new QFilterKey)
{
m_diffuseTexture->setMagnificationFilter(QAbstractTexture::Linear);
@@ -94,6 +97,8 @@ QDiffuseSpecularMapMaterialPrivate::QDiffuseSpecularMapMaterialPrivate()
void QDiffuseSpecularMapMaterialPrivate::init()
{
+ Q_Q(QDiffuseSpecularMapMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QDiffuseSpecularMapMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -105,10 +110,21 @@ void QDiffuseSpecularMapMaterialPrivate::init()
connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
this, &QDiffuseSpecularMapMaterialPrivate::handleTextureScaleChanged);
- m_diffuseSpecularMapGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/diffusemap.vert"))));
- m_diffuseSpecularMapGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/diffusespecularmap.frag"))));
- m_diffuseSpecularMapGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/diffusemap.vert"))));
- m_diffuseSpecularMapGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/diffusespecularmap.frag"))));
+ m_diffuseSpecularMapGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_diffuseSpecularMapGL3ShaderBuilder->setParent(q);
+ m_diffuseSpecularMapGL3ShaderBuilder->setShaderProgram(m_diffuseSpecularMapGL3Shader);
+ m_diffuseSpecularMapGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_diffuseSpecularMapGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specularTexture"),
+ QStringLiteral("normal")});
+
+ m_diffuseSpecularMapGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_diffuseSpecularMapGL2ES2ShaderBuilder->setParent(q);
+ m_diffuseSpecularMapGL2ES2ShaderBuilder->setShaderProgram(m_diffuseSpecularMapGL2ES2Shader);
+ m_diffuseSpecularMapGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_diffuseSpecularMapGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specularTexture"),
+ QStringLiteral("normal")});
m_diffuseSpecularMapGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_diffuseSpecularMapGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -125,7 +141,6 @@ void QDiffuseSpecularMapMaterialPrivate::init()
m_diffuseSpecularMapES2Technique->graphicsApiFilter()->setMinorVersion(0);
m_diffuseSpecularMapES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
- Q_Q(QDiffuseSpecularMapMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -193,6 +208,9 @@ void QDiffuseSpecularMapMaterialPrivate::handleTextureScaleChanged(const QVarian
\since 5.7
\inherits Qt3DRender::QMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The specular lighting effect is based on the combination of 3 lighting components ambient,
diffuse and specular. The relative strengths of these components are controlled by means of
their reflectivity coefficients which are modelled as RGB triplets:
diff --git a/src/extras/defaults/qdiffusespecularmapmaterial_p.h b/src/extras/defaults/qdiffusespecularmapmaterial_p.h
index b358e088a..f80922dff 100644
--- a/src/extras/defaults/qdiffusespecularmapmaterial_p.h
+++ b/src/extras/defaults/qdiffusespecularmapmaterial_p.h
@@ -63,6 +63,7 @@ class QAbstractTexture;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
} // namespace Qt3DRender
@@ -99,7 +100,9 @@ public:
Qt3DRender::QRenderPass *m_diffuseSpecularMapGL2RenderPass;
Qt3DRender::QRenderPass *m_diffuseSpecularMapES2RenderPass;
Qt3DRender::QShaderProgram *m_diffuseSpecularMapGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_diffuseSpecularMapGL3ShaderBuilder;
Qt3DRender::QShaderProgram *m_diffuseSpecularMapGL2ES2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_diffuseSpecularMapGL2ES2ShaderBuilder;
Qt3DRender::QFilterKey *m_filterKey;
Q_DECLARE_PUBLIC(QDiffuseSpecularMapMaterial)
diff --git a/src/extras/defaults/qdiffusespecularmaterial.cpp b/src/extras/defaults/qdiffusespecularmaterial.cpp
new file mode 100644
index 000000000..83bba9e41
--- /dev/null
+++ b/src/extras/defaults/qdiffusespecularmaterial.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qdiffusespecularmaterial.h"
+#include "qdiffusespecularmaterial_p.h"
+
+#include <Qt3DRender/qfilterkey.h>
+#include <Qt3DRender/qmaterial.h>
+#include <Qt3DRender/qeffect.h>
+#include <Qt3DRender/qtechnique.h>
+#include <Qt3DRender/qtexture.h>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qrenderpass.h>
+#include <Qt3DRender/qgraphicsapifilter.h>
+#include <Qt3DRender/qblendequation.h>
+#include <Qt3DRender/qblendequationarguments.h>
+#include <Qt3DRender/qnodepthmask.h>
+#include <QtCore/QUrl>
+#include <QtGui/QVector3D>
+#include <QtGui/QVector4D>
+
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DRender;
+
+namespace Qt3DExtras {
+
+QDiffuseSpecularMaterialPrivate::QDiffuseSpecularMaterialPrivate()
+ : QMaterialPrivate()
+ , m_effect(new QEffect())
+ , m_ambientParameter(new QParameter(QStringLiteral("ka"), QColor::fromRgbF(0.05f, 0.05f, 0.05f, 1.0f)))
+ , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(0.7f, 0.7f, 0.7f, 1.0f)))
+ , m_specularParameter(new QParameter(QStringLiteral("ks"), QColor::fromRgbF(0.01f, 0.01f, 0.01f, 1.0f)))
+ , m_diffuseTextureParameter(new QParameter(QStringLiteral("diffuseTexture"), QVariant()))
+ , m_specularTextureParameter(new QParameter(QStringLiteral("specularTexture"), QVariant()))
+ , m_shininessParameter(new QParameter(QStringLiteral("shininess"), 150.0f))
+ , m_normalTextureParameter(new QParameter(QStringLiteral("normalTexture"), QVariant()))
+ , m_textureScaleParameter(new QParameter(QStringLiteral("texCoordScale"), 1.0f))
+ , m_gl3Technique(new QTechnique())
+ , m_gl2Technique(new QTechnique())
+ , m_es2Technique(new QTechnique())
+ , m_gl3RenderPass(new QRenderPass())
+ , m_gl2RenderPass(new QRenderPass())
+ , m_es2RenderPass(new QRenderPass())
+ , m_gl3Shader(new QShaderProgram())
+ , m_gl3ShaderBuilder(new QShaderProgramBuilder())
+ , m_gl2es2Shader(new QShaderProgram())
+ , m_gl2es2ShaderBuilder(new QShaderProgramBuilder())
+ , m_noDepthMask(new QNoDepthMask())
+ , m_blendState(new QBlendEquationArguments())
+ , m_blendEquation(new QBlendEquation())
+ , m_filterKey(new QFilterKey)
+{
+}
+
+void QDiffuseSpecularMaterialPrivate::init()
+{
+ Q_Q(QDiffuseSpecularMaterial);
+
+ connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
+ this, &QDiffuseSpecularMaterialPrivate::handleAmbientChanged);
+ QObject::connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QDiffuseSpecularMaterial::diffuseChanged);
+ QObject::connect(m_specularParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QDiffuseSpecularMaterial::specularChanged);
+ connect(m_shininessParameter, &Qt3DRender::QParameter::valueChanged,
+ this, &QDiffuseSpecularMaterialPrivate::handleShininessChanged);
+ QObject::connect(m_normalTextureParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QDiffuseSpecularMaterial::normalChanged);
+ connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
+ this, &QDiffuseSpecularMaterialPrivate::handleTextureScaleChanged);
+ QObject::connect(m_noDepthMask, &QNoDepthMask::enabledChanged,
+ q, &QDiffuseSpecularMaterial::alphaBlendingEnabledChanged);
+
+ m_gl3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_gl3ShaderBuilder->setParent(q);
+ m_gl3ShaderBuilder->setShaderProgram(m_gl3Shader);
+ m_gl3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_gl3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
+
+ m_gl2es2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_gl2es2ShaderBuilder->setParent(q);
+ m_gl2es2ShaderBuilder->setShaderProgram(m_gl2es2Shader);
+ m_gl2es2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_gl2es2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
+
+
+ m_gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ m_gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ m_gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ m_gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ m_gl2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ m_gl2Technique->graphicsApiFilter()->setMajorVersion(2);
+ m_gl2Technique->graphicsApiFilter()->setMinorVersion(0);
+ m_gl2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
+
+ m_es2Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGLES);
+ m_es2Technique->graphicsApiFilter()->setMajorVersion(2);
+ m_es2Technique->graphicsApiFilter()->setMinorVersion(0);
+ m_es2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
+
+ m_noDepthMask->setEnabled(false);
+ m_blendState->setEnabled(false);
+ m_blendState->setSourceRgb(QBlendEquationArguments::SourceAlpha);
+ m_blendState->setDestinationRgb(QBlendEquationArguments::OneMinusSourceAlpha);
+ m_blendEquation->setEnabled(false);
+ m_blendEquation->setBlendFunction(QBlendEquation::Add);
+
+ m_gl3RenderPass->setShaderProgram(m_gl3Shader);
+ m_gl2RenderPass->setShaderProgram(m_gl2es2Shader);
+ m_es2RenderPass->setShaderProgram(m_gl2es2Shader);
+
+ m_gl3RenderPass->addRenderState(m_noDepthMask);
+ m_gl3RenderPass->addRenderState(m_blendState);
+ m_gl3RenderPass->addRenderState(m_blendEquation);
+
+ m_gl2RenderPass->addRenderState(m_noDepthMask);
+ m_gl2RenderPass->addRenderState(m_blendState);
+ m_gl2RenderPass->addRenderState(m_blendEquation);
+
+ m_es2RenderPass->addRenderState(m_noDepthMask);
+ m_es2RenderPass->addRenderState(m_blendState);
+ m_es2RenderPass->addRenderState(m_blendEquation);
+
+ m_gl3Technique->addRenderPass(m_gl3RenderPass);
+ m_gl2Technique->addRenderPass(m_gl2RenderPass);
+ m_es2Technique->addRenderPass(m_es2RenderPass);
+
+ m_filterKey->setParent(q);
+ m_filterKey->setName(QStringLiteral("renderingStyle"));
+ m_filterKey->setValue(QStringLiteral("forward"));
+
+ m_gl3Technique->addFilterKey(m_filterKey);
+ m_gl2Technique->addFilterKey(m_filterKey);
+ m_es2Technique->addFilterKey(m_filterKey);
+
+ m_effect->addTechnique(m_gl3Technique);
+ m_effect->addTechnique(m_gl2Technique);
+ m_effect->addTechnique(m_es2Technique);
+
+ m_effect->addParameter(m_ambientParameter);
+ m_effect->addParameter(m_diffuseParameter);
+ m_effect->addParameter(m_specularParameter);
+ m_effect->addParameter(m_shininessParameter);
+ m_effect->addParameter(m_textureScaleParameter);
+
+ q->setEffect(m_effect);
+}
+
+void QDiffuseSpecularMaterialPrivate::handleAmbientChanged(const QVariant &var)
+{
+ Q_Q(QDiffuseSpecularMaterial);
+ emit q->ambientChanged(var.value<QColor>());
+}
+
+void QDiffuseSpecularMaterialPrivate::handleShininessChanged(const QVariant &var)
+{
+ Q_Q(QDiffuseSpecularMaterial);
+ emit q->shininessChanged(var.toFloat());
+}
+
+void QDiffuseSpecularMaterialPrivate::handleTextureScaleChanged(const QVariant &var)
+{
+ Q_Q(QDiffuseSpecularMaterial);
+ emit q->textureScaleChanged(var.toFloat());
+}
+
+/*!
+ \class Qt3DExtras::QDiffuseSpecularMaterial
+ \brief The QDiffuseSpecularMaterial class provides a default implementation
+ of the phong lighting effect.
+ \inmodule Qt3DExtras
+ \since 5.10
+ \inherits Qt3DRender::QMaterial
+
+ The phong lighting effect is based on the combination of 3 lighting
+ components ambient, diffuse and specular. The relative strengths of these
+ components are controlled by means of their reflectivity coefficients which
+ are modelled as RGB triplets:
+
+ \list
+ \li Ambient is the color that is emitted by an object without any other
+ light source.
+ \li Diffuse is the color that is emitted for rought surface reflections
+ with the lights.
+ \li Specular is the color emitted for shiny surface reflections with the
+ lights.
+ \li The shininess of a surface is controlled by a float property.
+ \endlist
+
+ This material uses an effect with a single render pass approach and
+ performs per fragment lighting. Techniques are provided for OpenGL 2,
+ OpenGL 3 or above as well as OpenGL ES 2.
+*/
+/*!
+ \qmltype DiffuseSpecularMaterial
+ \brief The DiffuseSpecularMaterial class provides a default implementation
+ of the phong lighting effect.
+ \since 5.10
+ \inqmlmodule Qt3D.Extras
+ \instantiates Qt3DExtras::QDiffuseSpecularMaterial
+
+ The phong lighting effect is based on the combination of 3 lighting
+ components ambient, diffuse and specular. The relative strengths of these
+ components are controlled by means of their reflectivity coefficients which
+ are modelled as RGB triplets:
+
+ \list
+ \li Ambient is the color that is emitted by an object without any other
+ light source.
+ \li Diffuse is the color that is emitted for rought surface reflections
+ with the lights.
+ \li Specular is the color emitted for shiny surface reflections with the
+ lights.
+ \li The shininess of a surface is controlled by a float property.
+ \endlist
+
+ This material uses an effect with a single render pass approach and
+ performs per fragment lighting. Techniques are provided for OpenGL 2,
+ OpenGL 3 or above as well as OpenGL ES 2.
+ */
+
+/*!
+ Constructs a new QDiffuseSpecularMaterial instance with parent object \a parent.
+*/
+QDiffuseSpecularMaterial::QDiffuseSpecularMaterial(QNode *parent)
+ : QMaterial(*new QDiffuseSpecularMaterialPrivate, parent)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->init();
+}
+
+/*!
+ Destroys the QDiffuseSpecularMaterial.
+*/
+QDiffuseSpecularMaterial::~QDiffuseSpecularMaterial()
+{
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::ambient
+
+ Holds the ambient color.
+*/
+/*!
+ \qmlproperty color DiffuseSpecularMaterial::ambient
+
+ Holds the ambient color.
+*/
+QColor QDiffuseSpecularMaterial::ambient() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_ambientParameter->value().value<QColor>();
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::diffuse
+
+ Holds the diffuse color of the material. This can be either a plain color
+ value or a texture.
+*/
+/*!
+ \qmlproperty var DiffuseSpecularMaterial::diffuse
+
+ Holds the diffuse color of the material. This can be either a plain color
+ value or a texture.
+*/
+QVariant QDiffuseSpecularMaterial::diffuse() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_diffuseParameter->value();
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::specular
+
+ Holds the specular color of the material. This can be either a plain color
+ value or a texture.
+*/
+/*!
+ \qmlproperty var DiffuseSpecularMaterial::specular
+
+ Holds the specular color of the material. This can be either a plain color
+ value or a texture.
+*/
+QVariant QDiffuseSpecularMaterial::specular() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_specularParameter->value();
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::shininess
+
+ Holds the shininess exponent.
+*/
+/*!
+ \qmlproperty real DiffuseSpecularMaterial::shininess
+
+ Holds the shininess exponent.
+*/
+float QDiffuseSpecularMaterial::shininess() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_shininessParameter->value().toFloat();
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::normal
+
+ Holds the current normal map texture of the material. This can only be a
+ texture, otherwise it is ignored. By default this map is not set.
+*/
+/*!
+ \qmlproperty var DiffuseSpecularMaterial::normal
+
+ Holds the current normal map texture of the material. This can only be a
+ texture, otherwise it is ignored. By default this map is not set.
+*/
+QVariant QDiffuseSpecularMaterial::normal() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_normalTextureParameter->value();
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::textureScale
+
+ Holds the current texture scale. It is applied as a multiplier to texture
+ coordinates at render time. Defaults to 1.0.
+*/
+/*!
+ \qmlproperty real DiffuseSpecularMaterial::textureScale
+
+ Holds the current texture scale. It is applied as a multiplier to texture
+ coordinates at render time. Defaults to 1.0.
+*/
+float QDiffuseSpecularMaterial::textureScale() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_textureScaleParameter->value().toFloat();
+}
+
+/*!
+ \property QDiffuseSpecularMaterial::alphaBlending
+
+ Indicates if the alpha information coming from the diffuse property will
+ be taken into account during rendering. Defaults to false.
+*/
+/*!
+ \qmlproperty bool DiffuseSpecularMaterial::alphaBlending
+
+ Indicates if the alpha information coming from the diffuse property will
+ be taken into account during rendering. Defaults to false.
+*/
+bool QDiffuseSpecularMaterial::isAlphaBlendingEnabled() const
+{
+ Q_D(const QDiffuseSpecularMaterial);
+ return d->m_noDepthMask->isEnabled();
+}
+
+void QDiffuseSpecularMaterial::setAmbient(const QColor &ambient)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_ambientParameter->setValue(ambient);
+}
+
+void QDiffuseSpecularMaterial::setDiffuse(const QVariant &diffuse)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_diffuseParameter->setValue(diffuse);
+ d->m_diffuseTextureParameter->setValue(diffuse);
+
+ auto layers = d->m_gl3ShaderBuilder->enabledLayers();
+ if (diffuse.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("diffuse"));
+ layers.append(QStringLiteral("diffuseTexture"));
+ d->m_effect->addParameter(d->m_diffuseTextureParameter);
+ d->m_effect->removeParameter(d->m_diffuseParameter);
+ } else {
+ layers.removeAll(QStringLiteral("diffuseTexture"));
+ layers.append(QStringLiteral("diffuse"));
+ d->m_effect->removeParameter(d->m_diffuseTextureParameter);
+ d->m_effect->addParameter(d->m_diffuseParameter);
+ }
+ d->m_gl3ShaderBuilder->setEnabledLayers(layers);
+ d->m_gl2es2ShaderBuilder->setEnabledLayers(layers);
+}
+
+void QDiffuseSpecularMaterial::setSpecular(const QVariant &specular)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_specularParameter->setValue(specular);
+ d->m_specularTextureParameter->setValue(specular);
+
+ auto layers = d->m_gl3ShaderBuilder->enabledLayers();
+ if (specular.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("specular"));
+ layers.append(QStringLiteral("specularTexture"));
+ d->m_effect->addParameter(d->m_specularTextureParameter);
+ d->m_effect->removeParameter(d->m_specularParameter);
+ } else {
+ layers.removeAll(QStringLiteral("specularTexture"));
+ layers.append(QStringLiteral("specular"));
+ d->m_effect->removeParameter(d->m_specularTextureParameter);
+ d->m_effect->addParameter(d->m_specularParameter);
+ }
+ d->m_gl3ShaderBuilder->setEnabledLayers(layers);
+ d->m_gl2es2ShaderBuilder->setEnabledLayers(layers);
+}
+
+void QDiffuseSpecularMaterial::setShininess(float shininess)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_shininessParameter->setValue(shininess);
+}
+
+void QDiffuseSpecularMaterial::setNormal(const QVariant &normal)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_normalTextureParameter->setValue(normal);
+
+ auto layers = d->m_gl3ShaderBuilder->enabledLayers();
+ if (normal.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("normal"));
+ layers.append(QStringLiteral("normalTexture"));
+ d->m_effect->addParameter(d->m_normalTextureParameter);
+ } else {
+ layers.removeAll(QStringLiteral("normalTexture"));
+ layers.append(QStringLiteral("normal"));
+ d->m_effect->removeParameter(d->m_normalTextureParameter);
+ }
+ d->m_gl3ShaderBuilder->setEnabledLayers(layers);
+}
+
+void QDiffuseSpecularMaterial::setTextureScale(float textureScale)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_textureScaleParameter->setValue(textureScale);
+}
+
+void QDiffuseSpecularMaterial::setAlphaBlendingEnabled(bool enabled)
+{
+ Q_D(QDiffuseSpecularMaterial);
+ d->m_noDepthMask->setEnabled(enabled);
+ d->m_blendState->setEnabled(enabled);
+ d->m_blendEquation->setEnabled(enabled);
+}
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/extras/defaults/qdiffusespecularmaterial.h b/src/extras/defaults/qdiffusespecularmaterial.h
new file mode 100644
index 000000000..5f21da093
--- /dev/null
+++ b/src/extras/defaults/qdiffusespecularmaterial.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_H
+#define QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_H
+
+#include <Qt3DExtras/qt3dextras_global.h>
+#include <Qt3DRender/qmaterial.h>
+#include <QtGui/QColor>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QDiffuseSpecularMaterialPrivate;
+
+class QT3DEXTRASSHARED_EXPORT QDiffuseSpecularMaterial : public Qt3DRender::QMaterial
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor ambient READ ambient WRITE setAmbient NOTIFY ambientChanged)
+ Q_PROPERTY(QVariant diffuse READ diffuse WRITE setDiffuse NOTIFY diffuseChanged)
+ Q_PROPERTY(QVariant specular READ specular WRITE setSpecular NOTIFY specularChanged)
+ Q_PROPERTY(float shininess READ shininess WRITE setShininess NOTIFY shininessChanged)
+ Q_PROPERTY(QVariant normal READ normal WRITE setNormal NOTIFY normalChanged)
+ Q_PROPERTY(float textureScale READ textureScale WRITE setTextureScale NOTIFY textureScaleChanged)
+ Q_PROPERTY(bool alphaBlending READ isAlphaBlendingEnabled WRITE setAlphaBlendingEnabled NOTIFY alphaBlendingEnabledChanged)
+
+public:
+ explicit QDiffuseSpecularMaterial(Qt3DCore::QNode *parent = nullptr);
+ ~QDiffuseSpecularMaterial();
+
+ QColor ambient() const;
+ QVariant diffuse() const;
+ QVariant specular() const;
+ float shininess() const;
+ QVariant normal() const;
+ float textureScale() const;
+ bool isAlphaBlendingEnabled() const;
+
+public Q_SLOTS:
+ void setAmbient(const QColor &ambient);
+ void setDiffuse(const QVariant &diffuse);
+ void setSpecular(const QVariant &specular);
+ void setShininess(float shininess);
+ void setNormal(const QVariant &normal);
+ void setTextureScale(float textureScale);
+ void setAlphaBlendingEnabled(bool enabled);
+
+Q_SIGNALS:
+ void ambientChanged(const QColor &ambient);
+ void diffuseChanged(const QVariant &diffuse);
+ void specularChanged(const QVariant &specular);
+ void shininessChanged(float shininess);
+ void normalChanged(const QVariant &normal);
+ void textureScaleChanged(float textureScale);
+ void alphaBlendingEnabledChanged(bool enabled);
+
+private:
+ Q_DECLARE_PRIVATE(QDiffuseSpecularMaterial)
+};
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_H
diff --git a/src/extras/defaults/qtexturedmetalroughmaterial_p.h b/src/extras/defaults/qdiffusespecularmaterial_p.h
index 8972726e5..2b0b2184f 100644
--- a/src/extras/defaults/qtexturedmetalroughmaterial_p.h
+++ b/src/extras/defaults/qdiffusespecularmaterial_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_P_H
-#define QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_P_H
+#ifndef QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_P_H
+#define QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_P_H
//
// W A R N I N G
@@ -59,57 +59,62 @@ namespace Qt3DRender {
class QFilterKey;
class QEffect;
-class QAbstractTexture;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
+class QNoDepthMask;
+class QBlendEquationArguments;
+class QBlendEquation;
} // namespace Qt3DRender
namespace Qt3DExtras {
-class QTexturedMetalRoughMaterial;
+class QDiffuseSpecularMaterial;
-class QTexturedMetalRoughMaterialPrivate : public Qt3DRender::QMaterialPrivate
+class QDiffuseSpecularMaterialPrivate : public Qt3DRender::QMaterialPrivate
{
public:
- QTexturedMetalRoughMaterialPrivate();
+ QDiffuseSpecularMaterialPrivate();
void init();
- void handleBaseColorChanged(const QVariant &var);
- void handleMetallicChanged(const QVariant &var);
- void handleRoughnessChanged(const QVariant &var);
- void handleAmbientOcclusionChanged(const QVariant &var);
- void handleNormalChanged(const QVariant &var);
-
- Qt3DRender::QAbstractTexture *m_baseColorTexture;
- Qt3DRender::QAbstractTexture *m_metalnessTexture;
- Qt3DRender::QAbstractTexture *m_roughnessTexture;
- Qt3DRender::QAbstractTexture *m_ambientOcclusionTexture;
- Qt3DRender::QAbstractTexture *m_normalTexture;
- Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture;
- Qt3DRender::QAbstractTexture *m_environmentSpecularTexture;
- Qt3DRender::QParameter *m_baseColorParameter;
- Qt3DRender::QParameter *m_metalnessParameter;
- Qt3DRender::QParameter *m_roughnessParameter;
- Qt3DRender::QParameter *m_ambientOcclusionParameter;
- Qt3DRender::QParameter *m_normalParameter;
- Qt3DRender::QParameter *m_environmentIrradianceParameter;
- Qt3DRender::QParameter *m_environmentSpecularParameter;
- Qt3DRender::QEffect *m_metalRoughEffect;
- Qt3DRender::QTechnique *m_metalRoughGL3Technique;
- Qt3DRender::QRenderPass *m_metalRoughGL3RenderPass;
- Qt3DRender::QShaderProgram *m_metalRoughGL3Shader;
+ void handleAmbientChanged(const QVariant &var);
+ void handleShininessChanged(const QVariant &var);
+ void handleTextureScaleChanged(const QVariant &var);
+
+ Qt3DRender::QEffect *m_effect;
+ Qt3DRender::QParameter *m_ambientParameter;
+ Qt3DRender::QParameter *m_diffuseParameter;
+ Qt3DRender::QParameter *m_specularParameter;
+ Qt3DRender::QParameter *m_diffuseTextureParameter;
+ Qt3DRender::QParameter *m_specularTextureParameter;
+ Qt3DRender::QParameter *m_shininessParameter;
+ Qt3DRender::QParameter *m_normalTextureParameter;
+ Qt3DRender::QParameter *m_textureScaleParameter;
+ Qt3DRender::QTechnique *m_gl3Technique;
+ Qt3DRender::QTechnique *m_gl2Technique;
+ Qt3DRender::QTechnique *m_es2Technique;
+ Qt3DRender::QRenderPass *m_gl3RenderPass;
+ Qt3DRender::QRenderPass *m_gl2RenderPass;
+ Qt3DRender::QRenderPass *m_es2RenderPass;
+ Qt3DRender::QShaderProgram *m_gl3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_gl3ShaderBuilder;
+ Qt3DRender::QShaderProgram *m_gl2es2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_gl2es2ShaderBuilder;
+ Qt3DRender::QNoDepthMask *m_noDepthMask;
+ Qt3DRender::QBlendEquationArguments *m_blendState;
+ Qt3DRender::QBlendEquation *m_blendEquation;
Qt3DRender::QFilterKey *m_filterKey;
- Q_DECLARE_PUBLIC(QTexturedMetalRoughMaterial)
+ Q_DECLARE_PUBLIC(QDiffuseSpecularMaterial)
};
} // Qt3DExtras
QT_END_NAMESPACE
-#endif // QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_P_H
+#endif // QT3DEXTRAS_QDIFFUSESPECULARMATERIAL_P_H
diff --git a/src/extras/defaults/qfirstpersoncameracontroller.cpp b/src/extras/defaults/qfirstpersoncameracontroller.cpp
index 5321bfcf2..2ad997d05 100644
--- a/src/extras/defaults/qfirstpersoncameracontroller.cpp
+++ b/src/extras/defaults/qfirstpersoncameracontroller.cpp
@@ -35,188 +35,13 @@
****************************************************************************/
#include "qfirstpersoncameracontroller.h"
-#include "qfirstpersoncameracontroller_p.h"
-#include <Qt3DInput/QAction>
-#include <Qt3DInput/QActionInput>
-#include <Qt3DInput/QAnalogAxisInput>
-#include <Qt3DInput/QAxis>
-#include <Qt3DInput/QButtonAxisInput>
-#include <Qt3DLogic/QFrameAction>
-#include <Qt3DInput/QKeyboardDevice>
-#include <Qt3DInput/QLogicalDevice>
-#include <Qt3DInput/QMouseDevice>
-#include <Qt3DInput/QMouseEvent>
#include <Qt3DRender/QCamera>
QT_BEGIN_NAMESPACE
namespace Qt3DExtras {
-QFirstPersonCameraControllerPrivate::QFirstPersonCameraControllerPrivate()
- : Qt3DCore::QEntityPrivate()
- , m_camera(nullptr)
- , m_leftMouseButtonAction(new Qt3DInput::QAction())
- , m_fineMotionAction(new Qt3DInput::QAction())
- , m_rxAxis(new Qt3DInput::QAxis())
- , m_ryAxis(new Qt3DInput::QAxis())
- , m_txAxis(new Qt3DInput::QAxis())
- , m_tyAxis(new Qt3DInput::QAxis())
- , m_tzAxis(new Qt3DInput::QAxis())
- , m_leftMouseButtonInput(new Qt3DInput::QActionInput())
- , m_fineMotionKeyInput(new Qt3DInput::QActionInput())
- , m_mouseRxInput(new Qt3DInput::QAnalogAxisInput())
- , m_mouseRyInput(new Qt3DInput::QAnalogAxisInput())
- , m_mouseTzXInput(new Qt3DInput::QAnalogAxisInput())
- , m_mouseTzYInput(new Qt3DInput::QAnalogAxisInput())
- , m_keyboardTxPosInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTyPosInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTzPosInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTxNegInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTyNegInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTzNegInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardDevice(new Qt3DInput::QKeyboardDevice())
- , m_mouseDevice(new Qt3DInput::QMouseDevice())
- , m_logicalDevice(new Qt3DInput::QLogicalDevice())
- , m_frameAction(new Qt3DLogic::QFrameAction())
- , m_linearSpeed(10.0f)
- , m_lookSpeed(180.0f)
- , m_acceleration(-1.0f)
- , m_deceleration(-1.0f)
- , m_firstPersonUp(QVector3D(0.0f, 1.0f, 0.0f))
-{}
-
-void QFirstPersonCameraControllerPrivate::init()
-{
- //// Actions
-
- // Left Mouse Button Action
- m_leftMouseButtonInput->setButtons(QVector<int>() << Qt::LeftButton);
- m_leftMouseButtonInput->setSourceDevice(m_mouseDevice);
- m_leftMouseButtonAction->addInput(m_leftMouseButtonInput);
-
- // Fine Motion Action
- m_fineMotionKeyInput->setButtons(QVector<int>() << Qt::Key_Shift);
- m_fineMotionKeyInput->setSourceDevice(m_keyboardDevice);
- m_fineMotionAction->addInput(m_fineMotionKeyInput);
-
- //// Axes
-
- // Mouse X
- m_mouseRxInput->setAxis(Qt3DInput::QMouseDevice::X);
- m_mouseRxInput->setSourceDevice(m_mouseDevice);
- m_rxAxis->addInput(m_mouseRxInput);
-
- // Mouse Y
- m_mouseRyInput->setAxis(Qt3DInput::QMouseDevice::Y);
- m_mouseRyInput->setSourceDevice(m_mouseDevice);
- m_ryAxis->addInput(m_mouseRyInput);
-
- // Mouse Wheel X
- m_mouseTzXInput->setAxis(Qt3DInput::QMouseDevice::WheelX);
- m_mouseTzXInput->setSourceDevice(m_mouseDevice);
- m_tzAxis->addInput(m_mouseTzXInput);
-
- // Mouse Wheel Y
- m_mouseTzYInput->setAxis(Qt3DInput::QMouseDevice::WheelY);
- m_mouseTzYInput->setSourceDevice(m_mouseDevice);
- m_tzAxis->addInput(m_mouseTzYInput);
-
- // Keyboard Pos Tx
- m_keyboardTxPosInput->setButtons(QVector<int>() << Qt::Key_Right);
- m_keyboardTxPosInput->setScale(1.0f);
- m_keyboardTxPosInput->setSourceDevice(m_keyboardDevice);
- m_txAxis->addInput(m_keyboardTxPosInput);
-
- // Keyboard Pos Ty
- m_keyboardTyPosInput->setButtons(QVector<int>() << Qt::Key_PageUp);
- m_keyboardTyPosInput->setScale(1.0f);
- m_keyboardTyPosInput->setSourceDevice(m_keyboardDevice);
- m_tyAxis->addInput(m_keyboardTyPosInput);
-
- // Keyboard Pos Tz
- m_keyboardTzPosInput->setButtons(QVector<int>() << Qt::Key_Up);
- m_keyboardTzPosInput->setScale(1.0f);
- m_keyboardTzPosInput->setSourceDevice(m_keyboardDevice);
- m_tzAxis->addInput(m_keyboardTzPosInput);
-
- // Keyboard Neg Tx
- m_keyboardTxNegInput->setButtons(QVector<int>() << Qt::Key_Left);
- m_keyboardTxNegInput->setScale(-1.0f);
- m_keyboardTxNegInput->setSourceDevice(m_keyboardDevice);
- m_txAxis->addInput(m_keyboardTxNegInput);
-
- // Keyboard Neg Ty
- m_keyboardTyNegInput->setButtons(QVector<int>() << Qt::Key_PageDown);
- m_keyboardTyNegInput->setScale(-1.0f);
- m_keyboardTyNegInput->setSourceDevice(m_keyboardDevice);
- m_tyAxis->addInput(m_keyboardTyNegInput);
-
- // Keyboard Neg Tz
- m_keyboardTzNegInput->setButtons(QVector<int>() << Qt::Key_Down);
- m_keyboardTzNegInput->setScale(-1.0f);
- m_keyboardTzNegInput->setSourceDevice(m_keyboardDevice);
- m_tzAxis->addInput(m_keyboardTzNegInput);
-
- //// Logical Device
-
- m_logicalDevice->addAction(m_fineMotionAction);
- m_logicalDevice->addAction(m_leftMouseButtonAction);
- m_logicalDevice->addAxis(m_rxAxis);
- m_logicalDevice->addAxis(m_ryAxis);
- m_logicalDevice->addAxis(m_txAxis);
- m_logicalDevice->addAxis(m_tyAxis);
- m_logicalDevice->addAxis(m_tzAxis);
-
- applyAccelerations();
-
- Q_Q(QFirstPersonCameraController);
- //// FrameAction
-
- QObject::connect(m_frameAction, SIGNAL(triggered(float)),
- q, SLOT(_q_onTriggered(float)));
-
- // Disable the logical device when the entity is disabled
- QObject::connect(q, &Qt3DCore::QEntity::enabledChanged,
- m_logicalDevice, &Qt3DInput::QLogicalDevice::setEnabled);
-
- q->addComponent(m_frameAction);
- q->addComponent(m_logicalDevice);
-}
-
-void QFirstPersonCameraControllerPrivate::applyAccelerations()
-{
- const auto inputs = {
- m_keyboardTxPosInput,
- m_keyboardTyPosInput,
- m_keyboardTzPosInput,
- m_keyboardTxNegInput,
- m_keyboardTyNegInput,
- m_keyboardTzNegInput
- };
-
- for (auto input : inputs) {
- input->setAcceleration(m_acceleration);
- input->setDeceleration(m_deceleration);
- }
-}
-
-void QFirstPersonCameraControllerPrivate::_q_onTriggered(float dt)
-{
- if (m_camera != nullptr) {
- m_camera->translate(QVector3D(m_txAxis->value() * m_linearSpeed,
- m_tyAxis->value() * m_linearSpeed,
- m_tzAxis->value() * m_linearSpeed) * dt);
- if (m_leftMouseButtonAction->isActive()) {
- float lookSpeed = m_lookSpeed;
- if (m_fineMotionAction->isActive())
- lookSpeed *= 0.2f;
- m_camera->pan(m_rxAxis->value() * lookSpeed * dt, m_firstPersonUp);
- m_camera->tilt(m_ryAxis->value() * lookSpeed * dt);
- }
- }
-}
-
/*!
\class Qt3DExtras::QFirstPersonCameraController
\brief The QFirstPersonCameraController class allows controlling the scene camera
@@ -251,129 +76,35 @@ void QFirstPersonCameraControllerPrivate::_q_onTriggered(float dt)
*/
QFirstPersonCameraController::QFirstPersonCameraController(Qt3DCore::QNode *parent)
- : Qt3DCore::QEntity(*new QFirstPersonCameraControllerPrivate, parent)
+ : QAbstractCameraController(parent)
{
- Q_D(QFirstPersonCameraController);
- d->init();
}
QFirstPersonCameraController::~QFirstPersonCameraController()
{
}
-/*!
- \property QFirstPersonCameraController::camera
-
- Holds the currently controlled camera.
-*/
-Qt3DRender::QCamera *QFirstPersonCameraController::camera() const
-{
- Q_D(const QFirstPersonCameraController);
- return d->m_camera;
-}
-
-/*!
- \property QFirstPersonCameraController::linearSpeed
- Holds the current linear speed of the camera controller. Linear speed determines the
- movement speed of the camera.
-*/
-float QFirstPersonCameraController::linearSpeed() const
+void QFirstPersonCameraController::moveCamera(const QAbstractCameraController::InputState &state, float dt)
{
- Q_D(const QFirstPersonCameraController);
- return d->m_linearSpeed;
-}
-
-/*!
- \property QFirstPersonCameraController::lookSpeed
-
- Holds the current look speed of the camera controller. The look speed determines the turn rate
- of the camera pan and tilt.
-*/
-float QFirstPersonCameraController::lookSpeed() const
-{
- Q_D(const QFirstPersonCameraController);
- return d->m_lookSpeed;
-}
-
-/*!
- \property QFirstPersonCameraController::acceleration
-
- Holds the current acceleration of the camera controller.
-*/
-float QFirstPersonCameraController::acceleration() const
-{
- Q_D(const QFirstPersonCameraController);
- return d->m_acceleration;
-}
-
-/*!
- \property QFirstPersonCameraController::deceleration
-
- Holds the current deceleration of the camera controller.
-*/
-float QFirstPersonCameraController::deceleration() const
-{
- Q_D(const QFirstPersonCameraController);
- return d->m_deceleration;
-}
-
-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();
- }
-}
-
-void QFirstPersonCameraController::setLinearSpeed(float linearSpeed)
-{
- Q_D(QFirstPersonCameraController);
- if (d->m_linearSpeed != linearSpeed) {
- d->m_linearSpeed = linearSpeed;
- emit linearSpeedChanged();
- }
-}
-
-void QFirstPersonCameraController::setLookSpeed(float lookSpeed)
-{
- Q_D(QFirstPersonCameraController);
- if (d->m_lookSpeed != lookSpeed) {
- d->m_lookSpeed = lookSpeed;
- emit lookSpeedChanged();
- }
-}
+ Qt3DRender::QCamera *theCamera = camera();
+
+ if (theCamera == nullptr)
+ return;
+
+ theCamera->translate(QVector3D(state.txAxisValue * linearSpeed(),
+ state.tyAxisValue * linearSpeed(),
+ state.tzAxisValue * linearSpeed()) * dt);
+ if (state.leftMouseButtonActive) {
+ float theLookSpeed = lookSpeed();
+ if (state.shiftKeyActive) {
+ theLookSpeed *= 0.2f;
+ }
-void QFirstPersonCameraController::setAcceleration(float acceleration)
-{
- Q_D(QFirstPersonCameraController);
- if (d->m_acceleration != acceleration) {
- d->m_acceleration = acceleration;
- d->applyAccelerations();
- emit accelerationChanged(acceleration);
- }
-}
+ const QVector3D upVector(0.0f, 1.0f, 0.0f);
-void QFirstPersonCameraController::setDeceleration(float deceleration)
-{
- Q_D(QFirstPersonCameraController);
- if (d->m_deceleration != deceleration) {
- d->m_deceleration = deceleration;
- d->applyAccelerations();
- emit decelerationChanged(deceleration);
+ theCamera->pan(state.rxAxisValue * theLookSpeed * dt, upVector);
+ theCamera->tilt(state.ryAxisValue * theLookSpeed * dt);
}
}
diff --git a/src/extras/defaults/qfirstpersoncameracontroller.h b/src/extras/defaults/qfirstpersoncameracontroller.h
index 3f7a6acc4..60edf7cb8 100644
--- a/src/extras/defaults/qfirstpersoncameracontroller.h
+++ b/src/extras/defaults/qfirstpersoncameracontroller.h
@@ -37,53 +37,22 @@
#ifndef QT3DEXTRAS_QFIRSTPERSONCAMERACONTROLLER_H
#define QT3DEXTRAS_QFIRSTPERSONCAMERACONTROLLER_H
-#include <Qt3DExtras/qt3dextras_global.h>
-#include <Qt3DCore/QEntity>
+#include <Qt3DExtras/qabstractcameracontroller.h>
QT_BEGIN_NAMESPACE
-namespace Qt3DRender {
-class QCamera;
-}
-
namespace Qt3DExtras {
-class QFirstPersonCameraControllerPrivate;
-
-class QT3DEXTRASSHARED_EXPORT QFirstPersonCameraController : public Qt3DCore::QEntity
+class QT3DEXTRASSHARED_EXPORT QFirstPersonCameraController : public QAbstractCameraController
{
Q_OBJECT
- Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged)
- Q_PROPERTY(float linearSpeed READ linearSpeed WRITE setLinearSpeed NOTIFY linearSpeedChanged)
- Q_PROPERTY(float lookSpeed READ lookSpeed WRITE setLookSpeed NOTIFY lookSpeedChanged)
- Q_PROPERTY(float acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
- Q_PROPERTY(float deceleration READ deceleration WRITE setDeceleration NOTIFY decelerationChanged)
+
public:
explicit QFirstPersonCameraController(Qt3DCore::QNode *parent = nullptr);
~QFirstPersonCameraController();
- Qt3DRender::QCamera *camera() const;
- float linearSpeed() const;
- float lookSpeed() const;
- float acceleration() const;
- float deceleration() const;
-
- void setCamera(Qt3DRender::QCamera *camera);
- void setLinearSpeed(float linearSpeed);
- void setLookSpeed(float lookSpeed);
- void setAcceleration(float acceleration);
- void setDeceleration(float deceleration);
-
-Q_SIGNALS:
- void cameraChanged();
- void linearSpeedChanged();
- void lookSpeedChanged();
- void accelerationChanged(float acceleration);
- void decelerationChanged(float deceleration);
-
private:
- Q_DECLARE_PRIVATE(QFirstPersonCameraController)
- Q_PRIVATE_SLOT(d_func(), void _q_onTriggered(float))
+ void moveCamera(const QAbstractCameraController::InputState &state, float dt) override;
};
} // Qt3DExtras
diff --git a/src/extras/defaults/qfirstpersoncameracontroller_p.h b/src/extras/defaults/qfirstpersoncameracontroller_p.h
deleted file mode 100644
index 48a7c7998..000000000
--- a/src/extras/defaults/qfirstpersoncameracontroller_p.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#ifndef QT3DEXTRAS_QFIRSTPERSONCAMERACONTROLLER_P_H
-#define QT3DEXTRAS_QFIRSTPERSONCAMERACONTROLLER_P_H
-
-#include <Qt3DExtras/qfirstpersoncameracontroller.h>
-#include <QtGui/QVector3D>
-
-#include <Qt3DCore/private/qentity_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.
-//
-
-QT_BEGIN_NAMESPACE
-
-namespace Qt3DRender {
-class QCamera;
-}
-
-namespace Qt3DLogic {
-class QFrameAction;
-}
-
-namespace Qt3DInput {
-
-class QKeyboardDevice;
-class QMouseDevice;
-class QLogicalDevice;
-class QAction;
-class QActionInput;
-class QAxis;
-class QAnalogAxisInput;
-class QButtonAxisInput;
-class QAxisActionHandler;
-
-}
-
-namespace Qt3DExtras {
-
-class QFirstPersonCameraControllerPrivate : public Qt3DCore::QEntityPrivate
-{
-public:
- QFirstPersonCameraControllerPrivate();
-
- void init();
- void applyAccelerations();
-
- Qt3DRender::QCamera *m_camera;
-
- Qt3DInput::QAction *m_leftMouseButtonAction;
- Qt3DInput::QAction *m_fineMotionAction;
-
- Qt3DInput::QAxis *m_rxAxis;
- Qt3DInput::QAxis *m_ryAxis;
- Qt3DInput::QAxis *m_txAxis;
- Qt3DInput::QAxis *m_tyAxis;
- Qt3DInput::QAxis *m_tzAxis;
-
- Qt3DInput::QActionInput *m_leftMouseButtonInput;
- Qt3DInput::QActionInput *m_fineMotionKeyInput;
-
- Qt3DInput::QAnalogAxisInput *m_mouseRxInput;
- Qt3DInput::QAnalogAxisInput *m_mouseRyInput;
- Qt3DInput::QAnalogAxisInput *m_mouseTzXInput;
- Qt3DInput::QAnalogAxisInput *m_mouseTzYInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTxPosInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTyPosInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTzPosInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTxNegInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTyNegInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTzNegInput;
-
- Qt3DInput::QKeyboardDevice *m_keyboardDevice;
- Qt3DInput::QMouseDevice *m_mouseDevice;
-
- Qt3DInput::QLogicalDevice *m_logicalDevice;
-
- Qt3DLogic::QFrameAction *m_frameAction;
-
- float m_linearSpeed;
- float m_lookSpeed;
- float m_acceleration;
- float m_deceleration;
- QVector3D m_firstPersonUp;
-
- void _q_onTriggered(float);
-
- Q_DECLARE_PUBLIC(QFirstPersonCameraController)
-};
-
-} // Qt3DInput
-
-QT_END_NAMESPACE
-
-#endif // QT3DINPUT_QFIRSTPERSONCAMERACONTROLLER_P_H
diff --git a/src/extras/defaults/qforwardrenderer.cpp b/src/extras/defaults/qforwardrenderer.cpp
index f3137ea2d..b02077298 100644
--- a/src/extras/defaults/qforwardrenderer.cpp
+++ b/src/extras/defaults/qforwardrenderer.cpp
@@ -48,6 +48,13 @@
#include <Qt3DRender/qfrustumculling.h>
#include <Qt3DRender/qrendersurfaceselector.h>
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(extras);
+#endif
+}
+
QT_BEGIN_NAMESPACE
using namespace Qt3DRender;
@@ -68,6 +75,8 @@ void QForwardRendererPrivate::init()
{
Q_Q(QForwardRenderer);
+ initResources();
+
m_frustumCulling->setParent(m_clearBuffer);
m_clearBuffer->setParent(m_cameraSelector);
m_cameraSelector->setParent(m_viewport);
diff --git a/src/extras/defaults/qmetalroughmaterial.cpp b/src/extras/defaults/qmetalroughmaterial.cpp
index ea213ab82..4d537f20f 100644
--- a/src/extras/defaults/qmetalroughmaterial.cpp
+++ b/src/extras/defaults/qmetalroughmaterial.cpp
@@ -45,6 +45,7 @@
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
@@ -65,12 +66,19 @@ QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate()
, m_baseColorParameter(new QParameter(QStringLiteral("baseColor"), QColor("grey")))
, m_metalnessParameter(new QParameter(QStringLiteral("metalness"), 0.0f))
, m_roughnessParameter(new QParameter(QStringLiteral("roughness"), 0.0f))
+ , m_baseColorMapParameter(new QParameter(QStringLiteral("baseColorMap"), QVariant()))
+ , m_metalnessMapParameter(new QParameter(QStringLiteral("metalnessMap"), QVariant()))
+ , m_roughnessMapParameter(new QParameter(QStringLiteral("roughnessMap"), QVariant()))
+ , m_ambientOcclusionMapParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), QVariant()))
+ , m_normalMapParameter(new QParameter(QStringLiteral("normalMap"), QVariant()))
+ , m_textureScaleParameter(new QParameter(QStringLiteral("texCoordScale"), 1.0f))
, m_environmentIrradianceParameter(new QParameter(QStringLiteral("envLight.irradiance"), m_environmentIrradianceTexture))
, m_environmentSpecularParameter(new QParameter(QStringLiteral("envLight.specular"), m_environmentSpecularTexture))
, m_metalRoughEffect(new QEffect())
, m_metalRoughGL3Technique(new QTechnique())
, m_metalRoughGL3RenderPass(new QRenderPass())
, m_metalRoughGL3Shader(new QShaderProgram())
+ , m_metalRoughGL3ShaderBuilder(new QShaderProgramBuilder())
, m_filterKey(new QFilterKey)
{
m_environmentIrradianceTexture->setMagnificationFilter(QAbstractTexture::Linear);
@@ -88,22 +96,37 @@ QMetalRoughMaterialPrivate::QMetalRoughMaterialPrivate()
void QMetalRoughMaterialPrivate::init()
{
- connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QMetalRoughMaterialPrivate::handleBaseColorChanged);
- connect(m_metalnessParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QMetalRoughMaterialPrivate::handleMetallicChanged);
- connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QMetalRoughMaterialPrivate::handleRoughnessChanged);
+ Q_Q(QMetalRoughMaterial);
- m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert"))));
- m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalroughuniform.frag"))));
+ QObject::connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QMetalRoughMaterial::baseColorChanged);
+ QObject::connect(m_metalnessParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QMetalRoughMaterial::metalnessChanged);
+ QObject::connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QMetalRoughMaterial::roughnessChanged);
+ QObject::connect(m_ambientOcclusionMapParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QMetalRoughMaterial::roughnessChanged);
+ QObject::connect(m_normalMapParameter, &Qt3DRender::QParameter::valueChanged,
+ q, &QMetalRoughMaterial::normalChanged);
+ connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
+ this, &QMetalRoughMaterialPrivate::handleTextureScaleChanged);
+
+ m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+
+ m_metalRoughGL3ShaderBuilder->setParent(q);
+ m_metalRoughGL3ShaderBuilder->setShaderProgram(m_metalRoughGL3Shader);
+ m_metalRoughGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/metalrough.frag.json")));
+ m_metalRoughGL3ShaderBuilder->setEnabledLayers({QStringLiteral("baseColor"),
+ QStringLiteral("metalness"),
+ QStringLiteral("roughness"),
+ QStringLiteral("ambientOcclusion"),
+ QStringLiteral("normal")});
m_metalRoughGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_metalRoughGL3Technique->graphicsApiFilter()->setMajorVersion(3);
m_metalRoughGL3Technique->graphicsApiFilter()->setMinorVersion(1);
m_metalRoughGL3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
- Q_Q(QMetalRoughMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -116,6 +139,7 @@ void QMetalRoughMaterialPrivate::init()
m_metalRoughEffect->addParameter(m_baseColorParameter);
m_metalRoughEffect->addParameter(m_metalnessParameter);
m_metalRoughEffect->addParameter(m_roughnessParameter);
+ m_metalRoughEffect->addParameter(m_textureScaleParameter);
// Note that even though those parameters are not exposed in the API,
// they need to be kept around for now due to a bug in some drivers/GPUs
@@ -129,21 +153,10 @@ void QMetalRoughMaterialPrivate::init()
q->setEffect(m_metalRoughEffect);
}
-void QMetalRoughMaterialPrivate::handleBaseColorChanged(const QVariant &var)
+void QMetalRoughMaterialPrivate::handleTextureScaleChanged(const QVariant &var)
{
Q_Q(QMetalRoughMaterial);
- emit q->baseColorChanged(var.value<QColor>());
-}
-
-void QMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var)
-{
- Q_Q(QMetalRoughMaterial);
- emit q->metalnessChanged(var.toFloat());
-}
-void QMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var)
-{
- Q_Q(QMetalRoughMaterial);
- emit q->roughnessChanged(var.toFloat());
+ emit q->textureScaleChanged(var.toFloat());
}
/*!
@@ -186,53 +199,181 @@ QMetalRoughMaterial::~QMetalRoughMaterial()
/*!
\property QMetalRoughMaterial::baseColor
- Holds the current base color of the material.
+ Holds the current base color of the material. This can be either a plain
+ color value or a texture. By default the value of this property is "grey".
*/
-QColor QMetalRoughMaterial::baseColor() const
+QVariant QMetalRoughMaterial::baseColor() const
{
Q_D(const QMetalRoughMaterial);
- return d->m_baseColorParameter->value().value<QColor>();
+ return d->m_baseColorParameter->value();
}
/*!
\property QMetalRoughMaterial::metalness
- Holds the current metalness level of the material, since is a value between 0 (purely dielectric, the default)
- and 1 (purely metallic).
+ Holds the current metalness level of the material, since is a value between
+ 0 (purely dielectric, the default) and 1 (purely metallic). This can be
+ either a plain uniform value or a texture. By default the value of this
+ property is 0.
*/
-float QMetalRoughMaterial::metalness() const
+QVariant QMetalRoughMaterial::metalness() const
{
Q_D(const QMetalRoughMaterial);
- return d->m_metalnessParameter->value().toFloat();
+ return d->m_metalnessParameter->value();
}
/*!
\property QMetalRoughMaterial::roughness
- Holds the current roughness level of the material.
+ Holds the current roughness level of the material. This can be either a
+ plain uniform value or a texture. By default the value of this property is
+ 0.
+*/
+QVariant QMetalRoughMaterial::roughness() const
+{
+ Q_D(const QMetalRoughMaterial);
+ return d->m_roughnessParameter->value();
+}
+
+/*!
+ \property QMetalRoughMaterial::ambientOcclusion
+
+ Holds the current ambient occlusion map texture of the material. This can
+ only be a texture, otherwise it is ignored. By default this map is not set.
+*/
+QVariant QMetalRoughMaterial::ambientOcclusion() const
+{
+ Q_D(const QMetalRoughMaterial);
+ return d->m_ambientOcclusionMapParameter->value();
+}
+
+/*!
+ \property QMetalRoughMaterial::normal
+
+ Holds the current normal map texture of the material. This can only be a
+ texture, otherwise it is ignored. By default this map is not set.
*/
-float QMetalRoughMaterial::roughness() const
+QVariant QMetalRoughMaterial::normal() const
{
Q_D(const QMetalRoughMaterial);
- return d->m_roughnessParameter->value().toFloat();
+ return d->m_normalMapParameter->value();
+}
+
+/*!
+ \property QMetalRoughMaterial::textureScale
+
+ Holds the current texture scale. It is applied as a multiplier to texture
+ coordinates at render time. Defaults to 1.0.
+*/
+float QMetalRoughMaterial::textureScale() const
+{
+ Q_D(const QMetalRoughMaterial);
+ return d->m_textureScaleParameter->value().toFloat();
+}
+
+void QMetalRoughMaterial::setBaseColor(const QVariant &baseColor)
+{
+ Q_D(QMetalRoughMaterial);
+ d->m_baseColorParameter->setValue(baseColor);
+ d->m_baseColorMapParameter->setValue(baseColor);
+
+ auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
+ if (baseColor.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("baseColor"));
+ layers.append(QStringLiteral("baseColorMap"));
+ d->m_metalRoughEffect->addParameter(d->m_baseColorMapParameter);
+ d->m_metalRoughEffect->removeParameter(d->m_baseColorParameter);
+ } else {
+ layers.removeAll(QStringLiteral("baseColorMap"));
+ layers.append(QStringLiteral("baseColor"));
+ d->m_metalRoughEffect->removeParameter(d->m_baseColorMapParameter);
+ d->m_metalRoughEffect->addParameter(d->m_baseColorParameter);
+ }
+ d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
+}
+
+void QMetalRoughMaterial::setMetalness(const QVariant &metalness)
+{
+ Q_D(QMetalRoughMaterial);
+ d->m_metalnessParameter->setValue(metalness);
+ d->m_metalnessMapParameter->setValue(metalness);
+
+ auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
+ if (metalness.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("metalness"));
+ layers.append(QStringLiteral("metalnessMap"));
+ d->m_metalRoughEffect->addParameter(d->m_metalnessMapParameter);
+ d->m_metalRoughEffect->removeParameter(d->m_metalnessParameter);
+ } else {
+ layers.removeAll(QStringLiteral("metalnessMap"));
+ layers.append(QStringLiteral("metalness"));
+ d->m_metalRoughEffect->removeParameter(d->m_metalnessMapParameter);
+ d->m_metalRoughEffect->addParameter(d->m_metalnessParameter);
+ }
+ d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
+}
+
+void QMetalRoughMaterial::setRoughness(const QVariant &roughness)
+{
+ Q_D(QMetalRoughMaterial);
+ d->m_roughnessParameter->setValue(roughness);
+ d->m_roughnessMapParameter->setValue(roughness);
+
+ auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
+ if (roughness.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("roughness"));
+ layers.append(QStringLiteral("roughnessMap"));
+ d->m_metalRoughEffect->addParameter(d->m_roughnessMapParameter);
+ d->m_metalRoughEffect->removeParameter(d->m_roughnessParameter);
+ } else {
+ layers.removeAll(QStringLiteral("roughnessMap"));
+ layers.append(QStringLiteral("roughness"));
+ d->m_metalRoughEffect->removeParameter(d->m_roughnessMapParameter);
+ d->m_metalRoughEffect->addParameter(d->m_roughnessParameter);
+ }
+ d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
}
-void QMetalRoughMaterial::setBaseColor(const QColor &baseColor)
+void QMetalRoughMaterial::setAmbientOcclusion(const QVariant &ambientOcclusion)
{
Q_D(QMetalRoughMaterial);
- d->m_baseColorParameter->setValue(QVariant::fromValue(baseColor));
+ d->m_ambientOcclusionMapParameter->setValue(ambientOcclusion);
+
+ auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
+ if (ambientOcclusion.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("ambientOcclusion"));
+ layers.append(QStringLiteral("ambientOcclusionMap"));
+ d->m_metalRoughEffect->addParameter(d->m_ambientOcclusionMapParameter);
+ } else {
+ layers.removeAll(QStringLiteral("ambientOcclusionMap"));
+ layers.append(QStringLiteral("ambientOcclusion"));
+ d->m_metalRoughEffect->removeParameter(d->m_ambientOcclusionMapParameter);
+ }
+ d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
}
-void QMetalRoughMaterial::setMetalness(float metalness)
+void QMetalRoughMaterial::setNormal(const QVariant &normal)
{
Q_D(QMetalRoughMaterial);
- d->m_metalnessParameter->setValue(QVariant::fromValue(metalness));
+ d->m_normalMapParameter->setValue(normal);
+
+ auto layers = d->m_metalRoughGL3ShaderBuilder->enabledLayers();
+ if (normal.value<QAbstractTexture *>()) {
+ layers.removeAll(QStringLiteral("normal"));
+ layers.append(QStringLiteral("normalMap"));
+ d->m_metalRoughEffect->addParameter(d->m_normalMapParameter);
+ } else {
+ layers.removeAll(QStringLiteral("normalMap"));
+ layers.append(QStringLiteral("normal"));
+ d->m_metalRoughEffect->removeParameter(d->m_normalMapParameter);
+ }
+ d->m_metalRoughGL3ShaderBuilder->setEnabledLayers(layers);
}
-void QMetalRoughMaterial::setRoughness(float roughness)
+void QMetalRoughMaterial::setTextureScale(float textureScale)
{
Q_D(QMetalRoughMaterial);
- d->m_roughnessParameter->setValue(QVariant::fromValue(roughness));
+ d->m_textureScaleParameter->setValue(textureScale);
}
} // namespace Qt3DExtras
diff --git a/src/extras/defaults/qmetalroughmaterial.h b/src/extras/defaults/qmetalroughmaterial.h
index 28c9438a7..400437338 100644
--- a/src/extras/defaults/qmetalroughmaterial.h
+++ b/src/extras/defaults/qmetalroughmaterial.h
@@ -57,27 +57,39 @@ class QMetalRoughMaterialPrivate;
class QT3DEXTRASSHARED_EXPORT QMetalRoughMaterial : public Qt3DRender::QMaterial
{
Q_OBJECT
- Q_PROPERTY(QColor baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged)
- Q_PROPERTY(float metalness READ metalness WRITE setMetalness NOTIFY metalnessChanged)
- Q_PROPERTY(float roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged)
+ Q_PROPERTY(QVariant baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged)
+ Q_PROPERTY(QVariant metalness READ metalness WRITE setMetalness NOTIFY metalnessChanged)
+ Q_PROPERTY(QVariant roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged)
+ Q_PROPERTY(QVariant ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged REVISION 10)
+ Q_PROPERTY(QVariant normal READ normal WRITE setNormal NOTIFY normalChanged REVISION 10)
+ Q_PROPERTY(float textureScale READ textureScale WRITE setTextureScale NOTIFY textureScaleChanged REVISION 10)
public:
explicit QMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr);
~QMetalRoughMaterial();
- QColor baseColor() const;
- float metalness() const;
- float roughness() const;
+ QVariant baseColor() const;
+ QVariant metalness() const;
+ QVariant roughness() const;
+ QVariant ambientOcclusion() const;
+ QVariant normal() const;
+ float textureScale() const;
public Q_SLOTS:
- void setBaseColor(const QColor &baseColor);
- void setMetalness(float metalness);
- void setRoughness(float roughness);
+ void setBaseColor(const QVariant &baseColor);
+ void setMetalness(const QVariant &metalness);
+ void setRoughness(const QVariant &roughness);
+ void setAmbientOcclusion(const QVariant &ambientOcclusion);
+ void setNormal(const QVariant &normal);
+ void setTextureScale(float textureScale);
Q_SIGNALS:
- void baseColorChanged(const QColor &baseColor);
- void metalnessChanged(float metalness);
- void roughnessChanged(float roughness);
+ void baseColorChanged(const QVariant &baseColor);
+ void metalnessChanged(const QVariant &metalness);
+ void roughnessChanged(const QVariant &roughness);
+ void ambientOcclusionChanged(const QVariant &ambientOcclusion);
+ void normalChanged(const QVariant &normal);
+ void textureScaleChanged(float textureScale);
protected:
explicit QMetalRoughMaterial(QMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr);
diff --git a/src/extras/defaults/qmetalroughmaterial_p.h b/src/extras/defaults/qmetalroughmaterial_p.h
index 3090b9757..838474490 100644
--- a/src/extras/defaults/qmetalroughmaterial_p.h
+++ b/src/extras/defaults/qmetalroughmaterial_p.h
@@ -63,6 +63,7 @@ class QAbstractTexture;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
} // namespace Qt3DRender
@@ -78,21 +79,26 @@ public:
void init();
- void handleBaseColorChanged(const QVariant &var);
- void handleMetallicChanged(const QVariant &var);
- void handleRoughnessChanged(const QVariant &var);
+ void handleTextureScaleChanged(const QVariant &var);
Qt3DRender::QAbstractTexture *m_environmentIrradianceTexture;
Qt3DRender::QAbstractTexture *m_environmentSpecularTexture;
Qt3DRender::QParameter *m_baseColorParameter;
Qt3DRender::QParameter *m_metalnessParameter;
Qt3DRender::QParameter *m_roughnessParameter;
+ Qt3DRender::QParameter *m_baseColorMapParameter;
+ Qt3DRender::QParameter *m_metalnessMapParameter;
+ Qt3DRender::QParameter *m_roughnessMapParameter;
+ Qt3DRender::QParameter *m_ambientOcclusionMapParameter;
+ Qt3DRender::QParameter *m_normalMapParameter;
+ Qt3DRender::QParameter *m_textureScaleParameter;
Qt3DRender::QParameter *m_environmentIrradianceParameter;
Qt3DRender::QParameter *m_environmentSpecularParameter;
Qt3DRender::QEffect *m_metalRoughEffect;
Qt3DRender::QTechnique *m_metalRoughGL3Technique;
Qt3DRender::QRenderPass *m_metalRoughGL3RenderPass;
Qt3DRender::QShaderProgram *m_metalRoughGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_metalRoughGL3ShaderBuilder;
Qt3DRender::QFilterKey *m_filterKey;
Q_DECLARE_PUBLIC(QMetalRoughMaterial)
diff --git a/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp b/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp
index eb6398341..9b2a64520 100644
--- a/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp
+++ b/src/extras/defaults/qnormaldiffusemapalphamaterial.cpp
@@ -45,6 +45,7 @@
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
#include <Qt3DRender/qalphacoverage.h>
@@ -69,6 +70,8 @@ QNormalDiffuseMapAlphaMaterialPrivate::QNormalDiffuseMapAlphaMaterialPrivate()
void QNormalDiffuseMapAlphaMaterialPrivate::init()
{
+ Q_Q(QNormalDiffuseMapMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QNormalDiffuseMapMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -82,10 +85,21 @@ void QNormalDiffuseMapAlphaMaterialPrivate::init()
connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
this, &QNormalDiffuseMapMaterialPrivate::handleTextureScaleChanged);
- m_normalDiffuseGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/normaldiffusemap.vert"))));
- m_normalDiffuseGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/normaldiffusemapalpha.frag"))));
- m_normalDiffuseGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/normaldiffusemap.vert"))));
- m_normalDiffuseGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/normaldiffusemapalpha.frag"))));
+ m_normalDiffuseGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_normalDiffuseGL3ShaderBuilder->setParent(q);
+ m_normalDiffuseGL3ShaderBuilder->setShaderProgram(m_normalDiffuseGL3Shader);
+ m_normalDiffuseGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_normalDiffuseGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specular"),
+ QStringLiteral("normalTexture")});
+
+ m_normalDiffuseGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_normalDiffuseGL2ES2ShaderBuilder->setParent(q);
+ m_normalDiffuseGL2ES2ShaderBuilder->setShaderProgram(m_normalDiffuseGL2ES2Shader);
+ m_normalDiffuseGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_normalDiffuseGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specular"),
+ QStringLiteral("normalTexture")});
m_normalDiffuseGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_normalDiffuseGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -102,7 +116,6 @@ void QNormalDiffuseMapAlphaMaterialPrivate::init()
m_normalDiffuseES2Technique->graphicsApiFilter()->setMinorVersion(0);
m_normalDiffuseES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
- Q_Q(QNormalDiffuseMapMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -152,6 +165,9 @@ void QNormalDiffuseMapAlphaMaterialPrivate::init()
\since 5.7
\inherits Qt3DExtras::QNormalDiffuseMapMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The specular lighting effect is based on the combination of 3 lighting components ambient,
diffuse and specular. The relative strengths of these components are controlled by means of
their reflectivity coefficients which are modelled as RGB triplets:
diff --git a/src/extras/defaults/qnormaldiffusemapmaterial.cpp b/src/extras/defaults/qnormaldiffusemapmaterial.cpp
index 35cea095a..beed4085e 100644
--- a/src/extras/defaults/qnormaldiffusemapmaterial.cpp
+++ b/src/extras/defaults/qnormaldiffusemapmaterial.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
#include <QtCore/QUrl>
@@ -76,7 +77,9 @@ QNormalDiffuseMapMaterialPrivate::QNormalDiffuseMapMaterialPrivate()
, m_normalDiffuseGL2RenderPass(new QRenderPass())
, m_normalDiffuseES2RenderPass(new QRenderPass())
, m_normalDiffuseGL3Shader(new QShaderProgram())
+ , m_normalDiffuseGL3ShaderBuilder(new QShaderProgramBuilder())
, m_normalDiffuseGL2ES2Shader(new QShaderProgram())
+ , m_normalDiffuseGL2ES2ShaderBuilder(new QShaderProgramBuilder())
, m_filterKey(new QFilterKey)
{
m_diffuseTexture->setMagnificationFilter(QAbstractTexture::Linear);
@@ -94,6 +97,8 @@ QNormalDiffuseMapMaterialPrivate::QNormalDiffuseMapMaterialPrivate()
void QNormalDiffuseMapMaterialPrivate::init()
{
+ Q_Q(QNormalDiffuseMapMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QNormalDiffuseMapMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -107,10 +112,21 @@ void QNormalDiffuseMapMaterialPrivate::init()
connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
this, &QNormalDiffuseMapMaterialPrivate::handleTextureScaleChanged);
- m_normalDiffuseGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/normaldiffusemap.vert"))));
- m_normalDiffuseGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/normaldiffusemap.frag"))));
- m_normalDiffuseGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/normaldiffusemap.vert"))));
- m_normalDiffuseGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/normaldiffusemap.frag"))));
+ m_normalDiffuseGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_normalDiffuseGL3ShaderBuilder->setParent(q);
+ m_normalDiffuseGL3ShaderBuilder->setShaderProgram(m_normalDiffuseGL3Shader);
+ m_normalDiffuseGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_normalDiffuseGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specular"),
+ QStringLiteral("normalTexture")});
+
+ m_normalDiffuseGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_normalDiffuseGL2ES2ShaderBuilder->setParent(q);
+ m_normalDiffuseGL2ES2ShaderBuilder->setShaderProgram(m_normalDiffuseGL2ES2Shader);
+ m_normalDiffuseGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_normalDiffuseGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specular"),
+ QStringLiteral("normalTexture")});
m_normalDiffuseGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_normalDiffuseGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -127,7 +143,6 @@ void QNormalDiffuseMapMaterialPrivate::init()
m_normalDiffuseES2Technique->graphicsApiFilter()->setMinorVersion(0);
m_normalDiffuseES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
- Q_Q(QNormalDiffuseMapMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -203,6 +218,9 @@ void QNormalDiffuseMapMaterialPrivate::handleTextureScaleChanged(const QVariant
\since 5.7
\inherits Qt3DRender::QMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The specular lighting effect is based on the combination of 3 lighting components ambient,
diffuse and specular. The relative strengths of these components are controlled by means of
their reflectivity coefficients which are modelled as RGB triplets:
diff --git a/src/extras/defaults/qnormaldiffusemapmaterial_p.h b/src/extras/defaults/qnormaldiffusemapmaterial_p.h
index d88b01f1f..1ac937b1e 100644
--- a/src/extras/defaults/qnormaldiffusemapmaterial_p.h
+++ b/src/extras/defaults/qnormaldiffusemapmaterial_p.h
@@ -63,6 +63,7 @@ class QAbstractTexture;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
} // namespace Qt3DRender
@@ -101,7 +102,9 @@ public:
Qt3DRender::QRenderPass *m_normalDiffuseGL2RenderPass;
Qt3DRender::QRenderPass *m_normalDiffuseES2RenderPass;
Qt3DRender::QShaderProgram *m_normalDiffuseGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_normalDiffuseGL3ShaderBuilder;
Qt3DRender::QShaderProgram *m_normalDiffuseGL2ES2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_normalDiffuseGL2ES2ShaderBuilder;
Qt3DRender::QFilterKey *m_filterKey;
Q_DECLARE_PUBLIC(QNormalDiffuseMapMaterial)
diff --git a/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp b/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp
index c6f8ced9c..028fd14e7 100644
--- a/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp
+++ b/src/extras/defaults/qnormaldiffusespecularmapmaterial.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
@@ -78,7 +79,9 @@ QNormalDiffuseSpecularMapMaterialPrivate::QNormalDiffuseSpecularMapMaterialPriva
, m_normalDiffuseSpecularGL2RenderPass(new QRenderPass())
, m_normalDiffuseSpecularES2RenderPass(new QRenderPass())
, m_normalDiffuseSpecularGL3Shader(new QShaderProgram())
+ , m_normalDiffuseSpecularGL3ShaderBuilder(new QShaderProgramBuilder())
, m_normalDiffuseSpecularGL2ES2Shader(new QShaderProgram())
+ , m_normalDiffuseSpecularGL2ES2ShaderBuilder(new QShaderProgramBuilder())
, m_filterKey(new QFilterKey)
{
m_diffuseTexture->setMagnificationFilter(QAbstractTexture::Linear);
@@ -102,6 +105,8 @@ QNormalDiffuseSpecularMapMaterialPrivate::QNormalDiffuseSpecularMapMaterialPriva
void QNormalDiffuseSpecularMapMaterialPrivate::init()
{
+ Q_Q(QNormalDiffuseSpecularMapMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QNormalDiffuseSpecularMapMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -115,10 +120,21 @@ void QNormalDiffuseSpecularMapMaterialPrivate::init()
connect(m_textureScaleParameter, &Qt3DRender::QParameter::valueChanged,
this, &QNormalDiffuseSpecularMapMaterialPrivate::handleTextureScaleChanged);
- m_normalDiffuseSpecularGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/normaldiffusemap.vert"))));
- m_normalDiffuseSpecularGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/normaldiffusespecularmap.frag"))));
- m_normalDiffuseSpecularGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/normaldiffusemap.vert"))));
- m_normalDiffuseSpecularGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/normaldiffusespecularmap.frag"))));
+ m_normalDiffuseSpecularGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_normalDiffuseSpecularGL3ShaderBuilder->setParent(q);
+ m_normalDiffuseSpecularGL3ShaderBuilder->setShaderProgram(m_normalDiffuseSpecularGL3Shader);
+ m_normalDiffuseSpecularGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_normalDiffuseSpecularGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specularTexture"),
+ QStringLiteral("normalTexture")});
+
+ m_normalDiffuseSpecularGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_normalDiffuseSpecularGL2ES2ShaderBuilder->setParent(q);
+ m_normalDiffuseSpecularGL2ES2ShaderBuilder->setShaderProgram(m_normalDiffuseSpecularGL2ES2Shader);
+ m_normalDiffuseSpecularGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_normalDiffuseSpecularGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuseTexture"),
+ QStringLiteral("specularTexture"),
+ QStringLiteral("normalTexture")});
m_normalDiffuseSpecularGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_normalDiffuseSpecularGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -135,7 +151,6 @@ void QNormalDiffuseSpecularMapMaterialPrivate::init()
m_normalDiffuseSpecularES2Technique->graphicsApiFilter()->setMinorVersion(0);
m_normalDiffuseSpecularES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
- Q_Q(QNormalDiffuseSpecularMapMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -211,6 +226,9 @@ void QNormalDiffuseSpecularMapMaterialPrivate::handleTextureScaleChanged(const Q
\since 5.7
\inherits Qt3DRender::QMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The specular lighting effect is based on the combination of 3 lighting components ambient,
diffuse and specular. The relative strengths of these components are controlled by means of
their reflectivity coefficients which are modelled as RGB triplets:
diff --git a/src/extras/defaults/qnormaldiffusespecularmapmaterial_p.h b/src/extras/defaults/qnormaldiffusespecularmapmaterial_p.h
index 3316044ff..e02451cc0 100644
--- a/src/extras/defaults/qnormaldiffusespecularmapmaterial_p.h
+++ b/src/extras/defaults/qnormaldiffusespecularmapmaterial_p.h
@@ -63,6 +63,7 @@ class QAbstractTexture;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
} // namespace Qt3DRender
@@ -102,7 +103,9 @@ public:
Qt3DRender::QRenderPass *m_normalDiffuseSpecularGL2RenderPass;
Qt3DRender::QRenderPass *m_normalDiffuseSpecularES2RenderPass;
Qt3DRender::QShaderProgram *m_normalDiffuseSpecularGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_normalDiffuseSpecularGL3ShaderBuilder;
Qt3DRender::QShaderProgram *m_normalDiffuseSpecularGL2ES2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_normalDiffuseSpecularGL2ES2ShaderBuilder;
Qt3DRender::QFilterKey *m_filterKey;
Q_DECLARE_PUBLIC(QNormalDiffuseSpecularMapMaterial)
diff --git a/src/extras/defaults/qorbitcameracontroller.cpp b/src/extras/defaults/qorbitcameracontroller.cpp
index 565a75ea1..c4f976f89 100644
--- a/src/extras/defaults/qorbitcameracontroller.cpp
+++ b/src/extras/defaults/qorbitcameracontroller.cpp
@@ -38,22 +38,15 @@
#include "qorbitcameracontroller_p.h"
#include <Qt3DRender/QCamera>
-#include <Qt3DInput/QAxis>
-#include <Qt3DInput/QAnalogAxisInput>
-#include <Qt3DInput/QButtonAxisInput>
-#include <Qt3DInput/QAction>
-#include <Qt3DInput/QActionInput>
-#include <Qt3DInput/QLogicalDevice>
-#include <Qt3DInput/QKeyboardDevice>
-#include <Qt3DInput/QMouseDevice>
-#include <Qt3DInput/QMouseEvent>
-#include <Qt3DLogic/QFrameAction>
-#include <QtCore/QtGlobal>
QT_BEGIN_NAMESPACE
namespace Qt3DExtras {
+QOrbitCameraControllerPrivate::QOrbitCameraControllerPrivate()
+ : m_zoomInLimit(2.0f)
+{}
+
/*!
\class Qt3DExtras::QOrbitCameraController
\brief The QOrbitCameraController class allows controlling the scene camera along orbital path.
@@ -99,251 +92,20 @@ namespace Qt3DExtras {
\endtable
*/
-QOrbitCameraControllerPrivate::QOrbitCameraControllerPrivate()
- : Qt3DCore::QEntityPrivate()
- , m_camera(nullptr)
- , m_leftMouseButtonAction(new Qt3DInput::QAction())
- , m_rightMouseButtonAction(new Qt3DInput::QAction())
- , m_altButtonAction(new Qt3DInput::QAction())
- , m_shiftButtonAction(new Qt3DInput::QAction())
- , m_rxAxis(new Qt3DInput::QAxis())
- , m_ryAxis(new Qt3DInput::QAxis())
- , m_txAxis(new Qt3DInput::QAxis())
- , m_tyAxis(new Qt3DInput::QAxis())
- , m_tzAxis(new Qt3DInput::QAxis())
- , m_leftMouseButtonInput(new Qt3DInput::QActionInput())
- , m_rightMouseButtonInput(new Qt3DInput::QActionInput())
- , m_altButtonInput(new Qt3DInput::QActionInput())
- , m_shiftButtonInput(new Qt3DInput::QActionInput())
- , m_mouseRxInput(new Qt3DInput::QAnalogAxisInput())
- , m_mouseRyInput(new Qt3DInput::QAnalogAxisInput())
- , m_mouseTzXInput(new Qt3DInput::QAnalogAxisInput())
- , m_mouseTzYInput(new Qt3DInput::QAnalogAxisInput())
- , m_keyboardTxPosInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTyPosInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTzPosInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTxNegInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTyNegInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardTzNegInput(new Qt3DInput::QButtonAxisInput())
- , m_keyboardDevice(new Qt3DInput::QKeyboardDevice())
- , m_mouseDevice(new Qt3DInput::QMouseDevice())
- , m_logicalDevice(new Qt3DInput::QLogicalDevice())
- , m_frameAction(new Qt3DLogic::QFrameAction())
- , m_linearSpeed(10.0f)
- , m_lookSpeed(180.0f)
- , m_zoomInLimit(2.0f)
- , m_cameraUp(QVector3D(0.0f, 1.0f, 0.0f))
-{}
-
-void QOrbitCameraControllerPrivate::init()
-{
- //// Actions
-
- // Left Mouse Button Action
- m_leftMouseButtonInput->setButtons(QVector<int>() << Qt::LeftButton);
- m_leftMouseButtonInput->setSourceDevice(m_mouseDevice);
- m_leftMouseButtonAction->addInput(m_leftMouseButtonInput);
-
- // Right Mouse Button Action
- m_rightMouseButtonInput->setButtons(QVector<int>() << Qt::RightButton);
- m_rightMouseButtonInput->setSourceDevice(m_mouseDevice);
- m_rightMouseButtonAction->addInput(m_rightMouseButtonInput);
-
- // Alt Button Action
- m_altButtonInput->setButtons(QVector<int>() << Qt::Key_Alt);
- m_altButtonInput->setSourceDevice(m_keyboardDevice);
- m_altButtonAction->addInput(m_altButtonInput);
-
- // Shift Button Action
- m_shiftButtonInput->setButtons(QVector<int>() << Qt::Key_Shift);
- m_shiftButtonInput->setSourceDevice(m_keyboardDevice);
- m_shiftButtonAction->addInput(m_shiftButtonInput);
-
- //// Axes
-
- // Mouse X
- m_mouseRxInput->setAxis(Qt3DInput::QMouseDevice::X);
- m_mouseRxInput->setSourceDevice(m_mouseDevice);
- m_rxAxis->addInput(m_mouseRxInput);
-
- // Mouse Y
- m_mouseRyInput->setAxis(Qt3DInput::QMouseDevice::Y);
- m_mouseRyInput->setSourceDevice(m_mouseDevice);
- m_ryAxis->addInput(m_mouseRyInput);
-
- // Mouse Wheel X
- m_mouseTzXInput->setAxis(Qt3DInput::QMouseDevice::WheelX);
- m_mouseTzXInput->setSourceDevice(m_mouseDevice);
- m_tzAxis->addInput(m_mouseTzXInput);
-
- // Mouse Wheel Y
- m_mouseTzYInput->setAxis(Qt3DInput::QMouseDevice::WheelY);
- m_mouseTzYInput->setSourceDevice(m_mouseDevice);
- m_tzAxis->addInput(m_mouseTzYInput);
-
- // Keyboard Pos Tx
- m_keyboardTxPosInput->setButtons(QVector<int>() << Qt::Key_Right);
- m_keyboardTxPosInput->setScale(1.0f);
- m_keyboardTxPosInput->setSourceDevice(m_keyboardDevice);
- m_txAxis->addInput(m_keyboardTxPosInput);
-
- // Keyboard Pos Tz
- m_keyboardTzPosInput->setButtons(QVector<int>() << Qt::Key_PageUp);
- m_keyboardTzPosInput->setScale(1.0f);
- m_keyboardTzPosInput->setSourceDevice(m_keyboardDevice);
- m_tzAxis->addInput(m_keyboardTzPosInput);
-
- // Keyboard Pos Ty
- m_keyboardTyPosInput->setButtons(QVector<int>() << Qt::Key_Up);
- m_keyboardTyPosInput->setScale(1.0f);
- m_keyboardTyPosInput->setSourceDevice(m_keyboardDevice);
- m_tyAxis->addInput(m_keyboardTyPosInput);
-
- // Keyboard Neg Tx
- m_keyboardTxNegInput->setButtons(QVector<int>() << Qt::Key_Left);
- m_keyboardTxNegInput->setScale(-1.0f);
- m_keyboardTxNegInput->setSourceDevice(m_keyboardDevice);
- m_txAxis->addInput(m_keyboardTxNegInput);
-
- // Keyboard Neg Tz
- m_keyboardTzNegInput->setButtons(QVector<int>() << Qt::Key_PageDown);
- m_keyboardTzNegInput->setScale(-1.0f);
- m_keyboardTzNegInput->setSourceDevice(m_keyboardDevice);
- m_tzAxis->addInput(m_keyboardTzNegInput);
-
- // Keyboard Neg Ty
- m_keyboardTyNegInput->setButtons(QVector<int>() << Qt::Key_Down);
- m_keyboardTyNegInput->setScale(-1.0f);
- m_keyboardTyNegInput->setSourceDevice(m_keyboardDevice);
- m_tyAxis->addInput(m_keyboardTyNegInput);
-
- //// Logical Device
-
- m_logicalDevice->addAction(m_leftMouseButtonAction);
- m_logicalDevice->addAction(m_rightMouseButtonAction);
- m_logicalDevice->addAction(m_altButtonAction);
- m_logicalDevice->addAction(m_shiftButtonAction);
- m_logicalDevice->addAxis(m_rxAxis);
- m_logicalDevice->addAxis(m_ryAxis);
- m_logicalDevice->addAxis(m_txAxis);
- m_logicalDevice->addAxis(m_tyAxis);
- m_logicalDevice->addAxis(m_tzAxis);
-
- Q_Q(QOrbitCameraController);
- //// FrameAction
-
- QObject::connect(m_frameAction, SIGNAL(triggered(float)),
- q, SLOT(_q_onTriggered(float)));
-
- // Disable the logical device when the entity is disabled
- QObject::connect(q, &Qt3DCore::QEntity::enabledChanged,
- m_logicalDevice, &Qt3DInput::QLogicalDevice::setEnabled);
-
- q->addComponent(m_frameAction);
- q->addComponent(m_logicalDevice);
-}
-
-float clampInputs(float input1, float input2)
-{
- float axisValue = input1 + input2;
- return (axisValue < -1) ? -1 : (axisValue > 1) ? 1 : axisValue;
-}
-
-float zoomDistance(QVector3D firstPoint, QVector3D secondPoint)
-{
- return (secondPoint - firstPoint).lengthSquared();
-}
-
-void QOrbitCameraControllerPrivate::_q_onTriggered(float dt)
-{
- if (m_camera != nullptr) {
- // Mouse input
- if (m_leftMouseButtonAction->isActive()) {
- if (m_rightMouseButtonAction->isActive()) {
- if ( zoomDistance(m_camera->position(), m_camera->viewCenter()) > m_zoomInLimit * m_zoomInLimit) {
- // Dolly up to limit
- m_camera->translate(QVector3D(0, 0, m_ryAxis->value()), m_camera->DontTranslateViewCenter);
- } else {
- m_camera->translate(QVector3D(0, 0, -0.5), m_camera->DontTranslateViewCenter);
- }
- } else {
- // Translate
- m_camera->translate(QVector3D(clampInputs(m_rxAxis->value(), m_txAxis->value()) * m_linearSpeed,
- clampInputs(m_ryAxis->value(), m_tyAxis->value()) * m_linearSpeed,
- 0) * dt);
- }
- return;
- }
- else if (m_rightMouseButtonAction->isActive()) {
- // Orbit
- m_camera->panAboutViewCenter((m_rxAxis->value() * m_lookSpeed) * dt, m_cameraUp);
- m_camera->tiltAboutViewCenter((m_ryAxis->value() * m_lookSpeed) * dt);
- }
- // Keyboard Input
- if (m_altButtonAction->isActive()) {
- // Orbit
- m_camera->panAboutViewCenter((m_txAxis->value() * m_lookSpeed) * dt, m_cameraUp);
- m_camera->tiltAboutViewCenter((m_tyAxis->value() * m_lookSpeed) * dt);
- } else if (m_shiftButtonAction->isActive()) {
- if (zoomDistance(m_camera->position(), m_camera->viewCenter()) > m_zoomInLimit * m_zoomInLimit) {
- // Dolly
- m_camera->translate(QVector3D(0, 0, m_tyAxis->value()), m_camera->DontTranslateViewCenter);
- } else {
- m_camera->translate(QVector3D(0, 0, -0.5), m_camera->DontTranslateViewCenter);
- }
- } else {
- // Translate
- m_camera->translate(QVector3D(clampInputs(m_leftMouseButtonAction->isActive() ? m_rxAxis->value() : 0, m_txAxis->value()) * m_linearSpeed,
- clampInputs(m_leftMouseButtonAction->isActive() ? m_ryAxis->value() : 0, m_tyAxis->value()) * m_linearSpeed,
- m_tzAxis->value() * m_linearSpeed) * dt);
- }
- }
-}
-
QOrbitCameraController::QOrbitCameraController(Qt3DCore::QNode *parent)
- : Qt3DCore::QEntity(*new QOrbitCameraControllerPrivate, parent)
+ : QOrbitCameraController(*new QOrbitCameraControllerPrivate, parent)
{
- Q_D(QOrbitCameraController);
- d->init();
}
-QOrbitCameraController::~QOrbitCameraController()
+/*! \internal
+ */
+QOrbitCameraController::QOrbitCameraController(QOrbitCameraControllerPrivate &dd, Qt3DCore::QNode *parent)
+ : QAbstractCameraController(dd, parent)
{
}
-/*!
- \property QOrbitCameraController::camera
-
- Holds the currently controlled camera.
-*/
-Qt3DRender::QCamera *QOrbitCameraController::camera() const
-{
- Q_D(const QOrbitCameraController);
- return d->m_camera;
-}
-
-/*!
- \property QOrbitCameraController::linearSpeed
-
- Holds the current linear speed of the camera controller. Linear speed determines the
- movement speed of the camera.
-*/
-float QOrbitCameraController::linearSpeed() const
-{
- Q_D(const QOrbitCameraController);
- return d->m_linearSpeed;
-}
-
-/*!
- \property QOrbitCameraController::lookSpeed
-
- Holds the current look speed of the camera controller. The look speed determines the turn rate
- of the camera pan and tilt.
-*/
-float QOrbitCameraController::lookSpeed() const
+QOrbitCameraController::~QOrbitCameraController()
{
- Q_D(const QOrbitCameraController);
- return d->m_lookSpeed;
}
/*!
@@ -358,51 +120,77 @@ float QOrbitCameraController::zoomInLimit() const
return d->m_zoomInLimit;
}
-void QOrbitCameraController::setCamera(Qt3DRender::QCamera *camera)
+void QOrbitCameraController::setZoomInLimit(float zoomInLimit)
{
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();
+ if (d->m_zoomInLimit != zoomInLimit) {
+ d->m_zoomInLimit = zoomInLimit;
+ emit zoomInLimitChanged();
}
}
-void QOrbitCameraController::setLinearSpeed(float linearSpeed)
+inline float clampInputs(float input1, float input2)
{
- Q_D(QOrbitCameraController);
- if (d->m_linearSpeed != linearSpeed) {
- d->m_linearSpeed = linearSpeed;
- emit linearSpeedChanged();
- }
+ float axisValue = input1 + input2;
+ return (axisValue < -1) ? -1 : (axisValue > 1) ? 1 : axisValue;
}
-void QOrbitCameraController::setLookSpeed(float lookSpeed)
+inline float zoomDistance(QVector3D firstPoint, QVector3D secondPoint)
{
- Q_D(QOrbitCameraController);
- if (d->m_lookSpeed != lookSpeed) {
- d->m_lookSpeed = lookSpeed;
- emit lookSpeedChanged();
- }
+ return (secondPoint - firstPoint).lengthSquared();
}
-void QOrbitCameraController::setZoomInLimit(float zoomInLimit)
+void QOrbitCameraController::moveCamera(const QAbstractCameraController::InputState &state, float dt)
{
Q_D(QOrbitCameraController);
- if (d->m_zoomInLimit != zoomInLimit) {
- d->m_zoomInLimit = zoomInLimit;
- emit zoomInLimitChanged();
+
+ Qt3DRender::QCamera *theCamera = camera();
+
+ if (theCamera == nullptr)
+ return;
+
+ const QVector3D upVector(0.0f, 1.0f, 0.0f);
+
+ // Mouse input
+ if (state.leftMouseButtonActive) {
+ if (state.rightMouseButtonActive) {
+ if ( zoomDistance(camera()->position(), theCamera->viewCenter()) > d->m_zoomInLimit * d->m_zoomInLimit) {
+ // Dolly up to limit
+ theCamera->translate(QVector3D(0, 0, state.ryAxisValue), theCamera->DontTranslateViewCenter);
+ } else {
+ theCamera->translate(QVector3D(0, 0, -0.5), theCamera->DontTranslateViewCenter);
+ }
+ } else {
+ // Translate
+ theCamera->translate(QVector3D(clampInputs(state.rxAxisValue, state.txAxisValue) * linearSpeed(),
+ clampInputs(state.ryAxisValue, state.tyAxisValue) * linearSpeed(),
+ 0) * dt);
+ }
+ return;
+ }
+ else if (state.rightMouseButtonActive) {
+ // Orbit
+ theCamera->panAboutViewCenter((state.rxAxisValue * lookSpeed()) * dt, upVector);
+ theCamera->tiltAboutViewCenter((state.ryAxisValue * lookSpeed()) * dt);
+ }
+
+ // Keyboard Input
+ if (state.altKeyActive) {
+ // Orbit
+ theCamera->panAboutViewCenter((state.txAxisValue * lookSpeed()) * dt, upVector);
+ theCamera->tiltAboutViewCenter((state.tyAxisValue * lookSpeed()) * dt);
+ } else if (state.shiftKeyActive) {
+ if (zoomDistance(camera()->position(), theCamera->viewCenter()) > d->m_zoomInLimit * d->m_zoomInLimit) {
+ // Dolly
+ theCamera->translate(QVector3D(0, 0, state.tyAxisValue * linearSpeed() * dt), theCamera->DontTranslateViewCenter);
+ } else {
+ theCamera->translate(QVector3D(0, 0, -0.5), theCamera->DontTranslateViewCenter);
+ }
+ } else {
+ // Translate
+ theCamera->translate(QVector3D(clampInputs(state.leftMouseButtonActive ? state.rxAxisValue : 0, state.txAxisValue) * linearSpeed(),
+ clampInputs(state.leftMouseButtonActive ? state.ryAxisValue : 0, state.tyAxisValue) * linearSpeed(),
+ state.tzAxisValue * linearSpeed()) * dt);
}
}
diff --git a/src/extras/defaults/qorbitcameracontroller.h b/src/extras/defaults/qorbitcameracontroller.h
index 7cb8b3eb7..684bfddf1 100644
--- a/src/extras/defaults/qorbitcameracontroller.h
+++ b/src/extras/defaults/qorbitcameracontroller.h
@@ -37,50 +37,38 @@
#ifndef QT3DEXTRAS_QORBITCAMERACONTROLLER_H
#define QT3DEXTRAS_QORBITCAMERACONTROLLER_H
-#include <Qt3DCore/QEntity>
-#include <Qt3DExtras/qt3dextras_global.h>
+#include <Qt3DExtras/qabstractcameracontroller.h>
QT_BEGIN_NAMESPACE
-namespace Qt3DRender {
-class QCamera;
-}
-
namespace Qt3DExtras {
class QOrbitCameraControllerPrivate;
-class QT3DEXTRASSHARED_EXPORT QOrbitCameraController : public Qt3DCore::QEntity
+class QT3DEXTRASSHARED_EXPORT QOrbitCameraController : public QAbstractCameraController
{
Q_OBJECT
- Q_PROPERTY(Qt3DRender::QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged)
- Q_PROPERTY(float linearSpeed READ linearSpeed WRITE setLinearSpeed NOTIFY linearSpeedChanged)
- Q_PROPERTY(float lookSpeed READ lookSpeed WRITE setLookSpeed NOTIFY lookSpeedChanged)
Q_PROPERTY(float zoomInLimit READ zoomInLimit WRITE setZoomInLimit NOTIFY zoomInLimitChanged)
public:
explicit QOrbitCameraController(Qt3DCore::QNode *parent = nullptr);
~QOrbitCameraController();
- Qt3DRender::QCamera *camera() const;
- float linearSpeed() const;
- float lookSpeed() const;
float zoomInLimit() const;
- void setCamera(Qt3DRender::QCamera *camera);
- void setLinearSpeed(float linearSpeed);
- void setLookSpeed(float lookSpeed);
void setZoomInLimit(float zoomInLimit);
Q_SIGNALS:
- void cameraChanged();
- void linearSpeedChanged();
- void lookSpeedChanged();
void zoomInLimitChanged();
+protected:
+ QOrbitCameraController(QOrbitCameraControllerPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ void moveCamera(const QAbstractCameraController::InputState &state, float dt) override;
+
private:
Q_DECLARE_PRIVATE(QOrbitCameraController)
- Q_PRIVATE_SLOT(d_func(), void _q_onTriggered(float))
};
} // Qt3DExtras
diff --git a/src/extras/defaults/qorbitcameracontroller_p.h b/src/extras/defaults/qorbitcameracontroller_p.h
index 8105d4375..1e4e3d4d2 100644
--- a/src/extras/defaults/qorbitcameracontroller_p.h
+++ b/src/extras/defaults/qorbitcameracontroller_p.h
@@ -48,88 +48,25 @@
// We mean it.
//
-#include <Qt3DExtras/qorbitcameracontroller.h>
-#include <QtGui/QVector3D>
-
-#include <Qt3DCore/private/qentity_p.h>
+#include <Qt3DExtras/private/qabstractcameracontroller_p.h>
QT_BEGIN_NAMESPACE
-namespace Qt3DRender {
-class QCamera;
-}
-
-namespace Qt3DLogic {
-class QFrameAction;
-}
-
-namespace Qt3DInput {
-
-class QKeyboardDevice;
-class QMouseDevice;
-class QLogicalDevice;
-class QAction;
-class QActionInput;
-class QAxis;
-class QAnalogAxisInput;
-class QButtonAxisInput;
-class QAxisActionHandler;
-
-}
-
namespace Qt3DExtras {
-class QOrbitCameraControllerPrivate : public Qt3DCore::QEntityPrivate
+class QOrbitCameraControllerPrivate : public QAbstractCameraControllerPrivate
{
+ Q_DECLARE_PUBLIC(QOrbitCameraController)
+
public:
QOrbitCameraControllerPrivate();
void init();
- Qt3DRender::QCamera *m_camera;
-
- Qt3DInput::QAction *m_leftMouseButtonAction;
- Qt3DInput::QAction *m_rightMouseButtonAction;
- Qt3DInput::QAction *m_altButtonAction;
- Qt3DInput::QAction *m_shiftButtonAction;
-
- Qt3DInput::QAxis *m_rxAxis;
- Qt3DInput::QAxis *m_ryAxis;
- Qt3DInput::QAxis *m_txAxis;
- Qt3DInput::QAxis *m_tyAxis;
- Qt3DInput::QAxis *m_tzAxis;
-
- Qt3DInput::QActionInput *m_leftMouseButtonInput;
- Qt3DInput::QActionInput *m_rightMouseButtonInput;
- Qt3DInput::QActionInput *m_altButtonInput;
- Qt3DInput::QActionInput *m_shiftButtonInput;
-
- Qt3DInput::QAnalogAxisInput *m_mouseRxInput;
- Qt3DInput::QAnalogAxisInput *m_mouseRyInput;
- Qt3DInput::QAnalogAxisInput *m_mouseTzXInput;
- Qt3DInput::QAnalogAxisInput *m_mouseTzYInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTxPosInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTyPosInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTzPosInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTxNegInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTyNegInput;
- Qt3DInput::QButtonAxisInput *m_keyboardTzNegInput;
-
- Qt3DInput::QKeyboardDevice *m_keyboardDevice;
- Qt3DInput::QMouseDevice *m_mouseDevice;
-
- Qt3DInput::QLogicalDevice *m_logicalDevice;
-
- Qt3DLogic::QFrameAction *m_frameAction;
-
- float m_linearSpeed;
- float m_lookSpeed;
float m_zoomInLimit;
- QVector3D m_cameraUp;
- void _q_onTriggered(float);
-
- Q_DECLARE_PUBLIC(QOrbitCameraController)
+private:
+ QOrbitCameraController *q_ptr;
};
} // namespace Qt3DExtras
diff --git a/src/extras/defaults/qphongalphamaterial.cpp b/src/extras/defaults/qphongalphamaterial.cpp
index d7f054d71..24cff94e9 100644
--- a/src/extras/defaults/qphongalphamaterial.cpp
+++ b/src/extras/defaults/qphongalphamaterial.cpp
@@ -45,6 +45,7 @@
#include <Qt3DRender/qeffect.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
@@ -65,10 +66,9 @@ QPhongAlphaMaterialPrivate::QPhongAlphaMaterialPrivate()
: QMaterialPrivate()
, m_phongEffect(new QEffect())
, m_ambientParameter(new QParameter(QStringLiteral("ka"), QColor::fromRgbF(0.05f, 0.05f, 0.05f, 1.0f)))
- , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(0.7f, 0.7f, 0.7f, 1.0f)))
+ , m_diffuseParameter(new QParameter(QStringLiteral("kd"), QColor::fromRgbF(0.7f, 0.7f, 0.7f, 0.5f)))
, m_specularParameter(new QParameter(QStringLiteral("ks"), QColor::fromRgbF(0.01f, 0.01f, 0.01f, 1.0f)))
, m_shininessParameter(new QParameter(QStringLiteral("shininess"), 150.0f))
- , m_alphaParameter(new QParameter(QStringLiteral("alpha"), 0.5f))
, m_phongAlphaGL3Technique(new QTechnique())
, m_phongAlphaGL2Technique(new QTechnique())
, m_phongAlphaES2Technique(new QTechnique())
@@ -76,7 +76,9 @@ QPhongAlphaMaterialPrivate::QPhongAlphaMaterialPrivate()
, m_phongAlphaGL2RenderPass(new QRenderPass())
, m_phongAlphaES2RenderPass(new QRenderPass())
, m_phongAlphaGL3Shader(new QShaderProgram())
+ , m_phongAlphaGL3ShaderBuilder(new QShaderProgramBuilder())
, m_phongAlphaGL2ES2Shader(new QShaderProgram())
+ , m_phongAlphaGL2ES2ShaderBuilder(new QShaderProgramBuilder())
, m_noDepthMask(new QNoDepthMask())
, m_blendState(new QBlendEquationArguments())
, m_blendEquation(new QBlendEquation())
@@ -87,6 +89,8 @@ QPhongAlphaMaterialPrivate::QPhongAlphaMaterialPrivate()
// TODO: Define how lights are properties are set in the shaders. Ideally using a QShaderData
void QPhongAlphaMaterialPrivate::init()
{
+ Q_Q(QPhongAlphaMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QPhongAlphaMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -95,13 +99,22 @@ void QPhongAlphaMaterialPrivate::init()
this, &QPhongAlphaMaterialPrivate::handleSpecularChanged);
connect(m_shininessParameter, &Qt3DRender::QParameter::valueChanged,
this, &QPhongAlphaMaterialPrivate::handleShininessChanged);
- connect(m_alphaParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QPhongAlphaMaterialPrivate::handleAlphaChanged);
- m_phongAlphaGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/phong.vert"))));
- m_phongAlphaGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/phongalpha.frag"))));
- m_phongAlphaGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/phong.vert"))));
- m_phongAlphaGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/phongalpha.frag"))));
+ m_phongAlphaGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_phongAlphaGL3ShaderBuilder->setParent(q);
+ m_phongAlphaGL3ShaderBuilder->setShaderProgram(m_phongAlphaGL3Shader);
+ m_phongAlphaGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_phongAlphaGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
+
+ m_phongAlphaGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_phongAlphaGL2ES2ShaderBuilder->setParent(q);
+ m_phongAlphaGL2ES2ShaderBuilder->setShaderProgram(m_phongAlphaGL2ES2Shader);
+ m_phongAlphaGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_phongAlphaGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
m_phongAlphaGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_phongAlphaGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -118,7 +131,6 @@ void QPhongAlphaMaterialPrivate::init()
m_phongAlphaES2Technique->graphicsApiFilter()->setMinorVersion(0);
m_phongAlphaES2Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::NoProfile);
- Q_Q(QPhongAlphaMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -159,7 +171,6 @@ void QPhongAlphaMaterialPrivate::init()
m_phongEffect->addParameter(m_diffuseParameter);
m_phongEffect->addParameter(m_specularParameter);
m_phongEffect->addParameter(m_shininessParameter);
- m_phongEffect->addParameter(m_alphaParameter);
q->setEffect(m_phongEffect);
}
@@ -174,6 +185,7 @@ void QPhongAlphaMaterialPrivate::handleDiffuseChanged(const QVariant &var)
{
Q_Q(QPhongAlphaMaterial);
emit q->diffuseChanged(var.value<QColor>());
+ emit q->alphaChanged(var.value<QColor>().alphaF());
}
void QPhongAlphaMaterialPrivate::handleSpecularChanged(const QVariant &var)
@@ -188,12 +200,6 @@ void QPhongAlphaMaterialPrivate::handleShininessChanged(const QVariant &var)
emit q->shininessChanged(var.toFloat());
}
-void QPhongAlphaMaterialPrivate::handleAlphaChanged(const QVariant &var)
-{
- Q_Q(QPhongAlphaMaterial);
- emit q->alphaChanged(var.toFloat());
-}
-
/*!
\class Qt3DExtras::QPhongAlphaMaterial
@@ -203,6 +209,9 @@ void QPhongAlphaMaterialPrivate::handleAlphaChanged(const QVariant &var)
\since 5.7
\inherits Qt3DRender::QMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The phong lighting effect is based on the combination of 3 lighting components ambient, diffuse
and specular. The relative strengths of these components are controlled by means of their
reflectivity coefficients which are modelled as RGB triplets:
@@ -301,7 +310,7 @@ float QPhongAlphaMaterial::shininess() const
float QPhongAlphaMaterial::alpha() const
{
Q_D(const QPhongAlphaMaterial);
- return d->m_alphaParameter->value().toFloat();
+ return d->m_diffuseParameter->value().value<QColor>().alphaF();
}
/*!
@@ -378,7 +387,10 @@ void QPhongAlphaMaterial::setAmbient(const QColor &ambient)
void QPhongAlphaMaterial::setDiffuse(const QColor &diffuse)
{
Q_D(QPhongAlphaMaterial);
- d->m_diffuseParameter->setValue(diffuse);
+ QColor currentDiffuse = d->m_diffuseParameter->value().value<QColor>();
+ QColor newDiffuse = diffuse;
+ newDiffuse.setAlphaF(currentDiffuse.alphaF());
+ d->m_diffuseParameter->setValue(newDiffuse);
}
void QPhongAlphaMaterial::setSpecular(const QColor &specular)
@@ -396,7 +408,9 @@ void QPhongAlphaMaterial::setShininess(float shininess)
void QPhongAlphaMaterial::setAlpha(float alpha)
{
Q_D(QPhongAlphaMaterial);
- d->m_alphaParameter->setValue(alpha);
+ QColor diffuse = d->m_diffuseParameter->value().value<QColor>();
+ diffuse.setAlphaF(alpha);
+ d->m_diffuseParameter->setValue(diffuse);
}
void QPhongAlphaMaterial::setSourceRgbArg(QBlendEquationArguments::Blending sourceRgbArg)
diff --git a/src/extras/defaults/qphongalphamaterial_p.h b/src/extras/defaults/qphongalphamaterial_p.h
index 623eca0ea..97eaf7bc4 100644
--- a/src/extras/defaults/qphongalphamaterial_p.h
+++ b/src/extras/defaults/qphongalphamaterial_p.h
@@ -62,6 +62,7 @@ class QEffect;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
class QNoDepthMask;
class QBlendEquationArguments;
@@ -84,14 +85,12 @@ public:
void handleDiffuseChanged(const QVariant &var);
void handleSpecularChanged(const QVariant &var);
void handleShininessChanged(const QVariant &var);
- void handleAlphaChanged(const QVariant &var);
Qt3DRender::QEffect *m_phongEffect;
Qt3DRender::QParameter *m_ambientParameter;
Qt3DRender::QParameter *m_diffuseParameter;
Qt3DRender::QParameter *m_specularParameter;
Qt3DRender::QParameter *m_shininessParameter;
- Qt3DRender::QParameter *m_alphaParameter;
Qt3DRender::QTechnique *m_phongAlphaGL3Technique;
Qt3DRender::QTechnique *m_phongAlphaGL2Technique;
Qt3DRender::QTechnique *m_phongAlphaES2Technique;
@@ -99,7 +98,9 @@ public:
Qt3DRender::QRenderPass *m_phongAlphaGL2RenderPass;
Qt3DRender::QRenderPass *m_phongAlphaES2RenderPass;
Qt3DRender::QShaderProgram *m_phongAlphaGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_phongAlphaGL3ShaderBuilder;
Qt3DRender::QShaderProgram *m_phongAlphaGL2ES2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_phongAlphaGL2ES2ShaderBuilder;
Qt3DRender::QNoDepthMask *m_noDepthMask;
Qt3DRender::QBlendEquationArguments *m_blendState;
Qt3DRender::QBlendEquation *m_blendEquation;
diff --git a/src/extras/defaults/qphongmaterial.cpp b/src/extras/defaults/qphongmaterial.cpp
index 449eb7351..17d837568 100644
--- a/src/extras/defaults/qphongmaterial.cpp
+++ b/src/extras/defaults/qphongmaterial.cpp
@@ -45,6 +45,7 @@
#include <Qt3DRender/qeffect.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qgraphicsapifilter.h>
@@ -73,13 +74,17 @@ QPhongMaterialPrivate::QPhongMaterialPrivate()
, m_phongGL2RenderPass(new QRenderPass())
, m_phongES2RenderPass(new QRenderPass())
, m_phongGL3Shader(new QShaderProgram())
+ , m_phongGL3ShaderBuilder(new QShaderProgramBuilder())
, m_phongGL2ES2Shader(new QShaderProgram())
+ , m_phongGL2ES2ShaderBuilder(new QShaderProgramBuilder())
, m_filterKey(new QFilterKey)
{
}
void QPhongMaterialPrivate::init()
{
+ Q_Q(QPhongMaterial);
+
connect(m_ambientParameter, &Qt3DRender::QParameter::valueChanged,
this, &QPhongMaterialPrivate::handleAmbientChanged);
connect(m_diffuseParameter, &Qt3DRender::QParameter::valueChanged,
@@ -89,11 +94,21 @@ void QPhongMaterialPrivate::init()
connect(m_shininessParameter, &Qt3DRender::QParameter::valueChanged,
this, &QPhongMaterialPrivate::handleShininessChanged);
-
- m_phongGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/phong.vert"))));
- m_phongGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/phong.frag"))));
- m_phongGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/phong.vert"))));
- m_phongGL2ES2Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/phong.frag"))));
+ m_phongGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/default.vert"))));
+ m_phongGL3ShaderBuilder->setParent(q);
+ m_phongGL3ShaderBuilder->setShaderProgram(m_phongGL3Shader);
+ m_phongGL3ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_phongGL3ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
+
+ m_phongGL2ES2Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/es2/default.vert"))));
+ m_phongGL2ES2ShaderBuilder->setParent(q);
+ m_phongGL2ES2ShaderBuilder->setShaderProgram(m_phongGL2ES2Shader);
+ m_phongGL2ES2ShaderBuilder->setFragmentShaderGraph(QUrl(QStringLiteral("qrc:/shaders/graphs/phong.frag.json")));
+ m_phongGL2ES2ShaderBuilder->setEnabledLayers({QStringLiteral("diffuse"),
+ QStringLiteral("specular"),
+ QStringLiteral("normal")});
m_phongGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
m_phongGL3Technique->graphicsApiFilter()->setMajorVersion(3);
@@ -118,7 +133,6 @@ void QPhongMaterialPrivate::init()
m_phongGL2Technique->addRenderPass(m_phongGL2RenderPass);
m_phongES2Technique->addRenderPass(m_phongES2RenderPass);
- Q_Q(QPhongMaterial);
m_filterKey->setParent(q);
m_filterKey->setName(QStringLiteral("renderingStyle"));
m_filterKey->setValue(QStringLiteral("forward"));
@@ -170,6 +184,9 @@ void QPhongMaterialPrivate::handleShininessChanged(const QVariant &var)
\since 5.7
\inherits Qt3DRender::QMaterial
+ \deprecated
+ \see Qt3DExtras::QDiffuseSpecularMaterial
+
The phong lighting effect is based on the combination of 3 lighting components ambient, diffuse
and specular. The relative strengths of these components are controlled by means of their
reflectivity coefficients which are modelled as RGB triplets:
diff --git a/src/extras/defaults/qphongmaterial_p.h b/src/extras/defaults/qphongmaterial_p.h
index bc6d0ce44..f1e55242b 100644
--- a/src/extras/defaults/qphongmaterial_p.h
+++ b/src/extras/defaults/qphongmaterial_p.h
@@ -62,6 +62,7 @@ class QEffect;
class QTechnique;
class QParameter;
class QShaderProgram;
+class QShaderProgramBuilder;
class QRenderPass;
} // namespace Qt3DRender
@@ -94,7 +95,9 @@ public:
Qt3DRender::QRenderPass *m_phongGL2RenderPass;
Qt3DRender::QRenderPass *m_phongES2RenderPass;
Qt3DRender::QShaderProgram *m_phongGL3Shader;
+ Qt3DRender::QShaderProgramBuilder *m_phongGL3ShaderBuilder;
Qt3DRender::QShaderProgram *m_phongGL2ES2Shader;
+ Qt3DRender::QShaderProgramBuilder *m_phongGL2ES2ShaderBuilder;
Qt3DRender::QFilterKey *m_filterKey;
Q_DECLARE_PUBLIC(QPhongMaterial)
diff --git a/src/extras/defaults/qspritegrid.cpp b/src/extras/defaults/qspritegrid.cpp
new file mode 100644
index 000000000..31d4dd5c0
--- /dev/null
+++ b/src/extras/defaults/qspritegrid.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qspritegrid.h"
+#include "qspritegrid_p.h"
+
+#include <Qt3DRender/qabstracttexture.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DExtras {
+
+QSpriteGridPrivate::QSpriteGridPrivate()
+ : QAbstractSpriteSheetPrivate()
+ , m_numColumns(1)
+ , m_numRows(1)
+{
+}
+
+int QSpriteGridPrivate::maxIndex() const
+{
+ return m_numColumns * m_numRows;
+}
+
+void QSpriteGridPrivate::updateSizes()
+{
+ Q_Q(QSpriteGrid);
+ if (m_texture && m_numColumns && m_numRows) {
+ m_textureSize = QSize(m_texture->width(), m_texture->height());
+ m_cellSize = QSize(m_texture->width() / m_numColumns, m_texture->height() / m_numRows);
+ } else {
+ m_textureSize = QSize();
+ m_cellSize = QSize();
+ }
+
+ if (m_cellSize.isEmpty() || m_numColumns == 0 || m_numRows == 0) {
+ if (m_currentIndex != -1) {
+ m_currentIndex = -1;
+ emit q->currentIndexChanged(m_currentIndex);
+ }
+ m_textureTransform.setToIdentity();
+ emit q->textureTransformChanged(m_textureTransform);
+ return;
+ }
+
+ if (m_currentIndex == -1) {
+ m_currentIndex = 0;
+ emit q->currentIndexChanged(m_currentIndex);
+ }
+ updateTransform();
+}
+
+void QSpriteGridPrivate::updateTransform()
+{
+ Q_Q(QSpriteGrid);
+ const float xScale = (float) m_cellSize.width() / (float) m_textureSize.width();
+ const float yScale = (float) m_cellSize.height() / (float) m_textureSize.height();
+
+ const int currentRow = m_currentIndex / m_numColumns;
+ const int currentColumn = m_currentIndex % m_numColumns;
+ const float xTranslate = currentColumn * xScale;
+ const float yTranslate = currentRow * yScale;
+
+ m_textureTransform.setToIdentity();
+ m_textureTransform(0, 0) = xScale;
+ m_textureTransform(1, 1) = yScale;
+ m_textureTransform(0, 2) = xTranslate;
+ m_textureTransform(1, 2) = yTranslate;
+ emit q->textureTransformChanged(m_textureTransform);
+}
+
+/*!
+ Constructs a new QSpriteGrid instance with parent object \a parent.
+ */
+QSpriteGrid::QSpriteGrid(QNode *parent)
+ : QAbstractSpriteSheet(*new QSpriteGridPrivate, parent)
+{
+}
+
+QSpriteGrid::~QSpriteGrid()
+{
+}
+
+int QSpriteGrid::rows() const
+{
+ Q_D(const QSpriteGrid);
+ return d->m_numRows;
+}
+
+void QSpriteGrid::setRows(int rows)
+{
+ Q_D(QSpriteGrid);
+ if (d->m_numRows != rows) {
+ d->m_numRows = rows;
+ d->updateSizes();
+ emit rowsChanged(rows);
+ }
+}
+
+int QSpriteGrid::columns() const
+{
+ Q_D(const QSpriteGrid);
+ return d->m_numColumns;
+}
+
+void QSpriteGrid::setColumns(int columns)
+{
+ Q_D(QSpriteGrid);
+ if (d->m_numColumns != columns) {
+ d->m_numColumns = columns;
+ d->updateSizes();
+ emit columnsChanged(columns);
+ }
+}
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/extras/defaults/qspritegrid.h b/src/extras/defaults/qspritegrid.h
new file mode 100644
index 000000000..3b6a7005a
--- /dev/null
+++ b/src/extras/defaults/qspritegrid.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QSPRITEGRID_H
+#define QT3DEXTRAS_QSPRITEGRID_H
+
+#include <Qt3DExtras/qabstractspritesheet.h>
+#include <Qt3DCore/qcomponent.h>
+#include <QVector2D>
+#include <QMatrix3x3>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QSpriteGridPrivate;
+
+class QT3DEXTRASSHARED_EXPORT QSpriteGrid : public QAbstractSpriteSheet
+{
+ Q_OBJECT
+ Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
+ Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
+public:
+ explicit QSpriteGrid(Qt3DCore::QNode *parent = nullptr);
+ ~QSpriteGrid();
+
+ int rows() const;
+ int columns() const;
+
+public Q_SLOTS:
+ void setRows(int rows);
+ void setColumns(int columns);
+
+Q_SIGNALS:
+ void rowsChanged(int rows);
+ void columnsChanged(int columns);
+
+private:
+ Q_DECLARE_PRIVATE(QSpriteGrid)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QSPRITEGRID_H
diff --git a/src/extras/defaults/qspritegrid_p.h b/src/extras/defaults/qspritegrid_p.h
new file mode 100644
index 000000000..6135ebf0d
--- /dev/null
+++ b/src/extras/defaults/qspritegrid_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QSPRITEGRID_P_H
+#define QT3DEXTRAS_QSPRITEGRID_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 <Qt3DExtras/private/qabstractspritesheet_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QSpriteGrid;
+
+class QSpriteGridPrivate : public QAbstractSpriteSheetPrivate
+{
+ QSpriteGridPrivate();
+
+ int maxIndex() const override;
+ void updateSizes() override;
+ void updateTransform() override;
+
+ int m_numColumns;
+ int m_numRows;
+ QSize m_cellSize;
+
+ Q_DECLARE_PUBLIC(QSpriteGrid)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QSPRITEGRID_P_H
+
diff --git a/src/extras/defaults/qspritesheet.cpp b/src/extras/defaults/qspritesheet.cpp
new file mode 100644
index 000000000..87f664ce4
--- /dev/null
+++ b/src/extras/defaults/qspritesheet.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qspritesheet.h"
+#include "qspritesheetitem.h"
+#include "qspritesheet_p.h"
+
+#include <Qt3DRender/qabstracttexture.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DExtras {
+
+QSpriteSheetPrivate::QSpriteSheetPrivate()
+ : QAbstractSpriteSheetPrivate()
+{
+}
+
+int QSpriteSheetPrivate::maxIndex() const
+{
+ return m_sprites.count();
+}
+
+void QSpriteSheetPrivate::updateSizes()
+{
+ Q_Q(QSpriteSheet);
+ if (m_texture)
+ m_textureSize = QSize(m_texture->width(), m_texture->height());
+ else
+ m_textureSize = QSize();
+
+ if (m_textureSize.isEmpty() || m_sprites.isEmpty()) {
+ if (m_currentIndex != -1) {
+ m_currentIndex = -1;
+ emit q->currentIndexChanged(m_currentIndex);
+ }
+ m_textureTransform.setToIdentity();
+ emit q->textureTransformChanged(m_textureTransform);
+ return;
+ }
+
+ if (m_currentIndex < 0 || m_currentIndex > m_sprites.size()) {
+ m_currentIndex = 0;
+ emit q->currentIndexChanged(m_currentIndex);
+ }
+ updateTransform();
+}
+
+void QSpriteSheetPrivate::updateTransform()
+{
+ Q_Q(QSpriteSheet);
+ if (m_currentIndex < 0 || m_currentIndex >= m_sprites.size())
+ return;
+
+ const QSpriteSheetItem *r = m_sprites.at(m_currentIndex);
+ const float xScale = static_cast<float>(r->width()) / static_cast<float>(m_textureSize.width());
+ const float yScale = static_cast<float>(r->height()) / static_cast<float>(m_textureSize.height());
+
+ const float xTranslate = static_cast<float>(r->x()) / static_cast<float>(m_textureSize.width());
+ const float yTranslate = static_cast<float>(r->y()) / static_cast<float>(m_textureSize.height());
+
+ m_textureTransform.setToIdentity();
+ m_textureTransform(0, 0) = xScale;
+ m_textureTransform(1, 1) = yScale;
+ m_textureTransform(0, 2) = xTranslate;
+ m_textureTransform(1, 2) = yTranslate;
+ emit q->textureTransformChanged(m_textureTransform);
+}
+
+/*!
+ Constructs a new QSpriteSheet instance with parent object \a parent.
+ */
+QSpriteSheet::QSpriteSheet(QNode *parent)
+ : QAbstractSpriteSheet(*new QSpriteSheetPrivate, parent)
+{
+}
+
+QSpriteSheet::~QSpriteSheet()
+{
+}
+
+QVector<QSpriteSheetItem *> QSpriteSheet::sprites() const
+{
+ Q_D(const QSpriteSheet);
+ return d->m_sprites;
+}
+
+QSpriteSheetItem *QSpriteSheet::addSprite(int x, int y, int width, int height)
+{
+ QSpriteSheetItem *item = new QSpriteSheetItem(this);
+ item->setX(x);
+ item->setX(y);
+ item->setWidth(width);
+ item->setHeight(height);
+ addSprite(item);
+ return item;
+}
+
+void QSpriteSheet::addSprite(QSpriteSheetItem *sprite)
+{
+ Q_ASSERT(sprite);
+ Q_D(QSpriteSheet);
+ if (!d->m_sprites.contains(sprite)) {
+ d->m_sprites << sprite;
+
+ // Ensures proper bookkeeping
+ d->registerDestructionHelper(sprite, &QSpriteSheet::removeSprite, d->m_sprites);
+ if (!sprite->parent())
+ sprite->setParent(this);
+
+ emit spritesChanged(d->m_sprites);
+ d->updateSizes();
+ }
+}
+
+void QSpriteSheet::removeSprite(QSpriteSheetItem *sprite)
+{
+ Q_ASSERT(sprite);
+ Q_D(QSpriteSheet);
+ d->m_sprites.removeOne(sprite);
+ // Remove bookkeeping connection
+ d->unregisterDestructionHelper(sprite);
+}
+
+void QSpriteSheet::setSprites(QVector<QSpriteSheetItem *> sprites)
+{
+ Q_D(QSpriteSheet);
+ d->m_sprites = sprites;
+ emit spritesChanged(sprites);
+ d->updateSizes();
+}
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/extras/defaults/qspritesheet.h b/src/extras/defaults/qspritesheet.h
new file mode 100644
index 000000000..00fd293c3
--- /dev/null
+++ b/src/extras/defaults/qspritesheet.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QSPRITESHEET_H
+#define QT3DEXTRAS_QSPRITESHEET_H
+
+#include <Qt3DExtras/qabstractspritesheet.h>
+#include <QRect>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QSpriteSheetItem;
+class QSpriteSheetPrivate;
+
+class QT3DEXTRASSHARED_EXPORT QSpriteSheet : public QAbstractSpriteSheet
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector<QSpriteSheetItem *> sprites READ sprites WRITE setSprites NOTIFY spritesChanged)
+public:
+ explicit QSpriteSheet(Qt3DCore::QNode *parent = nullptr);
+ ~QSpriteSheet();
+
+ QVector<QSpriteSheetItem *> sprites() const;
+ QSpriteSheetItem *addSprite(int x, int y, int width, int height);
+ void addSprite(QSpriteSheetItem *sprite);
+ void removeSprite(QSpriteSheetItem *sprite);
+
+public Q_SLOTS:
+ void setSprites(QVector<QSpriteSheetItem *> sprites);
+
+Q_SIGNALS:
+ void spritesChanged(QVector<QSpriteSheetItem *> sprites);
+
+private:
+ Q_DECLARE_PRIVATE(QSpriteSheet)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QSPRITESHEET_H
diff --git a/src/extras/defaults/qspritesheet_p.h b/src/extras/defaults/qspritesheet_p.h
new file mode 100644
index 000000000..5091800fe
--- /dev/null
+++ b/src/extras/defaults/qspritesheet_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QSPRITESHEET_P_H
+#define QT3DEXTRAS_QSPRITESHEET_P_H
+#include <QRect>
+#include <QVector>
+
+//
+// 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 <Qt3DExtras/private/qabstractspritesheet_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QSpriteSheetItem;
+class QSpriteSheet;
+
+class QSpriteSheetPrivate : public QAbstractSpriteSheetPrivate
+{
+ QSpriteSheetPrivate();
+
+ int maxIndex() const override;
+ void updateSizes() override;
+ void updateTransform() override;
+
+ QVector<QSpriteSheetItem *> m_sprites;
+
+ Q_DECLARE_PUBLIC(QSpriteSheet)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QSPRITESHEET_P_H
+
diff --git a/src/extras/defaults/qspritesheetitem.cpp b/src/extras/defaults/qspritesheetitem.cpp
new file mode 100644
index 000000000..b4e096ae9
--- /dev/null
+++ b/src/extras/defaults/qspritesheetitem.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qspritesheetitem.h"
+#include "qspritesheetitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DExtras {
+
+QSpriteSheetItemPrivate::QSpriteSheetItemPrivate()
+ : QNodePrivate()
+ , m_x(0)
+ , m_y(0)
+ , m_width(0)
+ , m_height(0)
+{
+
+}
+
+QSpriteSheetItem::QSpriteSheetItem(QNode *parent)
+ : Qt3DCore::QNode(* new QSpriteSheetItemPrivate(), parent)
+{
+
+}
+
+int QSpriteSheetItem::x() const
+{
+ Q_D(const QSpriteSheetItem);
+ return d->m_x;
+}
+
+void QSpriteSheetItem::setX(int x)
+{
+ Q_D(QSpriteSheetItem);
+ if (x != d->m_x) {
+ d->m_x = x;
+ emit xChanged(x);
+ }
+}
+
+int QSpriteSheetItem::y() const
+{
+ Q_D(const QSpriteSheetItem);
+ return d->m_y;
+}
+
+void QSpriteSheetItem::setY(int y)
+{
+ Q_D(QSpriteSheetItem);
+ if (y != d->m_y) {
+ d->m_y = y;
+ emit yChanged(y);
+ }
+}
+
+int QSpriteSheetItem::width() const
+{
+ Q_D(const QSpriteSheetItem);
+ return d->m_width;
+}
+
+void QSpriteSheetItem::setWidth(int width)
+{
+ Q_D(QSpriteSheetItem);
+ if (width != d->m_width) {
+ d->m_width = width;
+ emit widthChanged(width);
+ }
+}
+
+int QSpriteSheetItem::height() const
+{
+ Q_D(const QSpriteSheetItem);
+ return d->m_height;
+}
+
+void QSpriteSheetItem::setHeight(int height)
+{
+ Q_D(QSpriteSheetItem);
+ if (height != d->m_height) {
+ d->m_height = height;
+ emit heightChanged(height);
+ }
+}
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/extras/defaults/qspritesheetitem.h b/src/extras/defaults/qspritesheetitem.h
new file mode 100644
index 000000000..f47846071
--- /dev/null
+++ b/src/extras/defaults/qspritesheetitem.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QSPRITESHEETITEM_H
+#define QT3DEXTRAS_QSPRITESHEETITEM_H
+
+#include <Qt3DExtras/qabstractspritesheet.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QSpriteSheetItemPrivate;
+
+class QT3DEXTRASSHARED_EXPORT QSpriteSheetItem : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
+ Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
+public:
+ explicit QSpriteSheetItem(Qt3DCore::QNode *parent = nullptr);
+
+ int x() const;
+ int y() const;
+ int width() const;
+ int height() const;
+
+public Q_SLOTS:
+ void setX(int x);
+ void setY(int y);
+ void setWidth(int width);
+ void setHeight(int height);
+
+Q_SIGNALS:
+ void xChanged(int x);
+ void yChanged(int y);
+ void widthChanged(int width);
+ void heightChanged(int height);
+
+private:
+ Q_DECLARE_PRIVATE(QSpriteSheetItem)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QSPRITESHEETITEM_H
diff --git a/src/extras/defaults/qspritesheetitem_p.h b/src/extras/defaults/qspritesheetitem_p.h
new file mode 100644
index 000000000..f23d71cd7
--- /dev/null
+++ b/src/extras/defaults/qspritesheetitem_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_QSPRITESHEET_P_H
+#define QT3DEXTRAS_QSPRITESHEET_P_H
+#include <QRect>
+#include <QVector>
+
+//
+// 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/qnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+class QSpriteSheetItem;
+
+class QSpriteSheetItemPrivate: public Qt3DCore::QNodePrivate
+{
+ QSpriteSheetItemPrivate();
+
+ int m_x;
+ int m_y;
+ int m_width;
+ int m_height;
+
+ Q_DECLARE_PUBLIC(QSpriteSheetItem)
+};
+
+} // Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_QSPRITESHEET_P_H
+
diff --git a/src/extras/defaults/qt3dwindow.cpp b/src/extras/defaults/qt3dwindow.cpp
index 635d81956..12e210f0d 100644
--- a/src/extras/defaults/qt3dwindow.cpp
+++ b/src/extras/defaults/qt3dwindow.cpp
@@ -62,6 +62,13 @@
#include <Qt3DRender/qcamera.h>
#include <QtGui/qopenglcontext.h>
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(extras);
+#endif
+}
+
QT_BEGIN_NAMESPACE
namespace Qt3DExtras {
@@ -86,6 +93,8 @@ Qt3DWindow::Qt3DWindow(QScreen *screen)
{
Q_D(Qt3DWindow);
+ initResources();
+
if (!d->parentWindow)
d->connectToScreen(screen ? screen : d->topLevelScreen.data());
@@ -125,6 +134,9 @@ Qt3DWindow::~Qt3DWindow()
delete d->m_aspectEngine;
}
+/*!
+ Registers the specified \a aspect.
+*/
void Qt3DWindow::registerAspect(Qt3DCore::QAbstractAspect *aspect)
{
Q_ASSERT(!isVisible());
@@ -132,6 +144,9 @@ void Qt3DWindow::registerAspect(Qt3DCore::QAbstractAspect *aspect)
d->m_aspectEngine->registerAspect(aspect);
}
+/*!
+ Registers the specified aspect \a name.
+*/
void Qt3DWindow::registerAspect(const QString &name)
{
Q_ASSERT(!isVisible());
@@ -139,6 +154,9 @@ void Qt3DWindow::registerAspect(const QString &name)
d->m_aspectEngine->registerAspect(name);
}
+/*!
+ Sets the specified \a root entity of the scene.
+*/
void Qt3DWindow::setRootEntity(Qt3DCore::QEntity *root)
{
Q_D(Qt3DWindow);
@@ -151,18 +169,27 @@ void Qt3DWindow::setRootEntity(Qt3DCore::QEntity *root)
}
}
+/*!
+ Activates the specified \a activeFrameGraph.
+*/
void Qt3DWindow::setActiveFrameGraph(Qt3DRender::QFrameGraphNode *activeFrameGraph)
{
Q_D(Qt3DWindow);
d->m_renderSettings->setActiveFrameGraph(activeFrameGraph);
}
+/*!
+ Returns the node of the active frame graph.
+*/
Qt3DRender::QFrameGraphNode *Qt3DWindow::activeFrameGraph() const
{
Q_D(const Qt3DWindow);
return d->m_renderSettings->activeFrameGraph();
}
+/*!
+ Returns the node of the default framegraph
+*/
Qt3DExtras::QForwardRenderer *Qt3DWindow::defaultFrameGraph() const
{
Q_D(const Qt3DWindow);
@@ -175,12 +202,18 @@ Qt3DRender::QCamera *Qt3DWindow::camera() const
return d->m_defaultCamera;
}
+/*!
+ Returns the render settings of the 3D Window.
+*/
Qt3DRender::QRenderSettings *Qt3DWindow::renderSettings() const
{
Q_D(const Qt3DWindow);
return d->m_renderSettings;
}
+/*!
+ Manages the display events specified in \a e.
+*/
void Qt3DWindow::showEvent(QShowEvent *e)
{
Q_D(Qt3DWindow);
@@ -194,7 +227,9 @@ void Qt3DWindow::showEvent(QShowEvent *e)
QWindow::showEvent(e);
}
-
+/*!
+ Resets the aspect ratio of the 3D window.
+*/
void Qt3DWindow::resizeEvent(QResizeEvent *)
{
Q_D(Qt3DWindow);
diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.cpp b/src/extras/defaults/qtexturedmetalroughmaterial.cpp
index e09517866..8e26ddccc 100644
--- a/src/extras/defaults/qtexturedmetalroughmaterial.cpp
+++ b/src/extras/defaults/qtexturedmetalroughmaterial.cpp
@@ -38,334 +38,28 @@
****************************************************************************/
#include "qtexturedmetalroughmaterial.h"
-#include "qtexturedmetalroughmaterial_p.h"
-#include <Qt3DRender/qfilterkey.h>
-#include <Qt3DRender/qmaterial.h>
-#include <Qt3DRender/qeffect.h>
-#include <Qt3DRender/qtexture.h>
-#include <Qt3DRender/qtechnique.h>
-#include <Qt3DRender/qshaderprogram.h>
-#include <Qt3DRender/qparameter.h>
-#include <Qt3DRender/qrenderpass.h>
-#include <Qt3DRender/qgraphicsapifilter.h>
-#include <QUrl>
-#include <QVector3D>
-#include <QVector4D>
QT_BEGIN_NAMESPACE
-using namespace Qt3DRender;
-
namespace Qt3DExtras {
-QTexturedMetalRoughMaterialPrivate::QTexturedMetalRoughMaterialPrivate()
- : QMaterialPrivate()
- , m_baseColorTexture(new QTexture2D())
- , m_metalnessTexture(new QTexture2D())
- , m_roughnessTexture(new QTexture2D())
- , m_ambientOcclusionTexture(new QTexture2D())
- , m_normalTexture(new QTexture2D())
- , m_environmentIrradianceTexture(new QTexture2D())
- , m_environmentSpecularTexture(new QTexture2D())
- , m_baseColorParameter(new QParameter(QStringLiteral("baseColorMap"), m_baseColorTexture))
- , m_metalnessParameter(new QParameter(QStringLiteral("metalnessMap"), m_metalnessTexture))
- , m_roughnessParameter(new QParameter(QStringLiteral("roughnessMap"), m_roughnessTexture))
- , m_ambientOcclusionParameter(new QParameter(QStringLiteral("ambientOcclusionMap"), m_ambientOcclusionTexture))
- , m_normalParameter(new QParameter(QStringLiteral("normalMap"), m_normalTexture))
- , m_environmentIrradianceParameter(new QParameter(QStringLiteral("envLight.irradiance"), m_environmentIrradianceTexture))
- , m_environmentSpecularParameter(new QParameter(QStringLiteral("envLight.specular"), m_environmentSpecularTexture))
- , m_metalRoughEffect(new QEffect())
- , m_metalRoughGL3Technique(new QTechnique())
- , m_metalRoughGL3RenderPass(new QRenderPass())
- , m_metalRoughGL3Shader(new QShaderProgram())
- , m_filterKey(new QFilterKey)
-{
- m_baseColorTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_baseColorTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_baseColorTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_baseColorTexture->setGenerateMipMaps(true);
- m_baseColorTexture->setMaximumAnisotropy(16.0f);
-
- m_metalnessTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_metalnessTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_metalnessTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_metalnessTexture->setGenerateMipMaps(true);
- m_metalnessTexture->setMaximumAnisotropy(16.0f);
-
- m_roughnessTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_roughnessTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_roughnessTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_roughnessTexture->setGenerateMipMaps(true);
- m_roughnessTexture->setMaximumAnisotropy(16.0f);
-
- m_ambientOcclusionTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_ambientOcclusionTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_ambientOcclusionTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_ambientOcclusionTexture->setGenerateMipMaps(true);
- m_ambientOcclusionTexture->setMaximumAnisotropy(16.0f);
-
- m_normalTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_normalTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_normalTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_normalTexture->setGenerateMipMaps(true);
- m_normalTexture->setMaximumAnisotropy(16.0f);
-
- m_environmentIrradianceTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_environmentIrradianceTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_environmentIrradianceTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_environmentIrradianceTexture->setGenerateMipMaps(true);
- m_environmentIrradianceTexture->setMaximumAnisotropy(16.0f);
-
- m_environmentSpecularTexture->setMagnificationFilter(QAbstractTexture::Linear);
- m_environmentSpecularTexture->setMinificationFilter(QAbstractTexture::LinearMipMapLinear);
- m_environmentSpecularTexture->setWrapMode(QTextureWrapMode(QTextureWrapMode::Repeat));
- m_environmentSpecularTexture->setGenerateMipMaps(true);
- m_environmentSpecularTexture->setMaximumAnisotropy(16.0f);
-}
-
-void QTexturedMetalRoughMaterialPrivate::init()
-{
- connect(m_baseColorParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QTexturedMetalRoughMaterialPrivate::handleBaseColorChanged);
- connect(m_metalnessParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QTexturedMetalRoughMaterialPrivate::handleMetallicChanged);
- connect(m_roughnessParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QTexturedMetalRoughMaterialPrivate::handleRoughnessChanged);
- connect(m_ambientOcclusionParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QTexturedMetalRoughMaterialPrivate::handleAmbientOcclusionChanged);
- connect(m_normalParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QTexturedMetalRoughMaterialPrivate::handleNormalChanged);
-
- m_metalRoughGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.vert"))));
- m_metalRoughGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/metalrough.frag"))));
-
- m_metalRoughGL3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
- m_metalRoughGL3Technique->graphicsApiFilter()->setMajorVersion(3);
- m_metalRoughGL3Technique->graphicsApiFilter()->setMinorVersion(1);
- m_metalRoughGL3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
-
- Q_Q(QTexturedMetalRoughMaterial);
- m_filterKey->setParent(q);
- m_filterKey->setName(QStringLiteral("renderingStyle"));
- m_filterKey->setValue(QStringLiteral("forward"));
-
- m_metalRoughGL3Technique->addFilterKey(m_filterKey);
- m_metalRoughGL3RenderPass->setShaderProgram(m_metalRoughGL3Shader);
- m_metalRoughGL3Technique->addRenderPass(m_metalRoughGL3RenderPass);
- m_metalRoughEffect->addTechnique(m_metalRoughGL3Technique);
-
- m_metalRoughEffect->addParameter(m_baseColorParameter);
- m_metalRoughEffect->addParameter(m_metalnessParameter);
- m_metalRoughEffect->addParameter(m_roughnessParameter);
- m_metalRoughEffect->addParameter(m_ambientOcclusionParameter);
- m_metalRoughEffect->addParameter(m_normalParameter);
-
- // Note that even though those parameters are not exposed in the API,
- // they need to be kept around for now due to a bug in some drivers/GPUs
- // (at least Intel) which cause issues with unbound textures even if you
- // don't try to sample from them.
- // Can probably go away once we generate the shaders and deal in this
- // case in a better way.
- m_metalRoughEffect->addParameter(m_environmentIrradianceParameter);
- m_metalRoughEffect->addParameter(m_environmentSpecularParameter);
-
- q->setEffect(m_metalRoughEffect);
-}
-
-void QTexturedMetalRoughMaterialPrivate::handleBaseColorChanged(const QVariant &var)
-{
- Q_Q(QTexturedMetalRoughMaterial);
- emit q->baseColorChanged(var.value<QAbstractTexture *>());
-}
-
-void QTexturedMetalRoughMaterialPrivate::handleMetallicChanged(const QVariant &var)
-{
- Q_Q(QTexturedMetalRoughMaterial);
- emit q->metalnessChanged(var.value<QAbstractTexture *>());
-}
-void QTexturedMetalRoughMaterialPrivate::handleRoughnessChanged(const QVariant &var)
-{
- Q_Q(QTexturedMetalRoughMaterial);
- emit q->roughnessChanged(var.value<QAbstractTexture *>());
-}
-void QTexturedMetalRoughMaterialPrivate::handleAmbientOcclusionChanged(const QVariant &var)
-{
- Q_Q(QTexturedMetalRoughMaterial);
- emit q->ambientOcclusionChanged(var.value<QAbstractTexture *>());
-}
-
-void QTexturedMetalRoughMaterialPrivate::handleNormalChanged(const QVariant &var)
-{
- Q_Q(QTexturedMetalRoughMaterial);
- emit q->normalChanged(var.value<QAbstractTexture *>());
-}
-
/*!
\class Qt3DExtras::QTexturedMetalRoughMaterial
- \brief The QTexturedMetalRoughMaterial provides a default implementation of PBR
- lighting, environment maps and bump effect where the components are read from texture
- maps (including normal maps).
+ \brief This is deprecated, please use QMetalRoughMaterial instead.
\inmodule Qt3DExtras
\since 5.9
- \inherits Qt3DRender::QMaterial
+ \inherits Qt3DExtras::QMetalRoughMaterial
- This material uses an effect with a single render pass approach and performs per fragment
- lighting. Techniques are provided for OpenGL 3 only.
+ \deprecated
+ \see Qt3DExtras::QMetalRoughMaterial
*/
/*!
Constructs a new QTexturedMetalRoughMaterial instance with parent object \a parent.
*/
QTexturedMetalRoughMaterial::QTexturedMetalRoughMaterial(QNode *parent)
- : QMaterial(*new QTexturedMetalRoughMaterialPrivate, parent)
-{
- Q_D(QTexturedMetalRoughMaterial);
- d->init();
-}
-
-/*! \internal */
-QTexturedMetalRoughMaterial::QTexturedMetalRoughMaterial(QTexturedMetalRoughMaterialPrivate &dd, QNode *parent)
- : QMaterial(dd, parent)
-{
- Q_D(QTexturedMetalRoughMaterial);
- d->init();
-}
-
-/*!
- Destroys the QTexturedMetalRoughMaterial instance.
-*/
-QTexturedMetalRoughMaterial::~QTexturedMetalRoughMaterial()
-{
-}
-
-/*!
- \property QTexturedMetalRoughMaterial::baseColor
-
- Holds the current base color map texture.
-
- By default, the base color texture has the following properties:
-
- \list
- \li Linear minification and magnification filters
- \li Linear mipmap with mipmapping enabled
- \li Repeat wrap mode
- \li Maximum anisotropy of 16.0
- \endlist
-*/
-QAbstractTexture *QTexturedMetalRoughMaterial::baseColor() const
-{
- Q_D(const QTexturedMetalRoughMaterial);
- return d->m_baseColorParameter->value().value<QAbstractTexture *>();
-}
-
-/*!
- \property QTexturedMetalRoughMaterial::metalness
-
- Holds the current metalness map texture.
-
- By default, the metalness texture has the following properties:
-
- \list
- \li Linear minification and magnification filters
- \li Linear mipmap with mipmapping enabled
- \li Repeat wrap mode
- \li Maximum anisotropy of 16.0
- \endlist
-*/
-QAbstractTexture *QTexturedMetalRoughMaterial::metalness() const
-{
- Q_D(const QTexturedMetalRoughMaterial);
- return d->m_metalnessParameter->value().value<QAbstractTexture *>();
-}
-
-/*!
- \property QTexturedMetalRoughMaterial::roughness
-
- Holds the current roughness map texture.
-
- By default, the roughness texture has the following properties:
-
- \list
- \li Linear minification and magnification filters
- \li Linear mipmap with mipmapping enabled
- \li Repeat wrap mode
- \li Maximum anisotropy of 16.0
- \endlist
-*/
-QAbstractTexture *QTexturedMetalRoughMaterial::roughness() const
-{
- Q_D(const QTexturedMetalRoughMaterial);
- return d->m_roughnessParameter->value().value<QAbstractTexture *>();
-}
-
-/*!
- \property QTexturedMetalRoughMaterial::ambientOcclusion
-
- Holds the current ambient occlusion map texture.
-
- By default, the ambient occlusion texture has the following properties:
-
- \list
- \li Linear minification and magnification filters
- \li Linear mipmap with mipmapping enabled
- \li Repeat wrap mode
- \li Maximum anisotropy of 16.0
- \endlist
-*/
-QAbstractTexture *QTexturedMetalRoughMaterial::ambientOcclusion() const
-{
- Q_D(const QTexturedMetalRoughMaterial);
- return d->m_ambientOcclusionParameter->value().value<QAbstractTexture *>();
-}
-
-/*!
- \property QTexturedMetalRoughMaterial::normal
-
- Holds the current normal map texture.
-
- By default, the normal texture has the following properties:
-
- \list
- \li Linear minification and magnification filters
- \li Repeat wrap mode
- \li Maximum anisotropy of 16.0
- \endlist
-*/
-QAbstractTexture *QTexturedMetalRoughMaterial::normal() const
-{
- Q_D(const QTexturedMetalRoughMaterial);
- return d->m_normalParameter->value().value<QAbstractTexture *>();
-}
-
-
-void QTexturedMetalRoughMaterial::setBaseColor(QAbstractTexture *baseColor)
-{
- Q_D(QTexturedMetalRoughMaterial);
- d->m_baseColorParameter->setValue(QVariant::fromValue(baseColor));
-}
-
-void QTexturedMetalRoughMaterial::setMetalness(QAbstractTexture *metalness)
-{
- Q_D(QTexturedMetalRoughMaterial);
- d->m_metalnessParameter->setValue(QVariant::fromValue(metalness));
-}
-
-void QTexturedMetalRoughMaterial::setRoughness(QAbstractTexture *roughness)
-{
- Q_D(QTexturedMetalRoughMaterial);
- d->m_roughnessParameter->setValue(QVariant::fromValue(roughness));
-}
-
-void QTexturedMetalRoughMaterial::setAmbientOcclusion(QAbstractTexture *ambientOcclusion)
-{
- Q_D(QTexturedMetalRoughMaterial);
- d->m_ambientOcclusionParameter->setValue(QVariant::fromValue(ambientOcclusion));
-}
-
-void QTexturedMetalRoughMaterial::setNormal(QAbstractTexture *normal)
+ : QMetalRoughMaterial(parent)
{
- Q_D(QTexturedMetalRoughMaterial);
- d->m_normalParameter->setValue(QVariant::fromValue(normal));
}
} // namespace Qt3DExtras
diff --git a/src/extras/defaults/qtexturedmetalroughmaterial.h b/src/extras/defaults/qtexturedmetalroughmaterial.h
index 62755a781..60f41b27f 100644
--- a/src/extras/defaults/qtexturedmetalroughmaterial.h
+++ b/src/extras/defaults/qtexturedmetalroughmaterial.h
@@ -40,53 +40,24 @@
#ifndef QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_H
#define QT3DEXTRAS_QTEXTUREDMETALROUGHMATERIAL_H
-#include <Qt3DExtras/qt3dextras_global.h>
-#include <Qt3DRender/qmaterial.h>
+#include <Qt3DExtras/qmetalroughmaterial.h>
QT_BEGIN_NAMESPACE
namespace Qt3DExtras {
-class QTexturedMetalRoughMaterialPrivate;
-
-class QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public Qt3DRender::QMaterial
+class QT_DEPRECATED_X("Use Qt3DExtras::QMetalRoughMaterial") QT3DEXTRASSHARED_EXPORT QTexturedMetalRoughMaterial : public QMetalRoughMaterial
{
Q_OBJECT
- Q_PROPERTY(Qt3DRender::QAbstractTexture *baseColor READ baseColor WRITE setBaseColor NOTIFY baseColorChanged)
- Q_PROPERTY(Qt3DRender::QAbstractTexture *metalness READ metalness WRITE setMetalness NOTIFY metalnessChanged)
- Q_PROPERTY(Qt3DRender::QAbstractTexture *roughness READ roughness WRITE setRoughness NOTIFY roughnessChanged)
- Q_PROPERTY(Qt3DRender::QAbstractTexture *ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged)
- Q_PROPERTY(Qt3DRender::QAbstractTexture *normal READ normal WRITE setNormal NOTIFY normalChanged)
+ Q_PROPERTY(QVariant ambientOcclusion READ ambientOcclusion WRITE setAmbientOcclusion NOTIFY ambientOcclusionChanged)
+ Q_PROPERTY(QVariant normal READ normal WRITE setNormal NOTIFY normalChanged)
public:
explicit QTexturedMetalRoughMaterial(Qt3DCore::QNode *parent = nullptr);
- ~QTexturedMetalRoughMaterial();
-
- Qt3DRender::QAbstractTexture *baseColor() const;
- Qt3DRender::QAbstractTexture *metalness() const;
- Qt3DRender::QAbstractTexture *roughness() const;
- Qt3DRender::QAbstractTexture *ambientOcclusion() const;
- Qt3DRender::QAbstractTexture *normal() const;
-
-public Q_SLOTS:
- void setBaseColor(Qt3DRender::QAbstractTexture *baseColor);
- void setMetalness(Qt3DRender::QAbstractTexture *metalness);
- void setRoughness(Qt3DRender::QAbstractTexture *roughness);
- void setAmbientOcclusion(Qt3DRender::QAbstractTexture *ambientOcclusion);
- void setNormal(Qt3DRender::QAbstractTexture *normal);
Q_SIGNALS:
- void baseColorChanged(Qt3DRender::QAbstractTexture *baseColor);
- void metalnessChanged(Qt3DRender::QAbstractTexture *metalness);
- void roughnessChanged(Qt3DRender::QAbstractTexture *roughness);
- void ambientOcclusionChanged(Qt3DRender::QAbstractTexture *ambientOcclusion);
- void normalChanged(Qt3DRender::QAbstractTexture *normal);
-
-protected:
- explicit QTexturedMetalRoughMaterial(QTexturedMetalRoughMaterialPrivate &dd, Qt3DCore::QNode *parent = nullptr);
-
-private:
- Q_DECLARE_PRIVATE(QTexturedMetalRoughMaterial)
+ void ambientOcclusionChanged(const QVariant &ambientOcclusion);
+ void normalChanged(const QVariant &normal);
};
} // namespace Qt3DExtras
diff --git a/src/extras/defaults/qtexturematerial.cpp b/src/extras/defaults/qtexturematerial.cpp
index 0038dd44a..32e60360e 100644
--- a/src/extras/defaults/qtexturematerial.cpp
+++ b/src/extras/defaults/qtexturematerial.cpp
@@ -60,7 +60,7 @@ QTextureMaterialPrivate::QTextureMaterialPrivate()
: QMaterialPrivate()
, m_textureEffect(new QEffect)
, m_textureParameter(new QParameter(QStringLiteral("diffuseTexture"), new QTexture2D))
- , m_textureOffsetParameter(new QParameter(QStringLiteral("texCoordOffset"), QVector2D(0.0f, 0.0f)))
+ , m_textureTransformParameter(new QParameter(QStringLiteral("texCoordTransform"), qVariantFromValue(QMatrix3x3())))
, m_textureGL3Technique(new QTechnique)
, m_textureGL2Technique(new QTechnique)
, m_textureES2Technique(new QTechnique)
@@ -77,8 +77,8 @@ void QTextureMaterialPrivate::init()
{
connect(m_textureParameter, &Qt3DRender::QParameter::valueChanged,
this, &QTextureMaterialPrivate::handleTextureChanged);
- connect(m_textureOffsetParameter, &Qt3DRender::QParameter::valueChanged,
- this, &QTextureMaterialPrivate::handleTextureOffsetChanged);
+ connect(m_textureTransformParameter, &Qt3DRender::QParameter::valueChanged,
+ this, &QTextureMaterialPrivate::handleTextureTransformChanged);
m_textureGL3Shader->setVertexShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/unlittexture.vert"))));
m_textureGL3Shader->setFragmentShaderCode(QShaderProgram::loadSource(QUrl(QStringLiteral("qrc:/shaders/gl3/unlittexture.frag"))));
@@ -122,7 +122,7 @@ void QTextureMaterialPrivate::init()
m_textureEffect->addTechnique(m_textureES2Technique);
m_textureEffect->addParameter(m_textureParameter);
- m_textureEffect->addParameter(m_textureOffsetParameter);
+ m_textureEffect->addParameter(m_textureTransformParameter);
q->setEffect(m_textureEffect);
}
@@ -133,10 +133,12 @@ void QTextureMaterialPrivate::handleTextureChanged(const QVariant &var)
emit q->textureChanged(var.value<QAbstractTexture *>());
}
-void QTextureMaterialPrivate::handleTextureOffsetChanged(const QVariant &var)
+void QTextureMaterialPrivate::handleTextureTransformChanged(const QVariant &var)
{
Q_Q(QTextureMaterial);
- emit q->textureOffsetChanged(var.value<QVector2D>());
+ const QMatrix3x3 matrix = var.value<QMatrix3x3>();
+ emit q->textureTransformChanged(matrix);
+ emit q->textureOffsetChanged(QVector2D(matrix(0, 2), matrix(1, 2)));
}
/*!
@@ -182,14 +184,29 @@ QAbstractTexture *QTextureMaterial::texture() const
/*!
\property QTextureMaterial::textureOffset
- Holds the current texture offset. It is applied to texture
- coordinates at render time. Defaults to (0.0, 0.0).
+ This is a utility property. It sets the translation component of the general
+ texture transform matrix
*/
QVector2D QTextureMaterial::textureOffset() const
{
Q_D(const QTextureMaterial);
- return d->m_textureOffsetParameter->value().value<QVector2D>();
+ const QMatrix3x3 matrix = d->m_textureTransformParameter->value().value<QMatrix3x3>();
+ return QVector2D(matrix(0, 2), matrix(1, 2));
+}
+
+
+/*!
+ \property QTextureMaterial::textureTransform
+
+ Holds the current texture transform. It is applied to texture
+ coordinates at render time. Defaults to identity matrix.
+
+*/
+QMatrix3x3 QTextureMaterial::textureTransform() const
+{
+ Q_D(const QTextureMaterial);
+ return d->m_textureTransformParameter->value().value<QMatrix3x3>();
}
void QTextureMaterial::setTexture(QAbstractTexture *texture)
@@ -201,7 +218,16 @@ void QTextureMaterial::setTexture(QAbstractTexture *texture)
void QTextureMaterial::setTextureOffset(QVector2D textureOffset)
{
Q_D(QTextureMaterial);
- d->m_textureOffsetParameter->setValue(QVariant::fromValue(textureOffset));
+ QMatrix3x3 matrix = d->m_textureTransformParameter->value().value<QMatrix3x3>();
+ matrix(0, 2) = textureOffset.x();
+ matrix(1, 2) = textureOffset.y();
+ d->m_textureTransformParameter->setValue(qVariantFromValue(matrix));
+}
+
+void QTextureMaterial::setTextureTransform(const QMatrix3x3 &matrix)
+{
+ Q_D(QTextureMaterial);
+ d->m_textureTransformParameter->setValue(qVariantFromValue(matrix));
}
} // namespace Qt3DExtras
diff --git a/src/extras/defaults/qtexturematerial.h b/src/extras/defaults/qtexturematerial.h
index 3101b9a1b..b6347aff4 100644
--- a/src/extras/defaults/qtexturematerial.h
+++ b/src/extras/defaults/qtexturematerial.h
@@ -43,6 +43,7 @@
#include <Qt3DExtras/qt3dextras_global.h>
#include <Qt3DRender/qmaterial.h>
#include <QVector2D>
+#include <QMatrix3x3>
QT_BEGIN_NAMESPACE
@@ -61,20 +62,24 @@ class QT3DEXTRASSHARED_EXPORT QTextureMaterial : public Qt3DRender::QMaterial
Q_OBJECT
Q_PROPERTY(Qt3DRender::QAbstractTexture *texture READ texture WRITE setTexture NOTIFY textureChanged)
Q_PROPERTY(QVector2D textureOffset READ textureOffset WRITE setTextureOffset NOTIFY textureOffsetChanged)
+ Q_PROPERTY(QMatrix3x3 textureTransform READ textureTransform WRITE setTextureTransform NOTIFY textureTransformChanged REVISION 10)
public:
explicit QTextureMaterial(Qt3DCore::QNode *parent = nullptr);
~QTextureMaterial();
Qt3DRender::QAbstractTexture *texture() const;
QVector2D textureOffset() const;
+ QMatrix3x3 textureTransform() const;
public Q_SLOTS:
void setTexture(Qt3DRender::QAbstractTexture *texture);
void setTextureOffset(QVector2D textureOffset);
+ void setTextureTransform(const QMatrix3x3 &matrix);
Q_SIGNALS:
void textureChanged(Qt3DRender::QAbstractTexture *texture);
void textureOffsetChanged(QVector2D textureOffset);
+ void textureTransformChanged(const QMatrix3x3 &textureTransform);
private:
Q_DECLARE_PRIVATE(QTextureMaterial)
diff --git a/src/extras/defaults/qtexturematerial_p.h b/src/extras/defaults/qtexturematerial_p.h
index 5a8e78154..d09458aa3 100644
--- a/src/extras/defaults/qtexturematerial_p.h
+++ b/src/extras/defaults/qtexturematerial_p.h
@@ -40,6 +40,8 @@
#ifndef QT3DEXTRAS_QTEXTUREMATERIAL_P_H
#define QT3DEXTRAS_QTEXTUREMATERIAL_P_H
+#include <QMatrix3x3>
+
//
// W A R N I N G
// -------------
@@ -78,11 +80,11 @@ class QTextureMaterialPrivate : public Qt3DRender::QMaterialPrivate
void init();
void handleTextureChanged(const QVariant &var);
- void handleTextureOffsetChanged(const QVariant &var);
+ void handleTextureTransformChanged(const QVariant &var);
Qt3DRender::QEffect *m_textureEffect;
Qt3DRender::QParameter *m_textureParameter;
- Qt3DRender::QParameter *m_textureOffsetParameter;
+ Qt3DRender::QParameter *m_textureTransformParameter;
Qt3DRender::QTechnique *m_textureGL3Technique;
Qt3DRender::QTechnique *m_textureGL2Technique;
Qt3DRender::QTechnique *m_textureES2Technique;
diff --git a/src/extras/extras.qrc b/src/extras/extras.qrc
index 9fce08a9f..bfb14f3f9 100644
--- a/src/extras/extras.qrc
+++ b/src/extras/extras.qrc
@@ -1,26 +1,18 @@
<RCC>
<qresource prefix="/">
+ <file>shaders/graphs/metalrough.frag.json</file>
+ <file>shaders/graphs/phong.frag.json</file>
<file>shaders/gl3/light.inc.frag</file>
<file>shaders/es2/light.inc.frag</file>
<file>shaders/es2/light.inc.frag100</file>
- <file>shaders/gl3/phong.vert</file>
- <file>shaders/gl3/phong.frag</file>
- <file>shaders/es2/phong.vert</file>
- <file>shaders/es2/phong.frag</file>
- <file>shaders/gl3/normaldiffusespecularmap.frag</file>
- <file>shaders/gl3/diffusemap.vert</file>
- <file>shaders/gl3/diffusemap.frag</file>
- <file>shaders/es2/normaldiffusespecularmap.frag</file>
- <file>shaders/es2/diffusemap.vert</file>
- <file>shaders/es2/diffusemap.frag</file>
- <file>shaders/es2/normaldiffusemap.vert</file>
- <file>shaders/es2/normaldiffusemap.frag</file>
- <file>shaders/es2/normaldiffusemapalpha.frag</file>
- <file>shaders/gl3/normaldiffusemap.frag</file>
- <file>shaders/gl3/normaldiffusemap.vert</file>
- <file>shaders/gl3/normaldiffusemapalpha.frag</file>
- <file>shaders/es2/diffusespecularmap.frag</file>
- <file>shaders/gl3/diffusespecularmap.frag</file>
+ <file>shaders/gl3/phong.inc.frag</file>
+ <file>shaders/es2/phong.inc.frag</file>
+ <file>shaders/es2/phong.inc.frag100</file>
+ <file>shaders/gl3/metalrough.inc.frag</file>
+ <file>shaders/gl3/coordinatesystems.inc</file>
+ <file>shaders/es2/coordinatesystems.inc</file>
+ <file>shaders/gl3/default.vert</file>
+ <file>shaders/es2/default.vert</file>
<file>shaders/gl3/pervertexcolor.frag</file>
<file>shaders/gl3/pervertexcolor.vert</file>
<file>shaders/es2/pervertexcolor.frag</file>
@@ -33,15 +25,10 @@
<file>shaders/gl3/gooch.frag</file>
<file>shaders/es2/gooch.frag</file>
<file>shaders/es2/gooch.vert</file>
- <file>shaders/gl3/phongalpha.frag</file>
- <file>shaders/es2/phongalpha.frag</file>
<file>shaders/gl3/unlittexture.vert</file>
<file>shaders/gl3/unlittexture.frag</file>
<file>shaders/es2/unlittexture.frag</file>
<file>shaders/es2/unlittexture.vert</file>
- <file>shaders/gl3/metalrough.vert</file>
- <file>shaders/gl3/metalrough.frag</file>
- <file>shaders/gl3/metalroughuniform.frag</file>
<file>shaders/gl3/distancefieldtext.vert</file>
<file>shaders/gl3/distancefieldtext.frag</file>
<file>shaders/es2/distancefieldtext.frag</file>
diff --git a/src/extras/geometries/qconegeometry.cpp b/src/extras/geometries/qconegeometry.cpp
index 12bbf7ce3..109d19b66 100644
--- a/src/extras/geometries/qconegeometry.cpp
+++ b/src/extras/geometries/qconegeometry.cpp
@@ -368,8 +368,8 @@ void QConeGeometryPrivate::init()
m_normalAttribute = new QAttribute(q);
m_texCoordAttribute = new QAttribute(q);
m_indexAttribute = new QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
// vec3 pos, vec2 tex, vec3 normal
const quint32 elementSize = 3 + 2 + 3;
diff --git a/src/extras/geometries/qcuboidgeometry.cpp b/src/extras/geometries/qcuboidgeometry.cpp
index 3bb68a500..968c12e49 100644
--- a/src/extras/geometries/qcuboidgeometry.cpp
+++ b/src/extras/geometries/qcuboidgeometry.cpp
@@ -497,8 +497,8 @@ void QCuboidGeometryPrivate::init()
m_texCoordAttribute = new Qt3DRender::QAttribute(q);
m_tangentAttribute = new Qt3DRender::QAttribute(q);
m_indexAttribute = new Qt3DRender::QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
// vec3 pos vec2 tex vec3 normal vec4 tangent
const quint32 stride = (3 + 2 + 3 + 4) * sizeof(float);
diff --git a/src/extras/geometries/qcylindergeometry.cpp b/src/extras/geometries/qcylindergeometry.cpp
index 4051477a6..affc3e516 100644
--- a/src/extras/geometries/qcylindergeometry.cpp
+++ b/src/extras/geometries/qcylindergeometry.cpp
@@ -299,8 +299,8 @@ void QCylinderGeometryPrivate::init()
m_normalAttribute = new QAttribute(q);
m_texCoordAttribute = new QAttribute(q);
m_indexAttribute = new QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
// vec3 pos, vec2 tex, vec3 normal
const quint32 elementSize = 3 + 2 + 3;
diff --git a/src/extras/geometries/qplanegeometry.cpp b/src/extras/geometries/qplanegeometry.cpp
index 14ddb25e6..99892fa24 100644
--- a/src/extras/geometries/qplanegeometry.cpp
+++ b/src/extras/geometries/qplanegeometry.cpp
@@ -509,8 +509,8 @@ void QPlaneGeometryPrivate::init()
m_texCoordAttribute = new QAttribute(q);
m_tangentAttribute = new QAttribute(q);
m_indexAttribute = new QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
const int nVerts = m_meshResolution.width() * m_meshResolution.height();
const int stride = (3 + 2 + 3 + 4) * sizeof(float);
diff --git a/src/extras/geometries/qspheregeometry.cpp b/src/extras/geometries/qspheregeometry.cpp
index eae12ef39..40a0c4475 100644
--- a/src/extras/geometries/qspheregeometry.cpp
+++ b/src/extras/geometries/qspheregeometry.cpp
@@ -254,8 +254,8 @@ void QSphereGeometryPrivate::init()
m_texCoordAttribute = new QAttribute(q);
m_tangentAttribute = new QAttribute(q);
m_indexAttribute = new QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
// vec3 pos, vec2 tex, vec3 normal, vec4 tangent
const quint32 elementSize = 3 + 2 + 3 + 4;
diff --git a/src/extras/geometries/qtorusgeometry.cpp b/src/extras/geometries/qtorusgeometry.cpp
index 57c94ec95..43a2566bb 100644
--- a/src/extras/geometries/qtorusgeometry.cpp
+++ b/src/extras/geometries/qtorusgeometry.cpp
@@ -243,8 +243,8 @@ void QTorusGeometryPrivate::init()
m_texCoordAttribute = new QAttribute(q);
m_tangentAttribute = new QAttribute(q);
m_indexAttribute = new QAttribute(q);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, q);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, q);
+ m_vertexBuffer = new Qt3DRender::QBuffer(q);
+ m_indexBuffer = new Qt3DRender::QBuffer(q);
// vec3 pos, vec2 tex, vec3 normal, vec4 tangent
const quint32 elementSize = 3 + 2 + 3 + 4;
const quint32 stride = elementSize * sizeof(float);
diff --git a/src/extras/shaders/es2/coordinatesystems.inc b/src/extras/shaders/es2/coordinatesystems.inc
new file mode 100644
index 000000000..5f6ee40f5
--- /dev/null
+++ b/src/extras/shaders/es2/coordinatesystems.inc
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+#define FP highp
+
+FP mat3 transpose(const in FP mat3 inputMatrix)
+{
+ FP vec3 i0 = inputMatrix[0];
+ FP vec3 i1 = inputMatrix[1];
+ FP vec3 i2 = inputMatrix[2];
+
+ FP mat3 outputMatrix = mat3(
+ vec3(i0.x, i1.x, i2.x),
+ vec3(i0.y, i1.y, i2.y),
+ vec3(i0.z, i1.z, i2.z)
+ );
+
+ return outputMatrix;
+}
+
+FP mat3 calcWorldSpaceToTangentSpaceMatrix(const in FP vec3 wNormal, const in FP vec4 wTangent)
+{
+ // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
+ // This allows to build the tangentMatrix below by simply transposing the
+ // tangent -> eyespace matrix (which would now be orthogonal)
+ FP vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal);
+
+ // Calculate binormal vector. No "real" need to renormalize it,
+ // as built by crossing two normal vectors.
+ // To orient the binormal correctly, use the fourth coordinate of the tangent,
+ // which is +1 for a right hand system, and -1 for a left hand system.
+ FP vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w;
+
+ // Construct matrix to transform from world space to tangent space
+ // This is the transpose of the tangentToWorld transformation matrix
+ FP mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal);
+ FP mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix);
+ return worldToTangentMatrix;
+}
+
diff --git a/src/extras/shaders/es2/default.vert b/src/extras/shaders/es2/default.vert
new file mode 100644
index 000000000..810f658bc
--- /dev/null
+++ b/src/extras/shaders/es2/default.vert
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+attribute vec3 vertexPosition;
+attribute vec3 vertexNormal;
+attribute vec4 vertexTangent;
+attribute vec2 vertexTexCoord;
+
+varying vec3 worldPosition;
+varying vec3 worldNormal;
+varying vec4 worldTangent;
+varying vec2 texCoord;
+
+uniform mat4 modelMatrix;
+uniform mat3 modelNormalMatrix;
+uniform mat4 modelViewProjection;
+
+uniform float texCoordScale;
+
+void main()
+{
+ // Pass through texture coordinates
+ texCoord = vertexTexCoord * texCoordScale;
+
+ // Transform position, normal, and tangent to world coords
+ worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0));
+ worldNormal = normalize(modelNormalMatrix * vertexNormal);
+ worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
+ worldTangent.w = vertexTangent.w;
+
+ // Calculate vertex position in clip coordinates
+ gl_Position = modelViewProjection * vec4(vertexPosition, 1.0);
+}
diff --git a/src/extras/shaders/es2/diffusemap.frag b/src/extras/shaders/es2/diffusemap.frag
deleted file mode 100644
index 7d06d8e2c..000000000
--- a/src/extras/shaders/es2/diffusemap.frag
+++ /dev/null
@@ -1,25 +0,0 @@
-#define FP highp
-
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP vec3 ks; // Specular reflectivity
-uniform FP float shininess; // Specular shininess factor
-
-uniform FP vec3 eyePosition;
-
-uniform sampler2D diffuseTexture;
-
-varying FP vec3 worldPosition;
-varying FP vec3 worldNormal;
-varying FP vec2 texCoord;
-
-#pragma include light.inc.frag
-
-void main()
-{
- FP vec3 diffuseTextureColor = texture2D( diffuseTexture, texCoord ).rgb;
-
- FP vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
-
- gl_FragColor = vec4( diffuseTextureColor * ( ka + diffuseColor ) + ks * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/es2/diffusemap.vert b/src/extras/shaders/es2/diffusemap.vert
deleted file mode 100644
index 13798279e..000000000
--- a/src/extras/shaders/es2/diffusemap.vert
+++ /dev/null
@@ -1,22 +0,0 @@
-attribute vec3 vertexPosition;
-attribute vec3 vertexNormal;
-attribute vec2 vertexTexCoord;
-
-varying vec3 worldPosition;
-varying vec3 worldNormal;
-varying vec2 texCoord;
-
-uniform mat4 modelMatrix;
-uniform mat3 modelNormalMatrix;
-uniform mat4 mvp;
-
-uniform float texCoordScale;
-
-void main()
-{
- texCoord = vertexTexCoord * texCoordScale;
- worldNormal = normalize( modelNormalMatrix * vertexNormal );
- worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
-
- gl_Position = mvp * vec4( vertexPosition, 1.0 );
-}
diff --git a/src/extras/shaders/es2/diffusespecularmap.frag b/src/extras/shaders/es2/diffusespecularmap.frag
deleted file mode 100644
index 4d776772c..000000000
--- a/src/extras/shaders/es2/diffusespecularmap.frag
+++ /dev/null
@@ -1,27 +0,0 @@
-#define FP highp
-
-// TODO: Replace with a struct
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP float shininess; // Specular shininess factor
-
-uniform FP vec3 eyePosition;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D specularTexture;
-
-varying FP vec3 worldPosition;
-varying FP vec3 worldNormal;
-varying FP vec2 texCoord;
-
-#pragma include light.inc.frag
-
-void main()
-{
- FP vec3 diffuseTextureColor = texture2D( diffuseTexture, texCoord ).rgb;
- FP vec3 specularTextureColor = texture2D( specularTexture, texCoord ).rgb;
-
- FP vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
-
- gl_FragColor = vec4( diffuseTextureColor * ( ka + diffuseColor ) + specularTextureColor * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/es2/light.inc.frag b/src/extras/shaders/es2/light.inc.frag
index 57a30036f..167ff306e 100644
--- a/src/extras/shaders/es2/light.inc.frag
+++ b/src/extras/shaders/es2/light.inc.frag
@@ -1,3 +1,5 @@
+#define FP highp
+
const int MAX_LIGHTS = 8;
const int TYPE_POINT = 0;
const int TYPE_DIRECTIONAL = 1;
@@ -13,186 +15,3 @@ struct Light {
};
uniform Light lights[MAX_LIGHTS];
uniform int lightCount;
-
-void adsModelNormalMapped(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3 eye, const in FP float shininess,
- const in FP mat3 tangentMatrix,
- out FP vec3 diffuseColor, out FP vec3 specularColor)
-{
- diffuseColor = vec3(0.0);
- specularColor = vec3(0.0);
-
- FP vec3 snormal = normalize( vec3( tangentMatrix[0][2], tangentMatrix[1][2], tangentMatrix[2][2] ) );
-
- FP vec3 n = normalize( vnormal );
-
- FP vec3 s, ts;
- Light light;
- for (int i = 0; i < MAX_LIGHTS; ++i) {
- if (i >= lightCount) // Make brcm happy with the for loop
- break;
- if (i == 0)
- light = lights[0];
- else if (i == 1)
- light = lights[1];
- else if (i == 2)
- light = lights[2];
- else if (i == 3)
- light = lights[3];
- else if (i == 4)
- light = lights[4];
- else if (i == 5)
- light = lights[5];
- else if (i == 6)
- light = lights[6];
- else if (i == 7)
- light = lights[7];
-
- FP float att = 1.0;
- if ( light.type != TYPE_DIRECTIONAL ) {
- s = light.position - vpos;
- if ( dot(snormal, s) < 0.0 )
- att = 0.0;
- else {
- ts = normalize( tangentMatrix * s );
- if (length( light.attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (light.attenuation.x + light.attenuation.y * dist + light.attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( light.type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(light.direction))) ) > light.cutOffAngle)
- att = 0.0;
- }
- }
- } else {
- if ( dot(snormal, -light.direction) > 0.0 )
- s = normalize( tangentMatrix * -light.direction );
- else
- att = 0.0;
- }
-
- FP float diffuse = max( dot( ts, n ), 0.0 );
-
- FP float specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
- FP vec3 r = reflect( -ts, n );
- FP vec3 v = normalize( tangentMatrix * ( eye - vpos ) );
- FP float normFactor = ( shininess + 2.0 ) / 2.0;
- specular = normFactor * pow( max( dot( r, v ), 0.0 ), shininess );
- }
-
- diffuseColor += att * light.intensity * diffuse * light.color;
- specularColor += att * light.intensity * specular * light.color;
- }
-}
-
-void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3 eye, const in FP float shininess,
- out FP vec3 diffuseColor, out FP vec3 specularColor)
-{
- diffuseColor = vec3(0.0);
- specularColor = vec3(0.0);
-
- FP vec3 n = normalize( vnormal );
-
- FP vec3 s;
- Light light;
- for (int i = 0; i < MAX_LIGHTS; ++i) {
- if (i >= lightCount) // Make brcm happy with the for loop
- break;
- if (i == 0)
- light = lights[0];
- else if (i == 1)
- light = lights[1];
- else if (i == 2)
- light = lights[2];
- else if (i == 3)
- light = lights[3];
- else if (i == 4)
- light = lights[4];
- else if (i == 5)
- light = lights[5];
- else if (i == 6)
- light = lights[6];
- else if (i == 7)
- light = lights[7];
-
- FP float att = 1.0;
- if ( light.type != TYPE_DIRECTIONAL ) {
- s = light.position - vpos;
- if (length( light.attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (light.attenuation.x + light.attenuation.y * dist + light.attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( light.type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(light.direction))) ) > light.cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( -light.direction );
- }
-
- FP float diffuse = max( dot( s, n ), 0.0 );
-
- FP float specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
- FP vec3 r = reflect( -s, n );
- FP vec3 v = normalize( eye - vpos );
- FP float normFactor = ( shininess + 2.0 ) / 2.0;
- specular = normFactor * pow( max( dot( r, v ), 0.0 ), shininess );
- }
-
- diffuseColor += att * light.intensity * diffuse * light.color;
- specularColor += att * light.intensity * specular * light.color;
- }
-}
-
-void adModel(const in FP vec3 vpos, const in FP vec3 vnormal, out FP vec3 diffuseColor)
-{
- diffuseColor = vec3(0.0);
-
- FP vec3 n = normalize( vnormal );
-
- FP vec3 s;
- Light light;
- for (int i = 0; i < MAX_LIGHTS; ++i) {
- if (i >= lightCount) // Make brcm happy with the for loop
- break;
- if (i == 0)
- light = lights[0];
- else if (i == 1)
- light = lights[1];
- else if (i == 2)
- light = lights[2];
- else if (i == 3)
- light = lights[3];
- else if (i == 4)
- light = lights[4];
- else if (i == 5)
- light = lights[5];
- else if (i == 6)
- light = lights[6];
- else if (i == 7)
- light = lights[7];
-
- FP float att = 1.0;
- if ( light.type != TYPE_DIRECTIONAL ) {
- s = light.position - vpos;
- if (length( light.attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (light.attenuation.x + light.attenuation.y * dist + light.attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( light.type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(light.direction))) ) > light.cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( -light.direction );
- }
-
- FP float diffuse = max( dot( s, n ), 0.0 );
-
- diffuseColor += att * light.intensity * diffuse * light.color;
- }
-}
diff --git a/src/extras/shaders/es2/light.inc.frag100 b/src/extras/shaders/es2/light.inc.frag100
index b4988ad82..8680ee423 100644
--- a/src/extras/shaders/es2/light.inc.frag100
+++ b/src/extras/shaders/es2/light.inc.frag100
@@ -1,3 +1,5 @@
+#define FP highp
+
const int MAX_LIGHTS = 2; // RPi: cannot use more than two as we run out of uniforms
const int TYPE_POINT = 0;
const int TYPE_DIRECTIONAL = 1;
@@ -13,206 +15,3 @@ struct Light {
};
uniform Light lights[MAX_LIGHTS];
uniform int lightCount;
-
-void adsModelNormalMapped(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3 eye, const in FP float shininess,
- const in FP mat3 tangentMatrix,
- out FP vec3 diffuseColor, out FP vec3 specularColor)
-{
- diffuseColor = vec3(0.0);
- specularColor = vec3(0.0);
-
- FP vec3 n = normalize( vnormal );
-
- // 0
- if (lightCount < 1)
- return;
- FP vec3 s;
- FP float att = 1.0;
- if ( lights[0].type != TYPE_DIRECTIONAL ) {
- s = tangentMatrix * ( lights[0].position - vpos );
- if (length( lights[0].attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (lights[0].attenuation.x + lights[0].attenuation.y * dist + lights[0].attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( lights[0].type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(lights[0].direction))) ) > lights[0].cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( tangentMatrix * -lights[0].direction );
- }
-
- FP float diffuse = max( dot( s, n ), 0.0 );
-
- FP float specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
- FP vec3 r = reflect( -s, n );
- FP vec3 v = normalize( tangentMatrix * ( eye - vpos ) );
- FP float normFactor = ( shininess + 2.0 ) / 2.0;
- specular = normFactor * pow( max( dot( r, v ), 0.0 ), shininess );
- }
-
- diffuseColor += att * lights[0].intensity * diffuse * lights[0].color;
- specularColor += att * specular;
-
- // 1
- if (lightCount < 2)
- return;
- att = 1.0;
- if ( lights[1].type != TYPE_DIRECTIONAL ) {
- s = tangentMatrix * ( lights[1].position - vpos );
- if (length( lights[1].attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (lights[1].attenuation.x + lights[1].attenuation.y * dist + lights[1].attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( lights[1].type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(lights[1].direction))) ) > lights[1].cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( tangentMatrix * -lights[1].direction );
- }
-
- diffuse = max( dot( s, n ), 0.0 );
-
- specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
- FP vec3 r = reflect( -s, n );
- FP vec3 v = normalize( tangentMatrix * ( eye - vpos ) );
- FP float normFactor = ( shininess + 2.0 ) / 2.0;
- specular = normFactor * pow( max( dot( r, v ), 0.0 ), shininess );
- }
-
- diffuseColor += att * lights[1].intensity * diffuse * lights[1].color;
- specularColor += att * specular;
-}
-
-void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3 eye, const in FP float shininess,
- out FP vec3 diffuseColor, out FP vec3 specularColor)
-{
- diffuseColor = vec3(0.0);
- specularColor = vec3(0.0);
-
- FP vec3 n = normalize( vnormal );
-
- // 0
- if (lightCount < 1)
- return;
- FP vec3 s;
- FP float att = 1.0;
- if ( lights[0].type != TYPE_DIRECTIONAL ) {
- s = lights[0].position - vpos;
- if (length( lights[0].attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (lights[0].attenuation.x + lights[0].attenuation.y * dist + lights[0].attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( lights[0].type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(lights[0].direction))) ) > lights[0].cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( -lights[0].direction );
- }
-
- FP float diffuse = max( dot( s, n ), 0.0 );
-
- FP float specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
- FP vec3 r = reflect( -s, n );
- FP vec3 v = normalize( eye - vpos );
- FP float normFactor = ( shininess + 2.0 ) / 2.0;
- specular = normFactor * pow( max( dot( r, v ), 0.0 ), shininess );
- }
-
- diffuseColor += att * lights[0].intensity * diffuse * lights[0].color;
- specularColor += att * specular;
-
- // 1
- if (lightCount < 2)
- return;
- att = 1.0;
- if ( lights[1].type != TYPE_DIRECTIONAL ) {
- s = lights[1].position - vpos;
- if (length( lights[1].attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (lights[1].attenuation.x + lights[1].attenuation.y * dist + lights[1].attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( lights[1].type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(lights[1].direction))) ) > lights[1].cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( -lights[1].direction );
- }
-
- diffuse = max( dot( s, n ), 0.0 );
-
- specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
- FP vec3 r = reflect( -s, n );
- FP vec3 v = normalize( eye - vpos );
- FP float normFactor = ( shininess + 2.0 ) / 2.0;
- specular = normFactor * pow( max( dot( r, v ), 0.0 ), shininess );
- }
-
- diffuseColor += att * lights[1].intensity * diffuse * lights[1].color;
- specularColor += att * specular;
-}
-
-void adModel(const in FP vec3 vpos, const in FP vec3 vnormal, out FP vec3 diffuseColor)
-{
- diffuseColor = vec3(0.0);
-
- FP vec3 n = normalize( vnormal );
-
- // 0
- if (lightCount < 1)
- return;
- FP vec3 s;
- FP float att = 1.0;
- if ( lights[0].type != TYPE_DIRECTIONAL ) {
- s = lights[0].position - vpos;
- if (length( lights[0].attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (lights[0].attenuation.x + lights[0].attenuation.y * dist + lights[0].attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( lights[0].type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(lights[0].direction))) ) > lights[0].cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( -lights[0].direction );
- }
-
- FP float diffuse = max( dot( s, n ), 0.0 );
-
- diffuseColor += att * lights[0].intensity * diffuse * lights[0].color;
-
- // 1
- if (lightCount < 2)
- return;
- att = 1.0;
- if ( lights[1].type != TYPE_DIRECTIONAL ) {
- s = lights[1].position - vpos;
- if (length( lights[1].attenuation ) != 0.0) {
- FP float dist = length(s);
- att = 1.0 / (lights[1].attenuation.x + lights[1].attenuation.y * dist + lights[1].attenuation.z * dist * dist);
- }
- s = normalize( s );
- if ( lights[1].type == TYPE_SPOT ) {
- if ( degrees(acos(dot(-s, normalize(lights[1].direction))) ) > lights[1].cutOffAngle)
- att = 0.0;
- }
- } else {
- s = normalize( -lights[1].direction );
- }
-
- diffuse = max( dot( s, n ), 0.0 );
-
- diffuseColor += att * lights[1].intensity * diffuse * lights[1].color;
-}
diff --git a/src/extras/shaders/es2/normaldiffusemap.frag b/src/extras/shaders/es2/normaldiffusemap.frag
deleted file mode 100644
index c69aa8b81..000000000
--- a/src/extras/shaders/es2/normaldiffusemap.frag
+++ /dev/null
@@ -1,31 +0,0 @@
-#define FP highp
-
-varying FP vec3 worldPosition;
-varying FP vec2 texCoord;
-varying FP mat3 tangentMatrix;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D normalTexture;
-
-// TODO: Replace with a struct
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP vec3 ks; // Specular reflectivity
-uniform FP float shininess; // Specular shininess factor
-
-uniform FP vec3 eyePosition;
-
-#pragma include light.inc.frag
-
-void main()
-{
- // Sample the textures at the interpolated texCoords
- FP vec4 diffuseTextureColor = texture2D( diffuseTexture, texCoord );
- FP vec3 normal = 2.0 * texture2D( normalTexture, texCoord ).rgb - vec3( 1.0 );
-
- // Calculate the lighting model, keeping the specular component separate
- FP vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
-
- // Combine spec with ambient+diffuse for final fragment color
- gl_FragColor = vec4( ka + diffuseTextureColor.rgb * diffuseColor + ks * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/es2/normaldiffusemap.vert b/src/extras/shaders/es2/normaldiffusemap.vert
deleted file mode 100644
index ecc689f69..000000000
--- a/src/extras/shaders/es2/normaldiffusemap.vert
+++ /dev/null
@@ -1,38 +0,0 @@
-attribute vec3 vertexPosition;
-attribute vec3 vertexNormal;
-attribute vec2 vertexTexCoord;
-attribute vec4 vertexTangent;
-
-varying vec3 worldPosition;
-varying vec2 texCoord;
-varying mat3 tangentMatrix;
-
-uniform mat4 modelMatrix;
-uniform mat3 modelNormalMatrix;
-uniform mat4 projectionMatrix;
-uniform mat4 mvp;
-
-uniform float texCoordScale;
-
-void main()
-{
- // Pass through texture coordinates
- texCoord = vertexTexCoord * texCoordScale;
-
- // Transform position, normal, and tangent to world coords
- vec3 normal = normalize( modelNormalMatrix * vertexNormal );
- vec3 tangent = normalize( modelNormalMatrix * vertexTangent.xyz );
- worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
-
- // Calculate binormal vector
- vec3 binormal = normalize( cross( normal, tangent ) );
-
- // Construct matrix to transform from eye coords to tangent space
- tangentMatrix = mat3 (
- tangent.x, binormal.x, normal.x,
- tangent.y, binormal.y, normal.y,
- tangent.z, binormal.z, normal.z );
-
- // Calculate vertex position in clip coordinates
- gl_Position = mvp * vec4( vertexPosition, 1.0 );
-}
diff --git a/src/extras/shaders/es2/normaldiffusemapalpha.frag b/src/extras/shaders/es2/normaldiffusemapalpha.frag
deleted file mode 100644
index 98acbf01d..000000000
--- a/src/extras/shaders/es2/normaldiffusemapalpha.frag
+++ /dev/null
@@ -1,32 +0,0 @@
-#define FP highp
-
-varying FP vec3 worldPosition;
-varying FP vec2 texCoord;
-varying FP mat3 tangentMatrix;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D normalTexture;
-
-// TODO: Replace with a struct
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP vec3 ks; // Specular reflectivity
-uniform FP float shininess; // Specular shininess factor
-
-uniform FP vec3 eyePosition;
-
-#pragma include light.inc.frag
-
-void main()
-{
- // Sample the textures at the interpolated texCoords
- FP vec4 diffuseTextureColor = texture2D( diffuseTexture, texCoord );
- FP vec3 normal = 2.0 * texture2D( normalTexture, texCoord ).rgb - vec3( 1.0 );
-
- // Calculate the lighting model, keeping the specular component separate
- FP vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
-
- // Combine spec with ambient+diffuse for final fragment color
- // Use the alpha from the diffuse texture (for alpha to coverage)
- gl_FragColor = vec4( ka + diffuseTextureColor.rgb * diffuseColor + ks * specularColor, diffuseTextureColor.a );
-}
diff --git a/src/extras/shaders/es2/normaldiffusespecularmap.frag b/src/extras/shaders/es2/normaldiffusespecularmap.frag
deleted file mode 100644
index b30c1bd5f..000000000
--- a/src/extras/shaders/es2/normaldiffusespecularmap.frag
+++ /dev/null
@@ -1,32 +0,0 @@
-#define FP highp
-
-varying FP vec3 worldPosition;
-varying FP vec2 texCoord;
-varying FP mat3 tangentMatrix;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D specularTexture;
-uniform sampler2D normalTexture;
-
-// TODO: Replace with a struct
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP float shininess; // Specular shininess factor
-
-uniform FP vec3 eyePosition;
-
-#pragma include light.inc.frag
-
-void main()
-{
- // Sample the textures at the interpolated texCoords
- FP vec4 diffuseTextureColor = texture2D( diffuseTexture, texCoord );
- FP vec4 specularTextureColor = texture2D( specularTexture, texCoord );
- FP vec3 normal = 2.0 * texture2D( normalTexture, texCoord ).rgb - vec3( 1.0 );
-
- // Calculate the lighting model, keeping the specular component separate
- FP vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
-
- // Combine spec with ambient+diffuse for final fragment color
- gl_FragColor = vec4( ka + diffuseTextureColor.rgb * diffuseColor + specularTextureColor.rgb * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/es2/pervertexcolor.frag b/src/extras/shaders/es2/pervertexcolor.frag
index ab429d942..a2f0e8bf2 100644
--- a/src/extras/shaders/es2/pervertexcolor.frag
+++ b/src/extras/shaders/es2/pervertexcolor.frag
@@ -2,13 +2,14 @@
varying FP vec3 worldPosition;
varying FP vec3 worldNormal;
-varying FP vec3 color;
+varying FP vec4 color;
-#pragma include light.inc.frag
+uniform FP vec3 eyePosition;
+
+#pragma include phong.inc.frag
void main()
{
- FP vec3 diffuseColor;
- adModel(worldPosition, worldNormal, diffuseColor);
- gl_FragColor = vec4( color + color * diffuseColor, 1.0 );
+ FP vec3 worldView = normalize(eyePosition - worldPosition);
+ gl_FragColor = phongFunction(color, color, vec4(0.0), 0.0, worldPosition, worldView, worldNormal);
}
diff --git a/src/extras/shaders/es2/pervertexcolor.vert b/src/extras/shaders/es2/pervertexcolor.vert
index 7fc3e649f..bfa2e615a 100644
--- a/src/extras/shaders/es2/pervertexcolor.vert
+++ b/src/extras/shaders/es2/pervertexcolor.vert
@@ -1,10 +1,10 @@
attribute vec3 vertexPosition;
attribute vec3 vertexNormal;
-attribute vec3 vertexColor;
+attribute vec4 vertexColor;
varying vec3 worldPosition;
varying vec3 worldNormal;
-varying vec3 color;
+varying vec4 color;
uniform mat4 modelMatrix;
uniform mat3 modelNormalMatrix;
diff --git a/src/extras/shaders/es2/phong.frag b/src/extras/shaders/es2/phong.frag
deleted file mode 100644
index c00f89db0..000000000
--- a/src/extras/shaders/es2/phong.frag
+++ /dev/null
@@ -1,20 +0,0 @@
-#define FP highp
-
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP vec3 kd; // Diffuse reflectivity
-uniform FP vec3 ks; // Specular reflectivity
-uniform FP float shininess; // Specular shininess factor
-
-uniform FP vec3 eyePosition;
-
-varying FP vec3 worldPosition;
-varying FP vec3 worldNormal;
-
-#pragma include light.inc.frag
-
-void main()
-{
- FP vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
- gl_FragColor = vec4( ka + kd * diffuseColor + ks * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/es2/phong.inc.frag b/src/extras/shaders/es2/phong.inc.frag
new file mode 100644
index 000000000..9d17b68b5
--- /dev/null
+++ b/src/extras/shaders/es2/phong.inc.frag
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+#pragma include light.inc.frag
+
+void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3 vview, const in FP float shininess,
+ out FP vec3 diffuseColor, out FP vec3 specularColor)
+{
+ diffuseColor = vec3(0.0);
+ specularColor = vec3(0.0);
+
+ FP vec3 n = normalize( vnormal );
+
+ FP vec3 s;
+ Light light;
+ for (int i = 0; i < lightCount; ++i) {
+ if (i == 0)
+ light = lights[0];
+ else if (i == 1)
+ light = lights[1];
+ else if (i == 2)
+ light = lights[2];
+ else if (i == 3)
+ light = lights[3];
+ else if (i == 4)
+ light = lights[4];
+ else if (i == 5)
+ light = lights[5];
+ else if (i == 6)
+ light = lights[6];
+ else if (i == 7)
+ light = lights[7];
+
+ FP float att = 1.0;
+ if ( light.type != TYPE_DIRECTIONAL ) {
+ s = light.position - vpos;
+ if (length( light.attenuation ) != 0.0) {
+ FP float dist = length(s);
+ att = 1.0 / (light.attenuation.x + light.attenuation.y * dist + light.attenuation.z * dist * dist);
+ }
+ s = normalize( s );
+ if ( light.type == TYPE_SPOT ) {
+ if ( degrees(acos(dot(-s, normalize(light.direction))) ) > light.cutOffAngle)
+ att = 0.0;
+ }
+ } else {
+ s = normalize( -light.direction );
+ }
+
+ FP float diffuse = max( dot( s, n ), 0.0 );
+
+ FP float specular = 0.0;
+ if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
+ FP vec3 r = reflect( -s, n );
+ FP float normFactor = ( shininess + 2.0 ) / 2.0;
+ specular = normFactor * pow( max( dot( r, vview ), 0.0 ), shininess );
+ }
+
+ diffuseColor += att * light.intensity * diffuse * light.color;
+ specularColor += att * light.intensity * specular * light.color;
+ }
+}
+
+FP vec4 phongFunction(const in FP vec4 ambient,
+ const in FP vec4 diffuse,
+ const in FP vec4 specular,
+ const in FP float shininess,
+ const in FP vec3 worldPosition,
+ const in FP vec3 worldView,
+ const in FP vec3 worldNormal)
+{
+ // Calculate the lighting model, keeping the specular component separate
+ FP vec3 diffuseColor, specularColor;
+ adsModel(worldPosition, worldNormal, worldView, shininess, diffuseColor, specularColor);
+
+ // Combine spec with ambient+diffuse for final fragment color
+ FP vec3 color = (ambient.rgb + diffuseColor) * diffuse.rgb
+ + specularColor * specular.rgb;
+
+ return vec4(color, diffuse.a);
+}
diff --git a/src/extras/shaders/es2/phong.inc.frag100 b/src/extras/shaders/es2/phong.inc.frag100
new file mode 100644
index 000000000..507d8eaf5
--- /dev/null
+++ b/src/extras/shaders/es2/phong.inc.frag100
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+#pragma include light.inc.frag
+
+void adsModel(const in FP vec3 vpos, const in FP vec3 vnormal, const in FP vec3 vview, const in FP float shininess,
+ out FP vec3 diffuseColor, out FP vec3 specularColor)
+{
+ diffuseColor = vec3(0.0);
+ specularColor = vec3(0.0);
+
+ FP vec3 n = normalize( vnormal );
+
+ // 0
+ if (lightCount < 1)
+ return;
+ FP vec3 s;
+ FP float att = 1.0;
+ if ( lights[0].type != TYPE_DIRECTIONAL ) {
+ s = lights[0].position - vpos;
+ if (length( lights[0].attenuation ) != 0.0) {
+ FP float dist = length(s);
+ att = 1.0 / (lights[0].attenuation.x + lights[0].attenuation.y * dist + lights[0].attenuation.z * dist * dist);
+ }
+ s = normalize( s );
+ if ( lights[0].type == TYPE_SPOT ) {
+ if ( degrees(acos(dot(-s, normalize(lights[0].direction))) ) > lights[0].cutOffAngle)
+ att = 0.0;
+ }
+ } else {
+ s = normalize( -lights[0].direction );
+ }
+
+ FP float diffuse = max( dot( s, n ), 0.0 );
+
+ FP float specular = 0.0;
+ if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
+ FP vec3 r = reflect( -s, n );
+ FP float normFactor = ( shininess + 2.0 ) / 2.0;
+ specular = normFactor * pow( max( dot( r, vview ), 0.0 ), shininess );
+ }
+
+ diffuseColor += att * lights[0].intensity * diffuse * lights[0].color;
+ specularColor += att * specular;
+
+ // 1
+ if (lightCount < 2)
+ return;
+ att = 1.0;
+ if ( lights[1].type != TYPE_DIRECTIONAL ) {
+ s = lights[1].position - vpos;
+ if (length( lights[1].attenuation ) != 0.0) {
+ FP float dist = length(s);
+ att = 1.0 / (lights[1].attenuation.x + lights[1].attenuation.y * dist + lights[1].attenuation.z * dist * dist);
+ }
+ s = normalize( s );
+ if ( lights[1].type == TYPE_SPOT ) {
+ if ( degrees(acos(dot(-s, normalize(lights[1].direction))) ) > lights[1].cutOffAngle)
+ att = 0.0;
+ }
+ } else {
+ s = normalize( -lights[1].direction );
+ }
+
+ diffuse = max( dot( s, n ), 0.0 );
+
+ specular = 0.0;
+ if (diffuse > 0.0 && shininess > 0.0 && att > 0.0) {
+ FP vec3 r = reflect( -s, n );
+ FP float normFactor = ( shininess + 2.0 ) / 2.0;
+ specular = normFactor * pow( max( dot( r, vview ), 0.0 ), shininess );
+ }
+
+ diffuseColor += att * lights[1].intensity * diffuse * lights[1].color;
+ specularColor += att * specular;
+}
+
+FP vec4 phongFunction(const in FP vec4 ambient,
+ const in FP vec4 diffuse,
+ const in FP vec4 specular,
+ const in FP float shininess,
+ const in FP vec3 worldPosition,
+ const in FP vec3 worldView,
+ const in FP vec3 worldNormal)
+{
+ // Calculate the lighting model, keeping the specular component separate
+ FP vec3 diffuseColor, specularColor;
+ adsModel(worldPosition, worldNormal, worldView, shininess, diffuseColor, specularColor);
+
+ // Combine spec with ambient+diffuse for final fragment color
+ FP vec3 color = (ambient.rgb + diffuseColor) * diffuse.rgb
+ + specularColor * specular.rgb;
+
+ return vec4(color, diffuse.a);
+}
diff --git a/src/extras/shaders/es2/phong.vert b/src/extras/shaders/es2/phong.vert
deleted file mode 100644
index 2b4c51b14..000000000
--- a/src/extras/shaders/es2/phong.vert
+++ /dev/null
@@ -1,17 +0,0 @@
-attribute vec3 vertexPosition;
-attribute vec3 vertexNormal;
-
-varying vec3 worldPosition;
-varying vec3 worldNormal;
-
-uniform mat4 modelMatrix;
-uniform mat3 modelNormalMatrix;
-uniform mat4 modelViewProjection;
-
-void main()
-{
- worldNormal = normalize( modelNormalMatrix * vertexNormal );
- worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
-
- gl_Position = modelViewProjection * vec4( vertexPosition, 1.0 );
-}
diff --git a/src/extras/shaders/es2/phongalpha.frag b/src/extras/shaders/es2/phongalpha.frag
deleted file mode 100644
index c5ec43049..000000000
--- a/src/extras/shaders/es2/phongalpha.frag
+++ /dev/null
@@ -1,22 +0,0 @@
-#define FP highp
-
-// TODO: Replace with a struct
-uniform FP vec3 ka; // Ambient reflectivity
-uniform FP vec3 kd; // Diffuse reflectivity
-uniform FP vec3 ks; // Specular reflectivity
-uniform FP float shininess; // Specular shininess factor
-uniform FP float alpha;
-
-uniform FP vec3 eyePosition;
-
-varying FP vec3 worldPosition;
-varying FP vec3 worldNormal;
-
-#pragma include light.inc.frag
-
-void main()
-{
- FP vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
- gl_FragColor = vec4( ka + kd * diffuseColor + ks * specularColor, alpha );
-}
diff --git a/src/extras/shaders/es2/unlittexture.vert b/src/extras/shaders/es2/unlittexture.vert
index 050b2b7e2..d2c8fe9f7 100644
--- a/src/extras/shaders/es2/unlittexture.vert
+++ b/src/extras/shaders/es2/unlittexture.vert
@@ -6,11 +6,12 @@ varying vec2 texCoord;
uniform mat4 modelView;
uniform mat4 mvp;
-uniform vec2 texCoordOffset;
+uniform mat3 texCoordTransform;
void main()
{
- texCoord = vertexTexCoord + texCoordOffset;
+ vec3 tt = texCoordTransform * vec3(vertexTexCoord, 1.0);
+ texCoord = (tt / tt.z).xy;
position = vec3( modelView * vec4( vertexPosition, 1.0 ) );
gl_Position = mvp * vec4( vertexPosition, 1.0 );
diff --git a/src/extras/shaders/gl3/coordinatesystems.inc b/src/extras/shaders/gl3/coordinatesystems.inc
new file mode 100644
index 000000000..ed3d2cb92
--- /dev/null
+++ b/src/extras/shaders/gl3/coordinatesystems.inc
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent)
+{
+ // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
+ // This allows to build the tangentMatrix below by simply transposing the
+ // tangent -> eyespace matrix (which would now be orthogonal)
+ vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal);
+
+ // Calculate binormal vector. No "real" need to renormalize it,
+ // as built by crossing two normal vectors.
+ // To orient the binormal correctly, use the fourth coordinate of the tangent,
+ // which is +1 for a right hand system, and -1 for a left hand system.
+ vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w;
+
+ // Construct matrix to transform from world space to tangent space
+ // This is the transpose of the tangentToWorld transformation matrix
+ mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal);
+ mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix);
+ return worldToTangentMatrix;
+}
+
diff --git a/src/extras/shaders/gl3/metalrough.vert b/src/extras/shaders/gl3/default.vert
index 6d3a60ef6..f97cd099d 100644
--- a/src/extras/shaders/gl3/metalrough.vert
+++ b/src/extras/shaders/gl3/default.vert
@@ -48,7 +48,7 @@
**
****************************************************************************/
-#version 150
+#version 150 core
in vec3 vertexPosition;
in vec3 vertexNormal;
@@ -62,12 +62,14 @@ out vec2 texCoord;
uniform mat4 modelMatrix;
uniform mat3 modelNormalMatrix;
-uniform mat4 mvp;
+uniform mat4 modelViewProjection;
+
+uniform float texCoordScale;
void main()
{
- // Pass the texture coordinates through
- texCoord = vertexTexCoord;
+ // Pass through scaled texture coordinates
+ texCoord = vertexTexCoord * texCoordScale;
// Transform position, normal, and tangent to world space
worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0));
@@ -75,5 +77,6 @@ void main()
worldTangent.xyz = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
worldTangent.w = vertexTangent.w;
- gl_Position = mvp * vec4(vertexPosition, 1.0);
+ // Calculate vertex position in clip coordinates
+ gl_Position = modelViewProjection * vec4(vertexPosition, 1.0);
}
diff --git a/src/extras/shaders/gl3/diffusemap.frag b/src/extras/shaders/gl3/diffusemap.frag
deleted file mode 100644
index 7810fdb68..000000000
--- a/src/extras/shaders/gl3/diffusemap.frag
+++ /dev/null
@@ -1,27 +0,0 @@
-#version 150 core
-
-uniform vec3 ka; // Ambient reflectivity
-uniform vec3 ks; // Specular reflectivity
-uniform float shininess; // Specular shininess factor
-
-uniform vec3 eyePosition;
-
-uniform sampler2D diffuseTexture;
-
-in vec3 worldPosition;
-in vec3 worldNormal;
-in vec2 texCoord;
-
-out vec4 fragColor;
-
-#pragma include light.inc.frag
-
-void main()
-{
- vec3 diffuseTextureColor = texture( diffuseTexture, texCoord ).rgb;
-
- vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
-
- fragColor = vec4( diffuseTextureColor * ( ka + diffuseColor ) + ks * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/gl3/diffusemap.vert b/src/extras/shaders/gl3/diffusemap.vert
deleted file mode 100644
index 439be6e99..000000000
--- a/src/extras/shaders/gl3/diffusemap.vert
+++ /dev/null
@@ -1,24 +0,0 @@
-#version 150 core
-
-in vec3 vertexPosition;
-in vec3 vertexNormal;
-in vec2 vertexTexCoord;
-
-out vec3 worldPosition;
-out vec3 worldNormal;
-out vec2 texCoord;
-
-uniform mat4 modelMatrix;
-uniform mat3 modelNormalMatrix;
-uniform mat4 mvp;
-
-uniform float texCoordScale;
-
-void main()
-{
- texCoord = vertexTexCoord * texCoordScale;
- worldNormal = normalize( modelNormalMatrix * vertexNormal );
- worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
-
- gl_Position = mvp * vec4( vertexPosition, 1.0 );
-}
diff --git a/src/extras/shaders/gl3/diffusespecularmap.frag b/src/extras/shaders/gl3/diffusespecularmap.frag
deleted file mode 100644
index fb809393a..000000000
--- a/src/extras/shaders/gl3/diffusespecularmap.frag
+++ /dev/null
@@ -1,29 +0,0 @@
-#version 150 core
-
-// TODO: Replace with a struct
-uniform vec3 ka; // Ambient reflectivity
-uniform float shininess; // Specular shininess factor
-
-uniform vec3 eyePosition;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D specularTexture;
-
-in vec3 worldPosition;
-in vec3 worldNormal;
-in vec2 texCoord;
-
-out vec4 fragColor;
-
-#pragma include light.inc.frag
-
-void main()
-{
- vec3 diffuseTextureColor = texture( diffuseTexture, texCoord ).rgb;
- vec3 specularTextureColor = texture( specularTexture, texCoord ).rgb;
-
- vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
-
- fragColor = vec4( diffuseTextureColor * ( ka + diffuseColor ) + specularTextureColor * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/gl3/light.inc.frag b/src/extras/shaders/gl3/light.inc.frag
index ce5c581cf..0b642638f 100644
--- a/src/extras/shaders/gl3/light.inc.frag
+++ b/src/extras/shaders/gl3/light.inc.frag
@@ -23,200 +23,3 @@ struct EnvironmentLight {
};
uniform EnvironmentLight envLight;
uniform int envLightCount = 0;
-
-void adsModelNormalMapped(const in vec3 worldPos,
- const in vec3 tsNormal,
- const in vec3 worldEye,
- const in float shininess,
- const in mat3 tangentMatrix,
- out vec3 diffuseColor,
- out vec3 specularColor)
-{
- diffuseColor = vec3(0.0);
- specularColor = vec3(0.0);
-
- // We perform all work in tangent space, so we convert quantities from world space
- vec3 tsPos = tangentMatrix * worldPos;
- vec3 n = normalize(tsNormal);
- vec3 v = normalize(tangentMatrix * (worldEye - worldPos));
- vec3 s = vec3(0.0);
-
- for (int i = 0; i < lightCount; ++i) {
- float att = 1.0;
- float sDotN = 0.0;
-
- if (lights[i].type != TYPE_DIRECTIONAL) {
- // Point and Spot lights
-
- // Transform the light position from world to tangent space
- vec3 tsLightPos = tangentMatrix * lights[i].position;
- vec3 sUnnormalized = tsLightPos - tsPos;
- s = normalize(sUnnormalized); // Light direction in tangent space
-
- // Calculate the attenuation factor
- sDotN = dot(s, n);
- if (sDotN > 0.0) {
- if (lights[i].constantAttenuation != 0.0
- || lights[i].linearAttenuation != 0.0
- || lights[i].quadraticAttenuation != 0.0) {
- float dist = length(sUnnormalized);
- att = 1.0 / (lights[i].constantAttenuation +
- lights[i].linearAttenuation * dist +
- lights[i].quadraticAttenuation * dist * dist);
- }
-
- // The light direction is in world space, convert to tangent space
- if (lights[i].type == TYPE_SPOT) {
- // Check if fragment is inside or outside of the spot light cone
- vec3 tsLightDirection = tangentMatrix * lights[i].direction;
- if (degrees(acos(dot(-s, tsLightDirection))) > lights[i].cutOffAngle)
- sDotN = 0.0;
- }
- }
- } else {
- // Directional lights
- // The light direction is in world space, convert to tangent space
- s = normalize(tangentMatrix * -lights[i].direction);
- sDotN = dot(s, n);
- }
-
- // Calculate the diffuse factor
- float diffuse = max(sDotN, 0.0);
-
- // Calculate the specular factor
- float specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0) {
- float normFactor = (shininess + 2.0) / 2.0;
- vec3 r = reflect(-s, n); // Reflection direction in tangent space
- specular = normFactor * pow(max(dot(r, v), 0.0), shininess);
- }
-
- // Accumulate the diffuse and specular contributions
- diffuseColor += att * lights[i].intensity * diffuse * lights[i].color;
- specularColor += att * lights[i].intensity * specular * lights[i].color;
- }
-}
-
-void adsModel(const in vec3 worldPos,
- const in vec3 worldNormal,
- const in vec3 worldEye,
- const in float shininess,
- out vec3 diffuseColor,
- out vec3 specularColor)
-{
- diffuseColor = vec3(0.0);
- specularColor = vec3(0.0);
-
- // We perform all work in world space
- vec3 n = normalize(worldNormal);
- vec3 v = normalize(worldEye - worldPos);
- vec3 s = vec3(0.0);
-
- for (int i = 0; i < lightCount; ++i) {
- float att = 1.0;
- float sDotN = 0.0;
-
- if (lights[i].type != TYPE_DIRECTIONAL) {
- // Point and Spot lights
-
- // Light position is already in world space
- vec3 sUnnormalized = lights[i].position - worldPos;
- s = normalize(sUnnormalized); // Light direction
-
- // Calculate the attenuation factor
- sDotN = dot(s, n);
- if (sDotN > 0.0) {
- if (lights[i].constantAttenuation != 0.0
- || lights[i].linearAttenuation != 0.0
- || lights[i].quadraticAttenuation != 0.0) {
- float dist = length(sUnnormalized);
- att = 1.0 / (lights[i].constantAttenuation +
- lights[i].linearAttenuation * dist +
- lights[i].quadraticAttenuation * dist * dist);
- }
-
- // The light direction is in world space already
- if (lights[i].type == TYPE_SPOT) {
- // Check if fragment is inside or outside of the spot light cone
- if (degrees(acos(dot(-s, lights[i].direction))) > lights[i].cutOffAngle)
- sDotN = 0.0;
- }
- }
- } else {
- // Directional lights
- // The light direction is in world space already
- s = normalize(-lights[i].direction);
- sDotN = dot(s, n);
- }
-
- // Calculate the diffuse factor
- float diffuse = max(sDotN, 0.0);
-
- // Calculate the specular factor
- float specular = 0.0;
- if (diffuse > 0.0 && shininess > 0.0) {
- float normFactor = (shininess + 2.0) / 2.0;
- vec3 r = reflect(-s, n); // Reflection direction in world space
- specular = normFactor * pow(max(dot(r, v), 0.0), shininess);
- }
-
- // Accumulate the diffuse and specular contributions
- diffuseColor += att * lights[i].intensity * diffuse * lights[i].color;
- specularColor += att * lights[i].intensity * specular * lights[i].color;
- }
-}
-
-void adModel(const in vec3 worldPos,
- const in vec3 worldNormal,
- out vec3 diffuseColor)
-{
- diffuseColor = vec3(0.0);
-
- // We perform all work in world space
- vec3 n = normalize(worldNormal);
- vec3 s = vec3(0.0);
-
- for (int i = 0; i < lightCount; ++i) {
- float att = 1.0;
- float sDotN = 0.0;
-
- if (lights[i].type != TYPE_DIRECTIONAL) {
- // Point and Spot lights
-
- // Light position is already in world space
- vec3 sUnnormalized = lights[i].position - worldPos;
- s = normalize(sUnnormalized); // Light direction
-
- // Calculate the attenuation factor
- sDotN = dot(s, n);
- if (sDotN > 0.0) {
- if (lights[i].constantAttenuation != 0.0
- || lights[i].linearAttenuation != 0.0
- || lights[i].quadraticAttenuation != 0.0) {
- float dist = length(sUnnormalized);
- att = 1.0 / (lights[i].constantAttenuation +
- lights[i].linearAttenuation * dist +
- lights[i].quadraticAttenuation * dist * dist);
- }
-
- // The light direction is in world space already
- if (lights[i].type == TYPE_SPOT) {
- // Check if fragment is inside or outside of the spot light cone
- if (degrees(acos(dot(-s, lights[i].direction))) > lights[i].cutOffAngle)
- sDotN = 0.0;
- }
- }
- } else {
- // Directional lights
- // The light direction is in world space already
- s = normalize(-lights[i].direction);
- sDotN = dot(s, n);
- }
-
- // Calculate the diffuse factor
- float diffuse = max(sDotN, 0.0);
-
- // Accumulate the diffuse contributions
- diffuseColor += att * lights[i].intensity * diffuse * lights[i].color;
- }
-}
diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag
deleted file mode 100644
index 7f2f3d20e..000000000
--- a/src/extras/shaders/gl3/metalrough.frag
+++ /dev/null
@@ -1,395 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt3D module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE: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$
-**
-****************************************************************************/
-
-#version 150
-
-in vec2 texCoord;
-in vec3 worldPosition;
-in vec3 worldNormal;
-in vec4 worldTangent;
-
-out vec4 fragColor;
-
-// Qt 3D built in uniforms
-uniform vec3 eyePosition; // World space eye position
-uniform float time; // Time in seconds
-
-// PBR Material maps
-uniform sampler2D baseColorMap;
-uniform sampler2D metalnessMap;
-uniform sampler2D roughnessMap;
-uniform sampler2D normalMap;
-uniform sampler2D ambientOcclusionMap;
-
-// User control parameters
-uniform float metalFactor = 1.0;
-
-// Exposure correction
-uniform float exposure = 0.0;
-// Gamma correction
-uniform float gamma = 2.2;
-
-#pragma include light.inc.frag
-
-int mipLevelCount(const in samplerCube cube)
-{
- int baseSize = textureSize(cube, 0).x;
- int nMips = int(log2(float(baseSize>0 ? baseSize : 1))) + 1;
- return nMips;
-}
-
-float remapRoughness(const in float roughness)
-{
- // As per page 14 of
- // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
- // we remap the roughness to give a more perceptually linear response
- // of "bluriness" as a function of the roughness specified by the user.
- // r = roughness^2
- const float maxSpecPower = 999999.0;
- const float minRoughness = sqrt(2.0 / (maxSpecPower + 2));
- return max(roughness * roughness, minRoughness);
-}
-
-mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent)
-{
- // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
- // This allows to build the tangentMatrix below by simply transposing the
- // tangent -> eyespace matrix (which would now be orthogonal)
- vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal);
-
- // Calculate binormal vector. No "real" need to renormalize it,
- // as built by crossing two normal vectors.
- // To orient the binormal correctly, use the fourth coordinate of the tangent,
- // which is +1 for a right hand system, and -1 for a left hand system.
- vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w;
-
- // Construct matrix to transform from world space to tangent space
- // This is the transpose of the tangentToWorld transformation matrix
- mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal);
- mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix);
- return worldToTangentMatrix;
-}
-
-float alphaToMipLevel(float alpha)
-{
- float specPower = 2.0 / (alpha * alpha) - 2.0;
-
- // We use the mip level calculation from Lys' default power drop, which in
- // turn is a slight modification of that used in Marmoset Toolbag. See
- // https://docs.knaldtech.com/doku.php?id=specular_lys for details.
- // For now we assume a max specular power of 999999 which gives
- // maxGlossiness = 1.
- const float k0 = 0.00098;
- const float k1 = 0.9921;
- float glossiness = (pow(2.0, -10.0 / sqrt(specPower)) - k0) / k1;
-
- // TODO: Optimize by doing this on CPU and set as
- // uniform int envLight.specularMipLevels say (if present in shader).
- // Lookup the number of mips in the specular envmap
- int mipLevels = mipLevelCount(envLight.specular);
-
- // Offset of smallest miplevel we should use (corresponds to specular
- // power of 1). I.e. in the 32x32 sized mip.
- const float mipOffset = 5.0;
-
- // The final factor is really 1 - g / g_max but as mentioned above g_max
- // is 1 by definition here so we can avoid the division. If we make the
- // max specular power for the spec map configurable, this will need to
- // be handled properly.
- float mipLevel = (mipLevels - 1.0 - mipOffset) * (1.0 - glossiness);
- return mipLevel;
-}
-
-float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha)
-{
- // Blinn-Phong approximation - see
- // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html
- float specPower = 2.0 / (alpha * alpha) - 2.0;
- return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower);
-}
-
-vec3 fresnelFactor(const in vec3 color, const in float cosineFactor)
-{
- // Calculate the Fresnel effect value
- vec3 f = color;
- vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0);
- return clamp(F, f, vec3(1.0));
-}
-
-float geometricModel(const in float lDotN,
- const in float vDotN,
- const in vec3 h)
-{
- // Implicit geometric model (equal to denominator in specular model).
- // This currently assumes that there is no attenuation by geometric shadowing or
- // masking according to the microfacet theory.
- return lDotN * vDotN;
-}
-
-vec3 specularModel(const in vec3 F0,
- const in float sDotH,
- const in float sDotN,
- const in float vDotN,
- const in vec3 n,
- const in vec3 h)
-{
- // Clamp sDotN and vDotN to small positive value to prevent the
- // denominator in the reflection equation going to infinity. Balance this
- // by using the clamped values in the geometric factor function to
- // avoid ugly seams in the specular lighting.
- float sDotNPrime = max(sDotN, 0.001);
- float vDotNPrime = max(vDotN, 0.001);
-
- vec3 F = fresnelFactor(F0, sDotH);
- float G = geometricModel(sDotNPrime, vDotNPrime, h);
-
- vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime);
- return clamp(cSpec, vec3(0.0), vec3(1.0));
-}
-
-vec3 pbrModel(const in int lightIndex,
- const in vec3 wPosition,
- const in vec3 wNormal,
- const in vec3 wView,
- const in vec3 baseColor,
- const in float metalness,
- const in float alpha,
- const in float ambientOcclusion)
-{
- // Calculate some useful quantities
- vec3 n = wNormal;
- vec3 s = vec3(0.0);
- vec3 v = wView;
- vec3 h = vec3(0.0);
-
- float vDotN = dot(v, n);
- float sDotN = 0.0;
- float sDotH = 0.0;
- float att = 1.0;
-
- if (lights[lightIndex].type != TYPE_DIRECTIONAL) {
- // Point and Spot lights
- vec3 sUnnormalized = vec3(lights[lightIndex].position) - wPosition;
- s = normalize(sUnnormalized);
-
- // Calculate the attenuation factor
- sDotN = dot(s, n);
- if (sDotN > 0.0) {
- if (lights[lightIndex].constantAttenuation != 0.0
- || lights[lightIndex].linearAttenuation != 0.0
- || lights[lightIndex].quadraticAttenuation != 0.0) {
- float dist = length(sUnnormalized);
- att = 1.0 / (lights[lightIndex].constantAttenuation +
- lights[lightIndex].linearAttenuation * dist +
- lights[lightIndex].quadraticAttenuation * dist * dist);
- }
-
- // The light direction is in world space already
- if (lights[lightIndex].type == TYPE_SPOT) {
- // Check if fragment is inside or outside of the spot light cone
- if (degrees(acos(dot(-s, lights[lightIndex].direction))) > lights[lightIndex].cutOffAngle)
- sDotN = 0.0;
- }
- }
- } else {
- // Directional lights
- // The light direction is in world space already
- s = normalize(-lights[lightIndex].direction);
- sDotN = dot(s, n);
- }
-
- h = normalize(s + v);
- sDotH = dot(s, h);
-
- // Calculate diffuse component
- vec3 diffuseColor = (1.0 - metalness) * baseColor;
- vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159;
-
- // Calculate specular component
- vec3 dielectricColor = vec3(0.04);
- vec3 F0 = mix(dielectricColor, baseColor, metalness);
- vec3 specularFactor = vec3(0.0);
- if (sDotN > 0.0) {
- specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h);
- specularFactor *= normalDistribution(n, h, alpha);
- }
- vec3 specularColor = lights[lightIndex].color;
- vec3 specular = specularColor * specularFactor;
-
- // Blend between diffuse and specular to conserver energy
- vec3 color = lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular));
-
- // Reduce by ambient occlusion amount
- color *= ambientOcclusion;
-
- return color;
-}
-
-vec3 pbrIblModel(const in vec3 wNormal,
- const in vec3 wView,
- const in vec3 baseColor,
- const in float metalness,
- const in float alpha,
- const in float ambientOcclusion)
-{
- // Calculate reflection direction of view vector about surface normal
- // vector in world space. This is used in the fragment shader to sample
- // from the environment textures for a light source. This is equivalent
- // to the l vector for punctual light sources. Armed with this, calculate
- // the usual factors needed
- vec3 n = wNormal;
- vec3 l = reflect(-wView, n);
- vec3 v = wView;
- vec3 h = normalize(l + v);
- float vDotN = dot(v, n);
- float lDotN = dot(l, n);
- float lDotH = dot(l, h);
-
- // Calculate diffuse component
- vec3 diffuseColor = (1.0 - metalness) * baseColor;
- vec3 diffuse = diffuseColor * texture(envLight.irradiance, l).rgb;
-
- // Calculate specular component
- vec3 dielectricColor = vec3(0.04);
- vec3 F0 = mix(dielectricColor, baseColor, metalness);
- vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h);
-
- float lod = alphaToMipLevel(alpha);
-//#define DEBUG_SPECULAR_LODS
-#ifdef DEBUG_SPECULAR_LODS
- if (lod > 7.0)
- return vec3(1.0, 0.0, 0.0);
- else if (lod > 6.0)
- return vec3(1.0, 0.333, 0.0);
- else if (lod > 5.0)
- return vec3(1.0, 1.0, 0.0);
- else if (lod > 4.0)
- return vec3(0.666, 1.0, 0.0);
- else if (lod > 3.0)
- return vec3(0.0, 1.0, 0.666);
- else if (lod > 2.0)
- return vec3(0.0, 0.666, 1.0);
- else if (lod > 1.0)
- return vec3(0.0, 0.0, 1.0);
- else if (lod > 0.0)
- return vec3(1.0, 0.0, 1.0);
-#endif
- vec3 specularSkyColor = textureLod(envLight.specular, l, lod).rgb;
- vec3 specular = specularSkyColor * specularFactor;
-
- // Blend between diffuse and specular to conserve energy
- vec3 iblColor = specular + diffuse * (vec3(1.0) - specularFactor);
-
- // Reduce by ambient occlusion amount
- iblColor *= ambientOcclusion;
-
- return iblColor;
-}
-
-vec3 toneMap(const in vec3 c)
-{
- return c / (c + vec3(1.0));
-}
-
-vec3 gammaCorrect(const in vec3 color)
-{
- return pow(color, vec3(1.0 / gamma));
-}
-
-void main()
-{
- vec3 cLinear = vec3(0.0);
-
- // Calculate the perturbed texture coordinates from parallax occlusion mapping
- mat3 worldToTangentMatrix = calcWorldSpaceToTangentSpaceMatrix(worldNormal, worldTangent);
- vec3 wView = normalize(eyePosition - worldPosition);
- vec3 tView = worldToTangentMatrix * wView;
-
- // Sample the inputs needed for the metal-roughness PBR BRDF
- vec3 baseColor = texture(baseColorMap, texCoord).rgb;
- float metalness = texture(metalnessMap, texCoord).r * metalFactor;
- float roughness = texture(roughnessMap, texCoord).r;
- float ambientOcclusion = texture(ambientOcclusionMap, texCoord).r;
- vec3 tNormal = 2.0 * texture(normalMap, texCoord).rgb - vec3(1.0);
- vec3 wNormal = normalize(transpose(worldToTangentMatrix) * tNormal);
-
- // Remap roughness for a perceptually more linear correspondence
- float alpha = remapRoughness(roughness);
-
- for (int i = 0; i < envLightCount; ++i) {
- cLinear += pbrIblModel(wNormal,
- wView,
- baseColor,
- metalness,
- alpha,
- ambientOcclusion);
- }
-
- for (int i = 0; i < lightCount; ++i) {
- cLinear += pbrModel(i,
- worldPosition,
- wNormal,
- wView,
- baseColor.rgb,
- metalness,
- alpha,
- ambientOcclusion);
- }
-
- // Apply exposure correction
- cLinear *= pow(2.0, exposure);
-
- // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1]
- vec3 cToneMapped = toneMap(cLinear);
-
- // Apply gamma correction prior to display
- vec3 cGamma = gammaCorrect(cToneMapped);
- fragColor = vec4(cGamma, 1.0);
-}
diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalrough.inc.frag
index f4bad0a00..f7e3eecb7 100644
--- a/src/extras/shaders/gl3/metalroughuniform.frag
+++ b/src/extras/shaders/gl3/metalrough.inc.frag
@@ -48,24 +48,6 @@
**
****************************************************************************/
-#version 150
-
-in vec2 texCoord;
-in vec3 worldPosition;
-in vec3 worldNormal;
-in vec4 worldTangent;
-
-out vec4 fragColor;
-
-// Qt 3D built in uniforms
-uniform vec3 eyePosition; // World space eye position
-uniform float time; // Time in seconds
-
-// PBR Material maps
-uniform vec4 baseColor;
-uniform float metalness;
-uniform float roughness;
-
// Exposure correction
uniform float exposure = 0.0;
// Gamma correction
@@ -76,7 +58,7 @@ uniform float gamma = 2.2;
int mipLevelCount(const in samplerCube cube)
{
int baseSize = textureSize(cube, 0).x;
- int nMips = int(log2(float(baseSize>0 ? baseSize : 1))) + 1;
+ int nMips = int(log2(float(baseSize > 0 ? baseSize : 1))) + 1;
return nMips;
}
@@ -92,26 +74,6 @@ float remapRoughness(const in float roughness)
return max(roughness * roughness, minRoughness);
}
-mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent)
-{
- // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
- // This allows to build the tangentMatrix below by simply transposing the
- // tangent -> eyespace matrix (which would now be orthogonal)
- vec3 wFixedTangent = normalize(wTangent.xyz - dot(wTangent.xyz, wNormal) * wNormal);
-
- // Calculate binormal vector. No "real" need to renormalize it,
- // as built by crossing two normal vectors.
- // To orient the binormal correctly, use the fourth coordinate of the tangent,
- // which is +1 for a right hand system, and -1 for a left hand system.
- vec3 wBinormal = cross(wNormal, wFixedTangent.xyz) * wTangent.w;
-
- // Construct matrix to transform from world space to tangent space
- // This is the transpose of the tangentToWorld transformation matrix
- mat3 tangentToWorldMatrix = mat3(wFixedTangent, wBinormal, wNormal);
- mat3 worldToTangentMatrix = transpose(tangentToWorldMatrix);
- return worldToTangentMatrix;
-}
-
float alphaToMipLevel(float alpha)
{
float specPower = 2.0 / (alpha * alpha) - 2.0;
@@ -195,7 +157,8 @@ vec3 pbrModel(const in int lightIndex,
const in vec3 wView,
const in vec3 baseColor,
const in float metalness,
- const in float alpha)
+ const in float alpha,
+ const in float ambientOcclusion)
{
// Calculate some useful quantities
vec3 n = wNormal;
@@ -258,14 +221,20 @@ vec3 pbrModel(const in int lightIndex,
vec3 specular = specularColor * specularFactor;
// Blend between diffuse and specular to conserver energy
- return att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular));
+ vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular));
+
+ // Reduce by ambient occlusion amount
+ color *= ambientOcclusion;
+
+ return color;
}
vec3 pbrIblModel(const in vec3 wNormal,
const in vec3 wView,
const in vec3 baseColor,
const in float metalness,
- const in float alpha)
+ const in float alpha,
+ const in float ambientOcclusion)
{
// Calculate reflection direction of view vector about surface normal
// vector in world space. This is used in the fragment shader to sample
@@ -289,11 +258,6 @@ vec3 pbrIblModel(const in vec3 wNormal,
vec3 F0 = mix(dielectricColor, baseColor, metalness);
vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h);
- // As per page 14 of
- // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
- // we remap the roughness to give a more perceptually linear response
- // of "bluriness" as a function of the roughness specified by the user.
- // r = roughness^2
float lod = alphaToMipLevel(alpha);
//#define DEBUG_SPECULAR_LODS
#ifdef DEBUG_SPECULAR_LODS
@@ -318,7 +282,12 @@ vec3 pbrIblModel(const in vec3 wNormal,
vec3 specular = specularSkyColor * specularFactor;
// Blend between diffuse and specular to conserve energy
- return specular + diffuse * (vec3(1.0) - specularFactor);
+ vec3 color = specular + diffuse * (vec3(1.0) - specularFactor);
+
+ // Reduce by ambient occlusion amount
+ color *= ambientOcclusion;
+
+ return color;
}
vec3 toneMap(const in vec3 c)
@@ -331,32 +300,37 @@ vec3 gammaCorrect(const in vec3 color)
return pow(color, vec3(1.0 / gamma));
}
-void main()
+vec4 metalRoughFunction(const in vec4 baseColor,
+ const in float metalness,
+ const in float roughness,
+ const in float ambientOcclusion,
+ const in vec3 worldPosition,
+ const in vec3 worldView,
+ const in vec3 worldNormal)
{
vec3 cLinear = vec3(0.0);
// Remap roughness for a perceptually more linear correspondence
float alpha = remapRoughness(roughness);
-
- vec3 wNormal = normalize(worldNormal);
- vec3 worldView = normalize(eyePosition - worldPosition);
for (int i = 0; i < envLightCount; ++i) {
- cLinear += pbrIblModel(wNormal,
+ cLinear += pbrIblModel(worldNormal,
worldView,
baseColor.rgb,
metalness,
- alpha);
+ alpha,
+ ambientOcclusion);
}
for (int i = 0; i < lightCount; ++i) {
cLinear += pbrModel(i,
worldPosition,
- wNormal,
+ worldNormal,
worldView,
baseColor.rgb,
metalness,
- alpha);
+ alpha,
+ ambientOcclusion);
}
// Apply exposure correction
@@ -367,5 +341,6 @@ void main()
// Apply gamma correction prior to display
vec3 cGamma = gammaCorrect(cToneMapped);
- fragColor = vec4(cGamma, 1.0);
+
+ return vec4(cGamma, 1.0);
}
diff --git a/src/extras/shaders/gl3/normaldiffusemap.frag b/src/extras/shaders/gl3/normaldiffusemap.frag
deleted file mode 100644
index a99a7ed73..000000000
--- a/src/extras/shaders/gl3/normaldiffusemap.frag
+++ /dev/null
@@ -1,33 +0,0 @@
-#version 150 core
-
-in vec3 worldPosition;
-in vec2 texCoord;
-in mat3 tangentMatrix;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D normalTexture;
-
-// TODO: Replace with a struct
-uniform vec3 ka; // Ambient reflectivity
-uniform vec3 ks; // Specular reflectivity
-uniform float shininess; // Specular shininess factor
-
-uniform vec3 eyePosition;
-
-out vec4 fragColor;
-
-#pragma include light.inc.frag
-
-void main()
-{
- // Sample the textures at the interpolated texCoords
- vec4 diffuseTextureColor = texture( diffuseTexture, texCoord );
- vec3 normal = 2.0 * texture( normalTexture, texCoord ).rgb - vec3( 1.0 );
-
- // Calculate the lighting model, keeping the specular component separate
- vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
-
- // Combine spec with ambient+diffuse for final fragment color
- fragColor = vec4( ka + diffuseTextureColor.rgb * diffuseColor + ks * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/gl3/normaldiffusemap.vert b/src/extras/shaders/gl3/normaldiffusemap.vert
deleted file mode 100644
index 8da443e8d..000000000
--- a/src/extras/shaders/gl3/normaldiffusemap.vert
+++ /dev/null
@@ -1,47 +0,0 @@
-#version 150 core
-
-in vec3 vertexPosition;
-in vec3 vertexNormal;
-in vec2 vertexTexCoord;
-in vec4 vertexTangent;
-
-out vec3 worldPosition;
-out vec2 texCoord;
-out mat3 tangentMatrix;
-
-uniform mat4 modelMatrix;
-uniform mat3 modelNormalMatrix;
-uniform mat4 mvp;
-
-uniform float texCoordScale;
-
-void main()
-{
- // Pass through scaled texture coordinates
- texCoord = vertexTexCoord * texCoordScale;
-
- // Transform position, normal, and tangent to world coords
- worldPosition = vec3(modelMatrix * vec4(vertexPosition, 1.0));
- vec3 normal = normalize(modelNormalMatrix * vertexNormal);
- vec3 tangent = normalize(vec3(modelMatrix * vec4(vertexTangent.xyz, 0.0)));
-
- // Make the tangent truly orthogonal to the normal by using Gram-Schmidt.
- // This allows to build the tangentMatrix below by simply transposing the
- // tangent -> world space matrix (which would now be orthogonal)
- tangent = normalize(tangent - dot(tangent, normal) * normal);
-
- // Calculate binormal vector. No "real" need to renormalize it,
- // as built by crossing two normal vectors.
- // To orient the binormal correctly, use the fourth coordinate of the tangent,
- // which is +1 for a right hand system, and -1 for a left hand system.
- vec3 binormal = cross(normal, tangent) * vertexTangent.w;
-
- // Construct matrix to transform from eye coords to tangent space
- tangentMatrix = mat3(
- tangent.x, binormal.x, normal.x,
- tangent.y, binormal.y, normal.y,
- tangent.z, binormal.z, normal.z);
-
- // Calculate vertex position in clip coordinates
- gl_Position = mvp * vec4(vertexPosition, 1.0);
-}
diff --git a/src/extras/shaders/gl3/normaldiffusemapalpha.frag b/src/extras/shaders/gl3/normaldiffusemapalpha.frag
deleted file mode 100644
index ce5cf0e90..000000000
--- a/src/extras/shaders/gl3/normaldiffusemapalpha.frag
+++ /dev/null
@@ -1,34 +0,0 @@
-#version 150 core
-
-in vec3 worldPosition;
-in vec2 texCoord;
-in mat3 tangentMatrix;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D normalTexture;
-
-// TODO: Replace with a struct
-uniform vec3 ka; // Ambient reflectivity
-uniform vec3 ks; // Specular reflectivity
-uniform float shininess; // Specular shininess factor
-
-uniform vec3 eyePosition;
-
-out vec4 fragColor;
-
-#pragma include light.inc.frag
-
-void main()
-{
- // Sample the textures at the interpolated texCoords
- vec4 diffuseTextureColor = texture( diffuseTexture, texCoord );
- vec3 normal = 2.0 * texture( normalTexture, texCoord ).rgb - vec3( 1.0 );
-
- // Calculate the lighting model, keeping the specular component separate
- vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition, shininess, tangentMatrix, diffuseColor, specularColor);
-
- // Combine spec with ambient+diffuse for final fragment color
- // Use the alpha from the diffuse texture (for alpha to coverage)
- fragColor = vec4( ka + diffuseTextureColor.rgb * diffuseColor + ks * specularColor, diffuseTextureColor.a );
-}
diff --git a/src/extras/shaders/gl3/normaldiffusespecularmap.frag b/src/extras/shaders/gl3/normaldiffusespecularmap.frag
deleted file mode 100644
index b60cfe84c..000000000
--- a/src/extras/shaders/gl3/normaldiffusespecularmap.frag
+++ /dev/null
@@ -1,35 +0,0 @@
-#version 150 core
-
-in vec3 worldPosition;
-in vec2 texCoord;
-in mat3 tangentMatrix;
-
-out vec4 fragColor;
-
-uniform sampler2D diffuseTexture;
-uniform sampler2D specularTexture;
-uniform sampler2D normalTexture;
-
-uniform vec3 ka; // Ambient reflectivity
-uniform float shininess; // Specular shininess factor
-uniform vec3 eyePosition;
-
-#pragma include light.inc.frag
-
-void main()
-{
- // Sample the textures at the interpolated texCoords
- vec4 diffuseTextureColor = texture( diffuseTexture, texCoord );
- vec4 specularTextureColor = texture( specularTexture, texCoord );
- vec3 normal = 2.0 * texture( normalTexture, texCoord ).rgb - vec3( 1.0 );
-
- // Calculate the lighting model, keeping the specular component separate
- vec3 diffuseColor, specularColor;
- adsModelNormalMapped(worldPosition, normal, eyePosition,
- shininess, tangentMatrix,
- diffuseColor, specularColor);
-
- // Combine spec with ambient+diffuse for final fragment color
- fragColor = vec4((ka + diffuseColor) * diffuseTextureColor.rgb
- + specularColor * specularTextureColor.rgb, 1.0);
-}
diff --git a/src/extras/shaders/gl3/pervertexcolor.frag b/src/extras/shaders/gl3/pervertexcolor.frag
index b5ed5a33d..40fc066d6 100644
--- a/src/extras/shaders/gl3/pervertexcolor.frag
+++ b/src/extras/shaders/gl3/pervertexcolor.frag
@@ -2,15 +2,16 @@
in vec3 worldPosition;
in vec3 worldNormal;
-in vec3 color;
+in vec4 color;
out vec4 fragColor;
-#pragma include light.inc.frag
+uniform vec3 eyePosition;
+
+#pragma include phong.inc.frag
void main()
{
- vec3 diffuseColor;
- adModel(worldPosition, worldNormal, diffuseColor);
- fragColor = vec4( color + color * diffuseColor, 1.0 );
+ vec3 worldView = normalize(eyePosition - worldPosition);
+ fragColor = phongFunction(color, color, vec4(0.0), 0.0, worldPosition, worldView, worldNormal);
}
diff --git a/src/extras/shaders/gl3/pervertexcolor.vert b/src/extras/shaders/gl3/pervertexcolor.vert
index 87713a520..1d721e945 100644
--- a/src/extras/shaders/gl3/pervertexcolor.vert
+++ b/src/extras/shaders/gl3/pervertexcolor.vert
@@ -2,11 +2,11 @@
in vec3 vertexPosition;
in vec3 vertexNormal;
-in vec3 vertexColor;
+in vec4 vertexColor;
out vec3 worldPosition;
out vec3 worldNormal;
-out vec3 color;
+out vec4 color;
uniform mat4 modelMatrix;
uniform mat3 modelNormalMatrix;
diff --git a/src/extras/shaders/gl3/phong.frag b/src/extras/shaders/gl3/phong.frag
deleted file mode 100644
index a4d7e0969..000000000
--- a/src/extras/shaders/gl3/phong.frag
+++ /dev/null
@@ -1,22 +0,0 @@
-#version 150 core
-
-uniform vec3 ka; // Ambient reflectivity
-uniform vec3 kd; // Diffuse reflectivity
-uniform vec3 ks; // Specular reflectivity
-uniform float shininess; // Specular shininess factor
-
-uniform vec3 eyePosition;
-
-in vec3 worldPosition;
-in vec3 worldNormal;
-
-out vec4 fragColor;
-
-#pragma include light.inc.frag
-
-void main()
-{
- vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
- fragColor = vec4( ka + kd * diffuseColor + ks * specularColor, 1.0 );
-}
diff --git a/src/extras/shaders/gl3/phong.inc.frag b/src/extras/shaders/gl3/phong.inc.frag
new file mode 100644
index 000000000..47a6ecd4a
--- /dev/null
+++ b/src/extras/shaders/gl3/phong.inc.frag
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+#pragma include light.inc.frag
+
+void adsModel(const in vec3 worldPos,
+ const in vec3 worldNormal,
+ const in vec3 worldView,
+ const in float shininess,
+ out vec3 diffuseColor,
+ out vec3 specularColor)
+{
+ diffuseColor = vec3(0.0);
+ specularColor = vec3(0.0);
+
+ // We perform all work in world space
+ vec3 n = normalize(worldNormal);
+ vec3 s = vec3(0.0);
+
+ for (int i = 0; i < lightCount; ++i) {
+ float att = 1.0;
+ float sDotN = 0.0;
+
+ if (lights[i].type != TYPE_DIRECTIONAL) {
+ // Point and Spot lights
+
+ // Light position is already in world space
+ vec3 sUnnormalized = lights[i].position - worldPos;
+ s = normalize(sUnnormalized); // Light direction
+
+ // Calculate the attenuation factor
+ sDotN = dot(s, n);
+ if (sDotN > 0.0) {
+ if (lights[i].constantAttenuation != 0.0
+ || lights[i].linearAttenuation != 0.0
+ || lights[i].quadraticAttenuation != 0.0) {
+ float dist = length(sUnnormalized);
+ att = 1.0 / (lights[i].constantAttenuation +
+ lights[i].linearAttenuation * dist +
+ lights[i].quadraticAttenuation * dist * dist);
+ }
+
+ // The light direction is in world space already
+ if (lights[i].type == TYPE_SPOT) {
+ // Check if fragment is inside or outside of the spot light cone
+ if (degrees(acos(dot(-s, lights[i].direction))) > lights[i].cutOffAngle)
+ sDotN = 0.0;
+ }
+ }
+ } else {
+ // Directional lights
+ // The light direction is in world space already
+ s = normalize(-lights[i].direction);
+ sDotN = dot(s, n);
+ }
+
+ // Calculate the diffuse factor
+ float diffuse = max(sDotN, 0.0);
+
+ // Calculate the specular factor
+ float specular = 0.0;
+ if (diffuse > 0.0 && shininess > 0.0) {
+ float normFactor = (shininess + 2.0) / 2.0;
+ vec3 r = reflect(-s, n); // Reflection direction in world space
+ specular = normFactor * pow(max(dot(r, worldView), 0.0), shininess);
+ }
+
+ // Accumulate the diffuse and specular contributions
+ diffuseColor += att * lights[i].intensity * diffuse * lights[i].color;
+ specularColor += att * lights[i].intensity * specular * lights[i].color;
+ }
+}
+
+vec4 phongFunction(const in vec4 ambient,
+ const in vec4 diffuse,
+ const in vec4 specular,
+ const in float shininess,
+ const in vec3 worldPosition,
+ const in vec3 worldView,
+ const in vec3 worldNormal)
+{
+ // Calculate the lighting model, keeping the specular component separate
+ vec3 diffuseColor, specularColor;
+ adsModel(worldPosition, worldNormal, worldView, shininess, diffuseColor, specularColor);
+
+ // Combine spec with ambient+diffuse for final fragment color
+ vec3 color = (ambient.rgb + diffuseColor) * diffuse.rgb
+ + specularColor * specular.rgb;
+
+ return vec4(color, diffuse.a);
+}
diff --git a/src/extras/shaders/gl3/phong.vert b/src/extras/shaders/gl3/phong.vert
deleted file mode 100644
index cdb3c70e9..000000000
--- a/src/extras/shaders/gl3/phong.vert
+++ /dev/null
@@ -1,19 +0,0 @@
-#version 150 core
-
-in vec3 vertexPosition;
-in vec3 vertexNormal;
-
-out vec3 worldPosition;
-out vec3 worldNormal;
-
-uniform mat4 modelMatrix;
-uniform mat3 modelNormalMatrix;
-uniform mat4 modelViewProjection;
-
-void main()
-{
- worldNormal = normalize( modelNormalMatrix * vertexNormal );
- worldPosition = vec3( modelMatrix * vec4( vertexPosition, 1.0 ) );
-
- gl_Position = modelViewProjection * vec4( vertexPosition, 1.0 );
-}
diff --git a/src/extras/shaders/gl3/phongalpha.frag b/src/extras/shaders/gl3/phongalpha.frag
deleted file mode 100644
index cb019e9aa..000000000
--- a/src/extras/shaders/gl3/phongalpha.frag
+++ /dev/null
@@ -1,24 +0,0 @@
-#version 150 core
-
-// TODO: Replace with a struct
-uniform vec3 ka; // Ambient reflectivity
-uniform vec3 kd; // Diffuse reflectivity
-uniform vec3 ks; // Specular reflectivity
-uniform float shininess; // Specular shininess factor
-uniform float alpha;
-
-uniform vec3 eyePosition;
-
-in vec3 worldPosition;
-in vec3 worldNormal;
-
-out vec4 fragColor;
-
-#pragma include light.inc.frag
-
-void main()
-{
- vec3 diffuseColor, specularColor;
- adsModel(worldPosition, worldNormal, eyePosition, shininess, diffuseColor, specularColor);
- fragColor = vec4( ka + kd * diffuseColor + ks * specularColor, alpha );
-}
diff --git a/src/extras/shaders/gl3/unlittexture.vert b/src/extras/shaders/gl3/unlittexture.vert
index 4aaa10a8f..7e245bd7f 100644
--- a/src/extras/shaders/gl3/unlittexture.vert
+++ b/src/extras/shaders/gl3/unlittexture.vert
@@ -8,11 +8,12 @@ out vec2 texCoord;
uniform mat4 modelView;
uniform mat4 mvp;
-uniform vec2 texCoordOffset;
+uniform mat3 texCoordTransform;
void main()
{
- texCoord = vertexTexCoord + texCoordOffset;
+ vec3 tt = texCoordTransform * vec3(vertexTexCoord, 1.0);
+ texCoord = (tt / tt.z).xy;
position = vec3( modelView * vec4( vertexPosition, 1.0 ) );
gl_Position = mvp * vec4( vertexPosition, 1.0 );
diff --git a/src/extras/shaders/graphs/metalrough.frag.json b/src/extras/shaders/graphs/metalrough.frag.json
new file mode 100644
index 000000000..b40044d1b
--- /dev/null
+++ b/src/extras/shaders/graphs/metalrough.frag.json
@@ -0,0 +1,569 @@
+{
+ "nodes": [
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000001}",
+ "type": "input",
+ "parameters": {
+ "name": "worldPosition",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000002}",
+ "type": "eyePosition"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000003}",
+ "type": "input",
+ "parameters": {
+ "name": "worldNormal",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000004}",
+ "type": "input",
+ "layers": ["normalMap"],
+ "parameters": {
+ "name": "worldTangent",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000005}",
+ "type": "input",
+ "layers": ["baseColorMap", "metalnessMap", "roughnessMap", "ambientOcclusionMap", "normalMap"],
+ "parameters": {
+ "name": "texCoord",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec2"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000006}",
+ "type": "input",
+ "layers": ["baseColor"],
+ "parameters": {
+ "name": "baseColor",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000007}",
+ "type": "sampleTexture",
+ "layers": ["baseColorMap"],
+ "parameters": {
+ "name": "baseColorMap"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000008}",
+ "type": "input",
+ "layers": ["metalness"],
+ "parameters": {
+ "name": "metalness",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000009}",
+ "layers": ["metalnessMap"],
+ "type": "sampleTexture",
+ "parameters": {
+ "name": "metalnessMap"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000010}",
+ "type": "swizzle",
+ "layers": ["metalnessMap"],
+ "parameters": {
+ "fields": "r",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000011}",
+ "type": "input",
+ "layers": ["roughness"],
+ "parameters": {
+ "name": "roughness",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000012}",
+ "type": "sampleTexture",
+ "layers": ["roughnessMap"],
+ "parameters": {
+ "name": "roughnessMap"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000013}",
+ "type": "swizzle",
+ "layers": ["roughnessMap"],
+ "parameters": {
+ "fields": "r",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000014}",
+ "type": "constant",
+ "layers": ["ambientOcclusion"],
+ "parameters": {
+ "constant": "1.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000015}",
+ "type": "sampleTexture",
+ "layers": ["ambientOcclusionMap"],
+ "parameters": {
+ "name": "ambientOcclusionMap"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000016}",
+ "type": "swizzle",
+ "layers": ["ambientOcclusionMap"],
+ "parameters": {
+ "fields": "r",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000017}",
+ "type": "sampleTexture",
+ "layers": ["normalMap"],
+ "parameters": {
+ "name": "normalMap"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000018}",
+ "type": "swizzle",
+ "layers": ["normalMap"],
+ "parameters": {
+ "fields": "rgb",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000019}",
+ "type": "subtract",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000020}",
+ "type": "normalize",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000021}",
+ "type": "worldSpaceToTangentSpaceMatrix",
+ "layers": ["normalMap"]
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000022}",
+ "type": "transpose",
+ "layers": ["normalMap"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Mat3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000023}",
+ "type": "multiply",
+ "layers": ["normalMap"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000024}",
+ "type": "constant",
+ "layers": ["normalMap"],
+ "parameters": {
+ "constant": "2.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000025}",
+ "type": "multiply",
+ "layers": ["normalMap"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000026}",
+ "type": "constant",
+ "layers": ["normalMap"],
+ "parameters": {
+ "constant": "1.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000027}",
+ "type": "subtract",
+ "layers": ["normalMap"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000028}",
+ "type": "normalize",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000029}",
+ "type": "metalRoughFunction"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000030}",
+ "type": "fragColor"
+ }
+ ],
+ "edges": [
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "worldPosition"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000019}",
+ "targetPort": "subtrahend"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000002}",
+ "sourcePort": "eyePosition",
+ "targetUuid": "{00000000-0000-0000-0000-000000000019}",
+ "targetPort": "minuend"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000019}",
+ "sourcePort": "difference",
+ "targetUuid": "{00000000-0000-0000-0000-000000000020}",
+ "targetPort": "input"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000020}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "worldView"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000028}",
+ "targetPort": "input",
+ "layers": ["normal"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000021}",
+ "targetPort": "worldNormal",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000004}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000021}",
+ "targetPort": "worldTangent",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000021}",
+ "sourcePort": "matrix",
+ "targetUuid": "{00000000-0000-0000-0000-000000000022}",
+ "targetPort": "input",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000022}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000023}",
+ "targetPort": "first",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000017}",
+ "targetPort": "coord",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000017}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000018}",
+ "targetPort": "input",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000018}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000025}",
+ "targetPort": "first",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000024}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000025}",
+ "targetPort": "second",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000025}",
+ "sourcePort": "product",
+ "targetUuid": "{00000000-0000-0000-0000-000000000027}",
+ "targetPort": "minuend",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000026}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000027}",
+ "targetPort": "subtrahend",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000027}",
+ "sourcePort": "difference",
+ "targetUuid": "{00000000-0000-0000-0000-000000000023}",
+ "targetPort": "second",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000023}",
+ "sourcePort": "product",
+ "targetUuid": "{00000000-0000-0000-0000-000000000028}",
+ "targetPort": "input",
+ "layers": ["normalMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000028}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "worldNormal"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000006}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "baseColor",
+ "layers": ["baseColor"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000007}",
+ "targetPort": "coord",
+ "layers": ["baseColorMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000007}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "baseColor",
+ "layers": ["baseColorMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000008}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "metalness",
+ "layers": ["metalness"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000009}",
+ "targetPort": "coord",
+ "layers": ["metalnessMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000009}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000010}",
+ "targetPort": "input",
+ "layers": ["metalnessMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000010}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "metalness",
+ "layers": ["metalnessMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000011}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "roughness",
+ "layers": ["roughness"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000012}",
+ "targetPort": "coord",
+ "layers": ["roughnessMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000012}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000013}",
+ "targetPort": "input",
+ "layers": ["roughnessMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000013}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "roughness",
+ "layers": ["roughnessMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000014}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "ambientOcclusion",
+ "layers": ["ambientOcclusion"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000015}",
+ "targetPort": "coord",
+ "layers": ["ambientOcclusionMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000015}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000016}",
+ "targetPort": "input",
+ "layers": ["ambientOcclusionMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000016}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000029}",
+ "targetPort": "ambientOcclusion",
+ "layers": ["ambientOcclusionMap"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000029}",
+ "sourcePort": "outputColor",
+ "targetUuid": "{00000000-0000-0000-0000-000000000030}",
+ "targetPort": "fragColor"
+ }
+ ]
+}
diff --git a/src/extras/shaders/graphs/phong.frag.json b/src/extras/shaders/graphs/phong.frag.json
new file mode 100644
index 000000000..dedeb1067
--- /dev/null
+++ b/src/extras/shaders/graphs/phong.frag.json
@@ -0,0 +1,466 @@
+{
+ "nodes": [
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000001}",
+ "type": "input",
+ "parameters": {
+ "name": "worldPosition",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000002}",
+ "type": "eyePosition"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000003}",
+ "type": "input",
+ "parameters": {
+ "name": "worldNormal",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000004}",
+ "type": "input",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "name": "worldTangent",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000005}",
+ "type": "input",
+ "layers": ["diffuseTexture", "specularTexture", "normalTexture"],
+ "parameters": {
+ "name": "texCoord",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec2"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000006}",
+ "type": "input",
+ "parameters": {
+ "name": "ka",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000007}",
+ "type": "input",
+ "layers": ["diffuse"],
+ "parameters": {
+ "name": "kd",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000008}",
+ "type": "sampleTexture",
+ "layers": ["diffuseTexture"],
+ "parameters": {
+ "name": "diffuseTexture"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000009}",
+ "type": "input",
+ "layers": ["specular"],
+ "parameters": {
+ "name": "ks",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000010}",
+ "layers": ["specularTexture"],
+ "type": "sampleTexture",
+ "parameters": {
+ "name": "specularTexture"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000011}",
+ "type": "input",
+ "parameters": {
+ "name": "shininess",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Uniform"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000012}",
+ "type": "subtract",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000013}",
+ "type": "normalize",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000014}",
+ "type": "normalize",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000015}",
+ "type": "worldSpaceToTangentSpaceMatrix",
+ "layers": ["normalTexture"]
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000016}",
+ "type": "transpose",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Mat3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000017}",
+ "type": "sampleTexture",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "name": "normalTexture"
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000018}",
+ "type": "swizzle",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "fields": "rgb",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000019}",
+ "type": "constant",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "constant": "2.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000020}",
+ "type": "multiply",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000021}",
+ "type": "constant",
+ "layers": ["normalTexture"],
+ "parameters": {
+ "constant": "1.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000022}",
+ "type": "subtract",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000023}",
+ "type": "multiply",
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ }
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000024}",
+ "type": "phongFunction"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000025}",
+ "type": "fragColor"
+ }
+ ],
+ "edges": [
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "worldPosition"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000012}",
+ "targetPort": "subtrahend"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000002}",
+ "sourcePort": "eyePosition",
+ "targetUuid": "{00000000-0000-0000-0000-000000000012}",
+ "targetPort": "minuend"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000012}",
+ "sourcePort": "difference",
+ "targetUuid": "{00000000-0000-0000-0000-000000000013}",
+ "targetPort": "input"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000013}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "worldView"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000014}",
+ "targetPort": "input",
+ "layers": ["normal"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000015}",
+ "targetPort": "worldNormal",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000004}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000015}",
+ "targetPort": "worldTangent",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000015}",
+ "sourcePort": "matrix",
+ "targetUuid": "{00000000-0000-0000-0000-000000000016}",
+ "targetPort": "input",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000016}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000023}",
+ "targetPort": "first",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000017}",
+ "targetPort": "coord",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000017}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000018}",
+ "targetPort": "input",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000018}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000020}",
+ "targetPort": "first",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000019}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000020}",
+ "targetPort": "second",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000020}",
+ "sourcePort": "product",
+ "targetUuid": "{00000000-0000-0000-0000-000000000022}",
+ "targetPort": "minuend",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000021}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000022}",
+ "targetPort": "subtrahend",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000022}",
+ "sourcePort": "difference",
+ "targetUuid": "{00000000-0000-0000-0000-000000000023}",
+ "targetPort": "second",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000023}",
+ "sourcePort": "product",
+ "targetUuid": "{00000000-0000-0000-0000-000000000014}",
+ "targetPort": "input",
+ "layers": ["normalTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000014}",
+ "sourcePort": "output",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "worldNormal"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000006}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "ambient"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000007}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "diffuse",
+ "layers": ["diffuse"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000008}",
+ "targetPort": "coord",
+ "layers": ["diffuseTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000008}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "diffuse",
+ "layers": ["diffuseTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000009}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "specular",
+ "layers": ["specular"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000010}",
+ "targetPort": "coord",
+ "layers": ["specularTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000010}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "specular",
+ "layers": ["specularTexture"]
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000011}",
+ "sourcePort": "value",
+ "targetUuid": "{00000000-0000-0000-0000-000000000024}",
+ "targetPort": "shininess"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000024}",
+ "sourcePort": "outputColor",
+ "targetUuid": "{00000000-0000-0000-0000-000000000025}",
+ "targetPort": "fragColor"
+ }
+ ]
+}
diff --git a/src/extras/text/distancefieldtextrenderer.cpp b/src/extras/text/distancefieldtextrenderer.cpp
index 9f390e8da..4cf9c0b4a 100644
--- a/src/extras/text/distancefieldtextrenderer.cpp
+++ b/src/extras/text/distancefieldtextrenderer.cpp
@@ -80,8 +80,8 @@ void DistanceFieldTextRendererPrivate::init()
m_geometry = new Qt3DRender::QGeometry(m_renderer);
m_renderer->setGeometry(m_geometry);
- m_vertexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::VertexBuffer, m_geometry);
- m_indexBuffer = new Qt3DRender::QBuffer(Qt3DRender::QBuffer::IndexBuffer, m_geometry);
+ m_vertexBuffer = new Qt3DRender::QBuffer(m_geometry);
+ m_indexBuffer = new Qt3DRender::QBuffer(m_geometry);
m_positionAttr = new Qt3DRender::QAttribute(m_geometry);
m_positionAttr->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
diff --git a/src/extras/text/qtextureatlas.cpp b/src/extras/text/qtextureatlas.cpp
index bc29537da..1f4b22d83 100644
--- a/src/extras/text/qtextureatlas.cpp
+++ b/src/extras/text/qtextureatlas.cpp
@@ -117,7 +117,7 @@ QByteArray QTextureAtlasData::createUpdatedImageData()
}
}
- return QByteArray(reinterpret_cast<const char*>(m_image.constBits()), m_image.byteCount());
+ return QByteArray(reinterpret_cast<const char*>(m_image.constBits()), m_image.sizeInBytes());
}
QTextureAtlasPrivate::QTextureAtlasPrivate()
diff --git a/src/logic/manager.cpp b/src/logic/manager.cpp
index 7b654ccd4..e10ace592 100644
--- a/src/logic/manager.cpp
+++ b/src/logic/manager.cpp
@@ -88,6 +88,11 @@ void Manager::removeHandler(Qt3DCore::QNodeId id)
m_logicHandlerManager->releaseResource(id);
}
+bool Manager::hasFrameActions() const
+{
+ return m_logicHandlers.count() > 0;
+}
+
void Manager::triggerLogicFrameUpdates()
{
Q_ASSERT(m_executor);
diff --git a/src/logic/manager_p.h b/src/logic/manager_p.h
index 39c0b5342..918bd57e0 100644
--- a/src/logic/manager_p.h
+++ b/src/logic/manager_p.h
@@ -83,6 +83,7 @@ public:
void appendHandler(Handler *handler);
void removeHandler(Qt3DCore::QNodeId id);
+ bool hasFrameActions() const;
void triggerLogicFrameUpdates();
diff --git a/src/logic/qlogicaspect.cpp b/src/logic/qlogicaspect.cpp
index 04add1408..d36e9b09d 100644
--- a/src/logic/qlogicaspect.cpp
+++ b/src/logic/qlogicaspect.cpp
@@ -124,7 +124,10 @@ QVector<QAspectJobPtr> QLogicAspect::jobsToExecute(qint64 time)
// Create jobs that will get executed by the threadpool
QVector<QAspectJobPtr> jobs;
- jobs.append(d->m_callbackJob);
+
+ if (d->m_manager->hasFrameActions())
+ jobs.append(d->m_callbackJob);
+
return jobs;
}
diff --git a/src/plugins/geometryloaders/default/plygeometryloader.cpp b/src/plugins/geometryloaders/default/plygeometryloader.cpp
index a51c991af..1e50dbfeb 100644
--- a/src/plugins/geometryloaders/default/plygeometryloader.cpp
+++ b/src/plugins/geometryloaders/default/plygeometryloader.cpp
@@ -217,6 +217,11 @@ bool PlyGeometryLoader::doLoad(QIODevice *ioDev, const QString &subMesh)
return true;
}
+/*!
+ Read and parse the header of the PLY format file.
+ Returns \c false if one of the lines is wrongly
+ formatted.
+*/
bool PlyGeometryLoader::parseHeader(QIODevice *ioDev)
{
Format format = FormatUnknown;
@@ -424,6 +429,59 @@ bool PlyGeometryLoader::parseMesh(QIODevice *ioDev)
return true;
}
+/*!
+ \enum Qt3DRender::PlyGeometryLoader::DataType
+
+ Specifies the data type specified in the parsed file.
+
+ \value Int8
+ \value Uint8
+ \value Int16
+ \value Uint16
+ \value Int32
+ \value Uint32
+ \value Float32
+ \value Float64
+ \value TypeList
+ \value TypeUnknown
+*/
+/*!
+ \enum Qt3DRender::PlyGeometryLoader::Format
+
+ Specifies the format mentioned in the header of the parsed file.
+
+ \value FormatAscii
+ \value FormatBinaryLittleEndian
+ \value FormatBinaryBigEndian
+ \value FormatUnknown
+*/
+/*!
+ \enum Qt3DRender::PlyGeometryLoader::ElementType
+
+ Specifies the element type mentioned in the header of the file.
+
+ \value ElementVertex
+ \value ElementFace
+ \value ElementUnknown
+
+*/
+/*!
+ \enum Qt3DRender::PlyGeometryLoader::PropertyType
+
+ Specifies the property type from the PLY format file that has been loaded.
+
+ \value PropertyVertexIndex Property name in header is \c vertex_index
+ \value PropertyX Property name in header is \c X
+ \value PropertyY Property name in header is \c Y
+ \value PropertyZ Property name in header is \c Z
+ \value PropertyNormalX Property name in header is \c NormalX
+ \value PropertyNormalY Property name in header is \c NormalY
+ \value PropertyNormalZ Property name in header is \c NormalZ
+ \value PropertyTextureU Property name in header is \c TextureU
+ \value PropertyTextureV Property name in header is \c TextureV
+ \value PropertyUnknown Property name in header is unknown
+
+*/
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/plugins/geometryloaders/fbx/fbxgeometryloader.cpp b/src/plugins/geometryloaders/fbx/fbxgeometryloader.cpp
index 7b1b8e4ee..10870dde8 100644
--- a/src/plugins/geometryloaders/fbx/fbxgeometryloader.cpp
+++ b/src/plugins/geometryloaders/fbx/fbxgeometryloader.cpp
@@ -234,12 +234,20 @@ FbxGeometryLoader::~FbxGeometryLoader()
m_manager->Destroy();
}
-QGeometry *FbxGeometryLoader::geometry() const
+/*!
+ Give the list of attributes that can be used to render
+ a 3D form.
+ Returns a pointer to the geometry object.
+*/
+QGeometry *Qt3DRender::FbxGeometryLoader::geometry() const
{
return m_geometry;
}
-bool FbxGeometryLoader::load(QIODevice *ioDev, const QString &subMesh)
+/*!
+ Load the specified \a subMesh using device \a ioDev.
+*/
+bool Qt3DRender::FbxGeometryLoader::load(QIODevice *ioDev, const QString &subMesh)
{
if (m_scene)
m_scene->Destroy();
@@ -310,6 +318,10 @@ bool FbxGeometryLoader::load(QIODevice *ioDev, const QString &subMesh)
return wasImported;
}
+/*!
+ Traverse the node hierarchy and process the children of each
+ node.
+*/
void FbxGeometryLoader::recurseNodes()
{
Q_ASSERT(m_scene);
@@ -323,8 +335,12 @@ void FbxGeometryLoader::recurseNodes()
processNode(node->GetChild(i));
}
}
-
-void FbxGeometryLoader::processNode(FbxNode *node)
+/*!
+ If the parameter \a node has the attribute eMesh,
+ process the Mesh. If not, process the children
+ of that node.
+*/
+void Qt3DRender::FbxGeometryLoader::processNode(FbxNode *node)
{
auto attr = node->GetNodeAttribute();
if (!attr)
@@ -347,8 +363,10 @@ void FbxGeometryLoader::processNode(FbxNode *node)
for (int i = 0; i < node->GetChildCount(); ++i)
processNode(node->GetChild(i));
}
-
-void FbxGeometryLoader::processMesh(FbxMesh *mesh)
+/*!
+ Process all vertices of the specified \a mesh.
+*/
+void Qt3DRender::FbxGeometryLoader::processMesh(FbxMesh *mesh)
{
const int normalCount = mesh->GetElementNormalCount();
const int polygonCount = mesh->GetPolygonCount();
diff --git a/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp b/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp
index 3ebb6bec2..ecb3824c9 100644
--- a/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp
+++ b/src/plugins/geometryloaders/gltf/gltfgeometryloader.cpp
@@ -42,6 +42,7 @@
#include <QtCore/QDir>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
+#include <QtCore/QVersionNumber>
#include <QtGui/QOpenGLTexture>
@@ -59,6 +60,7 @@ namespace Qt3DRender {
Q_LOGGING_CATEGORY(GLTFGeometryLoaderLog, "Qt3D.GLTFGeometryLoader", QtWarningMsg)
+#define KEY_ASSET QLatin1String("asset")
#define KEY_ACCESSORS QLatin1String("accessors")
#define KEY_ATTRIBUTES QLatin1String("attributes")
#define KEY_BUFFER QLatin1String("buffer")
@@ -75,6 +77,7 @@ Q_LOGGING_CATEGORY(GLTFGeometryLoaderLog, "Qt3D.GLTFGeometryLoader", QtWarningMs
#define KEY_TARGET QLatin1String("target")
#define KEY_TYPE QLatin1String("type")
#define KEY_URI QLatin1String("uri")
+#define KEY_VERSION QLatin1String("version")
#define KEY_BUFFER_VIEW QLatin1String("bufferView")
#define KEY_BUFFER_VIEWS QLatin1String("bufferViews")
@@ -147,6 +150,7 @@ GLTFGeometryLoader::AccessorData::AccessorData()
GLTFGeometryLoader::AccessorData::AccessorData(const QJsonObject &json)
: bufferViewName(json.value(KEY_BUFFER_VIEW).toString())
+ , bufferViewIndex(json.value(KEY_BUFFER_VIEW).toInt(-1))
, type(accessorTypeFromJSON(json.value(KEY_COMPONENT_TYPE).toInt()))
, dataSize(accessorDataSizeFromJson(json.value(KEY_TYPE).toString()))
, count(json.value(KEY_COUNT).toInt())
@@ -191,12 +195,36 @@ QString GLTFGeometryLoader::standardAttributeNameFromSemantic(const QString &sem
return QAttribute::defaultColorAttributeName();
if (semantic.startsWith(QLatin1String("TANGENT")))
return QAttribute::defaultTangentAttributeName();
+ if (semantic.startsWith(QLatin1String("JOINTS")))
+ return QAttribute::defaultJointIndicesAttributeName();
+ if (semantic.startsWith(QLatin1String("WEIGHTS")))
+ return QAttribute::defaultJointWeightsAttributeName();
return QString();
}
void GLTFGeometryLoader::parse()
{
+ // Find the glTF version
+ const QJsonObject asset = m_json.object().value(KEY_ASSET).toObject();
+ const QString versionString = asset.value(KEY_VERSION).toString();
+ const auto version = QVersionNumber::fromString(versionString);
+ switch (version.majorVersion()) {
+ case 1:
+ parseGLTF1();
+ break;
+
+ case 2:
+ parseGLTF2();
+ break;
+
+ default:
+ qWarning() << "Unsupported version of glTF" << versionString;
+ }
+}
+
+void GLTFGeometryLoader::parseGLTF1()
+{
const QJsonObject buffers = m_json.object().value(KEY_BUFFERS).toObject();
for (auto it = buffers.begin(), end = buffers.end(); it != end; ++it)
processJSONBuffer(it.key(), it.value().toObject());
@@ -220,24 +248,54 @@ void GLTFGeometryLoader::parse()
}
}
+void GLTFGeometryLoader::parseGLTF2()
+{
+ const QJsonArray buffers = m_json.object().value(KEY_BUFFERS).toArray();
+ for (auto it = buffers.begin(), end = buffers.end(); it != end; ++it)
+ processJSONBufferV2(it->toObject());
+
+ const QJsonArray views = m_json.object().value(KEY_BUFFER_VIEWS).toArray();
+ loadBufferDataV2();
+ for (auto it = views.begin(), end = views.end(); it != end; ++it)
+ processJSONBufferViewV2(it->toObject());
+ unloadBufferDataV2();
+
+ const QJsonArray attrs = m_json.object().value(KEY_ACCESSORS).toArray();
+ for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it)
+ processJSONAccessorV2(it->toObject());
+
+ const QJsonArray meshes = m_json.object().value(KEY_MESHES).toArray();
+ for (auto it = meshes.begin(), end = meshes.end(); it != end && !m_geometry; ++it) {
+ const QJsonObject &mesh = it->toObject();
+ if (m_mesh.isEmpty() || m_mesh.compare(mesh.value(KEY_NAME).toString(), Qt::CaseInsensitive) == 0)
+ processJSONMeshV2(mesh);
+ }
+}
+
void GLTFGeometryLoader::cleanup()
{
m_geometry = nullptr;
- m_accessorDict.clear();
- m_buffers.clear();
+ m_gltf1.m_accessorDict.clear();
+ m_gltf1.m_buffers.clear();
}
void GLTFGeometryLoader::processJSONBuffer(const QString &id, const QJsonObject &json)
{
// simply cache buffers for lookup by buffer-views
- m_bufferDatas[id] = BufferData(json);
+ m_gltf1.m_bufferDatas[id] = BufferData(json);
+}
+
+void GLTFGeometryLoader::processJSONBufferV2(const QJsonObject &json)
+{
+ // simply cache buffers for lookup by buffer-views
+ m_gltf2.m_bufferDatas.push_back(BufferData(json));
}
void GLTFGeometryLoader::processJSONBufferView(const QString &id, const QJsonObject &json)
{
QString bufName = json.value(KEY_BUFFER).toString();
- const auto it = qAsConst(m_bufferDatas).find(bufName);
- if (Q_UNLIKELY(it == m_bufferDatas.cend())) {
+ const auto it = qAsConst(m_gltf1.m_bufferDatas).find(bufName);
+ if (Q_UNLIKELY(it == m_gltf1.m_bufferDatas.cend())) {
qCWarning(GLTFGeometryLoaderLog, "unknown buffer: %ls processing view: %ls",
qUtf16PrintableImpl(bufName), qUtf16PrintableImpl(id));
return;
@@ -273,12 +331,55 @@ void GLTFGeometryLoader::processJSONBufferView(const QString &id, const QJsonObj
Qt3DRender::QBuffer *b(new Qt3DRender::QBuffer(ty));
b->setData(bytes);
- m_buffers[id] = b;
+ m_gltf1.m_buffers[id] = b;
+}
+
+void GLTFGeometryLoader::processJSONBufferViewV2(const QJsonObject &json)
+{
+ const int bufferIndex = json.value(KEY_BUFFER).toInt();
+ if (Q_UNLIKELY(bufferIndex) >= m_gltf2.m_bufferDatas.size()) {
+ qCWarning(GLTFGeometryLoaderLog, "unknown buffer: %d processing view", bufferIndex);
+ return;
+ }
+ const auto bufferData = m_gltf2.m_bufferDatas[bufferIndex];
+
+ int target = json.value(KEY_TARGET).toInt();
+ Qt3DRender::QBuffer::BufferType ty(Qt3DRender::QBuffer::VertexBuffer);
+
+ switch (target) {
+ case GL_ARRAY_BUFFER: ty = Qt3DRender::QBuffer::VertexBuffer; break;
+ case GL_ELEMENT_ARRAY_BUFFER: ty = Qt3DRender::QBuffer::IndexBuffer; break;
+ default:
+ return;
+ }
+
+ quint64 offset = 0;
+ const auto byteOffset = json.value(KEY_BYTE_OFFSET);
+ if (!byteOffset.isUndefined()) {
+ offset = byteOffset.toInt();
+ qCDebug(GLTFGeometryLoaderLog, "bufferview has offset: %lld", offset);
+ }
+
+ const quint64 len = json.value(KEY_BYTE_LENGTH).toInt();
+ QByteArray bytes = bufferData.data->mid(offset, len);
+ if (Q_UNLIKELY(bytes.count() != int(len))) {
+ qCWarning(GLTFGeometryLoaderLog, "failed to read sufficient bytes from: %ls for view",
+ qUtf16PrintableImpl(bufferData.path));
+ }
+
+ Qt3DRender::QBuffer *b(new Qt3DRender::QBuffer(ty));
+ b->setData(bytes);
+ m_gltf2.m_buffers.push_back(b);
}
void GLTFGeometryLoader::processJSONAccessor(const QString &id, const QJsonObject &json)
{
- m_accessorDict[id] = AccessorData(json);
+ m_gltf1.m_accessorDict[id] = AccessorData(json);
+}
+
+void GLTFGeometryLoader::processJSONAccessorV2(const QJsonObject &json)
+{
+ m_gltf2.m_accessors.push_back(AccessorData(json));
}
void GLTFGeometryLoader::processJSONMesh(const QString &id, const QJsonObject &json)
@@ -299,8 +400,8 @@ void GLTFGeometryLoader::processJSONMesh(const QString &id, const QJsonObject &j
const QJsonObject attrs = primitiveObject.value(KEY_ATTRIBUTES).toObject();
for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it) {
QString k = it.value().toString();
- const auto accessorIt = qAsConst(m_accessorDict).find(k);
- if (Q_UNLIKELY(accessorIt == m_accessorDict.cend())) {
+ const auto accessorIt = qAsConst(m_gltf1.m_accessorDict).find(k);
+ if (Q_UNLIKELY(accessorIt == m_gltf1.m_accessorDict.cend())) {
qCWarning(GLTFGeometryLoaderLog, "unknown attribute accessor: %ls on mesh %ls",
qUtf16PrintableImpl(k), qUtf16PrintableImpl(id));
continue;
@@ -312,7 +413,7 @@ void GLTFGeometryLoader::processJSONMesh(const QString &id, const QJsonObject &j
attributeName = attrName;
//Get buffer handle for accessor
- Qt3DRender::QBuffer *buffer = m_buffers.value(accessorIt->bufferViewName, nullptr);
+ Qt3DRender::QBuffer *buffer = m_gltf1.m_buffers.value(accessorIt->bufferViewName, nullptr);
if (Q_UNLIKELY(!buffer)) {
qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %ls processing accessor: %ls",
qUtf16PrintableImpl(accessorIt->bufferViewName), qUtf16PrintableImpl(id));
@@ -333,13 +434,13 @@ void GLTFGeometryLoader::processJSONMesh(const QString &id, const QJsonObject &j
const auto indices = primitiveObject.value(KEY_INDICES);
if (!indices.isUndefined()) {
QString k = indices.toString();
- const auto accessorIt = qAsConst(m_accessorDict).find(k);
- if (Q_UNLIKELY(accessorIt == m_accessorDict.cend())) {
+ const auto accessorIt = qAsConst(m_gltf1.m_accessorDict).find(k);
+ if (Q_UNLIKELY(accessorIt == m_gltf1.m_accessorDict.cend())) {
qCWarning(GLTFGeometryLoaderLog, "unknown index accessor: %ls on mesh %ls",
qUtf16PrintableImpl(k), qUtf16PrintableImpl(id));
} else {
//Get buffer handle for accessor
- Qt3DRender::QBuffer *buffer = m_buffers.value(accessorIt->bufferViewName, nullptr);
+ Qt3DRender::QBuffer *buffer = m_gltf1.m_buffers.value(accessorIt->bufferViewName, nullptr);
if (Q_UNLIKELY(!buffer)) {
qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %ls processing accessor: %ls",
qUtf16PrintableImpl(accessorIt->bufferViewName), qUtf16PrintableImpl(id));
@@ -363,9 +464,85 @@ void GLTFGeometryLoader::processJSONMesh(const QString &id, const QJsonObject &j
} // of primitives iteration
}
+void GLTFGeometryLoader::processJSONMeshV2(const QJsonObject &json)
+{
+ const QJsonArray primitivesArray = json.value(KEY_PRIMITIVES).toArray();
+ for (const QJsonValue &primitiveValue : primitivesArray) {
+ QJsonObject primitiveObject = primitiveValue.toObject();
+
+ QGeometry *meshGeometry = new QGeometry;
+
+ const QJsonObject attrs = primitiveObject.value(KEY_ATTRIBUTES).toObject();
+ for (auto it = attrs.begin(), end = attrs.end(); it != end; ++it) {
+ const int accessorIndex = it.value().toInt();
+ if (Q_UNLIKELY(accessorIndex >= m_gltf2.m_accessors.size())) {
+ qCWarning(GLTFGeometryLoaderLog, "unknown attribute accessor: %d on mesh %ls",
+ accessorIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString()));
+ continue;
+ }
+ const auto &accessor = m_gltf2.m_accessors[accessorIndex];
+
+ const QString attrName = it.key();
+ QString attributeName = standardAttributeNameFromSemantic(attrName);
+ if (attributeName.isEmpty())
+ attributeName = attrName;
+
+ // Get buffer handle for accessor
+ if (Q_UNLIKELY(accessor.bufferViewIndex >= m_gltf2.m_buffers.size())) {
+ qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %d processing accessor: %ls",
+ accessor.bufferViewIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString()));
+ continue;
+ }
+ Qt3DRender::QBuffer *buffer = m_gltf2.m_buffers[accessor.bufferViewIndex];
+
+ QAttribute *attribute = new QAttribute(buffer,
+ attributeName,
+ accessor.type,
+ accessor.dataSize,
+ accessor.count,
+ accessor.offset,
+ accessor.stride);
+ attribute->setAttributeType(QAttribute::VertexAttribute);
+ meshGeometry->addAttribute(attribute);
+ }
+
+ const auto indices = primitiveObject.value(KEY_INDICES);
+ if (!indices.isUndefined()) {
+ const int accessorIndex = indices.toInt();
+ if (Q_UNLIKELY(accessorIndex >= m_gltf2.m_accessors.size())) {
+ qCWarning(GLTFGeometryLoaderLog, "unknown index accessor: %d on mesh %ls",
+ accessorIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString()));
+ } else {
+ const auto &accessor = m_gltf2.m_accessors[accessorIndex];
+
+ //Get buffer handle for accessor
+ if (Q_UNLIKELY(accessor.bufferViewIndex >= m_gltf2.m_buffers.size())) {
+ qCWarning(GLTFGeometryLoaderLog, "unknown buffer-view: %d processing accessor: %ls",
+ accessor.bufferViewIndex, qUtf16PrintableImpl(json.value(KEY_NAME).toString()));
+ continue;
+ }
+ Qt3DRender::QBuffer *buffer = m_gltf2.m_buffers[accessor.bufferViewIndex];
+
+ QAttribute *attribute = new QAttribute(buffer,
+ accessor.type,
+ accessor.dataSize,
+ accessor.count,
+ accessor.offset,
+ accessor.stride);
+ attribute->setAttributeType(QAttribute::IndexAttribute);
+ meshGeometry->addAttribute(attribute);
+ }
+ } // of has indices
+
+ m_geometry = meshGeometry;
+
+ break;
+ } // of primitives iteration
+}
+
void GLTFGeometryLoader::loadBufferData()
{
- for (auto &bufferData : m_bufferDatas) {
+ for (auto &bufferData : m_gltf1.m_bufferDatas) {
if (!bufferData.data) {
bufferData.data = new QByteArray(resolveLocalData(bufferData.path));
}
@@ -374,7 +551,23 @@ void GLTFGeometryLoader::loadBufferData()
void GLTFGeometryLoader::unloadBufferData()
{
- for (const auto &bufferData : qAsConst(m_bufferDatas)) {
+ for (const auto &bufferData : qAsConst(m_gltf1.m_bufferDatas)) {
+ QByteArray *data = bufferData.data;
+ delete data;
+ }
+}
+
+void GLTFGeometryLoader::loadBufferDataV2()
+{
+ for (auto &bufferData : m_gltf2.m_bufferDatas) {
+ if (!bufferData.data)
+ bufferData.data = new QByteArray(resolveLocalData(bufferData.path));
+ }
+}
+
+void GLTFGeometryLoader::unloadBufferDataV2()
+{
+ for (const auto &bufferData : qAsConst(m_gltf2.m_bufferDatas)) {
QByteArray *data = bufferData.data;
delete data;
}
diff --git a/src/plugins/geometryloaders/gltf/gltfgeometryloader.h b/src/plugins/geometryloaders/gltf/gltfgeometryloader.h
index b2245b8ab..2938829c2 100644
--- a/src/plugins/geometryloaders/gltf/gltfgeometryloader.h
+++ b/src/plugins/geometryloaders/gltf/gltfgeometryloader.h
@@ -110,6 +110,7 @@ class GLTFGeometryLoader : public QGeometryLoaderInterface
explicit AccessorData(const QJsonObject &json);
QString bufferViewName;
+ int bufferViewIndex;
QAttribute::VertexBaseType type;
uint dataSize;
int count;
@@ -117,6 +118,20 @@ class GLTFGeometryLoader : public QGeometryLoaderInterface
int stride;
};
+ struct Gltf1
+ {
+ QHash<QString, AccessorData> m_accessorDict;
+ QHash<QString, BufferData> m_bufferDatas;
+ QHash<QString, Qt3DRender::QBuffer*> m_buffers;
+ };
+
+ struct Gltf2
+ {
+ QVector<BufferData> m_bufferDatas;
+ QVector<Qt3DRender::QBuffer*> m_buffers;
+ QVector<AccessorData> m_accessors;
+ };
+
Q_OBJECT
public:
GLTFGeometryLoader();
@@ -133,6 +148,8 @@ protected:
static QString standardAttributeNameFromSemantic(const QString &semantic);
void parse();
+ void parseGLTF1();
+ void parseGLTF2();
void cleanup();
void processJSONBuffer(const QString &id, const QJsonObject &json);
@@ -143,6 +160,14 @@ protected:
void loadBufferData();
void unloadBufferData();
+ void processJSONBufferV2(const QJsonObject &json);
+ void processJSONBufferViewV2(const QJsonObject &json);
+ void processJSONAccessorV2(const QJsonObject &json);
+ void processJSONMeshV2(const QJsonObject &json);
+
+ void loadBufferDataV2();
+ void unloadBufferDataV2();
+
QByteArray resolveLocalData(const QString &path) const;
static QAttribute::VertexBaseType accessorTypeFromJSON(int componentType);
@@ -153,10 +178,8 @@ private:
QString m_basePath;
QString m_mesh;
- QHash<QString, AccessorData> m_accessorDict;
-
- QHash<QString, BufferData> m_bufferDatas;
- QHash<QString, Qt3DRender::QBuffer*> m_buffers;
+ Gltf1 m_gltf1;
+ Gltf2 m_gltf2;
QGeometry *m_geometry;
};
diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
index af0f22f5d..3f110e1e0 100644
--- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp
+++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
@@ -375,17 +375,15 @@ AssimpImporter::~AssimpImporter()
}
/*!
- * Returns \c true if the provided \a path has a suffix supported
+ * Returns \c true if the extensions are supported
* by the Assimp Assets importer.
*/
-bool AssimpImporter::isAssimpPath(const QString &path)
+bool AssimpImporter::areAssimpExtensions(const QStringList &extensions)
{
- QFileInfo fileInfo(path);
-
- if (!fileInfo.exists() ||
- !AssimpImporter::assimpSupportedFormatsList.contains(fileInfo.suffix().toLower()))
- return false;
- return true;
+ for (const auto ext : qAsConst(extensions))
+ if (AssimpImporter::assimpSupportedFormatsList.contains(ext.toLower()))
+ return true;
+ return false;
}
/*!
@@ -405,13 +403,21 @@ void AssimpImporter::setSource(const QUrl &source)
}
/*!
- * Returns \c true if the extension of \a source is supported by
+ * Sets the \a basePath used by the parser to load the asset file.
+ * If the file specified in \a data is valid, this will trigger parsing of the file.
+ */
+void AssimpImporter::setData(const QByteArray &data, const QString &basePath)
+{
+ readSceneData(data, basePath);
+}
+
+/*!
+ * Returns \c true if the extension in QStringList \a extensions is supported by
* the assimp parser.
*/
-bool AssimpImporter::isFileTypeSupported(const QUrl &source) const
+bool AssimpImporter::areFileTypesSupported(const QStringList &extensions) const
{
- const QString path = QUrlHelper::urlToLocalFileOrQrc(source);
- return AssimpImporter::isAssimpPath(path);
+ return AssimpImporter::areAssimpExtensions(extensions);
}
/*!
@@ -604,6 +610,36 @@ void AssimpImporter::readSceneFile(const QString &path)
}
/*!
+ * Reads the scene file pointed by \a path and launches the parsing of
+ * the scene using Assimp, after having cleaned up previously saved values
+ * from eventual previous parsings.
+ */
+void AssimpImporter::readSceneData(const QByteArray& data, const QString &basePath)
+{
+ cleanup();
+
+ m_scene = new SceneImporter();
+
+ // SET THIS TO REMOVE POINTS AND LINES -> HAVE ONLY TRIANGLES
+ m_scene->m_importer->SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE|aiPrimitiveType_POINT);
+ // SET CUSTOM FILE HANDLER TO HANDLE FILE READING THROUGH QT (RESOURCES, SOCKET ...)
+ m_scene->m_importer->SetIOHandler(new AssimpHelper::AssimpIOSystem());
+
+ // type and aiProcess_Triangulate discompose polygons with more than 3 points in triangles
+ // aiProcess_SortByPType makes sure that meshes data are triangles
+ m_scene->m_aiScene = m_scene->m_importer->ReadFileFromMemory(data.data(), data.size(),
+ aiProcess_SortByPType|
+ aiProcess_Triangulate|
+ aiProcess_GenSmoothNormals|
+ aiProcess_FlipUVs);
+ if (m_scene->m_aiScene == nullptr) {
+ qCWarning(AssimpImporterLog) << "Assimp scene import failed";
+ return ;
+ }
+ parse();
+}
+
+/*!
* Cleans the various dictionaries holding the scene's information.
*/
void AssimpImporter::cleanup()
diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.h b/src/plugins/sceneparsers/assimp/assimpimporter.h
index c461cda08..068f6eed2 100644
--- a/src/plugins/sceneparsers/assimp/assimpimporter.h
+++ b/src/plugins/sceneparsers/assimp/assimpimporter.h
@@ -98,17 +98,19 @@ public:
// SceneParserInterface interface
void setSource(const QUrl& source) Q_DECL_OVERRIDE;
- bool isFileTypeSupported(const QUrl &source) const Q_DECL_OVERRIDE;
+ void setData(const QByteArray& data, const QString &basePath) Q_DECL_OVERRIDE;
+ bool areFileTypesSupported(const QStringList &extensions) const Q_DECL_OVERRIDE;
Qt3DCore::QEntity *scene(const QString &id = QString()) Q_DECL_OVERRIDE;
Qt3DCore::QEntity *node(const QString &id) Q_DECL_OVERRIDE;
private:
- static bool isAssimpPath(const QString &path);
+ static bool areAssimpExtensions(const QStringList &extensions);
static QStringList assimpSupportedFormats();
Qt3DCore::QEntity *node(aiNode *node);
void readSceneFile(const QString &file);
+ void readSceneData(const QByteArray& data, const QString &basePath);
void cleanup();
void parse();
diff --git a/src/plugins/sceneparsers/gltf/gltfimporter.cpp b/src/plugins/sceneparsers/gltf/gltfimporter.cpp
index 6f61d2ed9..4419bd708 100644
--- a/src/plugins/sceneparsers/gltf/gltfimporter.cpp
+++ b/src/plugins/sceneparsers/gltf/gltfimporter.cpp
@@ -268,11 +268,23 @@ GLTFImporter::~GLTFImporter()
}
+/*!
+ \class Qt3DRender::GLTFImporter
+ \inmodule Qt3DRender
+ \brief Handles importing of gltf files
+*/
+/*!
+ Set the base \a path for importing scenes.
+*/
void GLTFImporter::setBasePath(const QString& path)
{
m_basePath = path;
}
+/*!
+ Set a \a json document as the file used for importing a scene.
+ Returns true if the operation is successful.
+*/
bool GLTFImporter::setJSON(const QJsonDocument &json )
{
if ( !json.isObject() ) {
@@ -286,7 +298,8 @@ bool GLTFImporter::setJSON(const QJsonDocument &json )
}
/*!
- * Sets the \a path used by the parser to load the scene file.
+ * Sets the path based on parameter \a source. The path is
+ * used by the parser to load the scene file.
* If the file is valid, parsing is automatically triggered.
*/
void GLTFImporter::setSource(const QUrl &source)
@@ -314,15 +327,36 @@ void GLTFImporter::setSource(const QUrl &source)
}
/*!
- * Returns true if the extension of \a path is supported by the
+ * Sets the \a basePath used by the parser to load the scene file.
+ * If the file derived from \a data is valid, parsing is automatically
+ * triggered.
+ */
+void GLTFImporter::setData(const QByteArray& data, const QString &basePath)
+{
+ QJsonDocument sceneDocument = QJsonDocument::fromBinaryData(data);
+ if (sceneDocument.isNull())
+ sceneDocument = QJsonDocument::fromJson(data);
+
+ if (Q_UNLIKELY(!setJSON(sceneDocument))) {
+ qCWarning(GLTFImporterLog, "not a JSON document");
+ return;
+ }
+
+ setBasePath(basePath);
+}
+
+/*!
+ * Returns true if the \a extensions are supported by the
* GLTF parser.
*/
-bool GLTFImporter::isFileTypeSupported(const QUrl &source) const
+bool GLTFImporter::areFileTypesSupported(const QStringList &extensions) const
{
- const QString path = QUrlHelper::urlToLocalFileOrQrc(source);
- return GLTFImporter::isGLTFPath(path);
+ return GLTFImporter::isGLTFSupported(extensions);
}
+/*!
+ Imports the node specified in \a id from the GLTF file.
+*/
Qt3DCore::QEntity* GLTFImporter::node(const QString &id)
{
QJsonObject nodes = m_json.object().value(KEY_NODES).toObject();
@@ -490,6 +524,9 @@ Qt3DCore::QEntity* GLTFImporter::node(const QString &id)
return result;
}
+/*!
+ Imports the scene specified in parameter \a id.
+*/
Qt3DCore::QEntity* GLTFImporter::scene(const QString &id)
{
parse();
@@ -570,16 +607,14 @@ GLTFImporter::AccessorData::AccessorData(const QJsonObject &json)
stride = byteStride.toInt();
}
-bool GLTFImporter::isGLTFPath(const QString& path)
+bool GLTFImporter::isGLTFSupported(const QStringList &extensions)
{
- 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 == QLatin1String("json") || suffix == QLatin1String("gltf") || suffix == QLatin1String("qgltf");
+ for (auto suffix: qAsConst(extensions)) {
+ suffix = suffix.toLower();
+ if (suffix == QLatin1String("json") || suffix == QLatin1String("gltf") || suffix == QLatin1String("qgltf"))
+ return true;
+ }
+ return false;
}
void GLTFImporter::renameFromJson(const QJsonObject &json, QObject * const object)
@@ -1072,8 +1107,8 @@ void GLTFImporter::cleanup()
m_shaderPaths.clear();
delete_if_without_parent(m_programs);
m_programs.clear();
- for (auto it = m_techniqueParameters.begin(); it != m_techniqueParameters.end(); ++it)
- delete_if_without_parent(it.value());
+ for (auto params : qAsConst(m_techniqueParameters))
+ delete_if_without_parent(params);
m_techniqueParameters.clear();
delete_if_without_parent(m_techniques);
m_techniques.clear();
@@ -1641,6 +1676,9 @@ void GLTFImporter::processJSONRenderPass(const QString &id, const QJsonObject &j
m_renderPasses[id] = pass;
}
+/*!
+ Loads raw data from the GLTF file into the buffer.
+*/
void GLTFImporter::loadBufferData()
{
for (auto &bufferData : m_bufferDatas) {
@@ -1650,6 +1688,9 @@ void GLTFImporter::loadBufferData()
}
}
+/*!
+ Removes all data from the buffer.
+*/
void GLTFImporter::unloadBufferData()
{
for (const auto &bufferData : qAsConst(m_bufferDatas)) {
diff --git a/src/plugins/sceneparsers/gltf/gltfimporter.h b/src/plugins/sceneparsers/gltf/gltfimporter.h
index 975a9ef01..8a8e1b3ee 100644
--- a/src/plugins/sceneparsers/gltf/gltfimporter.h
+++ b/src/plugins/sceneparsers/gltf/gltfimporter.h
@@ -98,7 +98,8 @@ public:
// SceneParserInterface interface
void setSource(const QUrl &source) Q_DECL_FINAL;
- bool isFileTypeSupported(const QUrl &source) const Q_DECL_FINAL;
+ void setData(const QByteArray& data, const QString &basePath) Q_DECL_FINAL;
+ bool areFileTypesSupported(const QStringList &extensions) const Q_DECL_FINAL;
Qt3DCore::QEntity *node(const QString &id) Q_DECL_FINAL;
Qt3DCore::QEntity *scene(const QString &id = QString()) Q_DECL_FINAL;
@@ -139,7 +140,7 @@ private:
int stride;
};
- static bool isGLTFPath(const QString &path);
+ static bool isGLTFSupported(const QStringList &extensions);
static void renameFromJson(const QJsonObject& json, QObject * const object );
static bool hasStandardUniformNameFromSemantic(const QString &semantic);
static QString standardAttributeNameFromSemantic(const QString &semantic);
diff --git a/src/plugins/sceneparsers/gltfexport/gltfexporter.cpp b/src/plugins/sceneparsers/gltfexport/gltfexporter.cpp
index 4b1d0fb40..ba100e095 100644
--- a/src/plugins/sceneparsers/gltfexport/gltfexporter.cpp
+++ b/src/plugins/sceneparsers/gltfexport/gltfexporter.cpp
@@ -266,6 +266,13 @@ GLTFExporter::~GLTFExporter()
{
}
+/*!
+ \class Qt3DRender::GLTFExporter
+ \inmodule Qt3DRender
+ \brief Manages the export of a 3D scene to the GLTF format.
+
+ Handles the export of a 3D scene to the GLTF format.
+*/
// sceneRoot : The root entity that contains the exported scene. If the sceneRoot doesn't have
// any exportable components, it is not exported itself. This is because importing a
// scene creates an empty top level entity to hold the scene.
@@ -278,6 +285,23 @@ GLTFExporter::~GLTFExporter()
// "binaryJson" (bool): Generates a binary JSON file, which is more efficient to parse.
// "compactJson" (bool): Removes unnecessary whitespace from the generated JSON file.
// Ignored if "binaryJson" option is true.
+
+/*!
+ Exports the scene to the GLTF format
+
+ \a sceneRoot is the root entity that will be exported.
+ If the sceneRoot does not have any exportable components, it is not exported itself.
+
+ \a outDir is the directory in which the scene export is created.
+
+ \a exportName is the name of the directory created in \c outDir that will hold
+ the exported scene.
+
+ \a options contain the export options.
+
+ Returns true if the export was carried out successfully.
+*/
+
bool GLTFExporter::exportScene(QEntity *sceneRoot, const QString &outDir,
const QString &exportName, const QVariantHash &options)
{
@@ -643,18 +667,23 @@ void GLTFExporter::parseMaterials()
for (auto param : parameters) {
if (param->value().type() == QVariant::Color) {
QColor color = param->value().value<QColor>();
- if (param->name() == MATERIAL_AMBIENT_COLOR)
+ if (param->name() == MATERIAL_AMBIENT_COLOR) {
matInfo.colors.insert(QStringLiteral("ambient"), color);
- else if (param->name() == MATERIAL_DIFFUSE_COLOR)
+ } else if (param->name() == MATERIAL_DIFFUSE_COLOR) {
+ if (matInfo.type == MaterialInfo::TypePhongAlpha) {
+ matInfo.values.insert(QStringLiteral("transparency"), float(color.alphaF()));
+ color.setAlphaF(1.0f);
+ }
matInfo.colors.insert(QStringLiteral("diffuse"), color);
- else if (param->name() == MATERIAL_SPECULAR_COLOR)
+ } else if (param->name() == MATERIAL_SPECULAR_COLOR) {
matInfo.colors.insert(QStringLiteral("specular"), color);
- else if (param->name() == MATERIAL_COOL_COLOR) // Custom Qt3D gooch
+ } else if (param->name() == MATERIAL_COOL_COLOR) { // Custom Qt3D gooch
matInfo.colors.insert(QStringLiteral("cool"), color);
- else if (param->name() == MATERIAL_WARM_COLOR) // Custom Qt3D gooch
+ } else if (param->name() == MATERIAL_WARM_COLOR) { // Custom Qt3D gooch
matInfo.colors.insert(QStringLiteral("warm"), color);
- else
+ } else {
matInfo.colors.insert(param->name(), color);
+ }
} else if (param->value().canConvert<QAbstractTexture *>()) {
const QString urlString = textureVariantToUrl(param->value());
if (param->name() == MATERIAL_DIFFUSE_TEXTURE)
@@ -1253,8 +1282,7 @@ bool GLTFExporter::saveScene()
m_obj["meshes"] = meshes;
QJsonObject cameras;
- for (auto it = m_cameraInfo.begin(); it != m_cameraInfo.end(); ++it) {
- const auto &camInfo = it.value();
+ for (auto camInfo : qAsConst(m_cameraInfo)) {
QJsonObject camera;
QJsonObject proj;
proj["znear"] = camInfo.znear;
diff --git a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp
index 7feeaf84c..017e2a453 100644
--- a/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp
+++ b/src/quick3d/imports/animation/qt3dquick3danimationplugin.cpp
@@ -45,10 +45,11 @@
#include <Qt3DAnimation/qblendedclipanimator.h>
#include <Qt3DAnimation/qclipanimator.h>
#include <Qt3DAnimation/qchannelmapping.h>
+#include <Qt3DAnimation/qskeletonmapping.h>
#include <Qt3DAnimation/qlerpclipblend.h>
#include <Qt3DAnimation/qadditiveclipblend.h>
#include <Qt3DAnimation/qclipblendvalue.h>
-
+#include <Qt3DAnimation/qclock.h>
#include <Qt3DAnimation/qkeyframeanimation.h>
#include <Qt3DAnimation/qanimationcontroller.h>
#include <Qt3DAnimation/qabstractanimation.h>
@@ -87,6 +88,7 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DAnimation::QLerpClipBlend>(uri, 2, 9, "LerpClipBlend");
qmlRegisterType<Qt3DAnimation::QAdditiveClipBlend>(uri, 2, 9, "AdditiveClipBlend");
qmlRegisterType<Qt3DAnimation::QClipBlendValue>(uri, 2, 9, "ClipBlendValue");
+ qmlRegisterType<Qt3DAnimation::QClock>(uri, 2, 9, "Clock");
qmlRegisterUncreatableType<Qt3DAnimation::QAbstractAnimation>(uri, 2, 9, "AbstractAnimation", QStringLiteral("AbstractAnimation is abstract"));
qmlRegisterExtendedType<Qt3DAnimation::QKeyframeAnimation, Qt3DAnimation::Quick::QQuick3DKeyframeAnimation>(uri, 2, 9, "KeyframeAnimation");
@@ -95,6 +97,9 @@ void Qt3DQuick3DAnimationPlugin::registerTypes(const char *uri)
qmlRegisterExtendedType<Qt3DAnimation::QMorphingAnimation, Qt3DAnimation::Quick::QQuick3DMorphingAnimation>(uri, 2, 9, "MorphingAnimation");
qmlRegisterExtendedType<Qt3DAnimation::QMorphTarget, Qt3DAnimation::Quick::QQuick3DMorphTarget>(uri, 2, 9, "MorphTarget");
qmlRegisterExtendedType<Qt3DAnimation::QVertexBlendAnimation, Qt3DAnimation::Quick::QQuick3DVertexBlendAnimation>(uri, 2, 9, "VertexBlendAnimation");
+
+ qmlRegisterUncreatableType<Qt3DAnimation::QAbstractChannelMapping>(uri, 2, 10, "AbstractChannelMapping", QStringLiteral("QAbstractChannelMapping is abstract"));
+ qmlRegisterType<Qt3DAnimation::QSkeletonMapping>(uri, 2, 10, "SkeletonMapping");
}
QT_END_NAMESPACE
diff --git a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
index 3ff63d9d9..05d99f05f 100644
--- a/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
+++ b/src/quick3d/imports/core/qt3dquick3dcoreplugin.cpp
@@ -39,13 +39,18 @@
#include "qt3dquick3dcoreplugin.h"
+#include <Qt3DCore/qarmature.h>
+#include <Qt3DCore/qabstractskeleton.h>
+#include <Qt3DCore/qskeletonloader.h>
#include <Qt3DCore/qtransform.h>
+#include <Qt3DCore/qjoint.h>
#include <QtCore/qvariantanimation.h>
#include <Qt3DQuick/private/quick3dnodev9_p.h>
#include <Qt3DQuick/private/quick3dentity_p.h>
#include <Qt3DQuick/private/quick3dentityloader_p.h>
#include <Qt3DQuick/private/quick3dnodeinstantiator_p.h>
+#include <Qt3DQuick/private/quick3djoint_p.h>
#include <Qt3DQuick/private/qquaternionanimation_p.h>
#include <Qt3DQuick/private/qt3dquick_global_p.h>
@@ -61,6 +66,9 @@ void Qt3DQuick3DCorePlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DCore::Quick::Quick3DEntityLoader>(uri, 2, 0, "EntityLoader");
qmlRegisterType<Qt3DCore::Quick::Quick3DNodeInstantiator>(uri, 2, 0, "NodeInstantiator");
qmlRegisterType<Qt3DCore::QTransform>(uri, 2, 0, "Transform");
+ qmlRegisterType<Qt3DCore::QArmature>(uri, 2, 10, "Armature");
+ qmlRegisterUncreatableType<Qt3DCore::QAbstractSkeleton>(uri, 2, 10, "AbstractSkeleton", QStringLiteral("AbstractSkeleton is an abstract base class"));
+ qmlRegisterType<Qt3DCore::QSkeletonLoader>(uri, 2, 10, "SkeletonLoader");
qmlRegisterType<Qt3DCore::Quick::QQuaternionAnimation>(uri, 2, 0, "QuaternionAnimation");
qRegisterAnimationInterpolator<QQuaternion>(Qt3DCore::Quick::q_quaternionInterpolator);
@@ -69,6 +77,8 @@ void Qt3DQuick3DCorePlugin::registerTypes(const char *uri)
// We would need qmlRegisterUncreatableExtendedType for that
qmlRegisterExtendedUncreatableType<Qt3DCore::QNode, Qt3DCore::Quick::Quick3DNode>(uri, 2, 0, "Node", QStringLiteral("Node is a base class"));
qmlRegisterExtendedUncreatableType<Qt3DCore::QNode, Qt3DCore::Quick::Quick3DNodeV9, 9>(uri, 2, 9, "Node", QStringLiteral("Node is a base class"));
+
+ Qt3DCore::Quick::registerExtendedType<Qt3DCore::QJoint, Qt3DCore::Quick::Quick3DJoint>("QJoint", "Qt3D.Core/Joint", uri, 2, 10, "Joint");
}
Qt3DQuick3DCorePlugin::~Qt3DQuick3DCorePlugin()
diff --git a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp
index 879b79294..e893696ec 100644
--- a/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp
+++ b/src/quick3d/imports/extras/qt3dquick3dextrasplugin.cpp
@@ -53,6 +53,7 @@
#include <Qt3DExtras/qforwardrenderer.h>
#include <Qt3DExtras/qgoochmaterial.h>
#include <Qt3DExtras/qmetalroughmaterial.h>
+#include <Qt3DExtras/qdiffusespecularmaterial.h>
#include <Qt3DExtras/qmorphphongmaterial.h>
#include <Qt3DExtras/qnormaldiffusemapalphamaterial.h>
#include <Qt3DExtras/qnormaldiffusemapmaterial.h>
@@ -66,13 +67,16 @@
#include <Qt3DExtras/qskyboxentity.h>
#include <Qt3DExtras/qspheregeometry.h>
#include <Qt3DExtras/qspheremesh.h>
+#include <Qt3DExtras/qspritegrid.h>
+#include <Qt3DExtras/qspritesheetitem.h>
#include <Qt3DExtras/qtext2dentity.h>
-#include <Qt3DExtras/qtexturedmetalroughmaterial.h>
#include <Qt3DExtras/qtexturematerial.h>
+#include <Qt3DExtras/qtexturedmetalroughmaterial.h>
#include <Qt3DExtras/qtorusgeometry.h>
#include <Qt3DExtras/qtorusmesh.h>
#include <Qt3DQuickExtras/private/quick3dlevelofdetailloader_p.h>
+#include <Qt3DQuickExtras/private/quick3dspritesheet_p.h>
#include <QtQml/qqml.h>
@@ -104,10 +108,17 @@ void Qt3DQuick3DExtrasPlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DExtras::QPerVertexColorMaterial>(uri, 2, 0, "PerVertexColorMaterial");
qmlRegisterType<Qt3DExtras::QGoochMaterial>(uri, 2, 0, "GoochMaterial");
qmlRegisterType<Qt3DExtras::QTextureMaterial>(uri, 2, 0, "TextureMaterial");
+ qmlRegisterRevision<Qt3DExtras::QTextureMaterial, 10>(uri, 2, 10);
+ qmlRegisterType<Qt3DExtras::QDiffuseSpecularMaterial>(uri, 2, 10, "DiffuseSpecularMaterial");
qmlRegisterType<Qt3DExtras::QMetalRoughMaterial>(uri, 2, 9, "MetalRoughMaterial");
+ qmlRegisterRevision<Qt3DExtras::QMetalRoughMaterial, 10>(uri, 2, 10);
qmlRegisterType<Qt3DExtras::QTexturedMetalRoughMaterial>(uri, 2, 9, "TexturedMetalRoughMaterial");
qmlRegisterType<Qt3DExtras::QMorphPhongMaterial>(uri, 2, 9, "MorphPhongMaterial");
+ qmlRegisterType<Qt3DExtras::QSpriteGrid>(uri, 2, 10, "SpriteGrid");
+ qmlRegisterType<Qt3DExtras::QSpriteSheetItem>(uri, 2, 10, "SpriteItem");
+ Qt3DExtras::Quick::registerExtendedType<Qt3DExtras::QSpriteSheet, Qt3DExtras::Extras::Quick::Quick3DSpriteSheet>("QSpriteSheet", "Qt3D.Extras/SpriteSheet", uri, 2, 10, "SpriteSheet");
+
// Meshes
qmlRegisterType<Qt3DExtras::QConeMesh>(uri, 2, 0, "ConeMesh");
qmlRegisterType<Qt3DExtras::QConeGeometry>(uri, 2, 0, "ConeGeometry");
diff --git a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
index f81b1fa53..debc755d8 100644
--- a/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
+++ b/src/quick3d/imports/render/qt3dquick3drenderplugin.cpp
@@ -71,6 +71,7 @@
#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qlevelofdetailboundingsphere.h>
#include <Qt3DRender/qlevelofdetailswitch.h>
+#include <Qt3DRender/qlinewidth.h>
#include <Qt3DRender/qmemorybarrier.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/qmultisampleantialiasing.h>
@@ -96,6 +97,7 @@
#include <Qt3DRender/qseamlesscubemap.h>
#include <Qt3DRender/qshaderdata.h>
#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
#include <Qt3DRender/qsortpolicy.h>
#include <Qt3DRender/qspotlight.h>
#include <Qt3DRender/qstencilmask.h>
@@ -107,6 +109,8 @@
#include <Qt3DRender/qtechniquefilter.h>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qviewport.h>
+#include <Qt3DRender/qproximityfilter.h>
+#include <Qt3DRender/qblitframebuffer.h>
#include <QtGui/qwindow.h>
@@ -171,6 +175,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri)
Qt3DRender::Quick::registerExtendedType<Qt3DRender::QRenderPass, Qt3DRender::Render::Quick::Quick3DRenderPass>("QRenderPass", "Qt3D.Render/RenderPass", uri, 2, 0, "RenderPass");
qmlRegisterType<Qt3DRender::QShaderProgram>(uri, 2, 0, "ShaderProgram");
qmlRegisterRevision<Qt3DRender::QShaderProgram, 9>(uri, 2, 9);
+ qmlRegisterType<Qt3DRender::QShaderProgramBuilder>(uri, 2, 10, "ShaderProgramBuilder");
qmlRegisterUncreatableType<Qt3DRender::QShaderData>(uri, 2, 0, "QShaderData", "Quick3D should instantiate Quick3DShaderData only");
qmlRegisterType<Qt3DRender::Render::Quick::Quick3DShaderDataArray>(uri, 2, 0, "ShaderDataArray");
qmlRegisterType<Qt3DRender::Render::Quick::Quick3DShaderData>(uri, 2, 0, "ShaderData");
@@ -250,6 +255,8 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri)
qmlRegisterUncreatableType<Qt3DRender::QRenderCaptureReply>(uri, 2, 1, "RenderCaptureReply", QStringLiteral("RenderCaptureReply is only instantiated by RenderCapture"));
qmlRegisterType<Qt3DRender::QBufferCapture>(uri, 2, 9, "BufferCapture");
Qt3DRender::Quick::registerExtendedType<Qt3DRender::QMemoryBarrier, Qt3DRender::Render::Quick::Quick3DMemoryBarrier>("QMemoryBarrier", "Qt3D.Render/MemoryBarrier", uri, 2, 9, "MemoryBarrier");
+ qmlRegisterType<Qt3DRender::QProximityFilter>(uri, 2, 10, "ProximityFilter");
+ qmlRegisterType<Qt3DRender::QBlitFramebuffer>(uri, 2, 10, "BlitFramebuffer");
// RenderTarget
qmlRegisterType<Qt3DRender::QRenderTargetOutput>(uri, 2, 0, "RenderTargetOutput");
@@ -284,6 +291,7 @@ void Qt3DQuick3DRenderPlugin::registerTypes(const char *uri)
qmlRegisterType<Qt3DRender::QSeamlessCubemap>(uri, 2, 0, "SeamlessCubemap");
qmlRegisterType<Qt3DRender::QStencilOperation>(uri, 2, 0, "StencilOperation");
qmlRegisterType<Qt3DRender::QStencilMask>(uri, 2, 0, "StencilMask");
+ qmlRegisterType<Qt3DRender::QLineWidth>(uri, 2, 10, "LineWidth");
}
QT_END_NAMESPACE
diff --git a/src/quick3d/imports/scene3d/importsscene3d.pro b/src/quick3d/imports/scene3d/importsscene3d.pro
index 7aa3317c9..e41dc8c84 100644
--- a/src/quick3d/imports/scene3d/importsscene3d.pro
+++ b/src/quick3d/imports/scene3d/importsscene3d.pro
@@ -3,7 +3,10 @@ TARGET = qtquickscene3dplugin
TARGETPATH = QtQuick/Scene3D
IMPORT_VERSION = 2.0
-QT += qml quick 3dcore 3drender 3drender-private 3dinput 3dlogic
+QT += qml quick 3dcore 3drender 3drender-private
+
+qtConfig(qt3d-input): QT += 3dinput
+qtConfig(qt3d-logic): QT += 3dlogic
# Qt3D is free of Q_FOREACH - make sure it stays that way:
DEFINES += QT_NO_FOREACH
diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp
index c31f4aa97..4371e60b4 100644
--- a/src/quick3d/imports/scene3d/scene3ditem.cpp
+++ b/src/quick3d/imports/scene3d/scene3ditem.cpp
@@ -39,11 +39,19 @@
#include "scene3ditem_p.h"
-#include <Qt3DCore/QAspectEngine>
+#include <Qt3DCore/qt3dcore_global.h>
#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/QAspectEngine>
+
+#if QT_CONFIG(qt3d_input)
#include <Qt3DInput/QInputAspect>
#include <Qt3DInput/qinputsettings.h>
+#endif
+
+#if QT_CONFIG(qt3d_logic)
#include <Qt3DLogic/qlogicaspect.h>
+#endif
+
#include <Qt3DRender/QRenderAspect>
#include <Qt3DRender/qcamera.h>
#include <Qt3DRender/qrendersurfaceselector.h>
@@ -121,12 +129,20 @@ void Scene3DItem::setAspects(const QStringList &aspects)
if (aspect == QLatin1String("render")) // This one is hardwired anyway
continue;
if (aspect == QLatin1String("input")) {
+#if QT_CONFIG(qt3d_input)
m_aspectEngine->registerAspect(new Qt3DInput::QInputAspect);
continue;
+#else
+ qFatal("Scene3D requested the Qt 3D input aspect but Qt 3D wasn't configured to build the Qt 3D Input aspect");
+#endif
}
if (aspect == QLatin1String("logic")) {
+#if QT_CONFIG(qt3d_logic)
m_aspectEngine->registerAspect(new Qt3DLogic::QLogicAspect);
continue;
+#else
+ qFatal("Scene3D requested the Qt 3D input aspect but Qt 3D wasn't configured to build the Qt 3D Input aspect");
+#endif
}
m_aspectEngine->registerAspect(aspect);
}
@@ -189,6 +205,7 @@ void Scene3DItem::applyRootEntityChange()
}
}
+#if QT_CONFIG(qt3d_input)
// Set ourselves up as a source of input events for the input aspect
Qt3DInput::QInputSettings *inputSettings = m_entity->findChild<Qt3DInput::QInputSettings *>();
if (inputSettings) {
@@ -196,6 +213,7 @@ void Scene3DItem::applyRootEntityChange()
} else {
qCDebug(Scene3D) << "No Input Settings found, keyboard and mouse events won't be handled";
}
+#endif
}
}
diff --git a/src/quick3d/quick3d/items/items.pri b/src/quick3d/quick3d/items/items.pri
index 4749c83cf..36e7ccedc 100644
--- a/src/quick3d/quick3d/items/items.pri
+++ b/src/quick3d/quick3d/items/items.pri
@@ -4,13 +4,15 @@ HEADERS += \
$$PWD/quick3dentityloader_p_p.h \
$$PWD/quick3dentityloader_p.h \
$$PWD/quick3dnode_p.h \
- $$PWD/quick3dnodev9_p.h
+ $$PWD/quick3dnodev9_p.h \
+ $$PWD/quick3djoint_p.h
SOURCES += \
$$PWD/quick3dnode.cpp \
$$PWD/quick3dentity.cpp \
$$PWD/quick3dentityloader.cpp \
$$PWD/quick3dnodeinstantiator.cpp \
- $$PWD/quick3dnodev9.cpp
+ $$PWD/quick3dnodev9.cpp \
+ $$PWD/quick3djoint.cpp
INCLUDEPATH += $$PWD
diff --git a/src/quick3d/quick3d/items/quick3djoint.cpp b/src/quick3d/quick3d/items/quick3djoint.cpp
new file mode 100644
index 000000000..810e37e1a
--- /dev/null
+++ b/src/quick3d/quick3d/items/quick3djoint.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "quick3djoint_p.h"
+#include <Qt3DCore/qjoint.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+namespace Quick {
+
+Quick3DJoint::Quick3DJoint(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \qmlproperty list<Joint> Qt3DCore::Joint::childJoints
+ \readonly
+*/
+QQmlListProperty<QJoint> Quick3DJoint::childJoints()
+{
+ return QQmlListProperty<QJoint>(this, 0,
+ Quick3DJoint::appendJoint,
+ Quick3DJoint::jointCount,
+ Quick3DJoint::jointAt,
+ Quick3DJoint::clearJoints);
+}
+
+void Quick3DJoint::appendJoint(QQmlListProperty<QJoint> *list, QJoint *joint)
+{
+ Quick3DJoint *jointExtension = qobject_cast<Quick3DJoint *>(list->object);
+ jointExtension->parentJoint()->addChildJoint(joint);
+}
+
+QJoint *Quick3DJoint::jointAt(QQmlListProperty<QJoint> *list, int index)
+{
+ Quick3DJoint *jointExtension = qobject_cast<Quick3DJoint *>(list->object);
+ return jointExtension->parentJoint()->childJoints().at(index);
+}
+
+int Quick3DJoint::jointCount(QQmlListProperty<QJoint> *list)
+{
+ Quick3DJoint *jointExtension = qobject_cast<Quick3DJoint *>(list->object);
+ return jointExtension->parentJoint()->childJoints().count();
+}
+
+void Quick3DJoint::clearJoints(QQmlListProperty<QJoint> *list)
+{
+ Quick3DJoint *jointExtension = qobject_cast<Quick3DJoint *>(list->object);
+ const auto joints = jointExtension->parentJoint()->childJoints();
+ for (QJoint *joint : joints)
+ jointExtension->parentJoint()->removeChildJoint(joint);
+}
+
+} // namespace Quick
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/quick3d/items/quick3djoint_p.h b/src/quick3d/quick3d/items/quick3djoint_p.h
new file mode 100644
index 000000000..bef161643
--- /dev/null
+++ b/src/quick3d/quick3d/items/quick3djoint_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DCORE_QUICK_QUICK3DJOINT_P_H
+#define QT3DCORE_QUICK_QUICK3DJOINT_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 <QObject>
+#include <Qt3DCore/qjoint.h>
+#include <QtQml/QQmlListProperty>
+
+#include <Qt3DQuick/private/qt3dquick_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+namespace Quick {
+
+class QT3DQUICKSHARED_PRIVATE_EXPORT Quick3DJoint : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<Qt3DCore::QJoint> childJoints READ childJoints)
+public:
+ explicit Quick3DJoint(QObject *parent = nullptr);
+
+ QQmlListProperty<Qt3DCore::QJoint> childJoints();
+
+ inline QJoint *parentJoint() const { return qobject_cast<QJoint*>(parent()); }
+
+private:
+ static void appendJoint(QQmlListProperty<Qt3DCore::QJoint> *list, Qt3DCore::QJoint *obj);
+ static QJoint *jointAt(QQmlListProperty<Qt3DCore::QJoint> *list, int index);
+ static int jointCount(QQmlListProperty<Qt3DCore::QJoint> *list);
+ static void clearJoints(QQmlListProperty<Qt3DCore::QJoint> *list);
+};
+
+} // namespace Quick
+} // namespace Qt3DCore
+
+QT_END_NAMESPACE
+
+#endif // QT3DCORE_QUICK_QUICK3DJOINT_P_H
diff --git a/src/quick3d/quick3d/qt3dquicknodefactory.cpp b/src/quick3d/quick3d/qt3dquicknodefactory.cpp
index 62e8ac845..1a37f9acc 100644
--- a/src/quick3d/quick3d/qt3dquicknodefactory.cpp
+++ b/src/quick3d/quick3d/qt3dquicknodefactory.cpp
@@ -39,8 +39,6 @@
#include "qt3dquicknodefactory_p.h"
-#include <QtQml/private/qqmlmetatype_p.h>
-
QT_BEGIN_NAMESPACE
namespace Qt3DCore {
diff --git a/src/quick3d/quick3danimation/items/quick3dchannelmapper.cpp b/src/quick3d/quick3danimation/items/quick3dchannelmapper.cpp
index 55eb04be1..66ee7faef 100644
--- a/src/quick3d/quick3danimation/items/quick3dchannelmapper.cpp
+++ b/src/quick3d/quick3danimation/items/quick3dchannelmapper.cpp
@@ -50,38 +50,38 @@ Quick3DChannelMapper::Quick3DChannelMapper(QObject *parent)
{
}
-QQmlListProperty<QChannelMapping> Quick3DChannelMapper::qmlMappings()
+QQmlListProperty<QAbstractChannelMapping> Quick3DChannelMapper::qmlMappings()
{
- return QQmlListProperty<QChannelMapping>(this, 0,
- &Quick3DChannelMapper::appendMapping,
- &Quick3DChannelMapper::mappingCount,
- &Quick3DChannelMapper::mappingAt,
- &Quick3DChannelMapper::clearMappings);
+ return QQmlListProperty<QAbstractChannelMapping>(this, 0,
+ &Quick3DChannelMapper::appendMapping,
+ &Quick3DChannelMapper::mappingCount,
+ &Quick3DChannelMapper::mappingAt,
+ &Quick3DChannelMapper::clearMappings);
}
-void Quick3DChannelMapper::appendMapping(QQmlListProperty<QChannelMapping> *list, QChannelMapping *mapping)
+void Quick3DChannelMapper::appendMapping(QQmlListProperty<QAbstractChannelMapping> *list, QAbstractChannelMapping *mapping)
{
Quick3DChannelMapper *extension = qobject_cast<Quick3DChannelMapper *>(list->object);
extension->parentMapper()->addMapping(mapping);
}
-QChannelMapping *Quick3DChannelMapper::mappingAt(QQmlListProperty<QChannelMapping> *list, int index)
+QAbstractChannelMapping *Quick3DChannelMapper::mappingAt(QQmlListProperty<QAbstractChannelMapping> *list, int index)
{
Quick3DChannelMapper *extension = qobject_cast<Quick3DChannelMapper *>(list->object);
return extension->parentMapper()->mappings().at(index);
}
-int Quick3DChannelMapper::mappingCount(QQmlListProperty<QChannelMapping> *list)
+int Quick3DChannelMapper::mappingCount(QQmlListProperty<QAbstractChannelMapping> *list)
{
Quick3DChannelMapper *extension = qobject_cast<Quick3DChannelMapper *>(list->object);
return extension->parentMapper()->mappings().count();
}
-void Quick3DChannelMapper::clearMappings(QQmlListProperty<QChannelMapping> *list)
+void Quick3DChannelMapper::clearMappings(QQmlListProperty<QAbstractChannelMapping> *list)
{
Quick3DChannelMapper *extension = qobject_cast<Quick3DChannelMapper *>(list->object);
const auto mappings = extension->parentMapper()->mappings();
- for (QChannelMapping *mapping : mappings)
+ for (QAbstractChannelMapping *mapping : mappings)
extension->parentMapper()->removeMapping(mapping);
}
diff --git a/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h b/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h
index e44efad68..c3ec577a2 100644
--- a/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h
+++ b/src/quick3d/quick3danimation/items/quick3dchannelmapper_p.h
@@ -52,7 +52,7 @@
//
#include <Qt3DQuickAnimation/private/qt3dquickanimation_global_p.h>
-#include <Qt3DAnimation/qchannelmapping.h>
+#include <Qt3DAnimation/qabstractchannelmapping.h>
#include <Qt3DAnimation/qchannelmapper.h>
#include <QQmlListProperty>
@@ -65,20 +65,20 @@ namespace Quick {
class QT3DQUICKANIMATIONSHARED_PRIVATE_EXPORT Quick3DChannelMapper : public QObject
{
Q_OBJECT
- Q_PROPERTY(QQmlListProperty<Qt3DAnimation::QChannelMapping> mappings READ qmlMappings CONSTANT)
+ Q_PROPERTY(QQmlListProperty<Qt3DAnimation::QAbstractChannelMapping> mappings READ qmlMappings CONSTANT)
Q_CLASSINFO("DefaultProperty", "mappings")
public:
explicit Quick3DChannelMapper(QObject *parent = nullptr);
inline QChannelMapper *parentMapper() const { return qobject_cast<QChannelMapper *>(parent()); }
- QQmlListProperty<QChannelMapping> qmlMappings();
+ QQmlListProperty<QAbstractChannelMapping> qmlMappings();
private:
- static void appendMapping(QQmlListProperty<QChannelMapping> *list, QChannelMapping *mapping);
- static QChannelMapping *mappingAt(QQmlListProperty<QChannelMapping> *list, int index);
- static int mappingCount(QQmlListProperty<QChannelMapping> *list);
- static void clearMappings(QQmlListProperty<QChannelMapping> *list);
+ static void appendMapping(QQmlListProperty<QAbstractChannelMapping> *list, QAbstractChannelMapping *mapping);
+ static QAbstractChannelMapping *mappingAt(QQmlListProperty<QAbstractChannelMapping> *list, int index);
+ static int mappingCount(QQmlListProperty<QAbstractChannelMapping> *list);
+ static void clearMappings(QQmlListProperty<QAbstractChannelMapping> *list);
};
} // namespace Quick
diff --git a/src/quick3d/quick3dextras/items/items.pri b/src/quick3d/quick3dextras/items/items.pri
index b6f5d1877..f2fe09dcb 100644
--- a/src/quick3d/quick3dextras/items/items.pri
+++ b/src/quick3d/quick3dextras/items/items.pri
@@ -1,8 +1,10 @@
HEADERS += \
$$PWD/quick3dlevelofdetailloader_p.h \
- $$PWD/quick3dlevelofdetailloader_p_p.h
+ $$PWD/quick3dlevelofdetailloader_p_p.h \
+ $$PWD/quick3dspritesheet_p.h
SOURCES += \
- $$PWD/quick3dlevelofdetailloader.cpp
+ $$PWD/quick3dlevelofdetailloader.cpp \
+ $$PWD/quick3dspritesheet.cpp
INCLUDEPATH += $$PWD
diff --git a/src/quick3d/quick3dextras/items/quick3dspritesheet.cpp b/src/quick3d/quick3dextras/items/quick3dspritesheet.cpp
new file mode 100644
index 000000000..a38581cc7
--- /dev/null
+++ b/src/quick3d/quick3dextras/items/quick3dspritesheet.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "quick3dspritesheet_p.h"
+#include <Qt3DExtras/qspritesheetitem.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+namespace Extras {
+namespace Quick {
+
+Quick3DSpriteSheet::Quick3DSpriteSheet(QObject *parent)
+ : QObject(parent)
+{
+}
+
+Quick3DSpriteSheet::~Quick3DSpriteSheet()
+{
+}
+
+QQmlListProperty<Qt3DExtras::QSpriteSheetItem> Quick3DSpriteSheet::sprites()
+{
+ return QQmlListProperty<Qt3DExtras::QSpriteSheetItem>(this, 0,
+ &Quick3DSpriteSheet::appendSprite,
+ &Quick3DSpriteSheet::spriteCount,
+ &Quick3DSpriteSheet::spriteAt,
+ &Quick3DSpriteSheet::clearSprites);
+
+}
+
+void Quick3DSpriteSheet::appendSprite(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list,
+ Qt3DExtras::QSpriteSheetItem *sprite)
+{
+ Quick3DSpriteSheet *spritesheet = qobject_cast<Quick3DSpriteSheet *>(list->object);
+ spritesheet->parentSpriteSheet()->addSprite(sprite);
+}
+
+Qt3DExtras::QSpriteSheetItem *Quick3DSpriteSheet::spriteAt(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list, int index)
+{
+ Quick3DSpriteSheet *spritesheet = qobject_cast<Quick3DSpriteSheet *>(list->object);
+ return spritesheet->parentSpriteSheet()->sprites().at(index);
+}
+
+int Quick3DSpriteSheet::spriteCount(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list)
+{
+ Quick3DSpriteSheet *spritesheet = qobject_cast<Quick3DSpriteSheet *>(list->object);
+ return spritesheet->parentSpriteSheet()->sprites().count();
+}
+
+void Quick3DSpriteSheet::clearSprites(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list)
+{
+ Quick3DSpriteSheet *spritesheet = qobject_cast<Quick3DSpriteSheet *>(list->object);
+ const auto sprites = spritesheet->parentSpriteSheet()->sprites();
+ for (QSpriteSheetItem *sprite : sprites)
+ spritesheet->parentSpriteSheet()->removeSprite(sprite);
+}
+
+} // namespace Quick
+} // namespace Extras
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
+
diff --git a/src/quick3d/quick3dextras/items/quick3dspritesheet_p.h b/src/quick3d/quick3dextras/items/quick3dspritesheet_p.h
new file mode 100644
index 000000000..38a92dd2a
--- /dev/null
+++ b/src/quick3d/quick3dextras/items/quick3dspritesheet_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QT3DEXTRAS_EXTRAS_QUICK_QUICK3DSPRITESHEET_P_H
+#define QT3DEXTRAS_EXTRAS_QUICK_QUICK3DSPRITESHEET_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 <Qt3DQuickExtras/qt3dquickextras_global.h>
+#include <Qt3DExtras/qspritesheet.h>
+#include <QtQml/QQmlListProperty>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+namespace Extras {
+namespace Quick {
+
+class QT3DQUICKEXTRASSHARED_EXPORT Quick3DSpriteSheet : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> sprites READ sprites CONSTANT)
+ Q_CLASSINFO("DefaultProperty", "sprites")
+public:
+ explicit Quick3DSpriteSheet(QObject *parent = 0);
+ ~Quick3DSpriteSheet();
+
+ QQmlListProperty<Qt3DExtras::QSpriteSheetItem> sprites();
+ inline QSpriteSheet *parentSpriteSheet() const { return qobject_cast<QSpriteSheet *>(parent()); }
+
+private:
+ static void appendSprite(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list, Qt3DExtras::QSpriteSheetItem *state);
+ static Qt3DExtras::QSpriteSheetItem *spriteAt(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list, int index);
+ static int spriteCount(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list);
+ static void clearSprites(QQmlListProperty<Qt3DExtras::QSpriteSheetItem> *list);
+};
+
+} // namespace Quick
+} // namespace Extras
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QT3DEXTRAS_EXTRAS_QUICK_QUICK3DSPRITESHEET_P_H
diff --git a/src/quick3d/quick3dextras/qt3dquickextras_global.cpp b/src/quick3d/quick3dextras/qt3dquickextras_global.cpp
new file mode 100644
index 000000000..e9b71e081
--- /dev/null
+++ b/src/quick3d/quick3dextras/qt3dquickextras_global.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qt3dquickextras_global_p.h"
+
+#include <Qt3DQuickExtras/private/qt3dquickextrasnodefactory_p.h>
+#include <QtQml/private/qqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+namespace Quick {
+
+void Quick3DExtras_initialize()
+{
+ Qt3DCore::QAbstractNodeFactory::registerNodeFactory(QuickExtrasNodeFactory::instance());
+}
+
+void Quick3DExtras_registerType(const char *className, const char *quickName, int major, int minor)
+{
+ QuickExtrasNodeFactory::instance()->registerType(className, quickName, major, minor);
+}
+
+} // namespace Quick
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/quick3dextras/qt3dquickextras_global_p.h b/src/quick3d/quick3dextras/qt3dquickextras_global_p.h
index 524393743..a27533517 100644
--- a/src/quick3d/quick3dextras/qt3dquickextras_global_p.h
+++ b/src/quick3d/quick3dextras/qt3dquickextras_global_p.h
@@ -58,6 +58,22 @@
QT_BEGIN_NAMESPACE
+namespace Qt3DExtras {
+namespace Quick {
+
+QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT void Quick3DExtras_initialize();
+QT3DQUICKEXTRASSHARED_PRIVATE_EXPORT void Quick3DExtras_registerType(const char *className, const char *quickName, int major, int minor);
+
+template<class T, class E> void registerExtendedType(const char *className, const char *quickName,
+ const char *uri, int major, int minor, const char *name)
+{
+ qmlRegisterExtendedType<T, E>(uri, major, minor, name);
+ Quick3DExtras_registerType(className, quickName, major, minor);
+}
+
+} // Quick
+} // Qt3DExtras
+
QT_END_NAMESPACE
#endif // QT3DQUICKEXTRAS_GLOBAL_P_H
diff --git a/src/quick3d/quick3dextras/qt3dquickextrasnodefactory.cpp b/src/quick3d/quick3dextras/qt3dquickextrasnodefactory.cpp
new file mode 100644
index 000000000..2e1f993f9
--- /dev/null
+++ b/src/quick3d/quick3dextras/qt3dquickextrasnodefactory.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qt3dquickextrasnodefactory_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DExtras {
+
+Q_GLOBAL_STATIC(QuickExtrasNodeFactory, quick_extras_node_factory)
+
+QuickExtrasNodeFactory *QuickExtrasNodeFactory::instance()
+{
+ return quick_extras_node_factory();
+}
+
+void QuickExtrasNodeFactory::registerType(const char *className, const char *quickName, int major, int minor)
+{
+ m_types.insert(className, Type(quickName, major, minor));
+}
+
+Qt3DCore::QNode *QuickExtrasNodeFactory::createNode(const char *type)
+{
+ if (!m_types.contains(type))
+ return nullptr;
+
+ Type &typeInfo(m_types[type]);
+
+ if (!typeInfo.resolved) {
+ typeInfo.resolved = true;
+ typeInfo.t = QQmlMetaType::qmlType(QString::fromLatin1(typeInfo.quickName), typeInfo.version.first, typeInfo.version.second);
+ }
+
+ return typeInfo.t.isValid() ? qobject_cast<Qt3DCore::QNode *>(typeInfo.t.create()) : nullptr;
+}
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
diff --git a/src/quick3d/quick3dextras/qt3dquickextrasnodefactory_p.h b/src/quick3d/quick3dextras/qt3dquickextrasnodefactory_p.h
new file mode 100644
index 000000000..43172952c
--- /dev/null
+++ b/src/quick3d/quick3dextras/qt3dquickextrasnodefactory_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 QUICKEXTRASERNODEFACTORY_H
+#define QUICKEXTRASERNODEFACTORY_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 <private/qabstractnodefactory_p.h>
+#include <QtCore/qhash.h>
+#include <QtQml/private/qqmlmetatype_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlType;
+
+namespace Qt3DExtras {
+
+class QuickExtrasNodeFactory : public Qt3DCore::QAbstractNodeFactory
+{
+public:
+ Qt3DCore::QNode *createNode(const char *type) Q_DECL_OVERRIDE;
+
+ void registerType(const char *className, const char *quickName, int major, int minor);
+
+ static QuickExtrasNodeFactory *instance();
+
+private:
+ struct Type {
+ Type() : t(nullptr), resolved(false) { }
+ Type(const char *quickName, int major, int minor)
+ : quickName(quickName), version(major, minor), t(nullptr), resolved(false) { }
+ QByteArray quickName;
+ QPair<int, int> version;
+ QQmlType t;
+ bool resolved;
+ };
+ QHash<QByteArray, Type> m_types;
+};
+
+} // namespace Qt3DExtras
+
+QT_END_NAMESPACE
+
+#endif // QUICKEXTRASERNODEFACTORY_H
diff --git a/src/quick3d/quick3dextras/quick3dextras.pro b/src/quick3d/quick3dextras/quick3dextras.pro
index 976430eba..f89a93e8e 100644
--- a/src/quick3d/quick3dextras/quick3dextras.pro
+++ b/src/quick3d/quick3dextras/quick3dextras.pro
@@ -14,12 +14,15 @@ gcov {
}
SOURCES += \
+ qt3dquickextras_global.cpp \
+ qt3dquickextrasnodefactory.cpp \
qt3dquickwindow.cpp \
qt3dquickwindowlogging.cpp
HEADERS += \
qt3dquickextras_global.h \
qt3dquickextras_global_p.h \
+ qt3dquickextrasnodefactory_p.h \
qt3dquickwindow.h \
qt3dquickwindow_p.h \
qt3dquickwindowlogging_p.h
diff --git a/src/quick3d/quick3drender/items/quick3dbuffer.cpp b/src/quick3d/quick3drender/items/quick3dbuffer.cpp
index 362e60328..9ff349118 100644
--- a/src/quick3d/quick3drender/items/quick3dbuffer.cpp
+++ b/src/quick3d/quick3drender/items/quick3dbuffer.cpp
@@ -61,7 +61,7 @@ const int jsValueTypeId = qMetaTypeId<QJSValue>();
}
Quick3DBuffer::Quick3DBuffer(Qt3DCore::QNode *parent)
- : Qt3DRender::QBuffer(QBuffer::VertexBuffer, parent)
+ : Qt3DRender::QBuffer(parent)
, m_engine(nullptr)
, m_v4engine(nullptr)
{
diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp
index 13a253063..4abc7cf42 100644
--- a/src/quick3d/quick3dscene2d/items/scene2d.cpp
+++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp
@@ -58,6 +58,8 @@
#include <private/qpickevent_p.h>
#include <private/entity_p.h>
#include <private/platformsurfacefilter_p.h>
+#include <private/trianglesvisitor_p.h>
+
QT_BEGIN_NAMESPACE
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index f8d9850e7..4d80ec87d 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -95,11 +95,20 @@ public:
// Changes made to backend nodes are reported to the Renderer
enum BackendNodeDirtyFlag {
- TransformDirty = 1 << 0,
- MaterialDirty = 1 << 1,
- GeometryDirty = 1 << 2,
- ComputeDirty = 1 << 3,
- AllDirty = 1 << 15
+ TransformDirty = 1 << 0,
+ MaterialDirty = 1 << 1,
+ GeometryDirty = 1 << 2,
+ ComputeDirty = 1 << 3,
+ ParameterDirty = 1 << 4,
+ FrameGraphDirty = 1 << 5,
+ EntityEnabledDirty = 1 << 6,
+ BuffersDirty = 1 << 7,
+ TexturesDirty = 1 << 8,
+ ShadersDirty = 1 << 9,
+ SkeletonDataDirty = 1 << 10,
+ JointDirty = 1 << 11,
+ LayersDirty = 1 << 12,
+ AllDirty = 0xffffff
};
Q_DECLARE_FLAGS(BackendNodeDirtySet, BackendNodeDirtyFlag)
@@ -139,6 +148,7 @@ public:
virtual QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() = 0;
virtual Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() = 0;
virtual Qt3DCore::QAspectJobPtr syncTextureLoadingJob() = 0;
+ virtual Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() = 0;
virtual void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Entity *root) = 0;
diff --git a/src/render/backend/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp
index 6dee7587b..9a08fdde4 100644
--- a/src/render/backend/attachmentpack.cpp
+++ b/src/render/backend/attachmentpack.cpp
@@ -67,11 +67,13 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende
// If nothing is specified, use all the attachments as draw buffers
if (selectedAttachmentPoints.isEmpty()) {
+ m_drawBuffers.reserve(m_attachments.size());
for (const Attachment &attachment : qAsConst(m_attachments))
// only consider Color Attachments
if (attachment.m_point <= QRenderTargetOutput::Color15)
m_drawBuffers.push_back((int) attachment.m_point);
} else {
+ m_drawBuffers.reserve(selectedAttachmentPoints.size());
for (QRenderTargetOutput::AttachmentPoint drawBuffer : selectedAttachmentPoints)
if (drawBuffer <= QRenderTargetOutput::Color15)
m_drawBuffers.push_back((int) drawBuffer);
diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp
index 3d0e7fdaf..cf1f17d32 100644
--- a/src/render/backend/cameralens.cpp
+++ b/src/render/backend/cameralens.cpp
@@ -39,8 +39,14 @@
#include "cameralens_p.h"
#include <Qt3DRender/qcameralens.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/qcameralens_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/computefilteredboundingvolumejob_p.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qtransform.h>
@@ -52,8 +58,34 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
+
+namespace {
+
+class GetBoundingVolumeWithoutCameraJob : public ComputeFilteredBoundingVolumeJob
+{
+public:
+ GetBoundingVolumeWithoutCameraJob(CameraLens *lens,
+ QNodeCommand::CommandId commandId)
+ : m_lens(lens), m_commandId(commandId)
+ {
+ }
+
+protected:
+ void finished(const Sphere &sphere) override
+ {
+ m_lens->notifySceneBoundingVolume(sphere, m_commandId);
+ }
+
+private:
+ CameraLens *m_lens;
+ QNodeCommand::CommandId m_commandId;
+};
+
+} // namespace
+
CameraLens::CameraLens()
- : BackendNode()
+ : BackendNode(QBackendNode::ReadWrite)
+ , m_renderAspect(nullptr)
, m_exposure(0.0f)
{
}
@@ -68,6 +100,11 @@ void CameraLens::cleanup()
QBackendNode::setEnabled(false);
}
+void CameraLens::setRenderAspect(QRenderAspect *renderAspect)
+{
+ m_renderAspect = renderAspect;
+}
+
void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QCameraLensData>>(change);
@@ -76,6 +113,41 @@ void CameraLens::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &c
m_exposure = data.exposure;
}
+void CameraLens::computeSceneBoundingVolume(QNodeId entityId,
+ QNodeId cameraId,
+ QNodeCommand::CommandId commandId)
+{
+ if (!m_renderer || !m_renderAspect)
+ return;
+ NodeManagers *nodeManagers = m_renderer->nodeManagers();
+
+ Entity *root = m_renderer->sceneRoot();
+ if (!entityId.isNull())
+ root = nodeManagers->renderNodesManager()->lookupResource(entityId);
+ if (!root)
+ return;
+
+ Entity *camNode = nodeManagers->renderNodesManager()->lookupResource(cameraId);
+ ComputeFilteredBoundingVolumeJobPtr job(new GetBoundingVolumeWithoutCameraJob(this, commandId));
+ job->addDependency(m_renderer->expandBoundingVolumeJob());
+ job->setRoot(root);
+ job->ignoreSubTree(camNode);
+ m_renderAspect->scheduleSingleShotJob(job);
+}
+
+void CameraLens::notifySceneBoundingVolume(const Sphere &sphere, QNodeCommand::CommandId commandId)
+{
+ if (m_pendingViewAllCommand != commandId)
+ return;
+ if (sphere.radius() > 0.f) {
+ QVector<float> data = { sphere.center().x(), sphere.center().y(), sphere.center().z(),
+ sphere.radius() };
+ QVariant v;
+ v.setValue(data);
+ sendCommand(QLatin1Literal("ViewAll"), v, m_pendingViewAllCommand);
+ }
+}
+
void CameraLens::setProjection(const QMatrix4x4 &projection)
{
m_projection = projection;
@@ -103,12 +175,70 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
}
break;
+ case CommandRequested: {
+ QNodeCommandPtr command = qSharedPointerCast<QNodeCommand>(e);
+
+ if (command->name() == QLatin1Literal("QueryRootBoundingVolume")) {
+ m_pendingViewAllCommand = command->commandId();
+ QVariant v = command->data();
+ QNodeId id = v.value<QNodeId>();
+ computeSceneBoundingVolume({}, id, command->commandId());
+ } else if (command->name() == QLatin1Literal("QueryEntityBoundingVolume")) {
+ m_pendingViewAllCommand = command->commandId();
+ QVariant v = command->data();
+ QVector<QNodeId> ids = v.value<QVector<QNodeId>>();
+ if (ids.size() == 2)
+ computeSceneBoundingVolume(ids[0], ids[1], command->commandId());
+ }
+ }
+ break;
+
default:
break;
}
BackendNode::sceneChangeEvent(e);
}
+bool CameraLens::viewMatrixForCamera(EntityManager* manager, Qt3DCore::QNodeId cameraId,
+ QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix)
+{
+ Entity *camNode = manager->lookupResource(cameraId);
+ if (!camNode)
+ return false;
+ Render::CameraLens *lens = camNode->renderComponent<CameraLens>();
+ if (!lens || !lens->isEnabled())
+ return false;
+
+ viewMatrix = *camNode->worldTransform();
+ projectionMatrix = lens->projection();
+ return true;
+}
+
+CameraLensFunctor::CameraLensFunctor(AbstractRenderer *renderer, QRenderAspect *renderAspect)
+ : m_manager(renderer->nodeManagers()->manager<CameraLens, CameraManager>())
+ , m_renderer(renderer)
+ , m_renderAspect(renderAspect)
+{
+}
+
+QBackendNode *CameraLensFunctor::create(const QNodeCreatedChangeBasePtr &change) const
+{
+ CameraLens *backend = m_manager->getOrCreateResource(change->subjectId());
+ backend->setRenderer(m_renderer);
+ backend->setRenderAspect(m_renderAspect);
+ return backend;
+}
+
+QBackendNode *CameraLensFunctor::get(QNodeId id) const
+{
+ return m_manager->lookupResource(id);
+}
+
+void CameraLensFunctor::destroy(QNodeId id) const
+{
+ m_manager->releaseResource(id);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/cameralens_p.h b/src/render/backend/cameralens_p.h
index 72282a88b..d071619d8 100644
--- a/src/render/backend/cameralens_p.h
+++ b/src/render/backend/cameralens_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DRender/private/backendnode_p.h>
+#include <Qt3DCore/private/qnodecommand_p.h>
#include <QMatrix4x4>
#include <QRectF>
@@ -61,15 +62,33 @@ namespace Qt3DRender {
namespace Render {
+class EntityManager;
class CameraManager;
+class Sphere;
-class CameraLens : public BackendNode
+class CameraLensFunctor : public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit CameraLensFunctor(AbstractRenderer *renderer, QRenderAspect *renderAspect);
+ 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:
+ CameraManager *m_manager;
+ AbstractRenderer *m_renderer;
+ QRenderAspect *m_renderAspect;
+};
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT CameraLens : public BackendNode
{
public:
CameraLens();
~CameraLens();
void cleanup();
+ void setRenderAspect(QRenderAspect* renderAspect);
+
void setProjection(const QMatrix4x4 &projection);
inline QMatrix4x4 projection() const { return m_projection; }
@@ -77,11 +96,20 @@ public:
inline float exposure() const { return m_exposure; }
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+ void notifySceneBoundingVolume(const Sphere &sphere, Qt3DCore::QNodeCommand::CommandId commandId);
+
+ static bool viewMatrixForCamera(EntityManager *manager, Qt3DCore::QNodeId cameraId,
+ QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix);
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ void computeSceneBoundingVolume(Qt3DCore::QNodeId entityId,
+ Qt3DCore::QNodeId cameraId,
+ Qt3DCore::QNodeCommand::CommandId commandId);
+ QRenderAspect *m_renderAspect;
QMatrix4x4 m_projection;
+ Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
float m_exposure;
};
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp
index 84bf7455a..cd1ec0e2b 100644
--- a/src/render/backend/commandexecuter.cpp
+++ b/src/render/backend/commandexecuter.cpp
@@ -303,8 +303,9 @@ CommandExecuter::CommandExecuter(Render::Renderer *renderer)
// Render thread
void CommandExecuter::performAsynchronousCommandExecution(const QVector<Render::RenderView *> &views)
{
- // The renderer's mutex is already locked
+ QMutexLocker lock(&m_pendingCommandsMutex);
const QVector<Qt3DCore::Debug::AsynchronousCommandReply *> shellCommands = std::move(m_pendingCommands);
+ lock.unlock();
for (auto *reply : shellCommands) {
if (reply->commandName() == QLatin1String("glinfo")) {
@@ -375,7 +376,7 @@ QVariant CommandExecuter::executeCommand(const QStringList &args)
(args.first() == QLatin1String("glinfo") ||
args.first() == QLatin1String("rendercommands"))) {
auto reply = new Qt3DCore::Debug::AsynchronousCommandReply(args.first());
- QMutexLocker lock(m_renderer->mutex());
+ QMutexLocker lock(&m_pendingCommandsMutex);
m_pendingCommands.push_back(reply);
return QVariant::fromValue(reply);
}
diff --git a/src/render/backend/commandexecuter_p.h b/src/render/backend/commandexecuter_p.h
index 896164543..2d90bf4d6 100644
--- a/src/render/backend/commandexecuter_p.h
+++ b/src/render/backend/commandexecuter_p.h
@@ -50,6 +50,7 @@
#include <QVector>
#include <QVariant>
+#include <QMutex>
QT_BEGIN_NAMESPACE
@@ -82,6 +83,7 @@ public:
private:
Render::Renderer *m_renderer;
QVector<Qt3DCore::Debug::AsynchronousCommandReply *> m_pendingCommands;
+ QMutex m_pendingCommandsMutex;
};
} // Debug
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index 8a97eed81..95304007a 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -53,8 +53,10 @@
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/armature_p.h>
#include <Qt3DRender/qcameralens.h>
+#include <Qt3DCore/qarmature.h>
#include <Qt3DCore/qcomponentaddedchange.h>
#include <Qt3DCore/qcomponentremovedchange.h>
#include <Qt3DCore/qentity.h>
@@ -114,6 +116,7 @@ void Entity::cleanup()
m_objectPickerComponent = QNodeId();
m_boundingVolumeDebugComponent = QNodeId();
m_computeComponent = QNodeId();
+ m_armatureComponent = QNodeId();
m_childrenHandles.clear();
m_layerComponents.clear();
m_levelOfDetailComponents.clear();
@@ -199,6 +202,7 @@ void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto componentIdAndType = QNodeIdTypePair(change->componentId(), change->componentMetaObject());
addComponent(componentIdAndType);
qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Added. Id =" << change->componentId();
+ markDirty(AbstractRenderer::AllDirty);
break;
}
@@ -206,28 +210,42 @@ void Entity::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
QComponentRemovedChangePtr change = qSharedPointerCast<QComponentRemovedChange>(e);
removeComponent(change->componentId());
qCDebug(Render::RenderNodes) << Q_FUNC_INFO << "Component Removed. Id =" << change->componentId();
+ markDirty(AbstractRenderer::AllDirty);
break;
}
case PropertyValueAdded: {
QPropertyNodeAddedChangePtr change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->metaObject()->inherits(&QEntity::staticMetaObject))
+ if (change->metaObject()->inherits(&QEntity::staticMetaObject)) {
appendChildHandle(m_nodeManagers->renderNodesManager()->lookupHandle(change->addedNodeId()));
+ markDirty(AbstractRenderer::AllDirty);
+ }
break;
}
case PropertyValueRemoved: {
QPropertyNodeRemovedChangePtr change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->metaObject()->inherits(&QEntity::staticMetaObject))
+ if (change->metaObject()->inherits(&QEntity::staticMetaObject)) {
removeChildHandle(m_nodeManagers->renderNodesManager()->lookupHandle(change->removedNodeId()));
+ markDirty(AbstractRenderer::AllDirty);
+ }
break;
}
+ case PropertyUpdated: {
+ QPropertyUpdatedChangePtr change = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("enabled")) {
+ // We only mark as dirty the renderer
+ markDirty(AbstractRenderer::EntityEnabledDirty);
+ // We let QBackendNode::sceneChangeEvent change the enabled property
+ }
+
+ break;
+ }
default:
break;
}
- markDirty(AbstractRenderer::AllDirty);
BackendNode::sceneChangeEvent(e);
}
@@ -279,39 +297,6 @@ const QMatrix4x4 *Entity::worldTransform() const
return m_nodeManagers->worldMatrixManager()->data(m_worldTransform);
}
-void Entity::addComponent(Qt3DCore::QComponent *component)
-{
- // The backend element is always created when this method is called
- // If that's not the case something has gone wrong
-
- if (qobject_cast<Qt3DCore::QTransform*>(component) != nullptr) {
- m_transformComponent = component->id();
- } else if (qobject_cast<QCameraLens *>(component) != nullptr) {
- m_cameraComponent = component->id();
- } else if (qobject_cast<QLayer *>(component) != nullptr) {
- m_layerComponents.append(component->id());
- } else if (qobject_cast<QLevelOfDetail *>(component) != nullptr) {
- m_levelOfDetailComponents.append(component->id());
- } else if (qobject_cast<QMaterial *>(component) != nullptr) {
- m_materialComponent = component->id();
- } else if (qobject_cast<QAbstractLight *>(component) != nullptr) {
- m_lightComponents.append(component->id());
- } else if (qobject_cast<QEnvironmentLight *>(component) != nullptr) {
- m_environmentLightComponents.append(component->id());
- } else if (qobject_cast<QShaderData *>(component) != nullptr) {
- m_shaderDataComponents.append(component->id());
- } else if (qobject_cast<QGeometryRenderer *>(component) != nullptr) {
- m_geometryRendererComponent = component->id();
- m_boundingDirty = true;
- } else if (qobject_cast<QObjectPicker *>(component) != nullptr) {
- m_objectPickerComponent = component->id();
-// } else if (qobject_cast<QBoundingVolumeDebug *>(component) != nullptr) {
-// m_boundingVolumeDebugComponent = component->id();
- } else if (qobject_cast<QComputeCommand *>(component) != nullptr) {
- m_computeComponent = component->id();
- }
-}
-
void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
{
// The backend element is always created when this method is called
@@ -344,6 +329,8 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
// m_boundingVolumeDebugComponent = id;
} else if (type->inherits(&QComputeCommand::staticMetaObject)) {
m_computeComponent = id;
+ } else if (type->inherits(&QArmature::staticMetaObject)) {
+ m_armatureComponent = id;
}
}
@@ -374,6 +361,8 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
m_environmentLightComponents.removeAll(nodeId);
} else if (m_computeComponent == nodeId) {
m_computeComponent = QNodeId();
+ } else if (m_armatureComponent == nodeId) {
+ m_armatureComponent = QNodeId();
}
}
@@ -387,231 +376,29 @@ void Entity::unsetBoundingVolumeDirty()
m_boundingDirty = false;
}
-// Handles
-
-template<>
-HMaterial Entity::componentHandle<Material>() const
-{
- return m_nodeManagers->materialManager()->lookupHandle(m_materialComponent);
-}
-
-template<>
-HCamera Entity::componentHandle<CameraLens>() const
-{
- return m_nodeManagers->cameraManager()->lookupHandle(m_cameraComponent);
-}
-
-template<>
-HTransform Entity::componentHandle<Transform>() const
-{
- return m_nodeManagers->transformManager()->lookupHandle(m_transformComponent);
-}
-
-template<>
-HGeometryRenderer Entity::componentHandle<GeometryRenderer>() const
-{
- return m_nodeManagers->geometryRendererManager()->lookupHandle(m_geometryRendererComponent);
-}
-
-template<>
-HObjectPicker Entity::componentHandle<ObjectPicker>() const
-{
- return m_nodeManagers->objectPickerManager()->lookupHandle(m_objectPickerComponent);
-}
-
-template<>
-QVector<HLayer> Entity::componentsHandle<Layer>() const
-{
- QVector<HLayer> layerHandles;
- layerHandles.reserve(m_layerComponents.size());
- for (QNodeId id : m_layerComponents)
- layerHandles.append(m_nodeManagers->layerManager()->lookupHandle(id));
- return layerHandles;
-}
-
-template<>
-QVector<HLevelOfDetail> Entity::componentsHandle<LevelOfDetail>() const
-{
- QVector<HLevelOfDetail> lodHandles;
- lodHandles.reserve(m_levelOfDetailComponents.size());
- for (QNodeId id : m_levelOfDetailComponents)
- lodHandles.append(m_nodeManagers->levelOfDetailManager()->lookupHandle(id));
- return lodHandles;
-}
-
-template<>
-QVector<HShaderData> Entity::componentsHandle<ShaderData>() const
+void Entity::addRecursiveLayerId(const QNodeId layerId)
{
- QVector<HShaderData> shaderDataHandles;
- shaderDataHandles.reserve(m_shaderDataComponents.size());
- for (QNodeId id : m_shaderDataComponents)
- shaderDataHandles.append(m_nodeManagers->shaderDataManager()->lookupHandle(id));
- return shaderDataHandles;
+ if (!m_recursiveLayerComponents.contains(layerId) && !m_layerComponents.contains(layerId))
+ m_recursiveLayerComponents.push_back(layerId);
}
-//template<>
-//HBoundingVolumeDebug Entity::componentHandle<BoundingVolumeDebug>() const
-//{
-// return m_nodeManagers->boundingVolumeDebugManager()->lookupHandle(m_boundingVolumeDebugComponent);
-//}
-
-template<>
-QVector<HLight> Entity::componentsHandle<Light>() const
-{
- QVector<HLight> lightHandles;
- lightHandles.reserve(m_lightComponents.size());
- for (QNodeId id : m_lightComponents)
- lightHandles.append(m_nodeManagers->lightManager()->lookupHandle(id));
- return lightHandles;
-}
-
-template<>
-QVector<HEnvironmentLight> Entity::componentsHandle<EnvironmentLight>() const
-{
- QVector<HEnvironmentLight> lightHandles;
- lightHandles.reserve(m_environmentLightComponents.size());
- for (QNodeId id : m_environmentLightComponents)
- lightHandles.append(m_nodeManagers->environmentLightManager()->lookupHandle(id));
- return lightHandles;
-}
-
-template<>
-HComputeCommand Entity::componentHandle<ComputeCommand>() const
-{
- return m_nodeManagers->computeJobManager()->lookupHandle(m_computeComponent);
-}
-
-// Render components
-
-template<>
-Material *Entity::renderComponent<Material>() const
+void Entity::removeRecursiveLayerId(const QNodeId layerId)
{
- return m_nodeManagers->materialManager()->lookupResource(m_materialComponent);
+ m_recursiveLayerComponents.removeOne(layerId);
}
-template<>
-CameraLens *Entity::renderComponent<CameraLens>() const
-{
- return m_nodeManagers->cameraManager()->lookupResource(m_cameraComponent);
-}
-
-template<>
-Transform *Entity::renderComponent<Transform>() const
-{
- return m_nodeManagers->transformManager()->lookupResource(m_transformComponent);
-}
-
-template<>
-GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const
-{
- return m_nodeManagers->geometryRendererManager()->lookupResource(m_geometryRendererComponent);
-}
-
-template<>
-ObjectPicker *Entity::renderComponent<ObjectPicker>() const
-{
- return m_nodeManagers->objectPickerManager()->lookupResource(m_objectPickerComponent);
-}
-
-template<>
-QVector<Layer *> Entity::renderComponents<Layer>() const
-{
- QVector<Layer *> layers;
- layers.reserve(m_layerComponents.size());
- for (QNodeId id : m_layerComponents)
- layers.append(m_nodeManagers->layerManager()->lookupResource(id));
- return layers;
-}
-
-template<>
-QVector<LevelOfDetail *> Entity::renderComponents<LevelOfDetail>() const
-{
- QVector<LevelOfDetail *> lods;
- lods.reserve(m_levelOfDetailComponents.size());
- for (QNodeId id : m_levelOfDetailComponents)
- lods.append(m_nodeManagers->levelOfDetailManager()->lookupResource(id));
- return lods;
-}
-
-template<>
-QVector<ShaderData *> Entity::renderComponents<ShaderData>() const
-{
- QVector<ShaderData *> shaderDatas;
- shaderDatas.reserve(m_shaderDataComponents.size());
- for (QNodeId id : m_shaderDataComponents)
- shaderDatas.append(m_nodeManagers->shaderDataManager()->lookupResource(id));
- return shaderDatas;
-}
-
-template<>
-QVector<Light *> Entity::renderComponents<Light>() const
-{
- QVector<Light *> lights;
- lights.reserve(m_lightComponents.size());
- for (QNodeId id : m_lightComponents)
- lights.append(m_nodeManagers->lightManager()->lookupResource(id));
- return lights;
-}
-
-template<>
-QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const
-{
- QVector<EnvironmentLight *> lights;
- lights.reserve(m_environmentLightComponents.size());
- for (QNodeId id : m_environmentLightComponents)
- lights.append(m_nodeManagers->environmentLightManager()->lookupResource(id));
- return lights;
-}
-
-//template<>
-//BoundingVolumeDebug *Entity::renderComponent<BoundingVolumeDebug>() const
-//{
-// return m_nodeManagers->boundingVolumeDebugManager()->lookupResource(m_boundingVolumeDebugComponent);
-//}
-
-template<>
-ComputeCommand *Entity::renderComponent<ComputeCommand>() const
-{
- return m_nodeManagers->computeJobManager()->lookupResource(m_computeComponent);
-}
-
-// Uuid
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<Transform>() const { return m_transformComponent; }
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<CameraLens>() const { return m_cameraComponent; }
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<Material>() const { return m_materialComponent; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Layer>() const { return m_layerComponents; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<LevelOfDetail>() const { return m_levelOfDetailComponents; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const { return m_shaderDataComponents; }
-
-template<>
-Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const { return m_geometryRendererComponent; }
-
-template<>
-QNodeId Entity::componentUuid<ObjectPicker>() const { return m_objectPickerComponent; }
-
-template<>
-QNodeId Entity::componentUuid<BoundingVolumeDebug>() const { return m_boundingVolumeDebugComponent; }
-
-template<>
-QNodeId Entity::componentUuid<ComputeCommand>() const { return m_computeComponent; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const { return m_lightComponents; }
-
-template<>
-QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const { return m_environmentLightComponents; }
+ENTITY_COMPONENT_TEMPLATE_IMPL(Material, HMaterial, MaterialManager, m_materialComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(CameraLens, HCamera, CameraManager, m_cameraComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(Transform, HTransform, TransformManager, m_transformComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(GeometryRenderer, HGeometryRenderer, GeometryRendererManager, m_geometryRendererComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(ObjectPicker, HObjectPicker, ObjectPickerManager, m_objectPickerComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(ComputeCommand, HComputeCommand, ComputeCommandManager, m_computeComponent)
+ENTITY_COMPONENT_TEMPLATE_IMPL(Armature, HArmature, ArmatureManager, m_armatureComponent)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Layer, HLayer, LayerManager, m_layerComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(LevelOfDetail, HLevelOfDetail, LevelOfDetailManager, m_levelOfDetailComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(ShaderData, HShaderData, ShaderDataManager, m_shaderDataComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Light, HLight, LightManager, m_lightComponents)
+ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(EnvironmentLight, HEnvironmentLight, EnvironmentLightManager, m_environmentLightComponents)
RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager)
: m_nodeManagers(manager)
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index 4619314ad..52ad85281 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -110,7 +110,6 @@ public:
Sphere *worldBoundingVolume() const { return m_worldBoundingVolume.data(); }
Sphere *worldBoundingVolumeWithChildren() const { return m_worldBoundingVolumeWithChildren.data(); }
- void addComponent(Qt3DCore::QComponent *component);
void addComponent(Qt3DCore::QNodeIdTypePair idAndType);
void removeComponent(Qt3DCore::QNodeId nodeId);
@@ -120,6 +119,11 @@ public:
void setTreeEnabled(bool enabled) { m_treeEnabled = enabled; }
bool isTreeEnabled() const { return m_treeEnabled; }
+ Qt3DCore::QNodeIdVector layerIds() const { return m_layerComponents + m_recursiveLayerComponents; }
+ void addRecursiveLayerId(const Qt3DCore::QNodeId layerId);
+ void removeRecursiveLayerId(const Qt3DCore::QNodeId layerId);
+ void clearRecursiveLayerIds() { m_recursiveLayerComponents.clear(); }
+
template<class Backend, uint INDEXBITS>
Qt3DCore::QHandle<Backend, INDEXBITS> componentHandle() const
{
@@ -195,6 +199,10 @@ private:
Qt3DCore::QNodeId m_objectPickerComponent;
Qt3DCore::QNodeId m_boundingVolumeDebugComponent;
Qt3DCore::QNodeId m_computeComponent;
+ Qt3DCore::QNodeId m_armatureComponent;
+
+ // Includes recursive layers
+ Qt3DCore::QNodeIdVector m_recursiveLayerComponents;
QString m_objectName;
bool m_boundingDirty;
@@ -202,116 +210,91 @@ private:
bool m_treeEnabled;
};
-// Handles
-template<>
-HMaterial Entity::componentHandle<Material>() const;
-
-template<>
-HCamera Entity::componentHandle<CameraLens>() const;
-
-template<>
-HTransform Entity::componentHandle<Transform>() const;
-
-template<>
-Q_AUTOTEST_EXPORT HGeometryRenderer Entity::componentHandle<GeometryRenderer>() const;
-
-template<>
-Q_AUTOTEST_EXPORT HObjectPicker Entity::componentHandle<ObjectPicker>() const;
-
-template<>
-QVector<HLayer> Entity::componentsHandle<Layer>() const;
-
-template<>
-QVector<HLevelOfDetail> Entity::componentsHandle<LevelOfDetail>() const;
-
-template<>
-QVector<HShaderData> Entity::componentsHandle<ShaderData>() const;
-
-//template<>
-//Q_AUTOTEST_EXPORT HBoundingVolumeDebug Entity::componentHandle<BoundingVolumeDebug>() const;
-
-template<>
-QVector<HLight> Entity::componentsHandle<Light>() const;
-
-template<>
-QVector<HEnvironmentLight> Entity::componentsHandle<EnvironmentLight>() const;
-
-template<>
-Q_AUTOTEST_EXPORT HComputeCommand Entity::componentHandle<ComputeCommand>() const;
-
-// Render components
-template<>
-Material *Entity::renderComponent<Material>() const;
-
-template<>
-CameraLens *Entity::renderComponent<CameraLens>() const;
-
-template<>
-Transform *Entity::renderComponent<Transform>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPicker *Entity::renderComponent<ObjectPicker>() const;
-
-template<>
-QVector<Layer *> Entity::renderComponents<Layer>() const;
-
-template<>
-QVector<LevelOfDetail *> Entity::renderComponents<LevelOfDetail>() const;
-
-template<>
-QVector<ShaderData *> Entity::renderComponents<ShaderData>() const;
-
-//template<>
-//Q_AUTOTEST_EXPORT BoundingVolumeDebug *Entity::renderComponent<BoundingVolumeDebug>() const;
-
-template<>
-QVector<Light *> Entity::renderComponents<Light>() const;
-
-template<>
-QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const;
-
-template<>
-Q_AUTOTEST_EXPORT ComputeCommand *Entity::renderComponent<ComputeCommand>() const;
-
-// UUid
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<Transform>() const;
-
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<CameraLens>() const;
-
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<Material>() const;
-
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Layer>() const;
-
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<LevelOfDetail>() const;
-
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const;
-
-template<>
-QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ObjectPicker>() const;
-
-//template<>
-//Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<BoundingVolumeDebug>() const;
-
-template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ComputeCommand>() const;
+#define ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Type, Handle) \
+ /* Handle */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Handle Entity::componentHandle<Type>() const; \
+ /* Component */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Type *Entity::renderComponent<Type>() const; \
+ /* Uuid */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<Type>() const;
+
+
+#define ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Type, Handle) \
+ /* Handle */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT QVector<Handle> Entity::componentsHandle<Type>() const; \
+ /* Component */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT QVector<Type *> Entity::renderComponents<Type>() const; \
+ /* Uuid */ \
+ template<> \
+ QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeIdVector Entity::componentsUuid<Type>() const;
+
+#define ENTITY_COMPONENT_TEMPLATE_IMPL(Type, Handle, Manager, variable) \
+ /* Handle */ \
+ template<> \
+ Handle Entity::componentHandle<Type>() const \
+ { \
+ return m_nodeManagers->lookupHandle<Type, Manager, Handle>(variable); \
+ } \
+ /* Component */ \
+ template<> \
+ Type *Entity::renderComponent<Type>() const \
+ { \
+ return m_nodeManagers->lookupResource<Type, Manager>(variable); \
+ } \
+ /* Uuid */ \
+ template<> \
+ Qt3DCore::QNodeId Entity::componentUuid<Type>() const \
+ { \
+ return variable; \
+ }
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const;
+#define ENTITY_COMPONENT_LIST_TEMPLATE_IMPL(Type, Handle, Manager, variable) \
+ /* Handle */ \
+ template<> \
+ QVector<Handle> Entity::componentsHandle<Type>() const \
+ { \
+ Manager *manager = m_nodeManagers->manager<Type, Manager>(); \
+ QVector<Handle> entries; \
+ entries.reserve(variable.size()); \
+ for (const QNodeId id : variable) \
+ entries.push_back(manager->lookupHandle(id)); \
+ return entries; \
+ } \
+ /* Component */ \
+ template<> \
+ QVector<Type *> Entity::renderComponents<Type>() const \
+ { \
+ Manager *manager = m_nodeManagers->manager<Type, Manager>(); \
+ QVector<Type *> entries; \
+ entries.reserve(variable.size()); \
+ for (const QNodeId id : variable) \
+ entries.push_back(manager->lookupResource(id)); \
+ return entries; \
+ } \
+ /* Uuid */ \
+ template<> \
+ Qt3DCore::QNodeIdVector Entity::componentsUuid<Type>() const \
+ { \
+ return variable; \
+ }
-template<>
-Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const;
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Material, HMaterial)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(CameraLens, HCamera)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Transform, HTransform)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(GeometryRenderer, HGeometryRenderer)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(ObjectPicker, HObjectPicker)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(ComputeCommand, HComputeCommand)
+ENTITY_COMPONENT_TEMPLATE_SPECIALIZATION(Armature, HArmature)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Layer, HLayer)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(LevelOfDetail, HLevelOfDetail)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(ShaderData, HShaderData)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(Light, HLight)
+ENTITY_COMPONENT_LIST_TEMPLATE_SPECIALIZATION(EnvironmentLight, HEnvironmentLight)
class RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper
{
diff --git a/src/render/backend/frameprofiler_p.h b/src/render/backend/frameprofiler_p.h
index 9e7bcd038..06204a760 100644
--- a/src/render/backend/frameprofiler_p.h
+++ b/src/render/backend/frameprofiler_p.h
@@ -42,6 +42,7 @@
#include <QOpenGLTimeMonitor>
#include <Qt3DCore/private/qthreadpooler_p.h>
+#include <Qt3DCore/private/qt3dcore_global_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
@@ -69,7 +70,7 @@ enum RecordingType
RenderTargetUpdate
};
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
class FrameTimeRecorder
{
@@ -218,14 +219,14 @@ public:
explicit GLTimeRecorder(RecordingType type)
: m_type(type)
{
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
frameProfiler.startRecordEvent();
#endif
}
~GLTimeRecorder()
{
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
frameProfiler.recordEvent(m_type);
#else
Q_UNUSED(m_type);
@@ -234,19 +235,19 @@ public:
static void writeResults()
{
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
frameProfiler.writeResults();
#endif
}
private:
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
static FrameProfiler frameProfiler;
#endif
RecordingType m_type;
};
-#ifdef QT3D_OPENGL_RUN_STATS
+#if QT_CONFIG(qt3d_profile_gl)
FrameProfiler GLTimeRecorder::frameProfiler;
#endif
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index 352519e75..bb5836ab4 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -70,6 +70,7 @@ class FilterKey;
class Effect;
class Entity;
class Shader;
+class ShaderBuilder;
class FrameGraphNode;
class Layer;
class LevelOfDetail;
@@ -94,6 +95,9 @@ class EnvironmentLight;
class ComputeCommand;
class GLBuffer;
class RenderStateNode;
+class Armature;
+class Skeleton;
+class Joint;
typedef Qt3DCore::QHandle<RenderTargetOutput, 16> HAttachment;
typedef Qt3DCore::QHandle<CameraLens, 8> HCamera;
@@ -107,6 +111,7 @@ typedef Qt3DCore::QHandle<Material, 16> HMaterial;
typedef Qt3DCore::QHandle<QMatrix4x4, 16> HMatrix;
typedef Qt3DCore::QHandle<OpenGLVertexArrayObject, 16> HVao;
typedef Qt3DCore::QHandle<Shader, 16> HShader;
+typedef Qt3DCore::QHandle<ShaderBuilder, 16> HShaderBuilder;
typedef Qt3DCore::QHandle<Technique, 16> HTechnique;
typedef Qt3DCore::QHandle<Texture, 16> HTexture;
typedef Qt3DCore::QHandle<Transform, 16> HTransform;
@@ -127,6 +132,9 @@ typedef Qt3DCore::QHandle<EnvironmentLight, 16> HEnvironmentLight;
typedef Qt3DCore::QHandle<ComputeCommand, 16> HComputeCommand;
typedef Qt3DCore::QHandle<GLBuffer, 16> HGLBuffer;
typedef Qt3DCore::QHandle<RenderStateNode, 16> HRenderState;
+typedef Qt3DCore::QHandle<Armature, 16> HArmature;
+typedef Qt3DCore::QHandle<Skeleton, 16> HSkeleton;
+typedef Qt3DCore::QHandle<Joint, 16> HJoint;
} // namespace Render
diff --git a/src/render/backend/layer.cpp b/src/render/backend/layer.cpp
index 14c0317f8..976c35fd5 100644
--- a/src/render/backend/layer.cpp
+++ b/src/render/backend/layer.cpp
@@ -53,6 +53,7 @@ namespace Render {
Layer::Layer()
: BackendNode()
+ , m_recursive(false)
{
}
@@ -66,6 +67,38 @@ void Layer::cleanup()
QBackendNode::setEnabled(false);
}
+void Layer::sceneChangeEvent(const QSceneChangePtr &e)
+{
+ if (e->type() == PropertyUpdated) {
+ QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ QByteArray propertyName = propertyChange->propertyName();
+ if (propertyName == QByteArrayLiteral("recursive")) {
+ m_recursive = propertyChange->value().toBool();
+ markDirty(AbstractRenderer::LayersDirty);
+ }
+ if (propertyName == QByteArrayLiteral("enabled"))
+ markDirty(AbstractRenderer::LayersDirty);
+ }
+ BackendNode::sceneChangeEvent(e);
+}
+
+void Layer::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLayerData>>(change);
+ const auto &data = typedChange->data;
+ m_recursive = data.m_recursive;
+}
+
+bool Layer::recursive() const
+{
+ return m_recursive;
+}
+
+void Layer::setRecursive(bool recursive)
+{
+ m_recursive = recursive;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/layer_p.h b/src/render/backend/layer_p.h
index b6a78a1cf..d01d190e9 100644
--- a/src/render/backend/layer_p.h
+++ b/src/render/backend/layer_p.h
@@ -71,6 +71,17 @@ public:
Layer();
~Layer();
void cleanup();
+
+ // QBackendNode interface
+ bool recursive() const;
+ void setRecursive(bool recursive);
+
+protected:
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change);
+ bool m_recursive;
};
} // namespace Render
diff --git a/src/render/backend/managers.cpp b/src/render/backend/managers.cpp
index 844a44286..6e8c1376d 100644
--- a/src/render/backend/managers.cpp
+++ b/src/render/backend/managers.cpp
@@ -75,6 +75,42 @@ void FrameGraphManager::releaseNode(Qt3DCore::QNodeId id)
delete m_nodes.take(id);
}
+void SkeletonManager::addDirtySkeleton(DirtyFlag dirtyFlag, HSkeleton skeletonHandle)
+{
+ switch (dirtyFlag) {
+ case SkeletonDataDirty:
+ m_dirtyDataSkeletons.push_back(skeletonHandle);
+ break;
+
+ case SkeletonTransformsDirty:
+ m_dirtyTransformSkeletons.push_back(skeletonHandle);
+ break;
+ }
+}
+
+QVector<HSkeleton> SkeletonManager::dirtySkeletons(DirtyFlag dirtyFlag)
+{
+ switch (dirtyFlag) {
+ case SkeletonDataDirty:
+ return std::move(m_dirtyDataSkeletons);
+
+ case SkeletonTransformsDirty:
+ return std::move(m_dirtyTransformSkeletons);
+ }
+ return QVector<HSkeleton>();
+}
+
+void JointManager::addDirtyJoint(Qt3DCore::QNodeId jointId)
+{
+ const HJoint jointHandle = lookupHandle(jointId);
+ m_dirtyJoints.push_back(jointHandle);
+}
+
+QVector<HJoint> JointManager::dirtyJoints()
+{
+ return std::move(m_dirtyJoints);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index c5af93b8d..f19b9261a 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -61,6 +61,7 @@
#include <Qt3DRender/private/levelofdetail_p.h>
#include <Qt3DRender/private/material_p.h>
#include <Qt3DRender/private/shader_p.h>
+#include <Qt3DRender/private/shaderbuilder_p.h>
#include <Qt3DRender/private/texture_p.h>
#include <Qt3DRender/private/transform_p.h>
#include <Qt3DRender/private/rendertarget_p.h>
@@ -79,6 +80,9 @@
#include <Qt3DRender/private/light_p.h>
#include <Qt3DRender/private/environmentlight_p.h>
#include <Qt3DRender/private/computecommand_p.h>
+#include <Qt3DRender/private/armature_p.h>
+#include <Qt3DRender/private/skeleton_p.h>
+#include <Qt3DRender/private/joint_p.h>
QT_BEGIN_NAMESPACE
@@ -211,6 +215,16 @@ public:
ShaderManager() {}
};
+class ShaderBuilderManager : public Qt3DCore::QResourceManager<
+ ShaderBuilder,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ ShaderBuilderManager() {}
+};
+
class TextureManager : public Qt3DCore::QResourceManager<
Texture,
Qt3DCore::QNodeId,
@@ -385,6 +399,48 @@ class RenderStateManager : public Qt3DCore::QResourceManager<
{
};
+class ArmatureManager : public Qt3DCore::QResourceManager<
+ Armature,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+};
+
+class SkeletonManager : public Qt3DCore::QResourceManager<
+ Skeleton,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ enum DirtyFlag {
+ SkeletonDataDirty,
+ SkeletonTransformsDirty
+ };
+
+ void addDirtySkeleton(DirtyFlag dirtyFlag, HSkeleton skeletonHandle);
+ QVector<HSkeleton> dirtySkeletons(DirtyFlag dirtyFlag);
+
+private:
+ QVector<HSkeleton> m_dirtyDataSkeletons;
+ QVector<HSkeleton> m_dirtyTransformSkeletons;
+};
+
+class JointManager : public Qt3DCore::QResourceManager<
+ Joint,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ void addDirtyJoint(Qt3DCore::QNodeId jointId);
+ QVector<HJoint> dirtyJoints();
+
+private:
+ QVector<HJoint> m_dirtyJoints;
+};
+
} // namespace Render
} // namespace Qt3DRender
@@ -406,6 +462,9 @@ 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)
Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::OpenGLVertexArrayObject, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Armature, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Skeleton, Q_REQUIRES_CLEANUP)
+Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::Joint, Q_REQUIRES_CLEANUP)
QT_END_NAMESPACE
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index 80d0562b0..f5de64dae 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -46,6 +46,8 @@
#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
+#include <Qt3DRender/private/armature_p.h>
+#include <Qt3DRender/private/skeleton_p.h>
#include <private/resourceaccessor_p.h>
#include <QOpenGLVertexArrayObject>
@@ -63,6 +65,7 @@ NodeManagers::NodeManagers()
, m_worldMatrixManager(new MatrixManager())
, m_vaoManager(new VAOManager())
, m_shaderManager(new ShaderManager())
+ , m_shaderBuilderManager(new ShaderBuilderManager())
, m_techniqueManager(new TechniqueManager())
, m_effectManager(new EffectManager())
, m_renderPassManager(new RenderPassManager())
@@ -92,6 +95,9 @@ NodeManagers::NodeManagers()
, m_environmentLightManager(new EnvironmentLightManager())
, m_computeJobManager(new ComputeCommandManager())
, m_renderStateManager(new RenderStateManager())
+ , m_armatureManager(new ArmatureManager())
+ , m_skeletonManager(new SkeletonManager())
+ , m_jointManager(new JointManager())
, m_resourceAccessor(new ResourceAccessor(this))
{
}
@@ -103,6 +109,7 @@ NodeManagers::~NodeManagers()
delete m_worldMatrixManager;
delete m_vaoManager;
delete m_shaderManager;
+ delete m_shaderBuilderManager;
delete m_techniqueManager;
delete m_effectManager;
delete m_renderPassManager;
@@ -136,6 +143,9 @@ NodeManagers::~NodeManagers()
delete m_computeJobManager;
delete m_renderStateManager;
delete m_renderNodesManager;
+ delete m_armatureManager;
+ delete m_skeletonManager;
+ delete m_jointManager;
}
QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor()
@@ -180,6 +190,12 @@ ShaderManager *NodeManagers::manager<Shader>() const Q_DECL_NOTHROW
}
template<>
+ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const Q_DECL_NOTHROW
+{
+ return m_shaderBuilderManager;
+}
+
+template<>
TechniqueManager *NodeManagers::manager<Technique>() const Q_DECL_NOTHROW
{
return m_techniqueManager;
@@ -341,6 +357,24 @@ RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOTHRO
return m_renderStateManager;
}
+template<>
+ArmatureManager *NodeManagers::manager<Armature>() const Q_DECL_NOTHROW
+{
+ return m_armatureManager;
+}
+
+template<>
+SkeletonManager *NodeManagers::manager<Skeleton>() const Q_DECL_NOTHROW
+{
+ return m_skeletonManager;
+}
+
+template<>
+JointManager *NodeManagers::manager<Joint>() const Q_DECL_NOTHROW
+{
+ return m_jointManager;
+}
+
} // Render
} // Qt3DRender
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index 9e913eec4..6052c82d0 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -76,6 +76,7 @@ class MaterialManager;
class MatrixManager;
class VAOManager;
class ShaderManager;
+class ShaderBuilderManager;
class TechniqueManager;
class EffectManager;
class RenderPassManager;
@@ -99,12 +100,16 @@ class LightManager;
class EnvironmentLightManager;
class ComputeCommandManager;
class RenderStateManager;
+class ArmatureManager;
+class SkeletonManager;
+class JointManager;
class FrameGraphNode;
class Entity;
class CameraLens;
class Material;
class Shader;
+class ShaderBuilder;
class Technique;
class Effect;
class RenderPass;
@@ -131,6 +136,9 @@ class Light;
class EnvironmentLight;
class ComputeCommand;
class RenderStateNode;
+class Armature;
+class Skeleton;
+class Joint;
class OpenGLVertexArrayObject;
class ResourceAccessor;
@@ -181,6 +189,7 @@ public:
inline MatrixManager *worldMatrixManager() const Q_DECL_NOEXCEPT { return m_worldMatrixManager; }
inline VAOManager *vaoManager() const Q_DECL_NOEXCEPT { return m_vaoManager; }
inline ShaderManager *shaderManager() const Q_DECL_NOEXCEPT { return m_shaderManager; }
+ inline ShaderBuilderManager *shaderBuilderManager() const Q_DECL_NOEXCEPT { return m_shaderBuilderManager; }
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; }
@@ -210,6 +219,9 @@ public:
inline EnvironmentLightManager *environmentLightManager() const Q_DECL_NOEXCEPT { return m_environmentLightManager; }
inline ComputeCommandManager *computeJobManager() const Q_DECL_NOEXCEPT { return m_computeJobManager; }
inline RenderStateManager *renderStateManager() const Q_DECL_NOEXCEPT { return m_renderStateManager; }
+ inline ArmatureManager *armatureManager() const Q_DECL_NOEXCEPT { return m_armatureManager; }
+ inline SkeletonManager *skeletonManager() const Q_DECL_NOEXCEPT { return m_skeletonManager; }
+ inline JointManager *jointManager() const Q_DECL_NOEXCEPT { return m_jointManager; }
QSharedPointer<ResourceAccessor> resourceAccessor();
@@ -220,6 +232,7 @@ private:
MatrixManager *m_worldMatrixManager;
VAOManager *m_vaoManager;
ShaderManager *m_shaderManager;
+ ShaderBuilderManager *m_shaderBuilderManager;
TechniqueManager *m_techniqueManager;
EffectManager *m_effectManager;
RenderPassManager *m_renderPassManager;
@@ -249,6 +262,9 @@ private:
EnvironmentLightManager *m_environmentLightManager;
ComputeCommandManager *m_computeJobManager;
RenderStateManager *m_renderStateManager;
+ ArmatureManager *m_armatureManager;
+ SkeletonManager *m_skeletonManager;
+ JointManager *m_jointManager;
QSharedPointer<ResourceAccessor> m_resourceAccessor;
};
@@ -274,6 +290,9 @@ template<>
QT3DRENDERSHARED_PRIVATE_EXPORT ShaderManager *NodeManagers::manager<Shader>() const Q_DECL_NOEXCEPT;
template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT ShaderBuilderManager *NodeManagers::manager<ShaderBuilder>() const Q_DECL_NOEXCEPT;
+
+template<>
QT3DRENDERSHARED_PRIVATE_EXPORT TechniqueManager *NodeManagers::manager<Technique>() const Q_DECL_NOEXCEPT;
template<>
@@ -354,6 +373,15 @@ QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<Com
template<>
QT3DRENDERSHARED_PRIVATE_EXPORT RenderStateManager *NodeManagers::manager<RenderStateNode>() const Q_DECL_NOEXCEPT;
+template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT ArmatureManager *NodeManagers::manager<Armature>() const Q_DECL_NOEXCEPT;
+
+template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT SkeletonManager *NodeManagers::manager<Skeleton>() const Q_DECL_NOEXCEPT;
+
+template<>
+QT3DRENDERSHARED_PRIVATE_EXPORT JointManager *NodeManagers::manager<Joint>() const Q_DECL_NOEXCEPT;
+
} // Render
} // Qt3DRender
diff --git a/src/render/backend/pointsvisitor.cpp b/src/render/backend/pointsvisitor.cpp
new file mode 100644
index 000000000..663488357
--- /dev/null
+++ b/src/render/backend/pointsvisitor.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "pointsvisitor_p.h"
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/visitorutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace {
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseCoordinatesIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ PointsVisitor *visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx;
+ QVector3D abc;
+ while (i < indexInfo.count) {
+ ndx = indices[i];
+ const uint idx = ndx * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[j] = vertices[idx + j];
+ }
+ visitor->visit(ndx, abc);
+ ++i;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseCoordinates(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ PointsVisitor *visitor)
+{
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx = 0;
+ QVector3D abc;
+ while (ndx < vertexInfo.count) {
+ const uint idx = ndx * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[j] = vertices[idx + j];
+ visitor->visit(ndx, abc);
+ ++ndx;
+ }
+}
+
+template<typename Index, typename Visitor>
+struct IndexedVertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
+ {
+ traverseCoordinatesIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
+ }
+
+ BufferInfo m_indexBufferInfo;
+ Index *m_indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct IndexExecutor
+{
+ template<typename Index>
+ void operator ()( const BufferInfo &indexInfo, Index *indices)
+ {
+ IndexedVertexExecutor<Index, Visitor> exec;
+ exec.m_primitiveType = m_primitiveType;
+ exec.m_indices = indices;
+ exec.m_indexBufferInfo = indexInfo;
+ exec.m_visitor = m_visitor;
+ Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
+ }
+
+ BufferInfo m_vertexBufferInfo;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct VertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
+ {
+ switch (m_primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Points:
+ traverseCoordinates(vertices, vertexInfo, m_visitor);
+ return;
+ default:
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+} // anonymous
+
+
+PointsVisitor::~PointsVisitor()
+{
+
+}
+
+void PointsVisitor::apply(const Qt3DCore::QEntity *entity)
+{
+ GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(entity->id());
+ apply(renderer, entity->id());
+}
+
+void PointsVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
+{
+ m_nodeId = id;
+ if (renderer && renderer->instanceCount() == 1) {
+ Visitor::visitPrimitives<VertexExecutor<PointsVisitor>,
+ IndexExecutor<PointsVisitor>, PointsVisitor>(m_manager, renderer, this);
+ }
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/pointsvisitor_p.h b/src/render/backend/pointsvisitor_p.h
new file mode 100644
index 000000000..9d44ffec5
--- /dev/null
+++ b/src/render/backend/pointsvisitor_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_COORDINATESVISITOR_P_H
+#define QT3DRENDER_RENDER_COORDINATESVISITOR_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/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+
+class Q_AUTOTEST_EXPORT PointsVisitor
+{
+public:
+ explicit PointsVisitor(NodeManagers *manager) : m_manager(manager) { }
+ virtual ~PointsVisitor();
+
+ void apply(const Qt3DCore::QEntity *entity);
+ void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
+
+ virtual void visit(uint ndx, const QVector3D &c) = 0;
+
+protected:
+ NodeManagers *m_manager;
+ Qt3DCore::QNodeId m_nodeId;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_COORDINATESVISITOR_P_H
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 5d515a173..f7f30b5c9 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -41,7 +41,11 @@ HEADERS += \
$$PWD/frameprofiler_p.h \
$$PWD/offscreensurfacehelper_p.h \
$$PWD/resourceaccessor_p.h \
- $$PWD/commandthread_p.h
+ $$PWD/commandthread_p.h \
+ $$PWD/visitorutils_p.h \
+ $$PWD/segmentsvisitor_p.h \
+ $$PWD/pointsvisitor_p.h \
+ $$PWD/renderercache_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -76,12 +80,13 @@ SOURCES += \
$$PWD/renderviewbuilder.cpp \
$$PWD/offscreensurfacehelper.cpp \
$$PWD/resourceaccessor.cpp \
- $$PWD/commandthread.cpp
+ $$PWD/segmentsvisitor.cpp \
+ $$PWD/commandthread.cpp \
+ $$PWD/pointsvisitor.cpp
-include($$OUT_PWD/../core/qt3dcore-config.pri)
+include($$QT3D_BUILD_ROOT/src/core/qt3dcore-config.pri)
QT_FOR_CONFIG += 3dcore-private
qtConfig(qt3d-profile-jobs): {
HEADERS += $$PWD/commandexecuter_p.h
SOURCES += $$PWD/commandexecuter.cpp
}
-
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 19cc97dc5..7830faaa9 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -64,10 +64,12 @@
#include <Qt3DRender/private/renderqueue_p.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/glbuffer_p.h>
#include <Qt3DRender/private/renderstateset_p.h>
#include <Qt3DRender/private/technique_p.h>
#include <Qt3DRender/private/renderthread_p.h>
#include <Qt3DRender/private/renderview_p.h>
+#include <Qt3DRender/private/scenemanager_p.h>
#include <Qt3DRender/private/techniquefilternode_p.h>
#include <Qt3DRender/private/viewportnode_p.h>
#include <Qt3DRender/private/vsyncframeadvanceservice_p.h>
@@ -89,12 +91,11 @@
#include <Qt3DRender/private/renderviewbuilder_p.h>
#include <Qt3DRender/qcameralens.h>
-#include <Qt3DCore/qt3dcore-config.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
#include <Qt3DCore/private/qabstractaspectjobmanager_p.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
-#if defined(QT3D_JOBS_RUN_STATS)
+#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
#endif
@@ -115,7 +116,7 @@
#include <QThread>
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
#include <Qt3DCore/private/qthreadpooler_p.h>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/commandexecuter_p.h>
@@ -177,6 +178,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
, m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create())
+ , m_updateSkinningPaletteJob(Render::UpdateSkinningPaletteJobPtr::create())
, m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create())
, m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
, m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
@@ -187,7 +189,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
, m_ownedContext(false)
, m_offscreenHelper(nullptr)
- #ifdef QT3D_JOBS_RUN_STATS
+ #if QT_CONFIG(qt3d_profile_jobs)
, m_commandExecuter(new Qt3DRender::Debug::CommandExecuter(this))
#endif
{
@@ -209,6 +211,9 @@ Renderer::Renderer(QRenderAspect::RenderType type)
// m_syncTextureLoadingJob will depend on the texture loading jobs
m_textureGathererJob->addDependency(m_syncTextureLoadingJob);
+ // Ensures all skeletons are loaded before we try to update them
+ m_updateSkinningPaletteJob->addDependency(m_syncTextureLoadingJob);
+
// All world stuff depends on the RenderEntity's localBoundingVolume
m_updateLevelOfDetailJob->addDependency(m_updateMeshTriangleListJob);
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
@@ -275,10 +280,18 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_sendRenderCaptureJob->setManagers(m_nodesManager);
m_sendBufferCaptureJob->setManagers(m_nodesManager);
m_updateLevelOfDetailJob->setManagers(m_nodesManager);
+ m_updateSkinningPaletteJob->setManagers(m_nodesManager);
m_updateMeshTriangleListJob->setManagers(m_nodesManager);
m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager());
}
+void Renderer::setServices(QServiceLocator *services)
+{
+ m_services = services;
+
+ m_nodesManager->sceneManager()->setDownloadService(m_services->downloadHelperService());
+}
+
NodeManagers *Renderer::nodeManagers() const
{
return m_nodesManager;
@@ -497,7 +510,11 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
m_cleanupJob->setRoot(m_renderSceneRoot);
m_pickBoundingVolumeJob->setRoot(m_renderSceneRoot);
m_updateLevelOfDetailJob->setRoot(m_renderSceneRoot);
+ m_updateSkinningPaletteJob->setRoot(m_renderSceneRoot);
m_updateTreeEnabledJob->setRoot(m_renderSceneRoot);
+
+ // Set all flags to dirty
+ m_changeSet |= AbstractRenderer::AllDirty;
}
void Renderer::registerEventFilter(QEventFilterService *service)
@@ -548,7 +565,7 @@ void Renderer::doRender()
const bool canSubmit = isReadyToSubmit();
// Lock the mutex to protect access to the renderQueue while we look for its state
- QMutexLocker locker(&m_renderQueueMutex);
+ QMutexLocker locker(m_renderQueue->mutex());
const bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
@@ -563,7 +580,7 @@ void Renderer::doRender()
if (canSubmit && (queueIsComplete && !queueIsEmpty)) {
const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue();
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
// Save start of frame
JobRunStats submissionStatsPart1;
JobRunStats submissionStatsPart2;
@@ -575,14 +592,8 @@ void Renderer::doRender()
submissionStatsPart2.jobId.typeAndInstance[1] = 0;
submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
#endif
- if (canRender()) {
- // Clear all dirty flags but Compute so that
- // we still render every frame when a compute shader is used in a scene
- BackendNodeDirtySet changesToUnset = m_changeSet;
- if (changesToUnset.testFlag(Renderer::ComputeDirty))
- changesToUnset.setFlag(Renderer::ComputeDirty, false);
- clearDirtyBits(changesToUnset);
+ if (canRender()) {
{ // Scoped to destroy surfaceLock
QSurface *surface = nullptr;
for (const Render::RenderView *rv: renderViews) {
@@ -613,7 +624,7 @@ void Renderer::doRender()
m_vsyncFrameAdvanceService->proceedToNextFrame();
hasCleanedQueueAndProceeded = true;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
if (preprocessingComplete) {
submissionStatsPart2.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
submissionStatsPart1.endTime = submissionStatsPart2.startTime;
@@ -631,7 +642,7 @@ void Renderer::doRender()
}
}
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
// Execute the pending shell commands
m_commandExecuter->performAsynchronousCommandExecution(renderViews);
#endif
@@ -640,7 +651,7 @@ void Renderer::doRender()
// that were used for their allocation
qDeleteAll(renderViews);
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
if (preprocessingComplete) {
// Save submission elapsed time
submissionStatsPart2.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed();
@@ -694,7 +705,7 @@ void Renderer::doRender()
// we allow the render thread to proceed
void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder)
{
- QMutexLocker locker(&m_renderQueueMutex); // Prevent out of order execution
+ QMutexLocker locker(m_renderQueue->mutex()); // Prevent out of order execution
// We cannot use a lock free primitive here because:
// - QVector is not thread safe
// - Even if the insert is made correctly, the isFrameComplete call
@@ -712,8 +723,7 @@ void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder
bool Renderer::canRender() const
{
- // Make sure that we've not been told to terminate whilst waiting on
- // the above wait condition
+ // Make sure that we've not been told to terminate
if (m_renderThread && !m_running.load()) {
qCDebug(Rendering) << "RenderThread termination requested whilst waiting";
return false;
@@ -749,7 +759,7 @@ bool Renderer::isReadyToSubmit()
// Main thread
QVariant Renderer::executeCommand(const QStringList &args)
{
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
return m_commandExecuter->executeCommand(args);
#else
Q_UNUSED(args);
@@ -878,7 +888,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
// Update the draw command with all the information required for the drawing
if (command->m_drawIndexed) {
command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType());
- command->m_indexAttributeByteOffset = indexAttribute->byteOffset();
+ command->m_indexAttributeByteOffset = indexAttribute->byteOffset() + rGeometryRenderer->indexBufferByteOffset();
}
// Note: we only care about the primitiveCount when using direct draw calls
@@ -991,6 +1001,7 @@ void Renderer::lookForDirtyShaders()
{
if (isRunning()) {
const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
+ const QVector<HShaderBuilder> activeBuilders = m_nodesManager->shaderBuilderManager()->activeHandles();
for (HTechnique techniqueHandle : activeTechniques) {
Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
// If api of the renderer matches the one from the technique
@@ -1000,6 +1011,55 @@ void Renderer::lookForDirtyShaders()
RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+
+ ShaderBuilder *shaderBuilder = nullptr;
+ for (HShaderBuilder builderHandle : activeBuilders) {
+ ShaderBuilder *builder = m_nodesManager->shaderBuilderManager()->data(builderHandle);
+ if (builder->shaderProgramId() == shader->peerId()) {
+ shaderBuilder = builder;
+ break;
+ }
+ }
+
+ if (shaderBuilder) {
+ shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
+
+ for (int i = 0; i <= ShaderBuilder::Compute; i++) {
+ const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
+ if (!shaderBuilder->shaderGraph(builderType).isValid())
+ continue;
+
+ if (shaderBuilder->isShaderCodeDirty(builderType)) {
+ shaderBuilder->generateCode(builderType);
+ }
+
+ QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
+ switch (builderType) {
+ case ShaderBuilder::Vertex:
+ shaderType = QShaderProgram::Vertex;
+ break;
+ case ShaderBuilder::TessellationControl:
+ shaderType = QShaderProgram::TessellationControl;
+ break;
+ case ShaderBuilder::TessellationEvaluation:
+ shaderType = QShaderProgram::TessellationEvaluation;
+ break;
+ case ShaderBuilder::Geometry:
+ shaderType = QShaderProgram::Geometry;
+ break;
+ case ShaderBuilder::Fragment:
+ shaderType = QShaderProgram::Fragment;
+ break;
+ case ShaderBuilder::Compute:
+ shaderType = QShaderProgram::Compute;
+ break;
+ }
+
+ const auto code = shaderBuilder->shaderCode(builderType);
+ shader->setShaderCode(shaderType, code);
+ }
+ }
+
if (Q_UNLIKELY(shader->hasPendingNotifications()))
shader->submitPendingNotifications();
if (shader != nullptr && !shader->isLoaded())
@@ -1019,8 +1079,9 @@ void Renderer::updateGLResources()
for (HBuffer handle: dirtyBufferHandles) {
Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
// Forces creation if it doesn't exit
+ // Also note the binding point doesn't really matter here, we just upload data
if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
- m_graphicsContext->glBufferForRenderBuffer(buffer);
+ m_graphicsContext->glBufferForRenderBuffer(buffer, GLBuffer::ArrayBuffer);
// Update the glBuffer data
m_graphicsContext->updateBuffer(buffer);
buffer->unsetDirty();
@@ -1168,7 +1229,6 @@ void Renderer::downloadGLBuffers()
}
}
-
// 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)
@@ -1298,19 +1358,44 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
// of gc->currentContext() at the moment it was called (either
// renderViewStateSet or m_defaultRenderStateSet)
if (!renderView->renderCaptureNodeId().isNull()) {
+ const QRenderCaptureRequest request = renderView->renderCaptureRequest();
const QSize size = m_graphicsContext->renderTargetSize(renderView->surfaceSize() * renderView->devicePixelRatio());
- // Bind fbo as read framebuffer
- m_graphicsContext->bindFramebuffer(m_graphicsContext->activeFBO(), GraphicsHelperInterface::FBORead);
- const QImage image = m_graphicsContext->readFramebuffer(size);
+ QRect rect(QPoint(0, 0), size);
+ if (!request.rect.isEmpty())
+ rect = rect.intersected(request.rect);
+ QImage image;
+ if (!rect.isEmpty()) {
+ // Bind fbo as read framebuffer
+ m_graphicsContext->bindFramebuffer(m_graphicsContext->activeFBO(), GraphicsHelperInterface::FBORead);
+ image = m_graphicsContext->readFramebuffer(rect);
+ } else {
+ qWarning() << "Requested capture rectangle is outside framebuffer";
+ }
Render::RenderCapture *renderCapture =
static_cast<Render::RenderCapture*>(m_nodesManager->frameGraphManager()->lookupNode(renderView->renderCaptureNodeId()));
- renderCapture->addRenderCapture(image);
+ renderCapture->addRenderCapture(request.captureId, image);
addRenderCaptureSendRequest(renderView->renderCaptureNodeId());
}
if (renderView->isDownloadBuffersEnable())
downloadGLBuffers();
+ // Perform BlitFramebuffer operations
+ if (renderView->hasBlitFramebufferInfo()) {
+ const auto &blitFramebufferInfo = renderView->blitFrameBufferInfo();
+ const QNodeId inputTargetId = blitFramebufferInfo.sourceRenderTargetId;
+ const QNodeId outputTargetId = blitFramebufferInfo.destinationRenderTargetId;
+ const QRect inputRect = blitFramebufferInfo.sourceRect;
+ const QRect outputRect = blitFramebufferInfo.destinationRect;
+ const QRenderTargetOutput::AttachmentPoint inputAttachmentPoint = blitFramebufferInfo.sourceAttachmentPoint;
+ const QRenderTargetOutput::AttachmentPoint outputAttachmentPoint = blitFramebufferInfo.destinationAttachmentPoint;
+ const QBlitFramebuffer::InterpolationMethod interpolationMethod = blitFramebufferInfo.interpolationMethod;
+ m_graphicsContext->blitFramebuffer(inputTargetId, outputTargetId, inputRect, outputRect, lastBoundFBOId,
+ inputAttachmentPoint, outputAttachmentPoint,
+ interpolationMethod);
+ }
+
+
frameElapsed = timer.elapsed() - frameElapsed;
qCDebug(Rendering) << Q_FUNC_INFO << "Submitted Renderview " << i + 1 << "/" << renderViewsCount << "in " << frameElapsed << "ms";
frameElapsed = timer.elapsed();
@@ -1398,22 +1483,35 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_calculateBoundingVolumeJob->addDependency(bufferJob);
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
- // Set dependencies of resource gatherer
- for (const QAspectJobPtr &jobPtr : renderBinJobs) {
- jobPtr->addDependency(m_bufferGathererJob);
- jobPtr->addDependency(m_textureGathererJob);
- jobPtr->addDependency(m_shaderGathererJob);
- }
+
+ BackendNodeDirtySet changesToUnset = dirtyBits();
// Add jobs
- renderBinJobs.push_back(m_updateShaderDataTransformJob);
- renderBinJobs.push_back(m_updateMeshTriangleListJob);
- renderBinJobs.push_back(m_updateTreeEnabledJob);
+ const bool entitiesEnabledDirty = changesToUnset & AbstractRenderer::EntityEnabledDirty;
+ if (entitiesEnabledDirty) {
+ renderBinJobs.push_back(m_updateTreeEnabledJob);
+ m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
+ }
+
+ if (changesToUnset & AbstractRenderer::TransformDirty) {
+ renderBinJobs.push_back(m_worldTransformJob);
+ renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
+ renderBinJobs.push_back(m_updateShaderDataTransformJob);
+ }
+
+ if (changesToUnset & AbstractRenderer::GeometryDirty) {
+ renderBinJobs.push_back(m_calculateBoundingVolumeJob);
+ renderBinJobs.push_back(m_updateMeshTriangleListJob);
+ }
+
+ if (changesToUnset & AbstractRenderer::GeometryDirty ||
+ changesToUnset & AbstractRenderer::TransformDirty) {
+ renderBinJobs.push_back(m_expandBoundingVolumeJob);
+ }
+
+ m_updateSkinningPaletteJob->setDirtyJoints(m_nodesManager->jointManager()->dirtyJoints());
+ renderBinJobs.push_back(m_updateSkinningPaletteJob);
renderBinJobs.push_back(m_updateLevelOfDetailJob);
- 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_sendBufferCaptureJob);
@@ -1421,13 +1519,27 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
- renderBinJobs.push_back(m_syncTextureLoadingJob);
renderBinJobs.push_back(m_vaoGathererJob);
- renderBinJobs.push_back(m_bufferGathererJob);
- renderBinJobs.push_back(m_textureGathererJob);
- renderBinJobs.push_back(m_shaderGathererJob);
- QMutexLocker lock(&m_renderQueueMutex);
+ if (changesToUnset & AbstractRenderer::BuffersDirty)
+ renderBinJobs.push_back(m_bufferGathererJob);
+
+ if (changesToUnset & AbstractRenderer::ShadersDirty)
+ renderBinJobs.push_back(m_shaderGathererJob);
+
+ if (changesToUnset & AbstractRenderer::TexturesDirty) {
+ renderBinJobs.push_back(m_syncTextureLoadingJob);
+ renderBinJobs.push_back(m_textureGathererJob);
+ }
+
+
+ // Layer cache is dependent on layers, layer filters and the enabled flag
+ // on entities
+ const bool layersDirty = changesToUnset & AbstractRenderer::LayersDirty;
+ const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty;
+ bool layersCacheRebuilt = false;
+
+ QMutexLocker lock(m_renderQueue->mutex());
if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case)
// Traverse the current framegraph. For each leaf node create a
// RenderView and set its configuration then create a job to
@@ -1437,16 +1549,42 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
+ // Remove leaf nodes that no longer exist from cache
+ const QList<FrameGraphNode *> keys = m_cache.leafNodeCache.keys();
+ for (FrameGraphNode *leafNode : keys) {
+ if (!fgLeaves.contains(leafNode))
+ m_cache.leafNodeCache.remove(leafNode);
+ }
+
const int fgBranchCount = fgLeaves.size();
for (int i = 0; i < fgBranchCount; ++i) {
RenderViewBuilder builder(fgLeaves.at(i), i, this);
+ builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt);
+ builder.prepareJobs();
renderBinJobs.append(builder.buildJobHierachy());
}
+ layersCacheRebuilt = true;
// Set target number of RenderViews
m_renderQueue->setTargetRenderViewCount(fgBranchCount);
}
+ // Only reset LayersDirty flag once we have really rebuilt the caches
+ if (layersDirty && !layersCacheRebuilt)
+ changesToUnset.setFlag(AbstractRenderer::LayersDirty, false);
+ if (entitiesEnabledDirty && !layersCacheRebuilt)
+ changesToUnset.setFlag(AbstractRenderer::EntityEnabledDirty, false);
+
+ // Clear dirty bits
+ // TO DO: When secondary GL thread is integrated, the following line can be removed
+ changesToUnset.setFlag(AbstractRenderer::ShadersDirty, false);
+
+ // Clear all dirty flags but Compute so that
+ // we still render every frame when a compute shader is used in a scene
+ if (changesToUnset.testFlag(Renderer::ComputeDirty))
+ changesToUnset.setFlag(Renderer::ComputeDirty, false);
+ clearDirtyBits(changesToUnset);
+
return renderBinJobs;
}
@@ -1469,6 +1607,11 @@ QAspectJobPtr Renderer::syncTextureLoadingJob()
return m_syncTextureLoadingJob;
}
+QAspectJobPtr Renderer::expandBoundingVolumeJob()
+{
+ return m_expandBoundingVolumeJob;
+}
+
QAbstractFrameAdvanceService *Renderer::frameAdvanceService() const
{
return static_cast<Qt3DCore::QAbstractFrameAdvanceService *>(m_vsyncFrameAdvanceService.data());
@@ -1488,7 +1631,7 @@ void Renderer::performDraw(RenderCommand *command)
}
// Get GLBuffer from Buffer;
- GLBuffer *indirectDrawGLBuffer = m_graphicsContext->glBufferForRenderBuffer(indirectDrawBuffer);
+ GLBuffer *indirectDrawGLBuffer = m_graphicsContext->glBufferForRenderBuffer(indirectDrawBuffer, GLBuffer::DrawIndirectBuffer);
if (Q_UNLIKELY(indirectDrawGLBuffer == nullptr)) {
qWarning() << "Invalid Indirect Draw Buffer - failed to retrieve GLBuffer";
return;
@@ -1723,16 +1866,16 @@ bool Renderer::updateVAOWithAttributes(Geometry *geometry,
if ((attributeWasDirty = attribute->isDirty()) == true || forceUpdate) {
// Find the location for the attribute
const QVector<ShaderAttribute> shaderAttributes = shader->attributes();
- int attributeLocation = -1;
+ const ShaderAttribute *attributeDescription = nullptr;
for (const ShaderAttribute &shaderAttribute : shaderAttributes) {
if (shaderAttribute.m_nameId == attribute->nameId()) {
- attributeLocation = shaderAttribute.m_location;
+ attributeDescription = &shaderAttribute;
break;
}
}
- if (attributeLocation < 0)
+ if (!attributeDescription || attributeDescription->m_location < 0)
return false;
- m_graphicsContext->specifyAttribute(attribute, buffer, attributeLocation);
+ m_graphicsContext->specifyAttribute(attribute, buffer, attributeDescription);
}
}
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index af10108e9..28e8711a8 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -75,6 +75,8 @@
#include <Qt3DRender/private/genericlambdajob_p.h>
#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
#include <Qt3DRender/private/filtercompatibletechniquejob_p.h>
+#include <Qt3DRender/private/updateskinningpalettejob_p.h>
+#include <Qt3DRender/private/renderercache_p.h>
#include <QHash>
#include <QMatrix4x4>
@@ -113,7 +115,7 @@ class QAbstractShapeMesh;
struct GraphicsApiFilterData;
class QSceneImporter;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
namespace Debug {
class CommandExecuter;
}
@@ -157,7 +159,7 @@ public:
void setTime(qint64 time) Q_DECL_OVERRIDE;
void setNodeManagers(NodeManagers *managers) Q_DECL_OVERRIDE;
- void setServices(Qt3DCore::QServiceLocator *services) Q_DECL_OVERRIDE { m_services = services; }
+ void setServices(Qt3DCore::QServiceLocator *services) Q_DECL_OVERRIDE;
void setSurfaceExposed(bool exposed) Q_DECL_OVERRIDE;
NodeManagers *nodeManagers() const Q_DECL_OVERRIDE;
@@ -189,11 +191,11 @@ public:
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE;
Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE;
+ Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() Q_DECL_OVERRIDE;
QVector<Qt3DCore::QAspectJobPtr> createRenderBufferJobs() const;
inline FrameCleanupJobPtr frameCleanupJob() const { return m_cleanupJob; }
- inline ExpandBoundingVolumeJobPtr expandBoundingVolumeJob() const { return m_expandBoundingVolumeJob; }
inline UpdateShaderDataTransformJobPtr updateShaderDataTransformJob() const { return m_updateShaderDataTransformJob; }
inline CalculateBoundingVolumeJobPtr calculateBoundingVolumeJob() const { return m_calculateBoundingVolumeJob; }
inline UpdateTreeEnabledJobPtr updateTreeEnabledJob() const { return m_updateTreeEnabledJob; }
@@ -203,6 +205,7 @@ public:
inline UpdateMeshTriangleListJobPtr updateMeshTriangleListJob() const { return m_updateMeshTriangleListJob; }
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
+ inline UpdateSkinningPaletteJobPtr updateSkinningPaletteJob() const { return m_updateSkinningPaletteJob; }
Qt3DCore::QAbstractFrameAdvanceService *frameAdvanceService() const Q_DECL_OVERRIDE;
@@ -216,6 +219,11 @@ public:
void updateTexture(Texture *texture);
void cleanupTexture(const Texture *texture);
void downloadGLBuffers();
+ void blitFramebuffer(Qt3DCore::QNodeId inputRenderTargetId,
+ Qt3DCore::QNodeId outputRenderTargetId,
+ QRect inputRect,
+ QRect outputRect,
+ GLuint defaultFramebuffer);
void prepareCommandsSubmission(const QVector<RenderView *> &renderViews);
bool executeCommandsSubmission(const RenderView *rv);
@@ -259,8 +267,7 @@ public:
ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews);
- QMutex* mutex() { return &m_renderQueueMutex; }
-
+ RendererCache *cache() { return &m_cache; }
#ifdef QT3D_RENDER_UNIT_TESTS
public:
@@ -290,7 +297,6 @@ private:
QScopedPointer<RenderThread> m_renderThread;
QScopedPointer<VSyncFrameAdvanceService> m_vsyncFrameAdvanceService;
- QMutex m_renderQueueMutex;
QSemaphore m_submitRenderViewsSemaphore;
QSemaphore m_waitForInitializationToBeCompleted;
@@ -320,6 +326,7 @@ private:
UpdateTreeEnabledJobPtr m_updateTreeEnabledJob;
SendRenderCaptureJobPtr m_sendRenderCaptureJob;
SendBufferCaptureJobPtr m_sendBufferCaptureJob;
+ UpdateSkinningPaletteJobPtr m_updateSkinningPaletteJob;
UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob;
UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
@@ -358,12 +365,13 @@ private:
OffscreenSurfaceHelper *m_offscreenHelper;
QMutex m_offscreenSurfaceMutex;
-#ifdef QT3D_JOBS_RUN_STATS
+#if QT_CONFIG(qt3d_profile_jobs)
QScopedPointer<Qt3DRender::Debug::CommandExecuter> m_commandExecuter;
friend class Qt3DRender::Debug::CommandExecuter;
#endif
QMetaObject::Connection m_contextConnection;
+ RendererCache m_cache;
};
} // namespace Render
diff --git a/src/render/backend/renderercache_p.h b/src/render/backend/renderercache_p.h
new file mode 100644
index 000000000..f14b965ee
--- /dev/null
+++ b/src/render/backend/renderercache_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_RENDERERCACHE_P_H
+#define QT3DRENDER_RENDER_RENDERERCACHE_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 <Qt3DRender/QFrameGraphNode>
+
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/renderviewjobutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+struct RendererCache
+{
+ struct LeafNodeData
+ {
+ QVector<Entity *> filterEntitiesByLayer;
+ };
+
+ QHash<FrameGraphNode *, LeafNodeData> leafNodeCache;
+
+ QMutex *mutex() { return &m_mutex; }
+
+private:
+ QMutex m_mutex;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RENDERERCACHE_P_H
diff --git a/src/render/backend/renderqueue_p.h b/src/render/backend/renderqueue_p.h
index 611f5849a..e565115f2 100644
--- a/src/render/backend/renderqueue_p.h
+++ b/src/render/backend/renderqueue_p.h
@@ -53,6 +53,7 @@
#include <QVector>
#include <QtGlobal>
+#include <QMutex>
QT_BEGIN_NAMESPACE
@@ -81,12 +82,15 @@ public:
inline bool wasReset() const { return m_wasReset; }
+ inline QMutex *mutex() { return &m_mutex; }
+
private:
bool m_noRender;
bool m_wasReset;
int m_targetRenderViewCount;
int m_currentRenderViewCount;
QVector<RenderView *> m_currentWorkQueue;
+ QMutex m_mutex;
};
} // namespace Render
diff --git a/src/render/backend/rendersettings.cpp b/src/render/backend/rendersettings.cpp
index 2cd2b1d07..397d297e9 100644
--- a/src/render/backend/rendersettings.cpp
+++ b/src/render/backend/rendersettings.cpp
@@ -57,6 +57,7 @@ RenderSettings::RenderSettings()
, m_pickMethod(QPickingSettings::BoundingVolumePicking)
, m_pickResultMode(QPickingSettings::NearestPick)
, m_faceOrientationPickingMode(QPickingSettings::FrontFace)
+ , m_pickWorldSpaceTolerance(.1f)
, m_activeFrameGraph()
{
}
@@ -69,6 +70,7 @@ void RenderSettings::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt
m_renderPolicy = data.renderPolicy;
m_pickMethod = data.pickMethod;
m_pickResultMode = data.pickResultMode;
+ m_pickWorldSpaceTolerance = data.pickWorldSpaceTolerance;
m_faceOrientationPickingMode = data.faceOrientationPickingMode;
}
@@ -82,6 +84,8 @@ void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_pickResultMode = propertyChange->value().value<QPickingSettings::PickResultMode>();
else if (propertyChange->propertyName() == QByteArrayLiteral("faceOrientationPickingMode"))
m_faceOrientationPickingMode = propertyChange->value().value<QPickingSettings::FaceOrientationPickingMode>();
+ else if (propertyChange->propertyName() == QByteArrayLiteral("pickWorldSpaceTolerance"))
+ m_pickWorldSpaceTolerance = propertyChange->value().toFloat();
else if (propertyChange->propertyName() == QByteArrayLiteral("activeFrameGraph"))
m_activeFrameGraph = propertyChange->value().value<QNodeId>();
else if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy"))
diff --git a/src/render/backend/rendersettings_p.h b/src/render/backend/rendersettings_p.h
index 37771c40b..960edee29 100644
--- a/src/render/backend/rendersettings_p.h
+++ b/src/render/backend/rendersettings_p.h
@@ -74,6 +74,10 @@ public:
QPickingSettings::PickMethod pickMethod() const { return m_pickMethod; }
QPickingSettings::PickResultMode pickResultMode() const { return m_pickResultMode; }
QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode() const { return m_faceOrientationPickingMode; }
+ float pickWorldSpaceTolerance() const { return m_pickWorldSpaceTolerance; }
+
+ // For unit test purposes
+ void setActiveFrameGraphId(Qt3DCore::QNodeId frameGraphNodeId) { m_activeFrameGraph = frameGraphNodeId; }
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -82,6 +86,7 @@ private:
QPickingSettings::PickMethod m_pickMethod;
QPickingSettings::PickResultMode m_pickResultMode;
QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode;
+ float m_pickWorldSpaceTolerance;
Qt3DCore::QNodeId m_activeFrameGraph;
};
diff --git a/src/render/backend/renderthread.cpp b/src/render/backend/renderthread.cpp
index 03cbb7a5f..6b95ed396 100644
--- a/src/render/backend/renderthread.cpp
+++ b/src/render/backend/renderthread.cpp
@@ -75,23 +75,12 @@ void RenderThread::waitForStart( Priority priority )
// RenderThread context
void RenderThread::run()
{
- // We lock the renderer's mutex here before returning control to the calling
- // thread (the Aspect Thread). This is
- // to ensure that the Renderer's initialize() waitCondition is reached before
- // other threads try to wake it up. This is guaranteed by having the
- // Renderer::setSurface() function try to lock the renderer's mutex too.
- // That function will block until the mutex is unlocked by the wait condition
- // in the initialize() call below.
- QMutexLocker locker(m_renderer->mutex());
-
- // Now we have ensured we will reach the wait condition as described above,
// return control to the aspect thread that created us.
m_semaphore.release();
// This call to Renderer::initialize() waits for a surface to be set on the
// renderer in the context of the Aspect Thread
m_renderer->initialize();
- locker.unlock();
// Enter the main OpenGL submission loop.
m_renderer->render();
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 7adf7c5d2..dbb6ead21 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -129,10 +129,12 @@ RenderView::StandardUniformsNameToTypeHash RenderView::initializeStandardUniform
setters.insert(StringToInt::lookupId(QLatin1String("modelViewNormal")), ModelViewNormalMatrix);
setters.insert(StringToInt::lookupId(QLatin1String("viewportMatrix")), ViewportMatrix);
setters.insert(StringToInt::lookupId(QLatin1String("inverseViewportMatrix")), InverseViewportMatrix);
+ setters.insert(StringToInt::lookupId(QLatin1String("aspectRatio")), AspectRatio);
setters.insert(StringToInt::lookupId(QLatin1String("exposure")), Exposure);
setters.insert(StringToInt::lookupId(QLatin1String("gamma")), Gamma);
setters.insert(StringToInt::lookupId(QLatin1String("time")), Time);
setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition);
+ setters.insert(StringToInt::lookupId(QLatin1String("skinningPalette[0]")), SkinningPalette);
return setters;
}
@@ -153,7 +155,9 @@ static QMatrix4x4 getProjectionMatrix(const CameraLens *lens)
return lens ? lens->projection() : QMatrix4x4();
}
-UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standardUniformType, const QMatrix4x4 &model) const
+UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standardUniformType,
+ Entity *entity,
+ const QMatrix4x4 &model) const
{
switch (standardUniformType) {
case ModelMatrix:
@@ -197,6 +201,8 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize));
return UniformValue(viewportMatrix.inverted());
}
+ case AspectRatio:
+ return float(m_surfaceSize.width()) / float(m_surfaceSize.height());
case Exposure:
return UniformValue(m_data.m_renderCameraLens ? m_data.m_renderCameraLens->exposure() : 0.0f);
case Gamma:
@@ -205,6 +211,14 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
return UniformValue(float(m_renderer->time() / 1000000000.0f));
case EyePosition:
return UniformValue(m_data.m_eyePos);
+ case SkinningPalette: {
+ const Armature *armature = entity->renderComponent<Armature>();
+ if (!armature) {
+ qCWarning(Jobs, "Requesting skinningPalette uniform but no armature set on entity");
+ return UniformValue();
+ }
+ return armature->skinningPaletteUniform();
+ }
default:
Q_UNREACHABLE();
return UniformValue();
@@ -213,6 +227,7 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
RenderView::RenderView()
: m_isDownloadBuffersEnable(false)
+ , m_hasBlitFramebufferInfo(false)
, m_renderer(nullptr)
, m_devicePixelRatio(1.)
, m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f))
@@ -539,16 +554,16 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
QVector<RenderCommand *> commands;
commands.reserve(entities.size());
- for (Entity *node : entities) {
+ for (Entity *entity : entities) {
GeometryRenderer *geometryRenderer = nullptr;
- HGeometryRenderer geometryRendererHandle = node->componentHandle<GeometryRenderer, 16>();
+ HGeometryRenderer geometryRendererHandle = entity->componentHandle<GeometryRenderer, 16>();
// There is a geometry renderer with geometry
if ((geometryRenderer = m_manager->geometryRendererManager()->data(geometryRendererHandle)) != nullptr
&& geometryRenderer->isEnabled()
&& !geometryRenderer->geometryId().isNull()) {
- const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>();
- const HMaterial materialHandle = node->componentHandle<Material, 16>();
+ const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>();
+ const HMaterial materialHandle = entity->componentHandle<Material, 16>();
const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId);
HGeometry geometryHandle = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId());
Geometry *geometry = m_manager->data<Geometry, GeometryManager>(geometryHandle);
@@ -561,7 +576,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// Project the camera-to-object-center vector onto the camera
// view vector. This gives a depth value suitable as the key
// for BackToFront sorting.
- command->m_depth = QVector3D::dotProduct(node->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
+ command->m_depth = QVector3D::dotProduct(entity->worldBoundingVolume()->center() - m_data.m_eyePos, m_data.m_eyeViewDir);
command->m_geometry = geometryHandle;
command->m_geometryRenderer = geometryRendererHandle;
@@ -588,7 +603,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// Copy vector so that we can sort it concurrently and we only want to sort the one for the current command
QVector<LightSource> lightSources = m_lightSources;
if (lightSources.size() > 1)
- std::sort(lightSources.begin(), lightSources.end(), LightSourceCompare(node));
+ std::sort(lightSources.begin(), lightSources.end(), LightSourceCompare(entity));
ParameterInfoList globalParameters = passData.parameterInfo;
// setShaderAndUniforms can initialize a localData
@@ -596,7 +611,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
setShaderAndUniforms(command,
pass,
globalParameters,
- *(node->worldTransform()),
+ entity,
lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)),
m_environmentLight);
@@ -674,12 +689,12 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
// material/effect/technique/parameters/filters/
QVector<RenderCommand *> commands;
commands.reserve(entities.size());
- for (Entity *node : entities) {
+ for (Entity *entity : entities) {
ComputeCommand *computeJob = nullptr;
- if ((computeJob = node->renderComponent<ComputeCommand>()) != nullptr
+ if ((computeJob = entity->renderComponent<ComputeCommand>()) != nullptr
&& computeJob->isEnabled()) {
- const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>();
+ const Qt3DCore::QNodeId materialComponentId = entity->componentUuid<Material>();
const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId);
// 1 RenderCommand per RenderPass pass on an Entity with a Mesh
@@ -697,7 +712,7 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
setShaderAndUniforms(command,
pass,
globalParameters,
- *(node->worldTransform()),
+ entity,
QVector<LightSource>(),
nullptr);
commands.append(command);
@@ -750,9 +765,13 @@ void RenderView::setUniformValue(ShaderParameterPack &uniformPack, int nameId, c
}
}
-void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack, int glslNameId, int nameId, const QMatrix4x4 &worldTransform) const
+void RenderView::setStandardUniformValue(ShaderParameterPack &uniformPack,
+ int glslNameId,
+ int nameId,
+ Entity *entity,
+ const QMatrix4x4 &worldTransform) const
{
- uniformPack.setUniform(glslNameId, standardUniformValue(ms_standardUniformSetters[nameId], worldTransform));
+ uniformPack.setUniform(glslNameId, standardUniformValue(ms_standardUniformSetters[nameId], entity, worldTransform));
}
void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
@@ -887,8 +906,12 @@ void RenderView::prepareForSorting(RenderCommand *command) const
}
}
-void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const
+void RenderView::setShaderAndUniforms(RenderCommand *command,
+ RenderPass *rPass,
+ ParameterInfoList &parameters,
+ Entity *entity,
+ const QVector<LightSource> &activeLightSources,
+ EnvironmentLight *environmentLight) const
{
// The VAO Handle is set directly in the renderer thread so as to avoid having to use a mutex here
// Set shader, technique, and effect by basically doing :
@@ -931,9 +954,10 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
!shaderStorageBlockNamesIds.isEmpty() || !attributeNamesIds.isEmpty()) {
// Set default standard uniforms without bindings
+ QMatrix4x4 worldTransform = *(entity->worldTransform());
for (const int uniformNameId : uniformNamesIds) {
if (ms_standardUniformSetters.contains(uniformNameId))
- setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, worldTransform);
+ setStandardUniformValue(command->m_parameterPack, uniformNameId, uniformNameId, entity, worldTransform);
}
// Set default attributes
@@ -1039,6 +1063,26 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
}
}
+bool RenderView::hasBlitFramebufferInfo() const
+{
+ return m_hasBlitFramebufferInfo;
+}
+
+void RenderView::setHasBlitFramebufferInfo(bool hasBlitFramebufferInfo)
+{
+ m_hasBlitFramebufferInfo = hasBlitFramebufferInfo;
+}
+
+BlitFramebufferInfo RenderView::blitFrameBufferInfo() const
+{
+ return m_blitFrameBufferInfo;
+}
+
+void RenderView::setBlitFrameBufferInfo(const BlitFramebufferInfo &blitFrameBufferInfo)
+{
+ m_blitFrameBufferInfo = blitFrameBufferInfo;
+}
+
bool RenderView::isDownloadBuffersEnable() const
{
return m_isDownloadBuffersEnable;
diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h
index 295d820e6..21d25a528 100644
--- a/src/render/backend/renderview_p.h
+++ b/src/render/backend/renderview_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/qparameter.h>
#include <Qt3DRender/qclearbuffers.h>
+#include <Qt3DRender/qlayerfilter.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/clearbuffers_p.h>
#include <Qt3DRender/private/cameralens_p.h>
@@ -62,6 +63,8 @@
#include <Qt3DRender/private/qsortpolicy_p.h>
#include <Qt3DRender/private/lightsource_p.h>
#include <Qt3DRender/private/qmemorybarrier_p.h>
+#include <Qt3DRender/private/qrendercapture_p.h>
+#include <Qt3DRender/private/qblitframebuffer_p.h>
#include <Qt3DCore/private/qframeallocator_p.h>
@@ -113,6 +116,17 @@ struct Q_AUTOTEST_EXPORT ClearBufferInfo
QVector4D clearColor;
};
+struct Q_AUTOTEST_EXPORT BlitFramebufferInfo
+{
+ Qt3DCore::QNodeId sourceRenderTargetId;
+ Qt3DCore::QNodeId destinationRenderTargetId;
+ QRect sourceRect;
+ QRect destinationRect;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint;
+ QBlitFramebuffer::InterpolationMethod interpolationMethod;
+};
+
// This class is kind of analogous to RenderBin but I want to avoid trampling
// on that until we get this working
@@ -151,10 +165,11 @@ public:
inline void setEyeViewDirection(const QVector3D &dir) Q_DECL_NOTHROW { m_data.m_eyeViewDir = dir; }
inline QVector3D eyeViewDirection() const Q_DECL_NOTHROW { return m_data.m_eyeViewDir; }
- inline void setHasLayerFilter(bool filter) Q_DECL_NOTHROW { m_data.m_hasLayerFilter = filter; }
- inline bool hasLayerFilter() const Q_DECL_NOTHROW { return m_data.m_hasLayerFilter; }
- inline void appendLayerFilter(const Qt3DCore::QNodeIdVector &layerIds) Q_DECL_NOTHROW { m_data.m_layerIds << layerIds; }
- inline Qt3DCore::QNodeIdVector layerFilter() const Q_DECL_NOTHROW { return m_data.m_layerIds; }
+ inline void appendLayerFilter(const Qt3DCore::QNodeId layerFilterId) Q_DECL_NOTHROW { m_data.m_layerFilterIds.push_back(layerFilterId); }
+ inline Qt3DCore::QNodeIdVector layerFilters() const Q_DECL_NOTHROW { return m_data.m_layerFilterIds; }
+
+ inline void appendProximityFilterId(const Qt3DCore::QNodeId proximityFilterId) { m_data.m_proximityFilterIds.push_back(proximityFilterId); }
+ inline Qt3DCore::QNodeIdVector proximityFilterIds() const { return m_data.m_proximityFilterIds; }
inline void setRenderPassFilter(const RenderPassFilter *rpFilter) Q_DECL_NOTHROW { m_data.m_passFilter = rpFilter; }
inline const RenderPassFilter *renderPassFilter() const Q_DECL_NOTHROW { return m_data.m_passFilter; }
@@ -224,6 +239,8 @@ public:
inline void setRenderCaptureNodeId(const Qt3DCore::QNodeId nodeId) Q_DECL_NOTHROW { m_renderCaptureNodeId = nodeId; }
inline const Qt3DCore::QNodeId renderCaptureNodeId() const Q_DECL_NOTHROW { return m_renderCaptureNodeId; }
+ inline void setRenderCaptureRequest(const QRenderCaptureRequest& request) Q_DECL_NOTHROW { m_renderCaptureRequest = request; }
+ inline const QRenderCaptureRequest renderCaptureRequest() const Q_DECL_NOTHROW { return m_renderCaptureRequest; }
void setMemoryBarrier(QMemoryBarrier::Operations barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; }
QMemoryBarrier::Operations memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; }
@@ -237,7 +254,6 @@ public:
, m_renderCameraNode(nullptr)
, m_techniqueFilter(nullptr)
, m_passFilter(nullptr)
- , m_hasLayerFilter(false)
{
}
CameraLens *m_renderCameraLens;
@@ -246,25 +262,39 @@ public:
const RenderPassFilter *m_passFilter;
QMatrix4x4 m_viewMatrix;
QMatrix4x4 m_viewProjectionMatrix;
- bool m_hasLayerFilter;
- Qt3DCore::QNodeIdVector m_layerIds;
+ Qt3DCore::QNodeIdVector m_layerFilterIds;
QVector<Qt3DRender::QSortPolicy::SortType> m_sortingTypes;
QVector3D m_eyePos;
QVector3D m_eyeViewDir;
+ Qt3DCore::QNodeIdVector m_proximityFilterIds;
};
bool isDownloadBuffersEnable() const;
void setIsDownloadBuffersEnable(bool isDownloadBuffersEnable);
+ BlitFramebufferInfo blitFrameBufferInfo() const;
+ void setBlitFrameBufferInfo(const BlitFramebufferInfo &blitFrameBufferInfo);
+
+ bool hasBlitFramebufferInfo() const;
+ void setHasBlitFramebufferInfo(bool hasBlitFramebufferInfo);
+
private:
- void setShaderAndUniforms(RenderCommand *command, RenderPass *pass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const;
+ void setShaderAndUniforms(RenderCommand *command,
+ RenderPass *pass,
+ ParameterInfoList &parameters,
+ Entity *entity,
+ const QVector<LightSource> &activeLightSources,
+ EnvironmentLight *environmentLight) const;
mutable QThreadStorage<UniformBlockValueBuilder*> m_localData;
Qt3DCore::QNodeId m_renderCaptureNodeId;
+ QRenderCaptureRequest m_renderCaptureRequest;
bool m_isDownloadBuffersEnable;
+ bool m_hasBlitFramebufferInfo;
+ BlitFramebufferInfo m_blitFrameBufferInfo;
+
Renderer *m_renderer;
NodeManagers *m_manager;
QSize m_surfaceSize;
@@ -316,20 +346,28 @@ private:
ModelViewNormalMatrix,
ViewportMatrix,
InverseViewportMatrix,
+ AspectRatio,
Time,
Exposure,
Gamma,
- EyePosition
+ EyePosition,
+ SkinningPalette
};
typedef QHash<int, StandardUniform> StandardUniformsNameToTypeHash;
static StandardUniformsNameToTypeHash ms_standardUniformSetters;
static StandardUniformsNameToTypeHash initializeStandardUniformSetters();
- UniformValue standardUniformValue(StandardUniform standardUniformType, const QMatrix4x4 &model) const;
+ UniformValue standardUniformValue(StandardUniform standardUniformType,
+ Entity *entity,
+ const QMatrix4x4 &model) const;
void setUniformValue(ShaderParameterPack &uniformPack, int nameId, const UniformValue &value) const;
- void setStandardUniformValue(ShaderParameterPack &uniformPack, int glslNameId, int nameId, const QMatrix4x4 &worldTransform) const;
+ void setStandardUniformValue(ShaderParameterPack &uniformPack,
+ int glslNameId,
+ int nameId,
+ Entity *entity,
+ const QMatrix4x4 &worldTransform) const;
void setUniformBlockValue(ShaderParameterPack &uniformPack,
Shader *shader,
const ShaderUniformBlock &block,
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index f47c6f419..769eee29f 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -39,6 +39,8 @@
#include "renderviewbuilder_p.h"
+#include <QThread>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -121,11 +123,13 @@ public:
explicit SyncRenderViewInitialization(const RenderViewInitializerJobPtr &renderViewJob,
const FrustumCullingJobPtr &frustumCullingJob,
const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ const FilterProximityDistanceJobPtr &filterProximityJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
: m_renderViewJob(renderViewJob)
, m_frustumCullingJob(frustumCullingJob)
, m_filterEntityByLayerJob(filterEntityByLayerJob)
+ , m_filterProximityJob(filterProximityJob)
, m_materialGathererJobs(materialGathererJobs)
, m_renderViewBuilderJobs(renderViewBuilderJobs)
{}
@@ -135,8 +139,11 @@ public:
RenderView *rv = m_renderViewJob->renderView();
// Layer filtering
- m_filterEntityByLayerJob->setHasLayerFilter(rv->hasLayerFilter());
- m_filterEntityByLayerJob->setLayers(rv->layerFilter());
+ if (!m_filterEntityByLayerJob.isNull())
+ m_filterEntityByLayerJob->setLayerFilters(rv->layerFilters());
+
+ // Proximity filtering
+ m_filterProximityJob->setProximityFilterIds(rv->proximityFilterIds());
// Material Parameter building
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
@@ -156,6 +163,7 @@ private:
RenderViewInitializerJobPtr m_renderViewJob;
FrustumCullingJobPtr m_frustumCullingJob;
FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ FilterProximityDistanceJobPtr m_filterProximityJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
};
@@ -165,20 +173,24 @@ class SyncRenderCommandBuilding
public:
explicit SyncRenderCommandBuilding(const RenderViewInitializerJobPtr &renderViewJob,
const FrustumCullingJobPtr &frustumCullingJob,
- const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ const FilterProximityDistanceJobPtr &filterProximityJob,
const LightGathererPtr &lightGathererJob,
const RenderableEntityFilterPtr &renderableEntityFilterJob,
const ComputableEntityFilterPtr &computableEntityFilterJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs)
+ const QVector<RenderViewBuilderJobPtr> &renderViewBuilderJobs,
+ Renderer *renderer,
+ FrameGraphNode *leafNode)
: m_renderViewJob(renderViewJob)
, m_frustumCullingJob(frustumCullingJob)
- , m_filterEntityByLayerJob(filterEntityByLayerJob)
+ , m_filterProximityJob(filterProximityJob)
, m_lightGathererJob(lightGathererJob)
, m_renderableEntityFilterJob(renderableEntityFilterJob)
, m_computableEntityFilterJob(computableEntityFilterJob)
, m_materialGathererJobs(materialGathererJobs)
, m_renderViewBuilderJobs(renderViewBuilderJobs)
+ , m_renderer(renderer)
+ , m_leafNode(leafNode)
{}
void operator()()
@@ -202,8 +214,10 @@ public:
// Filter out entities that weren't selected by the layer filters
std::sort(renderableEntities.begin(), renderableEntities.end());
+ QMutexLocker lock(m_renderer->cache()->mutex());
+ const QVector<Entity *> filteredEntities = m_renderer->cache()->leafNodeCache.value(m_leafNode).filterEntitiesByLayer;
+ lock.unlock();
// Remove all entities from the compute and renderable vectors that aren't in the filtered layer vector
- QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities);
// Set the light sources, with layer filters applied.
@@ -214,9 +228,13 @@ public:
}
rv->setLightSources(lightSources);
- // Filter out frustum culled entity for drawable entities
- if (isDraw && rv->frustumCulling())
- RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
+ if (isDraw) {
+ // Filter out frustum culled entity for drawable entities
+ if (rv->frustumCulling())
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
+ // Filter out entities which didn't satisfy proximity filtering
+ RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_filterProximityJob->filteredEntities());
+ }
// Split among the number of command builders
int i = 0;
@@ -241,12 +259,14 @@ public:
private:
RenderViewInitializerJobPtr m_renderViewJob;
FrustumCullingJobPtr m_frustumCullingJob;
- FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ FilterProximityDistanceJobPtr m_filterProximityJob;
LightGathererPtr m_lightGathererJob;
RenderableEntityFilterPtr m_renderableEntityFilterJob;
ComputableEntityFilterPtr m_computableEntityFilterJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewBuilderJobPtr> m_renderViewBuilderJobs;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
};
class SetClearDrawBufferIndex
@@ -270,78 +290,51 @@ private:
RenderViewInitializerJobPtr m_renderViewJob;
};
+class SyncFilterEntityByLayer
+{
+public:
+ explicit SyncFilterEntityByLayer(const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ Renderer *renderer,
+ FrameGraphNode *leafNode)
+ : m_filterEntityByLayerJob(filterEntityByLayerJob)
+ , m_renderer(renderer)
+ , m_leafNode(leafNode)
+ {
+ }
+
+ void operator()()
+ {
+ QMutexLocker lock(m_renderer->cache()->mutex());
+ // Save the filtered by layer subset into the cache
+ const QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
+ RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
+ dataCacheForLeaf.filterEntitiesByLayer = filteredEntities;
+ }
+
+private:
+ FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
+};
+
} // anonymous
RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer)
- : m_renderViewIndex(renderViewIndex)
+ : m_leafNode(leafNode)
+ , m_renderViewIndex(renderViewIndex)
, m_renderer(renderer)
+ , m_layerCacheNeedsToBeRebuilt(false)
, m_renderViewJob(RenderViewInitializerJobPtr::create())
- , m_filterEntityByLayerJob(Render::FilterLayerEntityJobPtr::create())
+ , m_filterEntityByLayerJob()
, 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))
+ , m_syncFilterEntityByLayerJob()
+ , m_filterProximityJob(Render::FilterProximityDistanceJobPtr::create())
{
- // 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
@@ -409,6 +402,91 @@ SynchronizerJobPtr RenderViewBuilder::setClearDrawBufferIndexJob() const
return m_setClearDrawBufferIndexJob;
}
+SynchronizerJobPtr RenderViewBuilder::syncFilterEntityByLayerJob() const
+{
+ return m_syncFilterEntityByLayerJob;
+}
+
+FilterProximityDistanceJobPtr RenderViewBuilder::filterProximityJob() const
+{
+ return m_filterProximityJob;
+}
+
+void RenderViewBuilder::prepareJobs()
+{
+ // Init what we can here
+ EntityManager *entityManager = m_renderer->nodeManagers()->renderNodesManager();
+ m_filterProximityJob->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(m_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);
+ }
+
+ if (m_layerCacheNeedsToBeRebuilt) {
+ m_filterEntityByLayerJob = Render::FilterLayerEntityJobPtr::create();
+ m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers());
+ m_syncFilterEntityByLayerJob = SynchronizerJobPtr::create(SyncFilterEntityByLayer(m_filterEntityByLayerJob,
+ m_renderer,
+ m_leafNode),
+ JobTypes::SyncFilterEntityByLayer);
+ }
+
+ m_syncRenderCommandBuildingJob = SynchronizerJobPtr::create(SyncRenderCommandBuilding(m_renderViewJob,
+ m_frustumCullingJob,
+ m_filterProximityJob,
+ m_lightGathererJob,
+ m_renderableEntityFilterJob,
+ m_computableEntityFilterJob,
+ m_materialGathererJobs,
+ m_renderViewBuilderJobs,
+ m_renderer,
+ m_leafNode),
+ JobTypes::SyncRenderViewCommandBuilding);
+
+ m_syncRenderViewCommandBuildersJob = SynchronizerJobPtr::create(SyncRenderViewCommandBuilders(m_renderViewJob,
+ m_renderViewBuilderJobs,
+ m_renderer),
+ JobTypes::SyncRenderViewCommandBuilder);
+
+ m_syncRenderViewInitializationJob = SynchronizerJobPtr::create(SyncRenderViewInitialization(m_renderViewJob,
+ m_frustumCullingJob,
+ m_filterEntityByLayerJob,
+ m_filterProximityJob,
+ m_materialGathererJobs,
+ m_renderViewBuilderJobs),
+ JobTypes::SyncRenderViewInitialization);
+
+}
+
QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
{
QVector<Qt3DCore::QAspectJobPtr> jobs;
@@ -416,6 +494,11 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
jobs.reserve(m_materialGathererJobs.size() + m_renderViewBuilderJobs.size() + 11);
// Set dependencies
+
+ // Finish the skinning palette job before processing renderviews
+ // TODO: Maybe only update skinning palettes for non-culled entities
+ m_renderViewJob->addDependency(m_renderer->updateSkinningPaletteJob());
+
m_syncFrustumCullingJob->addDependency(m_renderer->updateWorldTransformJob());
m_syncFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob());
m_syncFrustumCullingJob->addDependency(m_syncRenderViewInitializationJob);
@@ -427,8 +510,8 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_syncRenderViewInitializationJob->addDependency(m_renderViewJob);
- m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob);
- m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob());
+ m_filterProximityJob->addDependency(m_renderer->expandBoundingVolumeJob());
+ m_filterProximityJob->addDependency(m_syncRenderViewInitializationJob);
m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
@@ -438,7 +521,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
}
m_syncRenderCommandBuildingJob->addDependency(m_renderableEntityFilterJob);
m_syncRenderCommandBuildingJob->addDependency(m_computableEntityFilterJob);
- m_syncRenderCommandBuildingJob->addDependency(m_filterEntityByLayerJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_filterProximityJob);
m_syncRenderCommandBuildingJob->addDependency(m_lightGathererJob);
m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob);
@@ -460,20 +543,30 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
jobs.push_back(m_syncRenderViewInitializationJob); // Step 2
+ if (m_layerCacheNeedsToBeRebuilt) {
+ m_filterEntityByLayerJob->addDependency(m_syncRenderViewInitializationJob);
+ m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob());
+
+ m_syncFilterEntityByLayerJob->addDependency(m_filterEntityByLayerJob);
+ m_syncRenderCommandBuildingJob->addDependency(m_syncFilterEntityByLayerJob);
+
+ jobs.push_back(m_filterEntityByLayerJob); // Step 3
+ jobs.push_back(m_syncFilterEntityByLayerJob); // Step 4
+ }
jobs.push_back(m_syncFrustumCullingJob); // Step 3
- jobs.push_back(m_filterEntityByLayerJob); // Step 3
+ jobs.push_back(m_filterProximityJob); // 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
+ jobs.push_back(m_syncRenderCommandBuildingJob); // Step 5
- for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 6
jobs.push_back(renderViewCommandBuilder);
- jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 6
+ jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 7
return jobs;
}
@@ -488,6 +581,16 @@ int RenderViewBuilder::renderViewIndex() const
return m_renderViewIndex;
}
+void RenderViewBuilder::setLayerCacheNeedsToBeRebuilt(bool needsToBeRebuilt)
+{
+ m_layerCacheNeedsToBeRebuilt = needsToBeRebuilt;
+}
+
+bool RenderViewBuilder::layerCacheNeedsToBeRebuilt() const
+{
+ return m_layerCacheNeedsToBeRebuilt;
+}
+
int RenderViewBuilder::optimalJobCount()
{
return RenderViewBuilder::m_optimalParallelJobCount;
diff --git a/src/render/backend/renderviewbuilder_p.h b/src/render/backend/renderviewbuilder_p.h
index 6f09a6282..a1fb4eb8b 100644
--- a/src/render/backend/renderviewbuilder_p.h
+++ b/src/render/backend/renderviewbuilder_p.h
@@ -62,6 +62,7 @@
#include <Qt3DRender/private/renderview_p.h>
#include <Qt3DRender/private/frustumcullingjob_p.h>
#include <Qt3DRender/private/lightgatherer_p.h>
+#include <Qt3DRender/private/filterproximitydistancejob_p.h>
QT_BEGIN_NAMESPACE
@@ -93,18 +94,26 @@ public:
SynchronizerJobPtr syncRenderCommandBuildingJob() const;
SynchronizerJobPtr syncRenderViewCommandBuildersJob() const;
SynchronizerJobPtr setClearDrawBufferIndexJob() const;
+ SynchronizerJobPtr syncFilterEntityByLayerJob() const;
+ FilterProximityDistanceJobPtr filterProximityJob() const;
+ void prepareJobs();
QVector<Qt3DCore::QAspectJobPtr> buildJobHierachy() const;
Renderer *renderer() const;
int renderViewIndex() const;
+ void setLayerCacheNeedsToBeRebuilt(bool needsToBeRebuilt);
+ bool layerCacheNeedsToBeRebuilt() const;
+
static int optimalJobCount();
static void removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset);
private:
+ Render::FrameGraphNode *m_leafNode;
const int m_renderViewIndex;
Renderer *m_renderer;
+ bool m_layerCacheNeedsToBeRebuilt;
RenderViewInitializerJobPtr m_renderViewJob;
FilterLayerEntityJobPtr m_filterEntityByLayerJob;
@@ -120,6 +129,8 @@ private:
SynchronizerJobPtr m_syncRenderCommandBuildingJob;
SynchronizerJobPtr m_syncRenderViewCommandBuildersJob;
SynchronizerJobPtr m_setClearDrawBufferIndexJob;
+ SynchronizerJobPtr m_syncFilterEntityByLayerJob;
+ FilterProximityDistanceJobPtr m_filterProximityJob;
static const int m_optimalParallelJobCount;
};
diff --git a/src/render/backend/segmentsvisitor.cpp b/src/render/backend/segmentsvisitor.cpp
new file mode 100644
index 000000000..96e2b3b6c
--- /dev/null
+++ b/src/render/backend/segmentsvisitor.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "segmentsvisitor_p.h"
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/visitorutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace {
+
+bool isSegmentBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_NOTHROW
+{
+ switch (type) {
+ case Qt3DRender::QGeometryRenderer::Lines:
+ case Qt3DRender::QGeometryRenderer::LineStrip:
+ case Qt3DRender::QGeometryRenderer::LineLoop:
+ case Qt3DRender::QGeometryRenderer::LinesAdjacency:
+ case Qt3DRender::QGeometryRenderer::LineStripAdjacency:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseSegmentsIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < indexInfo.count) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = indices[i + u];
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseSegments(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < vertexInfo.count) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = (i + u);
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[u][j] = vertices[idx + j];
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseSegmentStripIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor,
+ bool loop)
+{
+ uint i = 0;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ ndx[0] = indices[0];
+ uint idx = ndx[0] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[0][j] = vertices[idx + j];
+ while (i < indexInfo.count - 1) {
+ ndx[1] = indices[i + 1];
+ if (ndx[0] != ndx[1]) {
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ }
+ ++i;
+ ndx[0] = ndx[1];
+ abc[0] = abc[1];
+ }
+ if (loop) {
+ ndx[1] = indices[0];
+ if (ndx[0] != ndx[1]) {
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ }
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseSegmentStrip(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor,
+ bool loop)
+{
+ uint i = 0;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ ndx[0] = i;
+ uint idx = ndx[0] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[0][j] = vertices[idx + j];
+ while (i < vertexInfo.count - 1) {
+ ndx[1] = (i + 1);
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ ++i;
+ ndx[0] = ndx[1];
+ abc[0] = abc[1];
+ }
+ if (loop) {
+ ndx[1] = 0;
+ idx = ndx[1] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[1][j] = vertices[idx + j];
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ }
+}
+
+// indices, vertices are already offset
+template<typename Index, typename Vertex>
+void traverseSegmentAdjacencyIndexed(Index *indices,
+ Vertex *vertices,
+ const BufferInfo &indexInfo,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 1;
+ uint n = indexInfo.count - 1;
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < n) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = indices[i + u];
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j) {
+ abc[u][j] = vertices[idx + j];
+ }
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+// vertices are already offset
+template<typename Vertex>
+void traverseSegmentAdjacency(Vertex *vertices,
+ const BufferInfo &vertexInfo,
+ SegmentsVisitor *visitor)
+{
+ uint i = 1;
+ uint n = vertexInfo.count - 1;
+
+ const uint verticesStride = vertexInfo.byteStride / sizeof(Vertex);
+ const uint maxVerticesDataSize = qMin(vertexInfo.dataSize, 3U);
+
+ uint ndx[2];
+ QVector3D abc[2];
+ while (i < n) {
+ for (uint u = 0; u < 2; ++u) {
+ ndx[u] = (i + u);
+ const uint idx = ndx[u] * verticesStride;
+ for (uint j = 0; j < maxVerticesDataSize; ++j)
+ abc[u][j] = vertices[idx + j];
+ }
+ visitor->visit(ndx[0], abc[0], ndx[1], abc[1]);
+ i += 2;
+ }
+}
+
+template<typename Index, typename Visitor>
+struct IndexedVertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
+ {
+ switch (m_primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Lines:
+ traverseSegmentsIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStrip:
+ traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, false);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineLoop:
+ traverseSegmentStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor, true);
+ return;
+ case Qt3DRender::QGeometryRenderer::LinesAdjacency:
+ traverseSegmentAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through
+ default:
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+
+ BufferInfo m_indexBufferInfo;
+ Index *m_indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct IndexExecutor
+{
+ template<typename Index>
+ void operator ()( const BufferInfo &indexInfo, Index *indices)
+ {
+ IndexedVertexExecutor<Index, Visitor> exec;
+ exec.m_primitiveType = m_primitiveType;
+ exec.m_indices = indices;
+ exec.m_indexBufferInfo = indexInfo;
+ exec.m_visitor = m_visitor;
+ Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
+ }
+
+ BufferInfo m_vertexBufferInfo;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+template<typename Visitor>
+struct VertexExecutor
+{
+ template<typename Vertex>
+ void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
+ {
+ switch (m_primitiveType) {
+ case Qt3DRender::QGeometryRenderer::Lines:
+ traverseSegments(vertices, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStrip:
+ traverseSegmentStrip(vertices, vertexInfo, m_visitor, false);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineLoop:
+ traverseSegmentStrip(vertices, vertexInfo, m_visitor, true);
+ return;
+ case Qt3DRender::QGeometryRenderer::LinesAdjacency:
+ traverseSegmentAdjacency(vertices, vertexInfo, m_visitor);
+ return;
+ case Qt3DRender::QGeometryRenderer::LineStripAdjacency: // fall through
+ default:
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
+};
+
+} // anonymous
+
+
+SegmentsVisitor::~SegmentsVisitor()
+{
+
+}
+
+void SegmentsVisitor::apply(const Qt3DCore::QEntity *entity)
+{
+ GeometryRenderer *renderer = m_manager->geometryRendererManager()->lookupResource(entity->id());
+ apply(renderer, entity->id());
+}
+
+void SegmentsVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id)
+{
+ m_nodeId = id;
+ if (renderer && renderer->instanceCount() == 1 && isSegmentBased(renderer->primitiveType())) {
+ Visitor::visitPrimitives<VertexExecutor<SegmentsVisitor>,
+ IndexExecutor<SegmentsVisitor>, SegmentsVisitor>(m_manager, renderer, this);
+ }
+}
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/segmentsvisitor_p.h b/src/render/backend/segmentsvisitor_p.h
new file mode 100644
index 000000000..21867b0d5
--- /dev/null
+++ b/src/render/backend/segmentsvisitor_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_SEGMENTSVISITOR_P_H
+#define QT3DRENDER_RENDER_SEGMENTSVISITOR_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/qnodeid.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+
+class Q_AUTOTEST_EXPORT SegmentsVisitor
+{
+public:
+ explicit SegmentsVisitor(NodeManagers *manager) : m_manager(manager) { }
+ virtual ~SegmentsVisitor();
+
+ void apply(const Qt3DCore::QEntity *entity);
+ void apply(const GeometryRenderer *renderer, const Qt3DCore::QNodeId id);
+
+ virtual void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b) = 0;
+
+protected:
+ NodeManagers *m_manager;
+ Qt3DCore::QNodeId m_nodeId;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_SEGMENTSVISITOR_P_H
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 036f43fa0..57538c8d7 100644
--- a/src/render/backend/trianglesvisitor.cpp
+++ b/src/render/backend/trianglesvisitor.cpp
@@ -48,6 +48,7 @@
#include <Qt3DRender/private/geometry_p.h>
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/visitorutils_p.h>
#include <Qt3DRender/private/bufferutils_p.h>
QT_BEGIN_NAMESPACE
@@ -322,29 +323,21 @@ QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint i
return ret;
}
-template<typename Func>
-void processBuffer(const BufferInfo &info, Func &f)
+
+template <QAttribute::VertexBaseType> struct EnumToType;
+template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
+template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
+template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
+template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
+template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
+template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
+template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
+template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
+
+template<QAttribute::VertexBaseType v>
+typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
{
- switch (info.type) {
- case QAttribute::Byte: f(info, BufferTypeInfo::castToType<QAttribute::Byte>(info.data, info.byteOffset));
- return;
- case QAttribute::UnsignedByte: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
- return;
- case QAttribute::Short: f(info, BufferTypeInfo::castToType<QAttribute::Short>(info.data, info.byteOffset));
- return;
- case QAttribute::UnsignedShort: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
- return;
- case QAttribute::Int: f(info, BufferTypeInfo::castToType<QAttribute::Int>(info.data, info.byteOffset));
- return;
- case QAttribute::UnsignedInt: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
- return;
- case QAttribute::Float: f(info, BufferTypeInfo::castToType<QAttribute::Float>(info.data, info.byteOffset));
- return;
- case QAttribute::Double: f(info, BufferTypeInfo::castToType<QAttribute::Double>(info.data, info.byteOffset));
- return;
- default:
- return;
- }
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
}
QVector4D readBuffer(const BufferInfo &info, uint index)
@@ -372,24 +365,24 @@ QVector4D readBuffer(const BufferInfo &info, uint index)
return QVector4D();
}
-template<typename Index>
+template<typename Index, typename Visitor>
struct IndexedVertexExecutor
{
template<typename Vertex>
void operator ()(const BufferInfo &vertexInfo, Vertex * vertices)
{
- switch (primitiveType) {
+ switch (m_primitiveType) {
case Qt3DRender::QGeometryRenderer::Triangles:
- traverseTrianglesIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTrianglesIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStrip:
- traverseTriangleStripIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTriangleStripIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleFan:
- traverseTriangleFanIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTriangleFanIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- traverseTriangleAdjacencyIndexed(indices, vertices, indexBufferInfo, vertexInfo, visitor);
+ traverseTriangleAdjacencyIndexed(m_indices, vertices, m_indexBufferInfo, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
default:
@@ -397,48 +390,49 @@ struct IndexedVertexExecutor
}
}
- BufferInfo indexBufferInfo;
- Index *indices;
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- TrianglesVisitor* visitor;
+ BufferInfo m_indexBufferInfo;
+ Index *m_indices;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
};
+template<typename Visitor>
struct IndexExecutor
{
- BufferInfo vertexBufferInfo;
-
template<typename Index>
void operator ()( const BufferInfo &indexInfo, Index *indices)
{
- IndexedVertexExecutor<Index> exec;
- exec.primitiveType = primitiveType;
- exec.indices = indices;
- exec.indexBufferInfo = indexInfo;
- exec.visitor = visitor;
- processBuffer(vertexBufferInfo, exec);
+ IndexedVertexExecutor<Index, Visitor> exec;
+ exec.m_primitiveType = m_primitiveType;
+ exec.m_indices = indices;
+ exec.m_indexBufferInfo = indexInfo;
+ exec.m_visitor = m_visitor;
+ Qt3DRender::Render::Visitor::processBuffer(m_vertexBufferInfo, exec);
}
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- TrianglesVisitor* visitor;
+ BufferInfo m_vertexBufferInfo;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
};
+template<typename Visitor>
struct VertexExecutor
{
template<typename Vertex>
void operator ()(const BufferInfo &vertexInfo, Vertex *vertices)
{
- switch (primitiveType) {
+ switch (m_primitiveType) {
case Qt3DRender::QGeometryRenderer::Triangles:
- traverseTriangles(vertices, vertexInfo, visitor);
+ traverseTriangles(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStrip:
- traverseTriangleStrip(vertices, vertexInfo, visitor);
+ traverseTriangleStrip(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleFan:
- traverseTriangleFan(vertices, vertexInfo, visitor);
+ traverseTriangleFan(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TrianglesAdjacency:
- traverseTriangleAdjacency(vertices, vertexInfo, visitor);
+ traverseTriangleAdjacency(vertices, vertexInfo, m_visitor);
return;
case Qt3DRender::QGeometryRenderer::TriangleStripAdjacency: // fall through
default:
@@ -446,8 +440,8 @@ struct VertexExecutor
}
}
- Qt3DRender::QGeometryRenderer::PrimitiveType primitiveType;
- TrianglesVisitor* visitor;
+ Qt3DRender::QGeometryRenderer::PrimitiveType m_primitiveType;
+ Visitor* m_visitor;
};
} // anonymous
@@ -468,67 +462,8 @@ void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::Q
{
m_nodeId = id;
if (renderer && renderer->instanceCount() == 1 && isTriangleBased(renderer->primitiveType())) {
- Attribute *positionAttribute = nullptr;
- Attribute *indexAttribute = nullptr;
- Buffer *positionBuffer = nullptr;
- Buffer *indexBuffer = nullptr;
- Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
-
- if (geom) {
- Qt3DRender::Render::Attribute *attribute = nullptr;
- const auto attrIds = geom->attributes();
- for (const Qt3DCore::QNodeId attrId : attrIds) {
- attribute = m_manager->lookupResource<Attribute, AttributeManager>(attrId);
- if (attribute){
- if (attribute->name() == QAttribute::defaultPositionAttributeName())
- positionAttribute = attribute;
- else if (attribute->attributeType() == QAttribute::IndexAttribute)
- indexAttribute = attribute;
- }
- }
-
- if (positionAttribute)
- positionBuffer = m_manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
- if (indexAttribute)
- indexBuffer = m_manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId());
-
- if (positionBuffer) {
-
- BufferInfo vertexBufferInfo;
- vertexBufferInfo.data = positionBuffer->data();
- vertexBufferInfo.type = positionAttribute->vertexBaseType();
- vertexBufferInfo.byteOffset = positionAttribute->byteOffset();
- vertexBufferInfo.byteStride = positionAttribute->byteStride();
- vertexBufferInfo.dataSize = positionAttribute->vertexSize();
- vertexBufferInfo.count = positionAttribute->count();
-
- if (indexBuffer) { // Indexed
-
- BufferInfo indexBufferInfo;
- indexBufferInfo.data = indexBuffer->data();
- indexBufferInfo.type = indexAttribute->vertexBaseType();
- indexBufferInfo.byteOffset = indexAttribute->byteOffset();
- indexBufferInfo.byteStride = indexAttribute->byteStride();
- indexBufferInfo.count = indexAttribute->count();
-
- IndexExecutor executor;
- executor.vertexBufferInfo = vertexBufferInfo;
- executor.primitiveType = renderer->primitiveType();
- executor.visitor = this;
-
- return processBuffer(indexBufferInfo, executor);
-
- } else { // Non Indexed
-
- // Check into which type the buffer needs to be casted
- VertexExecutor executor;
- executor.primitiveType = renderer->primitiveType();
- executor.visitor = this;
-
- return processBuffer(vertexBufferInfo, executor);
- }
- }
- }
+ Visitor::visitPrimitives<VertexExecutor<TrianglesVisitor>,
+ IndexExecutor<TrianglesVisitor>, TrianglesVisitor>(m_manager, renderer, this);
}
}
diff --git a/src/render/backend/uniform.cpp b/src/render/backend/uniform.cpp
index c2088b60f..03220a219 100644
--- a/src/render/backend/uniform.cpp
+++ b/src/render/backend/uniform.cpp
@@ -225,12 +225,34 @@ UniformValue UniformValue::fromVariant(const QVariant &variant)
break;
}
- default:
+ default: {
+ if (variant.userType() == qMetaTypeId<QMatrix3x3>()) {
+ const QMatrix3x3 mat33 = variant.value<QMatrix3x3>();
+ // Use constData because we want column-major layout
+ v.m_data.resize(9);
+ memcpy(v.data<float>(), mat33.constData(), 9 * sizeof(float));
+ break;
+ }
qWarning() << "Unknown uniform type or value:" << variant << "Please check your QParameters";
}
+ }
return v;
}
+template<>
+void UniformValue::setData<QMatrix4x4>(const QVector<QMatrix4x4> &v)
+{
+ m_data.resize(16 * v.size());
+ m_valueType = ScalarValue;
+ int offset = 0;
+ const int byteSize = 16 * sizeof(float);
+ float *data = m_data.data();
+ for (const auto m : v) {
+ memcpy(data + offset, m.constData(), byteSize);
+ offset += 16;
+ }
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/uniform_p.h b/src/render/backend/uniform_p.h
index 6b5ae4172..e0d8fedeb 100644
--- a/src/render/backend/uniform_p.h
+++ b/src/render/backend/uniform_p.h
@@ -152,6 +152,18 @@ public:
memcpy(m_data.data(), mat44.constData(), 16 * sizeof(float));
}
+ UniformValue(const QVector<QMatrix4x4> &v)
+ : m_data(16 * v.size())
+ {
+ int offset = 0;
+ const int byteSize = 16 * sizeof(float);
+ float *data = m_data.data();
+ for (const auto m : v) {
+ memcpy(data + offset, m.constData(), byteSize);
+ offset += 16;
+ }
+ }
+
// For nodes which will later be replaced by a Texture or Buffer
UniformValue(Qt3DCore::QNodeId id)
: UniformValue()
@@ -171,8 +183,19 @@ public:
ValueType valueType() const { return m_valueType; }
UniformType storedType() const { return m_storedType; }
+ template<typename T>
+ void setData(const QVector<T> &v)
+ {
+ m_data.resize(v.size() * sizeof(T) / sizeof(float));
+ m_valueType = ScalarValue;
+ float *data = m_data.data();
+ memcpy(data, v.constData(), v.size() * sizeof(T));
+ }
+
static UniformValue fromVariant(const QVariant &variant);
+ int byteSize() const { return m_data.size() * sizeof(float); }
+
template<typename T>
const T *constData() const
{
@@ -205,6 +228,9 @@ private:
UniformType m_storedType = Unknown;
};
+template<>
+Q_AUTOTEST_EXPORT void UniformValue::setData<QMatrix4x4>(const QVector<QMatrix4x4> &v);
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/visitorutils_p.h b/src/render/backend/visitorutils_p.h
new file mode 100644
index 000000000..452cf153b
--- /dev/null
+++ b/src/render/backend/visitorutils_p.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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: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_VISITORUTILS_P_H
+#define QT3DRENDER_VISITORUTILS_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 <QtGlobal>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace Visitor {
+
+template <QAttribute::VertexBaseType> struct EnumToType;
+template <> struct EnumToType<QAttribute::Byte> { typedef const char type; };
+template <> struct EnumToType<QAttribute::UnsignedByte> { typedef const uchar type; };
+template <> struct EnumToType<QAttribute::Short> { typedef const short type; };
+template <> struct EnumToType<QAttribute::UnsignedShort> { typedef const ushort type; };
+template <> struct EnumToType<QAttribute::Int> { typedef const int type; };
+template <> struct EnumToType<QAttribute::UnsignedInt> { typedef const uint type; };
+template <> struct EnumToType<QAttribute::Float> { typedef const float type; };
+template <> struct EnumToType<QAttribute::Double> { typedef const double type; };
+
+template<QAttribute::VertexBaseType v>
+inline typename EnumToType<v>::type *castToType(const QByteArray &u, uint byteOffset)
+{
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+}
+
+template<typename Func>
+void processBuffer(const BufferInfo &info, Func &f)
+{
+ switch (info.type) {
+ case QAttribute::Byte: f(info, castToType<QAttribute::Byte>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedByte: f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Short: f(info, castToType<QAttribute::Short>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedShort: f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Int: f(info, castToType<QAttribute::Int>(info.data, info.byteOffset));
+ return;
+ case QAttribute::UnsignedInt: f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Float: f(info, castToType<QAttribute::Float>(info.data, info.byteOffset));
+ return;
+ case QAttribute::Double: f(info, castToType<QAttribute::Double>(info.data, info.byteOffset));
+ return;
+ default:
+ return;
+ }
+}
+
+template<typename VertexExecutor, typename IndexExecutor, typename Visitor>
+void visitPrimitives(NodeManagers *manager, const GeometryRenderer *renderer, Visitor* visitor)
+{
+ Geometry *geom = manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+ Attribute *positionAttribute = nullptr;
+ Attribute *indexAttribute = nullptr;
+ Buffer *positionBuffer = nullptr;
+ Buffer *indexBuffer = nullptr;
+
+ if (geom) {
+ Qt3DRender::Render::Attribute *attribute = nullptr;
+ const auto attrIds = geom->attributes();
+ for (const Qt3DCore::QNodeId attrId : attrIds) {
+ attribute = manager->lookupResource<Attribute, AttributeManager>(attrId);
+ if (attribute){
+ if (attribute->name() == QAttribute::defaultPositionAttributeName())
+ positionAttribute = attribute;
+ else if (attribute->attributeType() == QAttribute::IndexAttribute)
+ indexAttribute = attribute;
+ }
+ }
+
+ if (positionAttribute)
+ positionBuffer = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
+ if (indexAttribute)
+ indexBuffer = manager->lookupResource<Buffer, BufferManager>(indexAttribute->bufferId());
+
+ if (positionBuffer) {
+
+ BufferInfo vertexBufferInfo;
+ vertexBufferInfo.data = positionBuffer->data();
+ vertexBufferInfo.type = positionAttribute->vertexBaseType();
+ vertexBufferInfo.byteOffset = positionAttribute->byteOffset();
+ vertexBufferInfo.byteStride = positionAttribute->byteStride();
+ vertexBufferInfo.dataSize = positionAttribute->vertexSize();
+ vertexBufferInfo.count = positionAttribute->count();
+
+ if (indexBuffer) { // Indexed
+
+ BufferInfo indexBufferInfo;
+ indexBufferInfo.data = indexBuffer->data();
+ indexBufferInfo.type = indexAttribute->vertexBaseType();
+ indexBufferInfo.byteOffset = indexAttribute->byteOffset();
+ indexBufferInfo.byteStride = indexAttribute->byteStride();
+ indexBufferInfo.count = indexAttribute->count();
+
+ IndexExecutor executor;
+ executor.m_vertexBufferInfo = vertexBufferInfo;
+ executor.m_primitiveType = renderer->primitiveType();
+ executor.m_visitor = visitor;
+
+ return processBuffer(indexBufferInfo, executor);
+
+ } else { // Non Indexed
+
+ // Check into which type the buffer needs to be casted
+ VertexExecutor executor;
+ executor.m_primitiveType = renderer->primitiveType();
+ executor.m_visitor = visitor;
+
+ return processBuffer(vertexBufferInfo, executor);
+ }
+ }
+ }
+}
+
+} // namespace Visitor
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_VISITORUTILS_P_H
diff --git a/src/render/framegraph/blitframebuffer.cpp b/src/render/framegraph/blitframebuffer.cpp
new file mode 100644
index 000000000..70401e6d1
--- /dev/null
+++ b/src/render/framegraph/blitframebuffer.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DRender/private/qblitframebuffer_p.h>
+#include <Qt3DRender/private/blitframebuffer_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+BlitFramebuffer::BlitFramebuffer()
+ : FrameGraphNode(FrameGraphNode::BlitFramebuffer)
+ , m_sourceRenderTargetId(Qt3DCore::QNodeId())
+ , m_destinationRenderTargetId(Qt3DCore::QNodeId())
+ , m_sourceRect(QRect())
+ , m_destinationRect(QRect())
+ , m_sourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0)
+ , m_destinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0)
+ , m_interpolationMethod(Qt3DRender::QBlitFramebuffer::Linear)
+{
+}
+
+void BlitFramebuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ if (e->type() == PropertyUpdated) {
+ QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (propertyChange->propertyName() == QByteArrayLiteral("sourceRenderTarget")) {
+ m_sourceRenderTargetId = propertyChange->value().value<QNodeId>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("destinationRenderTarget")) {
+ m_destinationRenderTargetId = propertyChange->value().value<QNodeId>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("sourceRect")) {
+ m_sourceRect = propertyChange->value().value<QRect>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("destinationRect")) {
+ m_destinationRect = propertyChange->value().value<QRect>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("sourceAttachmentPoint")) {
+ m_sourceAttachmentPoint = propertyChange->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("destinationAttachmentPoint")) {
+ m_destinationAttachmentPoint = propertyChange->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>();
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("interpolationMethod")) {
+ m_interpolationMethod = propertyChange->value().value<QBlitFramebuffer::InterpolationMethod>();
+ }
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ FrameGraphNode::sceneChangeEvent(e);
+}
+
+void BlitFramebuffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ FrameGraphNode::initializeFromPeer(change);
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QBlitFramebufferData> >(change);
+ const auto &data = typedChange->data;
+ m_sourceRect = data.m_sourceRect;
+ m_destinationRect = data.m_destinationRect;
+ m_sourceRenderTargetId = data.m_sourceRenderTargetId;
+ m_destinationRenderTargetId = data.m_destinationRenderTargetId;
+ m_sourceAttachmentPoint = data.m_sourceAttachmentPoint;
+ m_destinationAttachmentPoint = data.m_destinationAttachmentPoint;
+ m_interpolationMethod = data.m_interpolationMethod;
+}
+
+Qt3DRender::QRenderTargetOutput::AttachmentPoint BlitFramebuffer::destinationAttachmentPoint() const
+{
+ return m_destinationAttachmentPoint;
+}
+
+QBlitFramebuffer::InterpolationMethod BlitFramebuffer::interpolationMethod() const
+{
+ return m_interpolationMethod;
+}
+
+Qt3DRender::QRenderTargetOutput::AttachmentPoint BlitFramebuffer::sourceAttachmentPoint() const
+{
+ return m_sourceAttachmentPoint;
+}
+
+QRect BlitFramebuffer::destinationRect() const
+{
+ return m_destinationRect;
+}
+
+QRect BlitFramebuffer::sourceRect() const
+{
+ return m_sourceRect;
+}
+
+Qt3DCore::QNodeId BlitFramebuffer::destinationRenderTargetId() const
+{
+ return m_destinationRenderTargetId;
+}
+
+Qt3DCore::QNodeId BlitFramebuffer::sourceRenderTargetId() const
+{
+ return m_sourceRenderTargetId;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/blitframebuffer_p.h b/src/render/framegraph/blitframebuffer_p.h
new file mode 100644
index 000000000..64800d0fa
--- /dev/null
+++ b/src/render/framegraph/blitframebuffer_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_BLITFRAMEBUFFER_P_H
+#define QT3DRENDER_RENDER_BLITFRAMEBUFFER_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 <Qt3DRender/private/qblitframebuffer_p.h>
+#include <Qt3DRender/private/framegraphnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT BlitFramebuffer : public FrameGraphNode
+{
+public:
+ BlitFramebuffer();
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
+ Qt3DCore::QNodeId sourceRenderTargetId() const;
+
+ Qt3DCore::QNodeId destinationRenderTargetId() const;
+
+ QRect sourceRect() const;
+
+ QRect destinationRect() const;
+
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint() const;
+
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint() const;
+
+ QBlitFramebuffer::InterpolationMethod interpolationMethod() const;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ Qt3DCore::QNodeId m_sourceRenderTargetId;
+ Qt3DCore::QNodeId m_destinationRenderTargetId;
+ QRect m_sourceRect;
+ QRect m_destinationRect;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint m_sourceAttachmentPoint;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint m_destinationAttachmentPoint;
+ QBlitFramebuffer::InterpolationMethod m_interpolationMethod;
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_BLITFRAMEBUFFER_H
diff --git a/src/render/framegraph/framegraph.pri b/src/render/framegraph/framegraph.pri
index 5e9ce68bf..9784a193c 100644
--- a/src/render/framegraph/framegraph.pri
+++ b/src/render/framegraph/framegraph.pri
@@ -52,7 +52,13 @@ HEADERS += \
$$PWD/qframegraphnodecreatedchange_p.h \
$$PWD/qmemorybarrier.h \
$$PWD/qmemorybarrier_p.h \
- $$PWD/memorybarrier_p.h
+ $$PWD/memorybarrier_p.h \
+ $$PWD/qproximityfilter.h \
+ $$PWD/qproximityfilter_p.h \
+ $$PWD/proximityfilter_p.h \
+ $$PWD/qblitframebuffer.h \
+ $$PWD/qblitframebuffer_p.h \
+ $$PWD/blitframebuffer_p.h
SOURCES += \
$$PWD/cameraselectornode.cpp \
@@ -90,4 +96,8 @@ SOURCES += \
$$PWD/buffercapture.cpp \
$$PWD/qframegraphnodecreatedchange.cpp \
$$PWD/qmemorybarrier.cpp \
- $$PWD/memorybarrier.cpp
+ $$PWD/memorybarrier.cpp \
+ $$PWD/qproximityfilter.cpp \
+ $$PWD/proximityfilter.cpp \
+ $$PWD/qblitframebuffer.cpp \
+ $$PWD/blitframebuffer.cpp
diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h
index c7b399f89..843ad63a0 100644
--- a/src/render/framegraph/framegraphnode_p.h
+++ b/src/render/framegraph/framegraphnode_p.h
@@ -99,7 +99,9 @@ public:
Surface,
RenderCapture,
BufferCapture,
- MemoryBarrier
+ MemoryBarrier,
+ ProximityFilter,
+ BlitFramebuffer
};
FrameGraphNodeType nodeType() const { return m_nodeType; }
@@ -157,26 +159,6 @@ public:
}
protected:
- Backend *createBackendFrameGraphNode(Qt3DCore::QNode *n) const
- {
- Frontend *f = qobject_cast<Frontend *>(n);
- if (f != nullptr) {
- if (!m_manager->containsNode(n->id())) {
- Backend *backend = new Backend();
- backend->setFrameGraphManager(m_manager);
- backend->setPeer(f);
- backend->setRenderer(m_renderer);
- QFrameGraphNode *parentFGNode = static_cast<QFrameGraphNode *>(n)->parentFrameGraphNode();
- if (parentFGNode)
- backend->setParentId(parentFGNode->id());
- m_manager->appendNode(backend->peerId(), backend);
- return backend;
- }
- return static_cast<Backend *>(m_manager->lookupNode(n->id()));
- }
- return nullptr;
- }
-
Backend *createBackendFrameGraphNode(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
{
if (!m_manager->containsNode(change->subjectId())) {
diff --git a/src/render/framegraph/layerfilternode.cpp b/src/render/framegraph/layerfilternode.cpp
index 17693eb83..4b6842015 100644
--- a/src/render/framegraph/layerfilternode.cpp
+++ b/src/render/framegraph/layerfilternode.cpp
@@ -53,6 +53,7 @@ namespace Render {
LayerFilterNode::LayerFilterNode()
: FrameGraphNode(FrameGraphNode::LayerFilter)
+ , m_filterMode(QLayerFilter::AcceptAnyMatchingLayers)
{
}
@@ -62,6 +63,7 @@ void LayerFilterNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBaseP
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QLayerFilterData>>(change);
const auto &data = typedChange->data;
setLayerIds(data.layerIds);
+ m_filterMode = data.filterMode;
}
void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -71,6 +73,7 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
if (change->propertyName() == QByteArrayLiteral("layer"))
m_layerIds.append(change->addedNodeId());
+ markDirty(AbstractRenderer::LayersDirty);
break;
}
@@ -78,13 +81,21 @@ void LayerFilterNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
if (change->propertyName() == QByteArrayLiteral("layer"))
m_layerIds.removeOne(change->removedNodeId());
+ markDirty(AbstractRenderer::LayersDirty);
break;
}
+ case PropertyUpdated: {
+ const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("filterMode")) {
+ m_filterMode = static_cast<QLayerFilter::FilterMode>(change->value().value<int>());
+ break;
+ }
+ }
+
default:
break;
}
- markDirty(AbstractRenderer::AllDirty);
FrameGraphNode::sceneChangeEvent(e);
}
@@ -99,6 +110,11 @@ void LayerFilterNode::setLayerIds(const QNodeIdVector &list)
m_layerIds = list;
}
+QLayerFilter::FilterMode LayerFilterNode::filterMode() const
+{
+ return m_filterMode;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/layerfilternode_p.h b/src/render/framegraph/layerfilternode_p.h
index ef443dfd0..59e16c934 100644
--- a/src/render/framegraph/layerfilternode_p.h
+++ b/src/render/framegraph/layerfilternode_p.h
@@ -52,14 +52,13 @@
//
#include <Qt3DRender/private/framegraphnode_p.h>
+#include <Qt3DRender/QLayerFilter>
#include <QStringList>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QLayerFilter;
-
namespace Render {
class Renderer;
@@ -73,10 +72,13 @@ public:
Qt3DCore::QNodeIdVector layerIds() const;
void setLayerIds(const Qt3DCore::QNodeIdVector &list);
+ QLayerFilter::FilterMode filterMode() const;
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
Qt3DCore::QNodeIdVector m_layerIds;
+ QLayerFilter::FilterMode m_filterMode;
};
} // namespace Render
diff --git a/src/render/framegraph/proximityfilter.cpp b/src/render/framegraph/proximityfilter.cpp
new file mode 100644
index 000000000..aed19828b
--- /dev/null
+++ b/src/render/framegraph/proximityfilter.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "proximityfilter_p.h"
+#include <Qt3DRender/private/qproximityfilter_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+ProximityFilter::ProximityFilter()
+ : FrameGraphNode(FrameGraphNode::ProximityFilter)
+ , m_distanceThreshold(0.0f)
+{
+}
+
+void ProximityFilter::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ FrameGraphNode::initializeFromPeer(change);
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QProximityFilterData>>(change);
+ const QProximityFilterData &data = typedChange->data;
+ m_entityId = data.entityId;
+ m_distanceThreshold = data.distanceThreshold;
+}
+
+void ProximityFilter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ qCDebug(Render::Framegraph) << Q_FUNC_INFO;
+ if (e->type() == Qt3DCore::PropertyUpdated) {
+ Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
+ if (propertyChange->propertyName() == QByteArrayLiteral("entity"))
+ m_entityId = propertyChange->value().value<Qt3DCore::QNodeId>();
+ else if (propertyChange->propertyName() == QByteArrayLiteral("distanceThreshold"))
+ m_distanceThreshold = propertyChange->value().toFloat();
+ markDirty(AbstractRenderer::AllDirty);
+ }
+ FrameGraphNode::sceneChangeEvent(e);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/proximityfilter_p.h b/src/render/framegraph/proximityfilter_p.h
new file mode 100644
index 000000000..cfd6af805
--- /dev/null
+++ b/src/render/framegraph/proximityfilter_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_PROXIMITYFILTER_P_H
+#define QT3DRENDER_RENDER_PROXIMITYFILTER_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 <Qt3DRender/private/framegraphnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT ProximityFilter : public FrameGraphNode
+{
+public:
+ ProximityFilter();
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
+ float distanceThreshold() const { return m_distanceThreshold; }
+ Qt3DCore::QNodeId entityId() const { return m_entityId; }
+
+#if defined(QT_BUILD_INTERNAL)
+ // For unit testing
+ void setDistanceThreshold(float distanceThreshold) { m_distanceThreshold = distanceThreshold; }
+ void setEntityId(Qt3DCore::QNodeId entityId) { m_entityId = entityId; }
+#endif
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ float m_distanceThreshold;
+ Qt3DCore::QNodeId m_entityId;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_PROXIMITYFILTER_P_H
diff --git a/src/render/framegraph/qblitframebuffer.cpp b/src/render/framegraph/qblitframebuffer.cpp
new file mode 100644
index 000000000..505bab96c
--- /dev/null
+++ b/src/render/framegraph/qblitframebuffer.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qblitframebuffer.h"
+#include "qblitframebuffer_p.h"
+
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DRender/qframegraphnodecreatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QBlitFramebufferPrivate::QBlitFramebufferPrivate()
+ : QFrameGraphNodePrivate()
+ , m_source(nullptr)
+ , m_destination(nullptr)
+ , m_sourceRect(QRect())
+ , m_destinationRect(QRect())
+ , m_sourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color0)
+ , m_destinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color0)
+ , m_interpolationMethod(QBlitFramebuffer::Linear)
+{
+}
+
+QBlitFramebuffer::QBlitFramebuffer(QNode *parent)
+ : QFrameGraphNode(*new QBlitFramebufferPrivate, parent)
+{
+
+}
+
+QBlitFramebuffer::QBlitFramebuffer(QBlitFramebufferPrivate &dd, QNode *parent)
+ : QFrameGraphNode(dd, parent)
+{
+}
+
+QBlitFramebuffer::~QBlitFramebuffer()
+{
+
+}
+
+QRenderTarget *QBlitFramebuffer::source() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_source;
+}
+
+QRenderTarget *QBlitFramebuffer::destination() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_destination;
+}
+
+QRectF QBlitFramebuffer::sourceRect() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_sourceRect;
+}
+
+QRectF QBlitFramebuffer::destinationRect() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_destinationRect;
+}
+
+Qt3DRender::QRenderTargetOutput::AttachmentPoint QBlitFramebuffer::sourceAttachmentPoint() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_sourceAttachmentPoint;
+}
+
+QRenderTargetOutput::AttachmentPoint QBlitFramebuffer::destinationAttachmentPoint() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_destinationAttachmentPoint;
+}
+
+QBlitFramebuffer::InterpolationMethod QBlitFramebuffer::interpolationMethod() const
+{
+ Q_D(const QBlitFramebuffer);
+ return d->m_interpolationMethod;
+}
+
+void QBlitFramebuffer::setSource(QRenderTarget *source)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_source != source) {
+ d->m_source = source;
+ emit sourceChanged();
+ }
+}
+
+void QBlitFramebuffer::setDestination(QRenderTarget *destination)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_destination != destination) {
+ d->m_destination = destination;
+ emit destinationChanged();
+ }
+}
+
+void QBlitFramebuffer::setSourceRect(const QRectF &inputRect)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_sourceRect != inputRect) {
+ d->m_sourceRect = inputRect.toRect();
+ emit sourceRectChanged();
+ }
+}
+
+void QBlitFramebuffer::setDestinationRect(const QRectF &outputRect)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_destinationRect != outputRect) {
+ d->m_destinationRect = outputRect.toRect();
+ emit destinationRectChanged();
+ }
+}
+
+void QBlitFramebuffer::setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_sourceAttachmentPoint != sourceAttachmentPoint) {
+ d->m_sourceAttachmentPoint = sourceAttachmentPoint;
+ emit sourceAttachmentPointChanged();
+ }
+}
+
+void QBlitFramebuffer::setDestinationAttachmentPoint(QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_destinationAttachmentPoint != destinationAttachmentPoint) {
+ d->m_destinationAttachmentPoint = destinationAttachmentPoint;
+ emit destinationAttachmentPointChanged();
+ }
+}
+
+void QBlitFramebuffer::setInterpolationMethod(QBlitFramebuffer::InterpolationMethod interpolationMethod)
+{
+ Q_D(QBlitFramebuffer);
+ if (d->m_interpolationMethod != interpolationMethod) {
+ d->m_interpolationMethod = interpolationMethod;
+ emit interpolationMethodChanged();
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QBlitFramebuffer::createNodeCreationChange() const
+{
+ auto creationChange = QFrameGraphNodeCreatedChangePtr<QBlitFramebufferData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QBlitFramebuffer);
+ data.m_sourceRect = d->m_sourceRect;
+ data.m_destinationRect = d->m_destinationRect;
+ data.m_sourceRenderTargetId = Qt3DCore::qIdForNode(d->m_source);
+ data.m_destinationRenderTargetId = Qt3DCore::qIdForNode(d->m_destination);
+ data.m_sourceAttachmentPoint = d->m_sourceAttachmentPoint;
+ data.m_destinationAttachmentPoint = d->m_destinationAttachmentPoint;
+ data.m_interpolationMethod = d->m_interpolationMethod;
+
+ return creationChange;
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qblitframebuffer.h b/src/render/framegraph/qblitframebuffer.h
new file mode 100644
index 000000000..75ce4c23a
--- /dev/null
+++ b/src/render/framegraph/qblitframebuffer.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QBLITFRAMEBUFFER_H
+#define QT3DRENDER_QBLITFRAMEBUFFER_H
+
+#include <Qt3DRender/qframegraphnode.h>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <QRect>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QBlitFramebufferPrivate;
+class QRenderTarget;
+
+class QT3DRENDERSHARED_EXPORT QBlitFramebuffer : public QFrameGraphNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QRenderTarget *source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(Qt3DRender::QRenderTarget *destination READ destination WRITE setDestination NOTIFY destinationChanged)
+ Q_PROPERTY(QRectF sourceRect READ sourceRect WRITE setSourceRect NOTIFY sourceRectChanged)
+ Q_PROPERTY(QRectF destinationRect READ destinationRect WRITE setDestinationRect NOTIFY destinationRectChanged)
+ Q_PROPERTY(Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint READ sourceAttachmentPoint WRITE setSourceAttachmentPoint NOTIFY sourceAttachmentPointChanged)
+ Q_PROPERTY(Qt3DRender::QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint READ destinationAttachmentPoint WRITE setDestinationAttachmentPoint NOTIFY destinationAttachmentPointChanged)
+ Q_PROPERTY(InterpolationMethod interpolationMethod READ interpolationMethod WRITE setInterpolationMethod NOTIFY interpolationMethodChanged)
+public:
+ enum InterpolationMethod {
+ Nearest = 0,
+ Linear,
+ };
+ Q_ENUM(InterpolationMethod) // LCOV_EXCL_LINE
+
+ explicit QBlitFramebuffer(Qt3DCore::QNode *parent = nullptr);
+ ~QBlitFramebuffer();
+
+ QRenderTarget *source() const;
+ QRenderTarget *destination() const;
+ QRectF sourceRect() const;
+ QRectF destinationRect() const;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint() const;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint() const;
+ InterpolationMethod interpolationMethod() const;
+
+ void setSource(QRenderTarget *source);
+ void setDestination(QRenderTarget *destination);
+ void setSourceRect(const QRectF &sourceRect);
+ void setDestinationRect(const QRectF &destinationRect);
+ void setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint sourceAttachmentPoint);
+ void setDestinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::AttachmentPoint destinationAttachmentPoint);
+ void setInterpolationMethod(InterpolationMethod interpolationMethod);
+
+Q_SIGNALS:
+ void sourceChanged();
+ void destinationChanged();
+ void sourceRectChanged();
+ void destinationRectChanged();
+ void sourceAttachmentPointChanged();
+ void destinationAttachmentPointChanged();
+ void interpolationMethodChanged();
+
+protected:
+ explicit QBlitFramebuffer(QBlitFramebufferPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QBlitFramebuffer)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QBLITFRAMEBUFFER_H
diff --git a/src/render/framegraph/qblitframebuffer_p.h b/src/render/framegraph/qblitframebuffer_p.h
new file mode 100644
index 000000000..8b5dc2165
--- /dev/null
+++ b/src/render/framegraph/qblitframebuffer_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QBLITFRAMEBUFFER_P_H
+#define QT3DRENDER_QBLITFRAMEBUFFER_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 <private/qframegraphnode_p.h>
+#include <Qt3DRender/qblitframebuffer.h>
+
+#include <Qt3DRender/QRenderTarget>
+#include <QRect>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QBlitFramebufferPrivate : public QFrameGraphNodePrivate
+{
+public:
+ QBlitFramebufferPrivate();
+
+ QRenderTarget *m_source;
+ QRenderTarget *m_destination;
+ QRect m_sourceRect;
+ QRect m_destinationRect;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint m_sourceAttachmentPoint;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint m_destinationAttachmentPoint;
+ QBlitFramebuffer::InterpolationMethod m_interpolationMethod;
+
+ Q_DECLARE_PUBLIC(QBlitFramebuffer)
+};
+
+struct QBlitFramebufferData
+{
+ Qt3DCore::QNodeId m_sourceRenderTargetId;
+ Qt3DCore::QNodeId m_destinationRenderTargetId;
+ QRect m_sourceRect;
+ QRect m_destinationRect;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint m_sourceAttachmentPoint;
+ Qt3DRender::QRenderTargetOutput::AttachmentPoint m_destinationAttachmentPoint;
+ QBlitFramebuffer::InterpolationMethod m_interpolationMethod;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QBLITFRAMEBUFFER_P_H
diff --git a/src/render/framegraph/qlayerfilter.cpp b/src/render/framegraph/qlayerfilter.cpp
index 2d4653fcb..04ebca572 100644
--- a/src/render/framegraph/qlayerfilter.cpp
+++ b/src/render/framegraph/qlayerfilter.cpp
@@ -51,6 +51,7 @@ namespace Qt3DRender {
QLayerFilterPrivate::QLayerFilterPrivate()
: QFrameGraphNodePrivate()
+ , m_filterMode(QLayerFilter::AcceptAnyMatchingLayers)
{
}
@@ -58,12 +59,55 @@ QLayerFilterPrivate::QLayerFilterPrivate()
\class Qt3DRender::QLayerFilter
\inmodule Qt3DRender
\since 5.5
- \brief Controls layers Drawn in a frame graph branch.
+ \brief Controls layers drawn in a frame graph branch.
- A Qt3DRender::QLayerFilter can be used to instruct the renderer as to which layer(s)
- to draw in that branch of the frame graph. The Qt3DRender::QLayerFilter selects which
- entities to draw based on the Qt3DRender::QLayer instances added to the QLayerFilter
- and as components to the \l Qt3DCore::QEntity.
+ A Qt3DRender::QLayerFilter can be used to instruct the renderer as to
+ which layer(s) to draw in that branch of the frame graph. QLayerFilter
+ selects which entities to draw based on the QLayer instance(s) added to
+ the QLayerFilter and as components to Qt3DCore::QEntity.
+
+ QLayerFilter can be configured to select or discard entities with a
+ specific \l QLayer depending on the filterMode property. By default,
+ entities referencing one of the \l QLayer objects that are also being
+ referenced by the \l QLayerFilter are selected (AcceptAnyMatchingLayers).
+
+ Within the FrameGraph tree, multiple \l QLayerFilter nodes can be nested
+ within a branch going from root to a leaf. In that case the filtering will
+ first operate on all entities of the scene using the filtering method
+ specified by the first declared \l QLayerFilter. Then the filtered subset
+ of entities will be filtered again based on the filtering method set on the
+ second \l QLayerFilter declared. This is then repeated until all \l
+ QLayerFilter nodes of the branch have been consumed.
+*/
+
+/*!
+ \enum QLayerFilter::FilterMode
+
+ Specifies the rules for selecting entities to draw.
+
+ \value AcceptAnyMatchingLayers
+ Accept entities that reference one or more \l QLayer objects added to this
+ QLayerFilter. This is the default
+
+ \value AcceptAllMatchingLayers
+ Accept entities that reference all the \l QLayer objects added to this
+ QLayerFilter
+
+ \value DiscardAnyMatchingLayers
+ Discard entities that reference one or more \l QLayer objects added to this
+ QLayerFilter
+
+ \value DiscardAllMatchingLayers
+ Discard entities that reference all \l QLayer objects added to this
+ QLayerFilter
+*/
+
+/*!
+ \property Qt3DRender::QLayerFilter::filterMode
+
+ Holds the filter mode specifying the entities to select for drawing.
+
+ The default value is AcceptMatchingLayers.
*/
/*!
@@ -72,12 +116,25 @@ QLayerFilterPrivate::QLayerFilterPrivate()
\inherits FrameGraphNode
\inqmlmodule Qt3D.Render
\since 5.5
- \brief Controls layers Drawn in a frame graph branch.
+ \brief Controls layers drawn in a frame graph branch.
A LayerFilter can be used to instruct the renderer as to which layer(s)
to draw in that branch of the frame graph. The LayerFilter selects which
entities to draw based on the \l Layer instances added to the LayerFilter
and as components to the \l Entity.
+
+ The LayerFilter can be configured to select or discard entities with a
+ specific \l Layer depending on the filterMode property. By default,
+ entities referencing one of the \l Layer objects that are also being
+ referenced by the \l LayerFilter are selected (AcceptAnyMatchingLayers).
+
+ Within the FrameGraph tree, multiple \l LayerFilter nodes can be nested
+ within a branch going from root to a leaf. In that case the filtering will
+ first operate on all entities of the scene using the filtering method
+ specified by the first declared \l LayerFilter. Then the filtered subset of
+ entities will be filtered again based on the filtering method set on the
+ second \l LayerFilter declared. This is then repeated until all \l
+ LayerFilter nodes of the branch have been consumed.
*/
/*!
@@ -87,6 +144,30 @@ QLayerFilterPrivate::QLayerFilterPrivate()
*/
/*!
+ \qmlproperty enumeration Qt3DRender::LayerFilter::filterMode
+
+ Holds the filter mode specifying the entities to select for drawing.
+
+ The default value is \c {LayerFilter.AcceptMatchingLayers}.
+
+ \value LayerFilter.AcceptAnyMatchingLayers
+ Accept entities that reference one or more \l Layer objects added to this
+ LayerFilter. This is the default
+
+ \value LayerFilter.AcceptAllMatchingLayers
+ Accept entities that reference all the \l Layer objects added to this
+ LayerFilter
+
+ \value LayerFilter.DiscardAnyMatchingLayers
+ Discard entities that reference one or more \l Layer objects added to this
+ LayerFilter
+
+ \value LayerFilter.DiscardAllMatchingLayers
+ Discard entities that reference all \l Layer objects added to this
+ LayerFilter
+*/
+
+/*!
The constructor creates an instance with the specified \a parent.
*/
QLayerFilter::QLayerFilter(QNode *parent)
@@ -159,12 +240,28 @@ QVector<QLayer *> QLayerFilter::layers() const
return d->m_layers;
}
+QLayerFilter::FilterMode QLayerFilter::filterMode() const
+{
+ Q_D(const QLayerFilter);
+ return d->m_filterMode;
+}
+
+void QLayerFilter::setFilterMode(QLayerFilter::FilterMode filterMode)
+{
+ Q_D(QLayerFilter);
+ if (d->m_filterMode != filterMode) {
+ d->m_filterMode = filterMode;
+ emit filterModeChanged(filterMode);
+ }
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QLayerFilter::createNodeCreationChange() const
{
auto creationChange = QFrameGraphNodeCreatedChangePtr<QLayerFilterData>::create(this);
auto &data = creationChange->data;
Q_D(const QLayerFilter);
data.layerIds = qIdsForNodes(d->m_layers);
+ data.filterMode = d->m_filterMode;
return creationChange;
}
diff --git a/src/render/framegraph/qlayerfilter.h b/src/render/framegraph/qlayerfilter.h
index 61eac5773..68854c722 100644
--- a/src/render/framegraph/qlayerfilter.h
+++ b/src/render/framegraph/qlayerfilter.h
@@ -53,7 +53,17 @@ class QLayerFilterPrivate;
class QT3DRENDERSHARED_EXPORT QLayerFilter : public QFrameGraphNode
{
Q_OBJECT
+ Q_PROPERTY(FilterMode filterMode READ filterMode WRITE setFilterMode NOTIFY filterModeChanged)
public:
+ enum FilterMode
+ {
+ AcceptAnyMatchingLayers = 0,
+ AcceptAllMatchingLayers,
+ DiscardAnyMatchingLayers,
+ DiscardAllMatchingLayers,
+ };
+ Q_ENUM(FilterMode) // LOVC_EXLC_LINE
+
explicit QLayerFilter(Qt3DCore::QNode *parent = nullptr);
~QLayerFilter();
@@ -61,6 +71,13 @@ public:
void removeLayer(QLayer *layer);
QVector<QLayer *> layers() const;
+ FilterMode filterMode() const;
+ void setFilterMode(FilterMode filterMode);
+
+Q_SIGNALS:
+ void filterModeChanged(FilterMode filterMode);
+
+
protected:
explicit QLayerFilter(QLayerFilterPrivate &dd, Qt3DCore::QNode *parent = nullptr);
diff --git a/src/render/framegraph/qlayerfilter_p.h b/src/render/framegraph/qlayerfilter_p.h
index 8ad7d3301..97469bda0 100644
--- a/src/render/framegraph/qlayerfilter_p.h
+++ b/src/render/framegraph/qlayerfilter_p.h
@@ -52,13 +52,13 @@
//
#include <private/qframegraphnode_p.h>
+#include <Qt3DRender/qlayerfilter.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
class QLayer;
-class QLayerFilter;
class QLayerFilterPrivate : public QFrameGraphNodePrivate
{
@@ -67,11 +67,13 @@ public:
Q_DECLARE_PUBLIC(QLayerFilter)
QVector<QLayer*> m_layers;
+ QLayerFilter::FilterMode m_filterMode;
};
struct QLayerFilterData
{
Qt3DCore::QNodeIdVector layerIds;
+ QLayerFilter::FilterMode filterMode;
};
} // namespace Qt3DRender
diff --git a/src/render/framegraph/qproximityfilter.cpp b/src/render/framegraph/qproximityfilter.cpp
new file mode 100644
index 000000000..cd1ecf776
--- /dev/null
+++ b/src/render/framegraph/qproximityfilter.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qproximityfilter.h"
+#include "qproximityfilter_p.h"
+#include <Qt3DCore/qentity.h>
+#include <Qt3DRender/qframegraphnodecreatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QProximityFilterPrivate::QProximityFilterPrivate()
+ : QFrameGraphNodePrivate()
+ , m_entity(nullptr)
+ , m_distanceThreshold(0.0f)
+{
+}
+
+/*!
+ \class Qt3DRender::QProximityFilter
+ \inmodule Qt3DRender
+ \since 5.10
+
+ \brief Select entities which are within a distance threshold of a target
+ entity.
+
+ A \l Qt3DRender::QProximityFilter can be used to select entities to render
+ when they are placed within a given distance threshold of another entity.
+*/
+
+/*!
+ \property Qt3DRender::QProximityFilter::entity
+
+ Holds the entity against which we should compare the distance to.
+*/
+
+/*!
+ \property Qt3DRender::QProximityFilter::distanceThreshold
+
+ Holds the distance to the target entity above which entities are filtered
+ out.
+*/
+
+/*!
+ \qmltype ProximityFilter
+ \instantiates Qt3DRender::QProximityFilter
+ \inherits FrameGraphNode
+ \inqmlmodule Qt3D.Render
+ \since 5.10
+
+ \brief Select entities which are within a distance threshold of a target
+ entity.
+
+ A \l ProximityFilter can be used to select entities to render
+ when they are placed within a given distance threshold of another entity.
+
+ \badcode
+ import Qt3DRender 2.10
+ ...
+ RenderSetting {
+ Viewport {
+ CameraSelector {
+ camera: mainCamera
+ ProximityFilter {
+ entity: mainCamera
+ distanceThreshold: 50 // select entities within 50m metre radius of mainCamera
+ }
+ }
+ }
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty Entity Qt3D.Render::ProximityFilter::entity
+
+ Holds the entity against which we should compare the distance to.
+ */
+
+/*!
+ \qmlproperty real Qt3D.Render::ProximityFilter::distanceThreshold
+
+ Holds the distance to the target entity above which entities are filtered
+ out.
+ */
+
+
+QProximityFilter::QProximityFilter(Qt3DCore::QNode *parent)
+ : QFrameGraphNode(*new QProximityFilterPrivate, parent)
+{
+
+}
+
+/*! \internal */
+QProximityFilter::QProximityFilter(QProximityFilterPrivate &dd, QNode *parent)
+ : QFrameGraphNode(dd, parent)
+{
+}
+
+/*! \internal */
+QProximityFilter::~QProximityFilter()
+{
+}
+
+Qt3DCore::QEntity *QProximityFilter::entity() const
+{
+ Q_D(const QProximityFilter);
+ return d->m_entity;
+}
+
+float QProximityFilter::distanceThreshold() const
+{
+ Q_D(const QProximityFilter);
+ return d->m_distanceThreshold;
+}
+
+void QProximityFilter::setEntity(Qt3DCore::QEntity *entity)
+{
+ Q_D(QProximityFilter);
+ if (d->m_entity != entity) {
+
+ if (d->m_entity)
+ d->unregisterDestructionHelper(d->m_entity);
+
+ if (entity && !entity->parent())
+ entity->setParent(this);
+
+ d->m_entity = entity;
+
+ if (d->m_entity)
+ d->registerDestructionHelper(d->m_entity, &QProximityFilter::setEntity, d->m_entity);
+
+ emit entityChanged(entity);
+ }
+}
+
+void QProximityFilter::setDistanceThreshold(float distanceThreshold)
+{
+ Q_D(QProximityFilter);
+ if (d->m_distanceThreshold == distanceThreshold)
+ return;
+
+ d->m_distanceThreshold = distanceThreshold;
+ emit distanceThresholdChanged(distanceThreshold);
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QProximityFilter::createNodeCreationChange() const
+{
+ auto creationChange = QFrameGraphNodeCreatedChangePtr<QProximityFilterData>::create(this);
+ QProximityFilterData &data = creationChange->data;
+ Q_D(const QProximityFilter);
+ data.entityId = Qt3DCore::qIdForNode(d->m_entity);
+ data.distanceThreshold = d->m_distanceThreshold;
+ return creationChange;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qproximityfilter.h b/src/render/framegraph/qproximityfilter.h
new file mode 100644
index 000000000..0fbe624a1
--- /dev/null
+++ b/src/render/framegraph/qproximityfilter.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QPROXIMITYFILTER_H
+#define QT3DRENDER_QPROXIMITYFILTER_H
+
+#include <Qt3DRender/qframegraphnode.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QProximityFilterPrivate;
+
+class QT3DRENDERSHARED_EXPORT QProximityFilter : public QFrameGraphNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DCore::QEntity *entity READ entity WRITE setEntity NOTIFY entityChanged)
+ Q_PROPERTY(float distanceThreshold READ distanceThreshold WRITE setDistanceThreshold NOTIFY distanceThresholdChanged)
+
+public:
+ explicit QProximityFilter(Qt3DCore::QNode *parent = nullptr);
+ ~QProximityFilter();
+
+ Qt3DCore::QEntity *entity() const;
+ float distanceThreshold() const;
+
+public Q_SLOTS:
+ void setEntity(Qt3DCore::QEntity *entity);
+ void setDistanceThreshold(float distanceThreshold);
+
+Q_SIGNALS:
+ void entityChanged(Qt3DCore::QEntity *entity);
+ void distanceThresholdChanged(float distanceThreshold);
+
+protected:
+ explicit QProximityFilter(QProximityFilterPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QProximityFilter)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QPROXIMITYFILTER_H
diff --git a/src/render/framegraph/qproximityfilter_p.h b/src/render/framegraph/qproximityfilter_p.h
new file mode 100644
index 000000000..8f8bba800
--- /dev/null
+++ b/src/render/framegraph/qproximityfilter_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QPROXIMITYFILTER_P_H
+#define QT3DRENDER_QPROXIMITYFILTER_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 <Qt3DRender/qproximityfilter.h>
+#include <Qt3DRender/private/qframegraphnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QProximityFilterPrivate : public QFrameGraphNodePrivate
+{
+public:
+ QProximityFilterPrivate();
+
+ Q_DECLARE_PUBLIC(QProximityFilter)
+
+ Qt3DCore::QEntity *m_entity;
+ float m_distanceThreshold;
+};
+
+struct QProximityFilterData
+{
+ Qt3DCore::QNodeId entityId;
+ float distanceThreshold;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QPROXIMITYFILTER_P_H
diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp
index 8ae97b8f0..28bc41b91 100644
--- a/src/render/framegraph/qrendercapture.cpp
+++ b/src/render/framegraph/qrendercapture.cpp
@@ -149,6 +149,15 @@ namespace Qt3DRender {
*/
/*!
+ * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(Rect rect)
+ *
+ * Used to request render capture from a specified \a rect. Only one render capture
+ * result is produced per requestCapture call even if the frame graph has multiple leaf nodes.
+ * The function returns a QRenderCaptureReply object, which receives the captured image
+ * when it is done. The user is responsible for deallocating the returned object.
+ */
+
+/*!
* \internal
*/
QRenderCaptureReplyPrivate::QRenderCaptureReplyPrivate()
@@ -322,19 +331,20 @@ QRenderCaptureReply *QRenderCapture::requestCapture(int captureId)
Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id()));
change->setPropertyName(QByteArrayLiteral("renderCaptureRequest"));
- change->setValue(QVariant::fromValue(captureId));
+ const QRenderCaptureRequest request = { captureId, QRect() };
+ change->setValue(QVariant::fromValue(request));
d->notifyObservers(change);
return reply;
}
/*!
- * Used to request render capture. Only one render capture result is produced per
- * requestCapture call even if the frame graph has multiple leaf nodes.
+ * Used to request render capture from a specified \a rect. Only one render capture result
+ * is produced per requestCapture call even if the frame graph has multiple leaf nodes.
* The function returns a QRenderCaptureReply object, which receives the captured image
* when it is done. The user is responsible for deallocating the returned object.
*/
-QRenderCaptureReply *QRenderCapture::requestCapture()
+QRenderCaptureReply *QRenderCapture::requestCapture(const QRect &rect)
{
Q_D(QRenderCapture);
static int captureId = 1;
@@ -346,7 +356,8 @@ QRenderCaptureReply *QRenderCapture::requestCapture()
Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id()));
change->setPropertyName(QByteArrayLiteral("renderCaptureRequest"));
- change->setValue(QVariant::fromValue(captureId));
+ const QRenderCaptureRequest request = { captureId, rect };
+ change->setValue(QVariant::fromValue(request));
d->notifyObservers(change);
captureId++;
@@ -355,6 +366,17 @@ QRenderCaptureReply *QRenderCapture::requestCapture()
}
/*!
+ * Used to request render capture. Only one render capture result is produced per
+ * requestCapture call even if the frame graph has multiple leaf nodes.
+ * The function returns a QRenderCaptureReply object, which receives the captured image
+ * when it is done. The user is responsible for deallocating the returned object.
+ */
+Qt3DRender::QRenderCaptureReply *QRenderCapture::requestCapture()
+{
+ return requestCapture(QRect());
+}
+
+/*!
* \internal
*/
void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
diff --git a/src/render/framegraph/qrendercapture.h b/src/render/framegraph/qrendercapture.h
index 5b768b593..b3545a8ec 100644
--- a/src/render/framegraph/qrendercapture.h
+++ b/src/render/framegraph/qrendercapture.h
@@ -84,9 +84,10 @@ class QT3DRENDERSHARED_EXPORT QRenderCapture : public QFrameGraphNode
public:
explicit QRenderCapture(Qt3DCore::QNode *parent = nullptr);
- Q_INVOKABLE Q_DECL_DEPRECATED_X("Use the overload with no parameter")
+ Q_INVOKABLE Q_DECL_DEPRECATED_X("Use the overload with no id parameter")
Qt3DRender::QRenderCaptureReply *requestCapture(int captureId);
Q_REVISION(9) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture();
+ Q_REVISION(10) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(const QRect &rect);
protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
diff --git a/src/render/framegraph/qrendercapture_p.h b/src/render/framegraph/qrendercapture_p.h
index c8253947d..4e509cc59 100644
--- a/src/render/framegraph/qrendercapture_p.h
+++ b/src/render/framegraph/qrendercapture_p.h
@@ -100,10 +100,17 @@ struct RenderCaptureData
typedef QSharedPointer<RenderCaptureData> RenderCaptureDataPtr;
+struct QRenderCaptureRequest
+{
+ int captureId;
+ QRect rect;
+};
+
} // Qt3DRender
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Qt3DRender::RenderCaptureDataPtr) // LCOV_EXCL_LINE
+Q_DECLARE_METATYPE(Qt3DRender::QRenderCaptureRequest); // LCOV_EXCL_LINE
#endif // QRENDERCAPTURE_P_H
diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp
index 52319fa41..d25a01b1f 100644
--- a/src/render/framegraph/rendercapture.cpp
+++ b/src/render/framegraph/rendercapture.cpp
@@ -50,23 +50,24 @@ RenderCapture::RenderCapture()
}
-// called by aspect thread
-void RenderCapture::requestCapture(int captureId)
+void RenderCapture::requestCapture(const QRenderCaptureRequest &request)
{
QMutexLocker lock(&m_mutex);
- m_requestedCaptures.push_back(captureId);
+ m_requestedCaptures.push_back(request);
}
+// called by render view initializer job
bool RenderCapture::wasCaptureRequested() const
{
QMutexLocker lock(&m_mutex);
return m_requestedCaptures.size() > 0 && isEnabled();
}
-void RenderCapture::acknowledgeCaptureRequest()
+// called by render view initializer job
+QRenderCaptureRequest RenderCapture::takeCaptureRequest()
{
- QMutexLocker lock(&m_mutex);
- m_acknowledgedCaptures.push_back(m_requestedCaptures.takeFirst());
+ Q_ASSERT(!m_requestedCaptures.isEmpty());
+ return m_requestedCaptures.takeFirst();
}
void RenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -74,18 +75,18 @@ void RenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (e->type() == Qt3DCore::PropertyUpdated) {
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureRequest")) {
- requestCapture(propertyChange->value().toInt());
+ requestCapture(propertyChange->value().value<QRenderCaptureRequest>());
}
}
FrameGraphNode::sceneChangeEvent(e);
}
// called by render thread
-void RenderCapture::addRenderCapture(const QImage &image)
+void RenderCapture::addRenderCapture(int captureId, const QImage &image)
{
QMutexLocker lock(&m_mutex);
auto data = RenderCaptureDataPtr::create();
- data.data()->captureId = m_acknowledgedCaptures.takeFirst();
+ data.data()->captureId = captureId;
data.data()->image = image;
m_renderCaptureData.push_back(data);
}
diff --git a/src/render/framegraph/rendercapture_p.h b/src/render/framegraph/rendercapture_p.h
index 7a759e5b8..8c9f4a31d 100644
--- a/src/render/framegraph/rendercapture_p.h
+++ b/src/render/framegraph/rendercapture_p.h
@@ -62,10 +62,10 @@ class Q_AUTOTEST_EXPORT RenderCapture : public FrameGraphNode
public:
RenderCapture();
- void requestCapture(int captureId);
+ void requestCapture(const QRenderCaptureRequest &request);
bool wasCaptureRequested() const;
- void acknowledgeCaptureRequest();
- void addRenderCapture(const QImage &image);
+ QRenderCaptureRequest takeCaptureRequest();
+ void addRenderCapture(int captureId, const QImage &image);
void sendRenderCaptures();
protected:
@@ -73,8 +73,7 @@ protected:
private:
- QVector<int> m_requestedCaptures;
- QVector<int> m_acknowledgedCaptures;
+ QVector<QRenderCaptureRequest> m_requestedCaptures;
QVector<RenderCaptureDataPtr> m_renderCaptureData;
mutable QMutex m_mutex;
};
diff --git a/src/render/framegraph/viewportnode_p.h b/src/render/framegraph/viewportnode_p.h
index 85003ff36..18adc3f0c 100644
--- a/src/render/framegraph/viewportnode_p.h
+++ b/src/render/framegraph/viewportnode_p.h
@@ -64,7 +64,7 @@ namespace Render {
class Renderer;
-class ViewportNode : public FrameGraphNode
+class Q_AUTOTEST_EXPORT ViewportNode : public FrameGraphNode
{
public:
ViewportNode();
diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp
index 38fda277f..13d689e0e 100644
--- a/src/render/frontend/qcamera.cpp
+++ b/src/render/frontend/qcamera.cpp
@@ -40,6 +40,8 @@
#include "qcamera.h"
#include "qcamera_p.h"
+#include <QtMath>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -199,6 +201,36 @@ QCameraPrivate::QCameraPrivate()
*/
/*!
+ * \qmlmethod void Qt3D.Render::Camera::viewAll()
+ *
+ * Rotates and moves the camera so that it's viewCenter is the center of the scene's bounding volume
+ * and the entire scene fits in the view port.
+ *
+ * \note Only works if the lens is in perspective projection mode.
+ * \sa Qt3D.Render::Camera::projectionType
+ */
+
+/*!
+ * \qmlmethod void Qt3D.Render::Camera::viewEntity(Entity entity)
+ *
+ * Rotates and moves the camera so that it's viewCenter is the center of the entity's bounding volume
+ * and the entire entity fits in the view port.
+ *
+ * \note Only works if the lens is in perspective projection mode.
+ * \sa Qt3D.Render::Camera::projectionType
+ */
+
+/*!
+ * \qmlmethod void Qt3D.Render::Camera::viewSphere(vector3d center, real radius)
+ *
+ * Rotates and moves the camera so that it's viewCenter is \a center
+ * and a sphere of \a radius fits in the view port.
+ *
+ * \note Only works if the lens is in perspective projection mode.
+ * \sa Qt3D.Render::Camera::projectionType
+ */
+
+/*!
* \qmlproperty enumeration Qt3D.Render::Camera::projectionType
*
* Holds the type of the camera projection.
@@ -393,6 +425,7 @@ QCamera::QCamera(Qt3DCore::QNode *parent)
QObject::connect(d_func()->m_lens, SIGNAL(topChanged(float)), this, SIGNAL(topChanged(float)));
QObject::connect(d_func()->m_lens, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)), this, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)));
QObject::connect(d_func()->m_lens, SIGNAL(exposureChanged(float)), this, SIGNAL(exposureChanged(float)));
+ QObject::connect(d_func()->m_lens, &QCameraLens::viewSphere, this, &QCamera::viewSphere);
QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(viewMatrixChanged()));
addComponent(d_func()->m_lens);
addComponent(d_func()->m_transform);
@@ -421,6 +454,7 @@ QCamera::QCamera(QCameraPrivate &dd, Qt3DCore::QNode *parent)
QObject::connect(d_func()->m_lens, SIGNAL(bottomChanged(float)), this, SIGNAL(bottomChanged(float)));
QObject::connect(d_func()->m_lens, SIGNAL(topChanged(float)), this, SIGNAL(topChanged(float)));
QObject::connect(d_func()->m_lens, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)), this, SIGNAL(projectionMatrixChanged(const QMatrix4x4 &)));
+ QObject::connect(d_func()->m_lens, &QCameraLens::viewSphere, this, &QCamera::viewSphere);
QObject::connect(d_func()->m_transform, SIGNAL(matrixChanged()), this, SIGNAL(viewMatrixChanged()));
addComponent(d_func()->m_lens);
addComponent(d_func()->m_transform);
@@ -636,6 +670,54 @@ void QCamera::rotateAboutViewCenter(const QQuaternion& q)
}
/*!
+ * Rotates and moves the camera so that it's viewCenter is the center of the scene's bounding volume
+ * and the entire scene fits in the view port.
+ *
+ * \note Only works if the lens is in perspective projection mode.
+ * \sa Qt3D.Render::Camera::projectionType
+ */
+void QCamera::viewAll()
+{
+ Q_D(QCamera);
+ d->m_lens->viewAll(id());
+}
+
+/*!
+ * Rotates and moves the camera so that it's viewCenter is \a center
+ * and a sphere of \a radius fits in the view port.
+ *
+ * \note Only works if the lens is in perspective projection mode.
+ * \sa Qt3D.Render::Camera::projectionType
+ */
+void QCamera::viewSphere(const QVector3D &center, float radius)
+{
+ Q_D(QCamera);
+ if (d->m_lens->projectionType() != QCameraLens::PerspectiveProjection || radius <= 0.f)
+ return;
+ double dist = radius / std::tan(qDegreesToRadians(d->m_lens->fieldOfView()) / 2.0f);
+ QVector3D dir = (d->m_viewCenter - d->m_position).normalized();
+ QVector3D newPos = center - (dir * dist);
+ setViewCenter(center);
+ setPosition(newPos);
+}
+
+/*!
+ * Rotates and moves the camera so that it's viewCenter is the center of the entity's bounding volume
+ * and the entire entity fits in the view port.
+ *
+ * \note Only works if the lens is in perspective projection mode.
+ * \sa Qt3D.Render::Camera::projectionType
+ */
+void QCamera::viewEntity(Qt3DCore::QEntity *entity)
+{
+ if (!entity)
+ return;
+
+ Q_D(QCamera);
+ d->m_lens->viewEntity(entity->id(), id());
+}
+
+/*!
* Sets the camera's projection type to \a type.
*/
void QCamera::setProjectionType(QCameraLens::ProjectionType type)
diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h
index dd7c63778..5c86ea122 100644
--- a/src/render/frontend/qcamera.h
+++ b/src/render/frontend/qcamera.h
@@ -150,6 +150,10 @@ public Q_SLOTS:
void setUpVector(const QVector3D &upVector);
void setViewCenter(const QVector3D &viewCenter);
+ void viewAll();
+ void viewSphere(const QVector3D &center, float radius);
+ void viewEntity(Qt3DCore::QEntity *entity);
+
Q_SIGNALS:
void projectionTypeChanged(QCameraLens::ProjectionType projectionType);
void nearPlaneChanged(float nearPlane);
diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp
index 3c6b8db68..c9be49484 100644
--- a/src/render/frontend/qcameralens.cpp
+++ b/src/render/frontend/qcameralens.cpp
@@ -224,6 +224,43 @@ QCameraLensPrivate::QCameraLensPrivate()
{
}
+void QCameraLens::viewAll(Qt3DCore::QNodeId cameraId)
+{
+ Q_D(QCameraLens);
+ if (d->m_projectionType == PerspectiveProjection) {
+ QVariant v;
+ v.setValue(cameraId);
+ d->m_pendingViewAllCommand = sendCommand(QLatin1Literal("QueryRootBoundingVolume"), v);
+ }
+}
+
+void QCameraLens::viewEntity(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId cameraId)
+{
+ Q_D(QCameraLens);
+ if (d->m_projectionType == PerspectiveProjection) {
+ QVector<Qt3DCore::QNodeId> ids = {entityId, cameraId};
+ QVariant v;
+ v.setValue(ids);
+ d->m_pendingViewAllCommand = sendCommand(QLatin1Literal("QueryEntityBoundingVolume"), v);
+ }
+}
+
+void QCameraLensPrivate::processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId,
+ const QVariant &data)
+{
+ Q_Q(QCameraLens);
+ if (m_pendingViewAllCommand != commandId)
+ return;
+
+ QVector<float> boundingVolumeData = data.value< QVector<float> >();
+ if (boundingVolumeData.size() != 4)
+ return;
+ QVector3D center(boundingVolumeData[0], boundingVolumeData[1], boundingVolumeData[2]);
+ float radius = boundingVolumeData[3];
+ Q_EMIT q->viewSphere(center, radius);
+ m_pendingViewAllCommand = Qt3DCore::QNodeCommand::CommandId();
+}
+
/*!
* Constructs a QCameraLens with given \a parent
*/
@@ -593,6 +630,22 @@ Qt3DCore::QNodeCreatedChangeBasePtr QCameraLens::createNodeCreationChange() cons
return creationChange;
}
+void QCameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ Q_D(QCameraLens);
+ switch (change->type()) {
+ case Qt3DCore::CommandRequested: {
+ Qt3DCore::QNodeCommandPtr command = qSharedPointerCast<Qt3DCore::QNodeCommand>(change);
+
+ if (command->name() == QLatin1Literal("ViewAll"))
+ d->processViewAllCommand(command->inReplyTo(), command->data());
+ }
+ break;
+ default:
+ break;
+ }
+}
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qcameralens.h b/src/render/frontend/qcameralens.h
index fdb0d5868..0cd22e348 100644
--- a/src/render/frontend/qcameralens.h
+++ b/src/render/frontend/qcameralens.h
@@ -105,6 +105,9 @@ public:
float exposure() const;
+ void viewAll(Qt3DCore::QNodeId cameraId);
+ void viewEntity(Qt3DCore::QNodeId entityId, Qt3DCore::QNodeId cameraId);
+
public Q_SLOTS:
void setProjectionType(ProjectionType projectionType);
void setNearPlane(float nearPlane);
@@ -130,6 +133,7 @@ Q_SIGNALS:
void topChanged(float top);
void projectionMatrixChanged(const QMatrix4x4 &projectionMatrix);
void exposureChanged(float exposure);
+ void viewSphere(const QVector3D &center, float radius);
protected:
explicit QCameraLens(QCameraLensPrivate &dd, QNode *parent = nullptr);
@@ -137,6 +141,7 @@ protected:
private:
Q_DECLARE_PRIVATE(QCameraLens)
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
};
} // Qt3DRender
diff --git a/src/render/frontend/qcameralens_p.h b/src/render/frontend/qcameralens_p.h
index e79645b3c..0ec197945 100644
--- a/src/render/frontend/qcameralens_p.h
+++ b/src/render/frontend/qcameralens_p.h
@@ -51,8 +51,10 @@
// We mean it.
//
-#include <Qt3DCore/private/qcomponent_p.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <Qt3DCore/private/qcomponent_p.h>
+#include <Qt3DCore/private/qnodecommand_p.h>
+
#include "qcameralens.h"
#include <Qt3DCore/qpropertyupdatedchange.h>
@@ -104,6 +106,9 @@ public:
float m_exposure;
+ Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
+ void processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, const QVariant &data);
+
private:
inline void updatePerpectiveProjection()
{
diff --git a/src/render/frontend/qitemmodelbuffer.cpp b/src/render/frontend/qitemmodelbuffer.cpp
index 3941ac2fd..82215204a 100644
--- a/src/render/frontend/qitemmodelbuffer.cpp
+++ b/src/render/frontend/qitemmodelbuffer.cpp
@@ -223,7 +223,7 @@ QBuffer *QItemModelBuffer::buffer()
m_attributes.clear();
m_itemStride = 0;
- m_buffer = new QBuffer(QBuffer::VertexBuffer);
+ m_buffer = new QBuffer;
// assume model will change
m_buffer->setUsage(QBuffer::DynamicDraw);
diff --git a/src/render/frontend/qlayer.cpp b/src/render/frontend/qlayer.cpp
index cd7d92caf..416525360 100644
--- a/src/render/frontend/qlayer.cpp
+++ b/src/render/frontend/qlayer.cpp
@@ -46,6 +46,7 @@ namespace Qt3DRender {
QLayerPrivate::QLayerPrivate()
: QComponentPrivate()
+ , m_recursive(false)
{
}
@@ -58,7 +59,7 @@ QLayerPrivate::QLayerPrivate()
Qt3DRender::QLayer works in conjunction with the Qt3DRender::QLayerFilter in the FrameGraph.
\sa Qt3DRender::QLayerFilter
- Qt3DRender::QLayer doesn't define any new properties but is supposed to only be referenced.
+ A QLayer can be applied to a subtree of entities by setting the recursive property to true.
\code
#include <Qt3DCore/QEntity>
@@ -73,6 +74,7 @@ QLayerPrivate::QLayerPrivate()
Qt3DCore::QEntity *renderableEntity = new Qt3DCore::Qt3DCore::QEntity(rootEntity);
Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DCore::QGeometryRenderer(renderableEntity);
Qt3DRender::QLayer *layer1 = new Qt3DCore::QLayer(renderableEntity);
+ layer1->setRecursive(true);
renderableEntity->addComponent(geometryRenderer);
renderableEntity->addComponent(layer1);
@@ -86,6 +88,10 @@ QLayerPrivate::QLayerPrivate()
...
\endcode
*/
+/*!
+ \property QLayer::recursive
+ Specifies if the layer is also applied to the entity subtree.
+*/
/*!
\qmltype Layer
@@ -98,7 +104,7 @@ QLayerPrivate::QLayerPrivate()
Layer works in conjunction with the LayerFilter in the FrameGraph.
- Layer doesn't define any new properties but is supposed to only be referenced.
+ A Layer can be applied to a subtree of entities by setting the recursive property to true.
\code
import Qt3D.Core 2.0
@@ -125,7 +131,10 @@ QLayerPrivate::QLayerPrivate()
// Scene
Camera { id: mainCamera }
- Layer { id: layer1 }
+ Layer {
+ id: layer1
+ recursive: true
+ }
GeometryRenderer { id: mesh }
@@ -137,6 +146,12 @@ QLayerPrivate::QLayerPrivate()
\endcode
*/
+/*!
+ \qmlproperty bool Layer::recursive
+
+ Specifies if the layer is also applied to the entity subtree.
+*/
+
/*! \fn Qt3DRender::QLayer::QLayer(Qt3DCore::QNode *parent)
Constructs a new QLayer with the specified \a parent.
*/
@@ -151,12 +166,36 @@ QLayer::~QLayer()
{
}
+bool QLayer::recursive() const
+{
+ Q_D(const QLayer);
+ return d->m_recursive;
+}
+
+void QLayer::setRecursive(bool recursive)
+{
+ Q_D(QLayer);
+ if (d->m_recursive != recursive) {
+ d->m_recursive = recursive;
+ emit recursiveChanged();
+ }
+}
+
/*! \internal */
QLayer::QLayer(QLayerPrivate &dd, QNode *parent)
: QComponent(dd, parent)
{
}
+Qt3DCore::QNodeCreatedChangeBasePtr QLayer::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QLayerData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QLayer);
+ data.m_recursive = d->m_recursive;
+ return creationChange;
+}
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qlayer.h b/src/render/frontend/qlayer.h
index f44685d7e..c57a6fe03 100644
--- a/src/render/frontend/qlayer.h
+++ b/src/render/frontend/qlayer.h
@@ -53,15 +53,23 @@ class QLayerPrivate;
class QT3DRENDERSHARED_EXPORT QLayer : public Qt3DCore::QComponent
{
Q_OBJECT
+ Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
public:
explicit QLayer(Qt3DCore::QNode *parent = nullptr);
~QLayer();
+ bool recursive() const;
+ void setRecursive(bool recursive);
+
+Q_SIGNALS:
+ void recursiveChanged();
+
protected:
explicit QLayer(QLayerPrivate &dd, Qt3DCore::QNode *parent = nullptr);
private:
Q_DECLARE_PRIVATE(QLayer)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const;
};
} // namespace Qt3DRender
diff --git a/src/render/frontend/qlayer_p.h b/src/render/frontend/qlayer_p.h
index 998dcce86..1c01955f7 100644
--- a/src/render/frontend/qlayer_p.h
+++ b/src/render/frontend/qlayer_p.h
@@ -64,9 +64,15 @@ class QT3DRENDERSHARED_PRIVATE_EXPORT QLayerPrivate : public Qt3DCore::QComponen
public:
QLayerPrivate();
+ bool m_recursive;
+
Q_DECLARE_PUBLIC(QLayer)
};
+struct QLayerData {
+ bool m_recursive;
+};
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp
index 1cda638cb..b24d0b7d0 100644
--- a/src/render/frontend/qpickingsettings.cpp
+++ b/src/render/frontend/qpickingsettings.cpp
@@ -81,6 +81,7 @@ QPickingSettingsPrivate::QPickingSettingsPrivate()
, m_pickMethod(QPickingSettings::BoundingVolumePicking)
, m_pickResultMode(QPickingSettings::NearestPick)
, m_faceOrientationPickingMode(QPickingSettings::FrontFace)
+ , m_worldSpaceTolerance(.1f)
{
}
@@ -121,6 +122,15 @@ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPi
}
/*!
+ * \return the line and point precision worldSpaceTolerance
+ */
+float QPickingSettings::worldSpaceTolerance() const
+{
+ Q_D(const QPickingSettings);
+ return d->m_worldSpaceTolerance;
+}
+
+/*!
* \enum Qt3DRender::QPickingSettings::PickMethod
*
* Specifies the picking method.
@@ -247,6 +257,29 @@ void QPickingSettings::setFaceOrientationPickingMode(QPickingSettings::FaceOrien
emit faceOrientationPickingModeChanged(faceOrientationPickingMode);
}
+/*!
+ \qmlproperty qreal worldSpaceTolerance
+
+ Holds the threshold, in model space coordinates, used to evaluate line and point picking.
+*/
+/*!
+ \property QPickingSettings::worldSpaceTolerance
+
+ Holds the threshold, in model space coordinates, used to evaluate line and point picking.
+*/
+/*!
+ * Set the threshold used for line and point picking
+ */
+void QPickingSettings::setWorldSpaceTolerance(float worldSpaceTolerance)
+{
+ Q_D(QPickingSettings);
+ if (qFuzzyCompare(worldSpaceTolerance, d->m_worldSpaceTolerance))
+ return;
+
+ d->m_worldSpaceTolerance = worldSpaceTolerance;
+ emit worldSpaceToleranceChanged(worldSpaceTolerance);
+}
+
} // namespace Qt3Drender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qpickingsettings.h b/src/render/frontend/qpickingsettings.h
index 655bf952a..9c8a2c856 100644
--- a/src/render/frontend/qpickingsettings.h
+++ b/src/render/frontend/qpickingsettings.h
@@ -57,14 +57,17 @@ class QT3DRENDERSHARED_EXPORT QPickingSettings : public Qt3DCore::QNode
Q_PROPERTY(PickMethod pickMethod READ pickMethod WRITE setPickMethod NOTIFY pickMethodChanged)
Q_PROPERTY(PickResultMode pickResultMode READ pickResultMode WRITE setPickResultMode NOTIFY pickResultModeChanged)
Q_PROPERTY(FaceOrientationPickingMode faceOrientationPickingMode READ faceOrientationPickingMode WRITE setFaceOrientationPickingMode NOTIFY faceOrientationPickingModeChanged)
-
+ Q_PROPERTY(float worldSpaceTolerance READ worldSpaceTolerance WRITE setWorldSpaceTolerance NOTIFY worldSpaceToleranceChanged REVISION 10)
public:
explicit QPickingSettings(Qt3DCore::QNode *parent = nullptr);
~QPickingSettings();
enum PickMethod {
- BoundingVolumePicking,
- TrianglePicking
+ BoundingVolumePicking = 0x00,
+ TrianglePicking = 0x01,
+ LinePicking = 0x02,
+ PointPicking = 0x04,
+ PrimitivePicking = TrianglePicking | LinePicking | PointPicking
};
Q_ENUM(PickMethod) // LCOV_EXCL_LINE
@@ -84,16 +87,19 @@ public:
PickMethod pickMethod() const;
PickResultMode pickResultMode() const;
FaceOrientationPickingMode faceOrientationPickingMode() const;
+ float worldSpaceTolerance() const;
public Q_SLOTS:
void setPickMethod(PickMethod pickMethod);
void setPickResultMode(PickResultMode pickResultMode);
void setFaceOrientationPickingMode(FaceOrientationPickingMode faceOrientationPickingMode);
+ void setWorldSpaceTolerance(float worldSpaceTolerance);
Q_SIGNALS:
void pickMethodChanged(QPickingSettings::PickMethod pickMethod);
void pickResultModeChanged(QPickingSettings::PickResultMode pickResult);
void faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode);
+ void worldSpaceToleranceChanged(float worldSpaceTolerance);
protected:
Q_DECLARE_PRIVATE(QPickingSettings)
diff --git a/src/render/frontend/qpickingsettings_p.h b/src/render/frontend/qpickingsettings_p.h
index 7928597c8..780a8b677 100644
--- a/src/render/frontend/qpickingsettings_p.h
+++ b/src/render/frontend/qpickingsettings_p.h
@@ -67,6 +67,7 @@ public:
QPickingSettings::PickMethod m_pickMethod;
QPickingSettings::PickResultMode m_pickResultMode;
QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode;
+ float m_worldSpaceTolerance;
};
} // namespace Qt3Drender
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index 3c2b36d85..10ce15108 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -83,9 +83,16 @@
#include <Qt3DRender/qrendercapture.h>
#include <Qt3DRender/qbuffercapture.h>
#include <Qt3DRender/qmemorybarrier.h>
+#include <Qt3DRender/qproximityfilter.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
+#include <Qt3DRender/qblitframebuffer.h>
+#include <Qt3DCore/qarmature.h>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qskeletonloader.h>
#include <Qt3DRender/private/cameraselectornode_p.h>
#include <Qt3DRender/private/layerfilternode_p.h>
+#include <Qt3DRender/private/cameralens_p.h>
#include <Qt3DRender/private/filterkey_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/renderer_p.h>
@@ -133,6 +140,13 @@
#include <Qt3DRender/private/technique_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DRender/private/memorybarrier_p.h>
+#include <Qt3DRender/private/shaderbuilder_p.h>
+#include <Qt3DRender/private/blitframebuffer_p.h>
+#include <Qt3DRender/private/armature_p.h>
+#include <Qt3DRender/private/skeleton_p.h>
+#include <Qt3DRender/private/joint_p.h>
+#include <Qt3DRender/private/loadskeletonjob_p.h>
+#include <Qt3DRender/private/proximityfilter_p.h>
#include <private/qrenderpluginfactory_p.h>
#include <private/qrenderplugin_p.h>
@@ -141,6 +155,7 @@
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/QAspectEngine>
#include <Qt3DCore/private/qservicelocator_p.h>
#include <QDebug>
@@ -188,6 +203,17 @@ QRenderAspectPrivate::~QRenderAspectPrivate()
qDeleteAll(m_sceneImporter);
}
+QRenderAspectPrivate *QRenderAspectPrivate::findPrivate(Qt3DCore::QAspectEngine *engine)
+{
+ const QVector<QAbstractAspect*> aspects = engine->aspects();
+ for (QAbstractAspect* aspect : aspects) {
+ QRenderAspect *renderAspect = qobject_cast<QRenderAspect *>(aspect);
+ if (renderAspect)
+ return static_cast<QRenderAspectPrivate *>(renderAspect->d_ptr.data());
+ }
+ return nullptr;
+}
+
/*! \internal */
void QRenderAspectPrivate::registerBackendTypes()
{
@@ -197,11 +223,13 @@ void QRenderAspectPrivate::registerBackendTypes()
qRegisterMetaType<Qt3DRender::QEffect*>();
qRegisterMetaType<Qt3DRender::QFrameGraphNode *>();
qRegisterMetaType<Qt3DRender::QCamera*>();
+ qRegisterMetaType<Qt3DRender::QShaderProgram*>();
+ qRegisterMetaType<Qt3DCore::QJoint*>();
q->registerBackendType<Qt3DCore::QEntity>(QSharedPointer<Render::RenderEntityFunctor>::create(m_renderer, m_nodeManagers));
q->registerBackendType<Qt3DCore::QTransform>(QSharedPointer<Render::NodeFunctor<Render::Transform, Render::TransformManager> >::create(m_renderer));
- q->registerBackendType<Qt3DRender::QCameraLens>(QSharedPointer<Render::NodeFunctor<Render::CameraLens, Render::CameraManager> >::create(m_renderer));
+ q->registerBackendType<Qt3DRender::QCameraLens>(QSharedPointer<Render::CameraLensFunctor>::create(m_renderer, q));
q->registerBackendType<QLayer>(QSharedPointer<Render::NodeFunctor<Render::Layer, Render::LayerManager> >::create(m_renderer));
q->registerBackendType<QLevelOfDetail>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
q->registerBackendType<QLevelOfDetailSwitch>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
@@ -217,6 +245,9 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QComputeCommand>(QSharedPointer<Render::NodeFunctor<Render::ComputeCommand, Render::ComputeCommandManager> >::create(m_renderer));
q->registerBackendType<QGeometry>(QSharedPointer<Render::NodeFunctor<Render::Geometry, Render::GeometryManager> >::create(m_renderer));
q->registerBackendType<QGeometryRenderer>(QSharedPointer<Render::GeometryRendererFunctor>::create(m_renderer, m_nodeManagers->geometryRendererManager()));
+ q->registerBackendType<Qt3DCore::QArmature>(QSharedPointer<Render::NodeFunctor<Render::Armature, Render::ArmatureManager>>::create(m_renderer));
+ q->registerBackendType<Qt3DCore::QSkeletonLoader>(QSharedPointer<Render::SkeletonFunctor>::create(m_renderer, m_nodeManagers->skeletonManager(), m_nodeManagers->jointManager()));
+ q->registerBackendType<Qt3DCore::QJoint>(QSharedPointer<Render::JointFunctor>::create(m_renderer, m_nodeManagers->jointManager(), m_nodeManagers->skeletonManager()));
// Textures
q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager()));
@@ -232,6 +263,7 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QRenderPass>(QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(m_renderer));
q->registerBackendType<QShaderData>(QSharedPointer<Render::RenderShaderDataFunctor>::create(m_renderer, m_nodeManagers));
q->registerBackendType<QShaderProgram>(QSharedPointer<Render::NodeFunctor<Render::Shader, Render::ShaderManager> >::create(m_renderer));
+ q->registerBackendType<QShaderProgramBuilder>(QSharedPointer<Render::NodeFunctor<Render::ShaderBuilder, Render::ShaderBuilderManager> >::create(m_renderer));
q->registerBackendType<QTechnique>(QSharedPointer<Render::TechniqueFunctor>::create(m_renderer, m_nodeManagers));
// Framegraph
@@ -252,6 +284,8 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QRenderCapture>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::RenderCapture, QRenderCapture> >::create(m_renderer));
q->registerBackendType<QBufferCapture>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BufferCapture, QBufferCapture> >::create(m_renderer));
q->registerBackendType<QMemoryBarrier>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::MemoryBarrier, QMemoryBarrier> >::create(m_renderer));
+ q->registerBackendType<QProximityFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ProximityFilter, QProximityFilter> >::create(m_renderer));
+ q->registerBackendType<QBlitFramebuffer>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::BlitFramebuffer, QBlitFramebuffer> >::create(m_renderer));
// Picking
q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer));
@@ -297,6 +331,7 @@ void QRenderAspectPrivate::unregisterBackendTypes()
unregisterBackendType<QRenderPass>();
unregisterBackendType<QShaderData>();
unregisterBackendType<QShaderProgram>();
+ unregisterBackendType<QShaderProgramBuilder>();
unregisterBackendType<QTechnique>();
// Framegraph
@@ -429,6 +464,18 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
jobs.append(loadTextureJob);
}
+ // Launch skeleton loader jobs. We join on the syncTextureLoadingJob for now
+ // which should likely be renamed to something more generic or we introduce
+ // another synchronizing job for skeleton loading
+ const QVector<Render::HSkeleton> skeletonsToLoad =
+ manager->skeletonManager()->dirtySkeletons(Render::SkeletonManager::SkeletonDataDirty);
+ for (const auto skeletonHandle : skeletonsToLoad) {
+ auto loadSkeletonJob = Render::LoadSkeletonJobPtr::create(skeletonHandle);
+ loadSkeletonJob->setNodeManagers(manager);
+ textureLoadingSync->addDependency(loadSkeletonJob);
+ jobs.append(loadSkeletonJob);
+ }
+
// TO DO: Have 2 jobs queue
// One for urgent jobs that are mandatory for the rendering of a frame
// Another for jobs that can span across multiple frames (Scene/Mesh loading)
@@ -513,7 +560,8 @@ void QRenderAspect::onRegistered()
advanceService);
}
- d->m_renderer->setServices(d->services());
+ if (d->services())
+ d->m_renderer->setServices(d->services());
d->m_initialized = true;
}
diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h
index 4f9983d32..b8c8538ee 100644
--- a/src/render/frontend/qrenderaspect_p.h
+++ b/src/render/frontend/qrenderaspect_p.h
@@ -83,6 +83,8 @@ public:
Q_DECLARE_PUBLIC(QRenderAspect)
+ static QRenderAspectPrivate* findPrivate(Qt3DCore::QAspectEngine *engine);
+
void registerBackendTypes();
void unregisterBackendTypes();
void loadSceneParsers();
diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp
index e89764b4e..23f88eb10 100644
--- a/src/render/frontend/qrendersettings.cpp
+++ b/src/render/frontend/qrendersettings.cpp
@@ -92,6 +92,8 @@ void QRenderSettingsPrivate::init()
q, SLOT(_q_onPickResultModeChanged(QPickingSettings::PickResultMode)));
QObject::connect(&m_pickingSettings, SIGNAL(faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)),
q, SLOT(_q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)));
+ QObject::connect(&m_pickingSettings, SIGNAL(worldSpaceToleranceChanged(float)),
+ q, SLOT(_q_onWorldSpaceToleranceChanged(float)));
}
/*! \internal */
@@ -112,6 +114,12 @@ void QRenderSettingsPrivate::_q_onFaceOrientationPickingModeChanged(QPickingSett
notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode);
}
+/*! \internal */
+void QRenderSettingsPrivate::_q_onWorldSpaceToleranceChanged(float worldSpaceTolerance)
+{
+ notifyPropertyChange("pickWorldSpaceTolerance", worldSpaceTolerance);
+}
+
QRenderSettings::QRenderSettings(Qt3DCore::QNode *parent)
: QRenderSettings(*new QRenderSettingsPrivate, parent) {}
@@ -251,6 +259,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QRenderSettings::createNodeCreationChange()
data.pickMethod = d->m_pickingSettings.pickMethod();
data.pickResultMode = d->m_pickingSettings.pickResultMode();
data.faceOrientationPickingMode = d->m_pickingSettings.faceOrientationPickingMode();
+ data.pickWorldSpaceTolerance = d->m_pickingSettings.worldSpaceTolerance();
return creationChange;
}
diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h
index 71da7c562..db6ffb6d8 100644
--- a/src/render/frontend/qrendersettings.h
+++ b/src/render/frontend/qrendersettings.h
@@ -90,6 +90,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_onPickingMethodChanged(QPickingSettings::PickMethod))
Q_PRIVATE_SLOT(d_func(), void _q_onPickResultModeChanged(QPickingSettings::PickResultMode))
Q_PRIVATE_SLOT(d_func(), void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode))
+ Q_PRIVATE_SLOT(d_func(), void _q_onWorldSpaceToleranceChanged(float))
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
};
diff --git a/src/render/frontend/qrendersettings_p.h b/src/render/frontend/qrendersettings_p.h
index 9420a9546..60ebd0f0d 100644
--- a/src/render/frontend/qrendersettings_p.h
+++ b/src/render/frontend/qrendersettings_p.h
@@ -74,6 +74,7 @@ public:
void _q_onPickingMethodChanged(QPickingSettings::PickMethod pickMethod);
void _q_onPickResultModeChanged(QPickingSettings::PickResultMode pickResultMode);
void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode);
+ void _q_onWorldSpaceToleranceChanged(float worldSpaceTolerance);
Q_DECLARE_PUBLIC(QRenderSettings)
};
@@ -85,6 +86,7 @@ struct QRenderSettingsData
QPickingSettings::PickMethod pickMethod;
QPickingSettings::PickResultMode pickResultMode;
QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode;
+ float pickWorldSpaceTolerance;
};
} // namespace Qt3Drender
diff --git a/src/render/geometry/armature.cpp b/src/render/geometry/armature.cpp
new file mode 100644
index 000000000..15a26c9ec
--- /dev/null
+++ b/src/render/geometry/armature.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "armature_p.h"
+
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+#include <Qt3DCore/private/qarmature_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+Armature::Armature()
+ : BackendNode(Qt3DCore::QBackendNode::ReadOnly)
+{
+}
+
+void Armature::cleanup()
+{
+ m_skeletonId = Qt3DCore::QNodeId();
+ setEnabled(false);
+}
+
+void Armature::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<QNodeCreatedChange<QArmatureData>>(change);
+ m_skeletonId = typedChange->data.skeletonId;
+}
+
+void Armature::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ switch (e->type()) {
+ case Qt3DCore::PropertyUpdated: {
+ const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("skeleton"))
+ m_skeletonId = change->value().value<QNodeId>();
+ break;
+ }
+
+ default:
+ break;
+ }
+ QBackendNode::sceneChangeEvent(e);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/geometry/armature_p.h b/src/render/geometry/armature_p.h
new file mode 100644
index 000000000..f0960d256
--- /dev/null
+++ b/src/render/geometry/armature_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_ARMATURE_H
+#define QT3DRENDER_RENDER_ARMATURE_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/backendnode_p.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DCore/qnodeid.h>
+#include <QtGui/qmatrix4x4.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT Armature : public BackendNode
+{
+public:
+ Armature();
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+ void cleanup();
+
+ Qt3DCore::QNodeId skeletonId() const { return m_skeletonId; }
+
+ // Called from jobs
+ UniformValue &skinningPaletteUniform() { return m_skinningPaletteUniform; }
+ const UniformValue &skinningPaletteUniform() const { return m_skinningPaletteUniform; }
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ Qt3DCore::QNodeId m_skeletonId;
+ UniformValue m_skinningPaletteUniform;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_ARMATURE_H
diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp
index ae2455184..3658ef335 100644
--- a/src/render/geometry/buffer.cpp
+++ b/src/render/geometry/buffer.cpp
@@ -51,7 +51,6 @@ namespace Render {
Buffer::Buffer()
: BackendNode(QBackendNode::ReadWrite)
- , m_type(QBuffer::VertexBuffer)
, m_usage(QBuffer::StaticDraw)
, m_bufferDirty(false)
, m_syncData(false)
@@ -68,7 +67,6 @@ Buffer::~Buffer()
void Buffer::cleanup()
{
- m_type = QBuffer::VertexBuffer;
m_usage = QBuffer::StaticDraw;
m_data.clear();
m_bufferUpdates.clear();
@@ -120,7 +118,6 @@ void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QBufferData>>(change);
const auto &data = typedChange->data;
m_data = data.data;
- m_type = data.type;
m_usage = data.usage;
m_syncData = data.syncData;
m_access = data.access;
@@ -135,6 +132,7 @@ void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang
m_manager->addDirtyBuffer(peerId());
m_manager->addBufferReference(peerId());
+ markDirty(AbstractRenderer::BuffersDirty);
}
void Buffer::forceDataUpload()
@@ -163,9 +161,6 @@ void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
Qt3DRender::QBufferUpdate updateData = propertyChange->value().value<Qt3DRender::QBufferUpdate>();
m_bufferUpdates.push_back(updateData);
m_bufferDirty = true;
- } else if (propertyName == QByteArrayLiteral("type")) {
- m_type = static_cast<QBuffer::BufferType>(propertyChange->value().value<int>());
- m_bufferDirty = true;
} else if (propertyName == QByteArrayLiteral("usage")) {
m_usage = static_cast<QBuffer::UsageType>(propertyChange->value().value<int>());
m_bufferDirty = true;
@@ -180,7 +175,7 @@ void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
} else if (propertyName == QByteArrayLiteral("syncData")) {
m_syncData = propertyChange->value().toBool();
}
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::BuffersDirty);
}
BackendNode::sceneChangeEvent(e);
}
diff --git a/src/render/geometry/buffer_p.h b/src/render/geometry/buffer_p.h
index 691d6cc60..dc45e3fbc 100644
--- a/src/render/geometry/buffer_p.h
+++ b/src/render/geometry/buffer_p.h
@@ -78,7 +78,6 @@ public:
void setManager(BufferManager *manager);
void executeFunctor();
void updateDataFromGPUToCPU(QByteArray data);
- inline QBuffer::BufferType type() const { return m_type; }
inline QBuffer::UsageType usage() const { return m_usage; }
inline QByteArray data() const { return m_data; }
inline QVector<Qt3DRender::QBufferUpdate> &pendingBufferUpdates() { return m_bufferUpdates; }
@@ -92,7 +91,6 @@ private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
void forceDataUpload();
- QBuffer::BufferType m_type;
QBuffer::UsageType m_usage;
QByteArray m_data;
QVector<Qt3DRender::QBufferUpdate> m_bufferUpdates;
diff --git a/src/render/geometry/buffermanager.cpp b/src/render/geometry/buffermanager.cpp
index 5bd44f80f..25f95189e 100644
--- a/src/render/geometry/buffermanager.cpp
+++ b/src/render/geometry/buffermanager.cpp
@@ -60,9 +60,7 @@ void BufferManager::addDirtyBuffer(Qt3DCore::QNodeId bufferId)
QVector<Qt3DCore::QNodeId> BufferManager::dirtyBuffers()
{
- QVector<Qt3DCore::QNodeId> vector(m_dirtyBuffers);
- m_dirtyBuffers.clear();
- return vector;
+ return qMove(m_dirtyBuffers);
}
// Called in QAspectThread::syncChanges
diff --git a/src/render/geometry/geometry.cpp b/src/render/geometry/geometry.cpp
index 2eebb8222..d87b4d8eb 100644
--- a/src/render/geometry/geometry.cpp
+++ b/src/render/geometry/geometry.cpp
@@ -77,6 +77,7 @@ void Geometry::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &cha
m_attributes = data.attributeIds;
m_boundingPositionAttribute = data.boundingVolumePositionAttributeId;
m_geometryDirty = true;
+ markDirty(AbstractRenderer::GeometryDirty);
}
void Geometry::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -112,7 +113,7 @@ void Geometry::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
default:
break;
}
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::GeometryDirty);
BackendNode::sceneChangeEvent(e);
}
diff --git a/src/render/geometry/geometry.pri b/src/render/geometry/geometry.pri
index 742cc1fef..63a18f24e 100644
--- a/src/render/geometry/geometry.pri
+++ b/src/render/geometry/geometry.pri
@@ -18,7 +18,12 @@ HEADERS += \
$$PWD/qmesh_p.h \
$$PWD/qattribute_p.h \
$$PWD/qattribute.h \
- $$PWD/qbufferdatagenerator.h
+ $$PWD/qbufferdatagenerator.h \
+ $$PWD/armature_p.h \
+ $$PWD/skeleton_p.h \
+ $$PWD/gltfskeletonloader_p.h \
+ $$PWD/skeletondata_p.h \
+ $$PWD/joint_p.h
SOURCES += \
$$PWD/attribute.cpp \
@@ -31,5 +36,10 @@ SOURCES += \
$$PWD/qgeometry.cpp \
$$PWD/qgeometryrenderer.cpp \
$$PWD/qmesh.cpp \
- $$PWD/qattribute.cpp
+ $$PWD/qattribute.cpp \
+ $$PWD/armature.cpp \
+ $$PWD/skeleton.cpp \
+ $$PWD/gltfskeletonloader.cpp \
+ $$PWD/skeletondata.cpp \
+ $$PWD/joint.cpp
diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp
index 4f5432e1d..270380e14 100644
--- a/src/render/geometry/geometryrenderer.cpp
+++ b/src/render/geometry/geometryrenderer.cpp
@@ -64,6 +64,7 @@ GeometryRenderer::GeometryRenderer()
, m_indexOffset(0)
, m_firstInstance(0)
, m_firstVertex(0)
+ , m_indexBufferByteOffset(0)
, m_restartIndexValue(-1)
, m_verticesPerPatch(0)
, m_primitiveRestartEnabled(false)
@@ -85,6 +86,7 @@ void GeometryRenderer::cleanup()
m_indexOffset = 0;
m_firstInstance = 0;
m_firstVertex = 0;
+ m_indexBufferByteOffset = 0;
m_restartIndexValue = -1;
m_verticesPerPatch = 0;
m_primitiveRestartEnabled = false;
@@ -111,6 +113,7 @@ void GeometryRenderer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBase
m_indexOffset = data.indexOffset;
m_firstInstance = data.firstInstance;
m_firstVertex = data.firstVertex;
+ m_indexBufferByteOffset = data.indexBufferByteOffset;
m_restartIndexValue = data.restartIndexValue;
m_verticesPerPatch = data.verticesPerPatch;
m_primitiveRestartEnabled = data.primitiveRestart;
@@ -122,6 +125,7 @@ void GeometryRenderer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBase
m_manager->addDirtyGeometryRenderer(peerId());
m_dirty = true;
+ markDirty(AbstractRenderer::GeometryDirty);
}
void GeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -146,6 +150,9 @@ void GeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
} else if (propertyName == QByteArrayLiteral("firstVertex")) {
m_firstVertex = propertyChange->value().value<int>();
m_dirty = true;
+ } else if (propertyName == QByteArrayLiteral("indexBufferByteOffset")) {
+ m_indexBufferByteOffset = propertyChange->value().value<int>();
+ m_dirty = true;
} else if (propertyName == QByteArrayLiteral("restartIndexValue")) {
m_restartIndexValue = propertyChange->value().value<int>();
m_dirty = true;
@@ -160,10 +167,15 @@ void GeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_dirty = true;
} else if (propertyName == QByteArrayLiteral("geometryFactory")) {
QGeometryFactoryPtr newFunctor = propertyChange->value().value<QGeometryFactoryPtr>();
- m_dirty |= !(newFunctor && m_geometryFactory && *newFunctor == *m_geometryFactory);
- m_geometryFactory = newFunctor;
- if (m_geometryFactory && m_manager != nullptr)
- m_manager->addDirtyGeometryRenderer(peerId());
+ const bool functorDirty = ((m_geometryFactory && !newFunctor)
+ || (!m_geometryFactory && newFunctor)
+ || (m_geometryFactory && newFunctor && !(*newFunctor == *m_geometryFactory)));
+ m_dirty |= functorDirty;
+ if (functorDirty) {
+ m_geometryFactory = newFunctor;
+ if (m_geometryFactory && m_manager != nullptr)
+ m_manager->addDirtyGeometryRenderer(peerId());
+ }
} else if (propertyName == QByteArrayLiteral("geometry")) {
m_geometryId = propertyChange->value().value<Qt3DCore::QNodeId>();
m_dirty = true;
@@ -175,7 +187,7 @@ void GeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
break;
}
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::GeometryDirty);
BackendNode::sceneChangeEvent(e);
diff --git a/src/render/geometry/geometryrenderer_p.h b/src/render/geometry/geometryrenderer_p.h
index 24edf6152..5a7358f00 100644
--- a/src/render/geometry/geometryrenderer_p.h
+++ b/src/render/geometry/geometryrenderer_p.h
@@ -83,6 +83,7 @@ public:
inline int indexOffset() const { return m_indexOffset; }
inline int firstInstance() const { return m_firstInstance; }
inline int firstVertex() const { return m_firstVertex; }
+ inline int indexBufferByteOffset() const { return m_indexBufferByteOffset; }
inline int restartIndexValue() const { return m_restartIndexValue; }
inline int verticesPerPatch() const { return m_verticesPerPatch; }
inline bool primitiveRestartEnabled() const { return m_primitiveRestartEnabled; }
@@ -105,6 +106,7 @@ private:
int m_indexOffset;
int m_firstInstance;
int m_firstVertex;
+ int m_indexBufferByteOffset;
int m_restartIndexValue;
int m_verticesPerPatch;
bool m_primitiveRestartEnabled;
diff --git a/src/render/geometry/gltfskeletonloader.cpp b/src/render/geometry/gltfskeletonloader.cpp
new file mode 100644
index 000000000..76601836a
--- /dev/null
+++ b/src/render/geometry/gltfskeletonloader.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "gltfskeletonloader_p.h"
+
+#include <QtGui/qopengl.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qversionnumber.h>
+
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DCore/private/qmath3d_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+void jsonArrayToSqt(const QJsonArray &jsonArray, Qt3DCore::Sqt &sqt)
+{
+ Q_ASSERT(jsonArray.size() == 16);
+ QMatrix4x4 m;
+ float *data = m.data();
+ int i = 0;
+ for (const auto element : jsonArray)
+ *(data + i++) = static_cast<float>(element.toDouble());
+
+ decomposeQMatrix4x4(m, sqt);
+}
+
+void jsonArrayToVector3D(const QJsonArray &jsonArray, QVector3D &v)
+{
+ Q_ASSERT(jsonArray.size() == 3);
+ v.setX(static_cast<float>(jsonArray.at(0).toDouble()));
+ v.setY(static_cast<float>(jsonArray.at(1).toDouble()));
+ v.setZ(static_cast<float>(jsonArray.at(2).toDouble()));
+}
+
+void jsonArrayToQuaternion(const QJsonArray &jsonArray, QQuaternion &q)
+{
+ Q_ASSERT(jsonArray.size() == 4);
+ q.setX(static_cast<float>(jsonArray.at(0).toDouble()));
+ q.setY(static_cast<float>(jsonArray.at(1).toDouble()));
+ q.setZ(static_cast<float>(jsonArray.at(2).toDouble()));
+ q.setScalar(static_cast<float>(jsonArray.at(3).toDouble()));
+}
+
+}
+
+namespace Qt3DRender {
+namespace Render {
+
+#define KEY_ACCESSORS QLatin1String("accessors")
+#define KEY_ASSET QLatin1String("asset")
+#define KEY_BUFFER QLatin1String("buffer")
+#define KEY_BUFFERS QLatin1String("buffers")
+#define KEY_BUFFER_VIEW QLatin1String("bufferView")
+#define KEY_BUFFER_VIEWS QLatin1String("bufferViews")
+#define KEY_BYTE_LENGTH QLatin1String("byteLength")
+#define KEY_BYTE_OFFSET QLatin1String("byteOffset")
+#define KEY_BYTE_STRIDE QLatin1String("byteStride")
+#define KEY_CAMERA QLatin1String("camera")
+#define KEY_CHILDREN QLatin1String("children")
+#define KEY_COMPONENT_TYPE QLatin1String("componentType")
+#define KEY_COUNT QLatin1String("count")
+#define KEY_JOINTS QLatin1String("joints")
+#define KEY_INVERSE_BIND_MATRICES QLatin1String("inverseBindMatrices")
+#define KEY_MATRIX QLatin1String("matrix")
+#define KEY_MESH QLatin1String("mesh")
+#define KEY_NAME QLatin1String("name")
+#define KEY_NODES QLatin1String("nodes")
+#define KEY_ROTATION QLatin1String("rotation")
+#define KEY_SCALE QLatin1String("scale")
+#define KEY_SKIN QLatin1String("skin")
+#define KEY_SKINS QLatin1String("skins")
+#define KEY_TARGET QLatin1String("target")
+#define KEY_TRANSLATION QLatin1String("translation")
+#define KEY_TYPE QLatin1String("type")
+#define KEY_URI QLatin1String("uri")
+#define KEY_VERSION QLatin1String("version")
+
+GLTFSkeletonLoader::BufferData::BufferData()
+ : byteLength(0)
+ , data()
+{
+}
+
+GLTFSkeletonLoader::BufferData::BufferData(const QJsonObject &json)
+ : byteLength(json.value(KEY_BYTE_LENGTH).toInt())
+ , path(json.value(KEY_URI).toString())
+ , data()
+{
+}
+
+GLTFSkeletonLoader::BufferView::BufferView()
+ : bufferIndex(-1)
+ , byteOffset(0)
+ , byteLength(0)
+ , target(0)
+{
+}
+
+GLTFSkeletonLoader::BufferView::BufferView(const QJsonObject &json)
+ : bufferIndex(json.value(KEY_BUFFER).toInt())
+ , byteOffset(json.value(KEY_BYTE_OFFSET).toInt())
+ , byteLength(json.value(KEY_BYTE_LENGTH).toInt())
+ , target(0)
+{
+ const auto targetValue = json.value(KEY_TARGET);
+ if (!targetValue.isUndefined())
+ target = targetValue.toInt();
+}
+
+GLTFSkeletonLoader::AccessorData::AccessorData()
+ : type(QAttribute::Float)
+ , dataSize(0)
+ , count(0)
+ , byteOffset(0)
+ , byteStride(0)
+{
+}
+
+GLTFSkeletonLoader::AccessorData::AccessorData(const QJsonObject &json)
+ : bufferViewIndex(json.value(KEY_BUFFER_VIEW).toInt(-1))
+ , type(accessorTypeFromJSON(json.value(KEY_COMPONENT_TYPE).toInt()))
+ , dataSize(accessorDataSizeFromJson(json.value(KEY_TYPE).toString()))
+ , count(json.value(KEY_COUNT).toInt())
+ , byteOffset(0)
+ , byteStride(0)
+{
+ const auto byteOffsetValue = json.value(KEY_BYTE_OFFSET);
+ if (!byteOffsetValue.isUndefined())
+ byteOffset = byteOffsetValue.toInt();
+ const auto byteStrideValue = json.value(KEY_BYTE_STRIDE);
+ if (!byteStrideValue.isUndefined())
+ byteStride = byteStrideValue.toInt();
+}
+
+GLTFSkeletonLoader::Skin::Skin()
+ : inverseBindAccessorIndex(-1)
+ , jointNodeIndices()
+{
+}
+
+GLTFSkeletonLoader::Skin::Skin(const QJsonObject &json)
+ : name(json.value(KEY_NAME).toString())
+ , inverseBindAccessorIndex(json.value(KEY_INVERSE_BIND_MATRICES).toInt())
+{
+ QJsonArray jointNodes = json.value(KEY_JOINTS).toArray();
+ jointNodeIndices.reserve(jointNodes.size());
+ for (const auto jointNodeValue : jointNodes)
+ jointNodeIndices.push_back(jointNodeValue.toInt());
+}
+
+GLTFSkeletonLoader::Node::Node()
+ : localTransform()
+ , childNodeIndices()
+ , name()
+ , parentNodeIndex(-1)
+ , cameraIndex(-1)
+ , meshIndex(-1)
+ , skinIndex(-1)
+{
+}
+
+GLTFSkeletonLoader::Node::Node(const QJsonObject &json)
+ : localTransform()
+ , childNodeIndices()
+ , name(json.value(KEY_NAME).toString())
+ , parentNodeIndex(-1)
+ , cameraIndex(-1)
+ , meshIndex(-1)
+ , skinIndex(-1)
+{
+ // Child nodes - we setup the parent links in a later pass
+ QJsonArray childNodes = json.value(KEY_CHILDREN).toArray();
+ childNodeIndices.reserve(childNodes.size());
+ for (const auto childNodeValue : childNodes)
+ childNodeIndices.push_back(childNodeValue.toInt());
+
+ // Local transform - matrix or scale, rotation, translation
+ const auto matrixValue = json.value(KEY_MATRIX);
+ if (!matrixValue.isUndefined()) {
+ jsonArrayToSqt(matrixValue.toArray(), localTransform);
+ } else {
+ const auto scaleValue = json.value(KEY_SCALE);
+ const auto rotationValue = json.value(KEY_ROTATION);
+ const auto translationValue = json.value(KEY_TRANSLATION);
+
+ QVector3D s(1.0f, 1.0f, 1.0f);
+ if (!scaleValue.isUndefined())
+ jsonArrayToVector3D(scaleValue.toArray(), localTransform.scale);
+
+ QQuaternion r;
+ if (!rotationValue.isUndefined())
+ jsonArrayToQuaternion(json.value(KEY_ROTATION).toArray(), localTransform.rotation);
+
+ QVector3D t;
+ if (!translationValue.isUndefined())
+ jsonArrayToVector3D(json.value(KEY_TRANSLATION).toArray(), localTransform.translation);
+ }
+
+ // Referenced objects
+ const auto cameraValue = json.value(KEY_CAMERA);
+ if (!cameraValue.isUndefined())
+ cameraIndex = cameraValue.toInt();
+
+ const auto meshValue = json.value(KEY_MESH);
+ if (!meshValue.isUndefined())
+ meshIndex = meshValue.toInt();
+
+ const auto skinValue = json.value(KEY_SKIN);
+ if (!skinValue.isUndefined())
+ skinIndex = skinValue.toInt();
+}
+
+QAttribute::VertexBaseType GLTFSkeletonLoader::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(Jobs, "unsupported accessor type %d", componentType);
+ return QAttribute::Float;
+}
+
+uint GLTFSkeletonLoader::accessorTypeSize(QAttribute::VertexBaseType componentType)
+{
+ switch (componentType) {
+ case QAttribute::Byte:
+ case QAttribute::UnsignedByte:
+ return 1;
+
+ case QAttribute::Short:
+ case QAttribute::UnsignedShort:
+ return 2;
+
+ case QAttribute::Int:
+ case QAttribute::Float:
+ return 4;
+
+ default:
+ qCWarning(Jobs, "Unhandled accessor data type %d", componentType);
+ return 0;
+ }
+}
+
+uint GLTFSkeletonLoader::accessorDataSizeFromJson(const QString &type)
+{
+ QString typeName = type.toUpper();
+ if (typeName == QLatin1String("SCALAR"))
+ return 1;
+ if (typeName == QLatin1String("VEC2"))
+ return 2;
+ if (typeName == QLatin1String("VEC3"))
+ return 3;
+ if (typeName == QLatin1String("VEC4"))
+ return 4;
+ if (typeName == QLatin1String("MAT2"))
+ return 4;
+ if (typeName == QLatin1String("MAT3"))
+ return 9;
+ if (typeName == QLatin1String("MAT4"))
+ return 16;
+
+ return 0;
+}
+
+GLTFSkeletonLoader::GLTFSkeletonLoader()
+{
+}
+
+bool GLTFSkeletonLoader::load(QIODevice *ioDev)
+{
+ QByteArray jsonData = ioDev->readAll();
+ QJsonDocument sceneDocument = QJsonDocument::fromBinaryData(jsonData);
+ if (sceneDocument.isNull())
+ sceneDocument = QJsonDocument::fromJson(jsonData);
+
+ if (Q_UNLIKELY(!setJSON(sceneDocument))) {
+ qCWarning(Jobs, "not a JSON document");
+ return false;
+ }
+
+ auto file = qobject_cast<QFile*>(ioDev);
+ if (file) {
+ QFileInfo finfo(file->fileName());
+ setBasePath(finfo.dir().absolutePath());
+ }
+
+ return parse();
+}
+
+SkeletonData GLTFSkeletonLoader::createSkeleton(const QString &skeletonName)
+{
+ if (m_skins.isEmpty()) {
+ qCWarning(Jobs, "glTF file does not contain any skins");
+ return SkeletonData();
+ }
+
+ Skin *skin = m_skins.begin();
+ if (!skeletonName.isNull()) {
+ const auto result = std::find_if(m_skins.begin(), m_skins.end(),
+ [skeletonName](const Skin &skin) { return skin.name == skeletonName; });
+ if (result != m_skins.end())
+ skin = result;
+ }
+
+ Q_ASSERT(skin != nullptr);
+ return createSkeletonFromSkin(skin);
+}
+
+SkeletonData GLTFSkeletonLoader::createSkeletonFromSkin(Skin *skin) const
+{
+ SkeletonData skel;
+
+ const int jointCount = skin->jointNodeIndices.size();
+ skel.reserve(jointCount);
+
+ QHash<const Node *, int> jointIndexMap;
+ for (int i = 0; i < jointCount; ++i) {
+ // Get a pointer to the node for this joint and store it in
+ // a map to the JointInfo index. We can later use this to set
+ // the parent indices of the joints
+ const Node *node = &m_nodes[skin->jointNodeIndices[i]];
+ jointIndexMap.insert(node, i);
+
+ JointInfo joint;
+ joint.inverseBindPose = inverseBindMatrix(skin, i);
+ joint.parentIndex = jointIndexMap.value(&m_nodes[node->parentNodeIndex], -1);
+ if (joint.parentIndex == -1 && i != 0)
+ qCDebug(Jobs) << "Cannot find parent joint for joint" << i;
+
+ skel.joints.push_back(joint);
+ skel.localPoses.push_back(node->localTransform);
+ skel.jointNames.push_back(node->name);
+ }
+
+ return skel;
+}
+
+QMatrix4x4 GLTFSkeletonLoader::inverseBindMatrix(Skin *skin, int jointIndex) const
+{
+ // Create a matrix and copy the data into it
+ RawData rawData = accessorData(skin->inverseBindAccessorIndex, jointIndex);
+ QMatrix4x4 m;
+ memcpy(m.data(), rawData.data, rawData.byteLength);
+ return m;
+}
+
+GLTFSkeletonLoader::RawData GLTFSkeletonLoader::accessorData(int accessorIndex, int index) const
+{
+ const AccessorData &accessor = m_accessors[accessorIndex];
+ const BufferView &bufferView = m_bufferViews[accessor.bufferViewIndex];
+ const BufferData &bufferData = m_bufferDatas[bufferView.bufferIndex];
+ const QByteArray &ba = bufferData.data;
+ const char *rawData = ba.constData() + bufferView.byteOffset + accessor.byteOffset;
+
+ const uint typeSize = accessorTypeSize(accessor.type);
+ const int stride = (accessor.byteStride == 0)
+ ? accessor.dataSize * typeSize
+ : accessor.byteStride;
+
+ const char* data = rawData + index * stride;
+ if (data - rawData > ba.size()) {
+ qCWarning(Jobs, "Attempting to access data beyond end of buffer");
+ return RawData{ nullptr, 0 };
+ }
+
+ const quint64 byteLength = accessor.dataSize * typeSize;
+ RawData rd{ data, byteLength };
+
+ return rd;
+}
+
+void GLTFSkeletonLoader::setBasePath(const QString &path)
+{
+ m_basePath = path;
+}
+
+bool GLTFSkeletonLoader::setJSON(const QJsonDocument &json)
+{
+ if (!json.isObject())
+ return false;
+ m_json = json;
+ cleanup();
+ return true;
+}
+
+bool GLTFSkeletonLoader::parse()
+{
+ // Find the glTF version
+ const QJsonObject asset = m_json.object().value(KEY_ASSET).toObject();
+ const QString versionString = asset.value(KEY_VERSION).toString();
+ const auto version = QVersionNumber::fromString(versionString);
+ switch (version.majorVersion()) {
+ case 2:
+ return parseGLTF2();
+
+ default:
+ qWarning() << "Unsupported version of glTF" << versionString;
+ return false;
+ }
+}
+
+bool GLTFSkeletonLoader::parseGLTF2()
+{
+ bool success = true;
+ const QJsonArray buffers = m_json.object().value(KEY_BUFFERS).toArray();
+ for (const auto &bufferValue : buffers)
+ success &= processJSONBuffer(bufferValue.toObject());
+
+ const QJsonArray bufferViews = m_json.object().value(KEY_BUFFER_VIEWS).toArray();
+ for (const auto &bufferViewValue : bufferViews)
+ success &= processJSONBufferView(bufferViewValue.toObject());
+
+ const QJsonArray accessors = m_json.object().value(KEY_ACCESSORS).toArray();
+ for (const auto &accessorValue : accessors)
+ success &= processJSONAccessor(accessorValue.toObject());
+
+ const QJsonArray skins = m_json.object().value(KEY_SKINS).toArray();
+ for (const auto &skinValue : skins)
+ success &= processJSONSkin(skinValue.toObject());
+
+ const QJsonArray nodes = m_json.object().value(KEY_NODES).toArray();
+ for (const auto &nodeValue : nodes)
+ success &= processJSONNode(nodeValue.toObject());
+ setupNodeParentLinks();
+
+ // TODO: Make a complete GLTF 2 parser by extending to other top level elements:
+ // scenes, animations, meshes etc.
+
+ return success;
+}
+
+void GLTFSkeletonLoader::cleanup()
+{
+ m_accessors.clear();
+ m_bufferViews.clear();
+ m_bufferDatas.clear();
+}
+
+bool GLTFSkeletonLoader::processJSONBuffer(const QJsonObject &json)
+{
+ // Store buffer details and load data into memory
+ BufferData buffer(json);
+ buffer.data = resolveLocalData(buffer.path);
+ if (buffer.data.isEmpty())
+ return false;
+
+ m_bufferDatas.push_back(buffer);
+ return true;
+}
+
+bool GLTFSkeletonLoader::processJSONBufferView(const QJsonObject &json)
+{
+ BufferView bufferView(json);
+
+ // Perform sanity checks
+ const auto bufferIndex = bufferView.bufferIndex;
+ if (Q_UNLIKELY(bufferIndex) >= m_bufferDatas.size()) {
+ qCWarning(Jobs, "Unknown buffer %d when processing buffer view", bufferIndex);
+ return false;
+ }
+
+ const auto &bufferData = m_bufferDatas[bufferIndex];
+ if (bufferView.byteOffset > bufferData.byteLength) {
+ qCWarning(Jobs, "Bufferview has offset greater than buffer %d length", bufferIndex);
+ return false;
+ }
+
+ if (Q_UNLIKELY(bufferView.byteOffset + bufferView.byteLength > bufferData.byteLength)) {
+ qCWarning(Jobs, "BufferView extends beyond end of buffer %d", bufferIndex);
+ return false;
+ }
+
+ m_bufferViews.push_back(bufferView);
+ return true;
+}
+
+bool GLTFSkeletonLoader::processJSONAccessor(const QJsonObject &json)
+{
+ AccessorData accessor(json);
+
+ // TODO: Perform sanity checks
+
+ m_accessors.push_back(accessor);
+ return true;
+}
+
+bool GLTFSkeletonLoader::processJSONSkin(const QJsonObject &json)
+{
+ Skin skin(json);
+
+ // TODO: Perform sanity checks
+
+ m_skins.push_back(skin);
+ return true;
+}
+
+bool GLTFSkeletonLoader::processJSONNode(const QJsonObject &json)
+{
+ Node node(json);
+
+ // TODO: Perform sanity checks
+
+ m_nodes.push_back(node);
+ return true;
+}
+
+void GLTFSkeletonLoader::setupNodeParentLinks()
+{
+ const int nodeCount = m_nodes.size();
+ for (int i = 0; i < nodeCount; ++i) {
+ const Node &node = m_nodes[i];
+ const QVector<int> &childNodeIndices = node.childNodeIndices;
+ for (const auto childNodeIndex : childNodeIndices) {
+ Q_ASSERT(childNodeIndex < m_nodes.size());
+ Node &childNode = m_nodes[childNodeIndex];
+ Q_ASSERT(childNode.parentNodeIndex == -1);
+ childNode.parentNodeIndex = i;
+ }
+ }
+}
+
+QByteArray GLTFSkeletonLoader::resolveLocalData(const QString &path) const
+{
+ QDir d(m_basePath);
+ Q_ASSERT(d.exists());
+
+ QString absPath = d.absoluteFilePath(path);
+ QFile f(absPath);
+ f.open(QIODevice::ReadOnly);
+ return f.readAll();
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/geometry/gltfskeletonloader_p.h b/src/render/geometry/gltfskeletonloader_p.h
new file mode 100644
index 000000000..b2a175ecb
--- /dev/null
+++ b/src/render/geometry/gltfskeletonloader_p.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GLTFSKELETONLOADER_P_H
+#define QT3DRENDER_RENDER_GLTFSKELETONLOADER_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 <QtGlobal>
+#include <Qt3DRender/qattribute.h>
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qjsondocument.h>
+
+#include <Qt3DRender/private/skeletondata_p.h>
+#include <Qt3DCore/private/sqt_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QJsonObject;
+
+namespace Qt3DRender {
+namespace Render {
+
+class GLTFSkeletonLoader
+{
+ class BufferData
+ {
+ public:
+ BufferData();
+ explicit BufferData(const QJsonObject &json);
+
+ quint64 byteLength;
+ QString path;
+ QByteArray data;
+ };
+
+ class BufferView
+ {
+ public:
+ BufferView();
+ explicit BufferView(const QJsonObject &json);
+
+ int bufferIndex;
+ quint64 byteOffset;
+ quint64 byteLength;
+ int target; // Only for per vertex attributes
+ };
+
+ class AccessorData
+ {
+ public:
+ AccessorData();
+ explicit AccessorData(const QJsonObject &json);
+
+ int bufferViewIndex;
+ QAttribute::VertexBaseType type;
+ uint dataSize;
+ int count;
+ int byteOffset;
+ int byteStride; // Only for per vertex attributes
+
+ // TODO: Extend to support sparse accessors
+ };
+
+ class Skin
+ {
+ public:
+ Skin();
+ explicit Skin(const QJsonObject &json);
+
+ QString name;
+ int inverseBindAccessorIndex;
+ QVector<int> jointNodeIndices;
+ };
+
+ class Node
+ {
+ public:
+ Node();
+ explicit Node(const QJsonObject &json);
+
+ Qt3DCore::Sqt localTransform;
+ QVector<int> childNodeIndices;
+ QString name;
+ int parentNodeIndex;
+ int cameraIndex;
+ int meshIndex;
+ int skinIndex;
+ };
+
+public:
+ GLTFSkeletonLoader();
+
+ bool load(QIODevice *ioDev);
+
+ SkeletonData createSkeleton(const QString &skeletonName);
+
+private:
+ static QAttribute::VertexBaseType accessorTypeFromJSON(int componentType);
+ static uint accessorTypeSize(QAttribute::VertexBaseType componentType);
+ static uint accessorDataSizeFromJson(const QString &type);
+
+ struct RawData
+ {
+ const char *data;
+ quint64 byteLength;
+ };
+
+ void setBasePath(const QString &path);
+ bool setJSON(const QJsonDocument &json);
+
+ bool parse();
+ bool parseGLTF2();
+ void cleanup();
+
+ bool processJSONBuffer(const QJsonObject &json);
+ bool processJSONBufferView(const QJsonObject &json);
+ bool processJSONAccessor(const QJsonObject &json);
+ bool processJSONSkin(const QJsonObject &json);
+ bool processJSONNode(const QJsonObject &json);
+ void setupNodeParentLinks();
+ QByteArray resolveLocalData(const QString &path) const;
+
+ SkeletonData createSkeletonFromSkin(Skin *skin) const;
+ QMatrix4x4 inverseBindMatrix(Skin *skin, int jointIndex) const;
+ RawData accessorData(int accessorIndex, int index) const;
+
+ QJsonDocument m_json;
+ QString m_basePath;
+ QVector<BufferData> m_bufferDatas;
+ QVector<BufferView> m_bufferViews;
+ QVector<AccessorData> m_accessors;
+ QVector<Skin> m_skins;
+ QVector<Node> m_nodes;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GLTFSKELETONLOADER_P_H
diff --git a/src/render/geometry/joint.cpp b/src/render/geometry/joint.cpp
new file mode 100644
index 000000000..9c53b8ef8
--- /dev/null
+++ b/src/render/geometry/joint.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "joint_p.h"
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DCore/private/qjoint_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+Joint::Joint()
+ : BackendNode(Qt3DCore::QBackendNode::ReadOnly)
+ , m_localPose()
+ , m_jointManager(nullptr)
+ , m_skeletonManager(nullptr)
+{
+}
+
+void Joint::cleanup()
+{
+ m_inverseBindMatrix.setToIdentity();
+ m_localPose = Sqt();
+ m_childJointIds.clear();
+ m_name.clear();
+ m_owningSkeleton = HSkeleton();
+ setEnabled(false);
+}
+
+void Joint::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ Q_ASSERT(m_jointManager);
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QJointData>>(change);
+ const auto &data = typedChange->data;
+ m_inverseBindMatrix = data.inverseBindMatrix;
+ m_localPose.rotation = data.rotation;
+ m_localPose.scale = data.scale;
+ m_localPose.translation = data.translation;
+ m_childJointIds = data.childJointIds;
+ m_name = data.name;
+ markDirty(AbstractRenderer::JointDirty);
+ m_jointManager->addDirtyJoint(peerId());
+}
+
+void Joint::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ if (e->type() == PropertyUpdated) {
+ const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (propertyChange->propertyName() == QByteArrayLiteral("scale")) {
+ m_localPose.scale = propertyChange->value().value<QVector3D>();
+ markDirty(AbstractRenderer::JointDirty);
+ m_jointManager->addDirtyJoint(peerId());
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("rotation")) {
+ m_localPose.rotation = propertyChange->value().value<QQuaternion>();
+ markDirty(AbstractRenderer::JointDirty);
+ m_jointManager->addDirtyJoint(peerId());
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("translation")) {
+ m_localPose.translation = propertyChange->value().value<QVector3D>();
+ markDirty(AbstractRenderer::JointDirty);
+ m_jointManager->addDirtyJoint(peerId());
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("inverseBindMatrix")) {
+ // Setting the inverse bind matrix should be a rare operation. Usually it is
+ // set once and then remains constant for the duration of the skeleton. So just
+ // trigger a rebuild of the skeleton's SkeletonData which will include obtaining
+ // the inverse bind matrix.
+ m_inverseBindMatrix = propertyChange->value().value<QMatrix4x4>();
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_owningSkeleton);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("name")) {
+ // Joint name doesn't affect anything in the render aspect so no need
+ // to mark anything as dirty.
+ m_name = propertyChange->value().toString();
+
+ // TODO: Notify other aspects (animation) about the name change.
+ }
+ } else if (e->type() == PropertyValueAdded) {
+ const auto addedChange = qSharedPointerCast<QPropertyNodeAddedChange>(e);
+ if (addedChange->propertyName() == QByteArrayLiteral("childJoint"))
+ m_childJointIds.push_back(addedChange->addedNodeId());
+ } else if (e->type() == PropertyValueRemoved) {
+ const auto removedChange = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
+ if (removedChange->propertyName() == QByteArrayLiteral("childJoint"))
+ m_childJointIds.removeOne(removedChange->removedNodeId());
+ }
+
+ BackendNode::sceneChangeEvent(e);
+}
+
+
+JointFunctor::JointFunctor(AbstractRenderer *renderer,
+ JointManager *jointManager,
+ SkeletonManager *skeletonManager)
+ : m_renderer(renderer)
+ , m_jointManager(jointManager)
+ , m_skeletonManager(skeletonManager)
+{
+}
+
+Qt3DCore::QBackendNode *JointFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
+{
+ Joint *backend = m_jointManager->getOrCreateResource(change->subjectId());
+ backend->setRenderer(m_renderer);
+ backend->setJointManager(m_jointManager);
+ backend->setSkeletonManager(m_skeletonManager);
+ return backend;
+}
+
+Qt3DCore::QBackendNode *JointFunctor::get(Qt3DCore::QNodeId id) const
+{
+ return m_jointManager->lookupResource(id);
+}
+
+void JointFunctor::destroy(Qt3DCore::QNodeId id) const
+{
+ m_jointManager->releaseResource(id);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/geometry/joint_p.h b/src/render/geometry/joint_p.h
new file mode 100644
index 000000000..e144ac489
--- /dev/null
+++ b/src/render/geometry/joint_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_JOINT_H
+#define QT3DRENDER_RENDER_JOINT_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/backendnode_p.h>
+#include <Qt3DCore/private/sqt_p.h>
+#include <Qt3DRender/private/handle_types_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class JointManager;
+class SkeletonManager;
+
+class Q_AUTOTEST_EXPORT Joint : public BackendNode
+{
+public:
+ Joint();
+
+ void cleanup();
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override;
+
+ Qt3DCore::Sqt localPose() const { return m_localPose; }
+ QMatrix4x4 inverseBindMatrix() const { return m_inverseBindMatrix; }
+ QString name() const { return m_name; }
+ QVector<Qt3DCore::QNodeId> childJointIds() const { return m_childJointIds; }
+
+ QVector3D translation() const { return m_localPose.translation; }
+ QQuaternion rotation() const { return m_localPose.rotation; }
+ QVector3D scale() const { return m_localPose.scale; }
+
+ void setOwningSkeleton(HSkeleton skeletonHandle) { m_owningSkeleton = skeletonHandle; }
+ HSkeleton owningSkeleton() const { return m_owningSkeleton; }
+
+ void setJointManager(JointManager *jointManager) { m_jointManager = jointManager; }
+ JointManager *jointManager() const { return m_jointManager; }
+
+ void setSkeletonManager(SkeletonManager *skeletonManager) { m_skeletonManager = skeletonManager; }
+ SkeletonManager *skeletonManager() const { return m_skeletonManager; }
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final;
+
+ QMatrix4x4 m_inverseBindMatrix;
+ Qt3DCore::Sqt m_localPose;
+ QVector<Qt3DCore::QNodeId> m_childJointIds;
+ QString m_name;
+ JointManager *m_jointManager;
+ SkeletonManager *m_skeletonManager;
+ HSkeleton m_owningSkeleton;
+};
+
+class JointFunctor : public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit JointFunctor(AbstractRenderer *renderer,
+ JointManager *jointManager,
+ SkeletonManager *skeletonManager);
+ Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const final;
+ Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const final;
+ void destroy(Qt3DCore::QNodeId id) const final;
+
+private:
+ AbstractRenderer *m_renderer;
+ JointManager *m_jointManager;
+ SkeletonManager *m_skeletonManager;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_JOINT_H
diff --git a/src/render/geometry/qattribute.cpp b/src/render/geometry/qattribute.cpp
index 121a2e552..bee6e7590 100644
--- a/src/render/geometry/qattribute.cpp
+++ b/src/render/geometry/qattribute.cpp
@@ -450,6 +450,24 @@ QString QAttribute::defaultTangentAttributeName()
return QStringLiteral("vertexTangent");
}
+/*!
+ * \brief QAttribute::defaultJointIndicesAttributeName
+ * \return the name of the default joint indices attribute
+ */
+QString QAttribute::defaultJointIndicesAttributeName()
+{
+ return QStringLiteral("vertexJointIndices");
+}
+
+/*!
+ * \brief QAttribute::defaultJointIndicesAttributeName
+ * \return the name of the default joint weights attribute
+ */
+QString QAttribute::defaultJointWeightsAttributeName()
+{
+ return QStringLiteral("vertexJointWeights");
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QAttribute::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QAttributeData>::create(this);
diff --git a/src/render/geometry/qattribute.h b/src/render/geometry/qattribute.h
index fe3e6e29e..b3ce270a0 100644
--- a/src/render/geometry/qattribute.h
+++ b/src/render/geometry/qattribute.h
@@ -70,6 +70,8 @@ class QT3DRENDERSHARED_EXPORT QAttribute : public Qt3DCore::QNode
Q_PROPERTY(QString defaultColorAttributeName READ defaultColorAttributeName CONSTANT)
Q_PROPERTY(QString defaultTextureCoordinateAttributeName READ defaultTextureCoordinateAttributeName CONSTANT)
Q_PROPERTY(QString defaultTangentAttributeName READ defaultTangentAttributeName CONSTANT)
+ Q_PROPERTY(QString defaultJointIndicesAttributeName READ defaultJointIndicesAttributeName CONSTANT REVISION 10)
+ Q_PROPERTY(QString defaultJointWeightsAttributeName READ defaultJointWeightsAttributeName CONSTANT REVISION 10)
public:
enum AttributeType {
@@ -113,6 +115,8 @@ public:
Q_INVOKABLE static QString defaultColorAttributeName();
Q_INVOKABLE static QString defaultTextureCoordinateAttributeName();
Q_INVOKABLE static QString defaultTangentAttributeName();
+ static QString defaultJointIndicesAttributeName();
+ static QString defaultJointWeightsAttributeName();
public Q_SLOTS:
void setBuffer(QBuffer *buffer);
diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp
index b978e0e0b..97f037f35 100644
--- a/src/render/geometry/qbuffer.cpp
+++ b/src/render/geometry/qbuffer.cpp
@@ -77,6 +77,8 @@ QBufferPrivate::QBufferPrivate()
* \qmlproperty QBuffer::BufferType Buffer::type
*
* Holds the buffer type.
+ *
+ * \deprecated
*/
/*!
@@ -220,6 +222,8 @@ QBufferPrivate::QBufferPrivate()
* GL_SHADER_STORAGE_BUFFER
* \value DrawIndirectBuffer
* GL_DRAW_INDIRECT_BUFFER
+ *
+ * \deprecated
*/
/*!
@@ -253,7 +257,17 @@ QBufferPrivate::QBufferPrivate()
*/
/*!
+ * Constructs a new QBuffer with \a parent.
+ */
+QBuffer::QBuffer(QNode *parent)
+ : QNode(*new QBufferPrivate(), parent)
+{
+}
+
+/*!
* Constructs a new QBuffer of buffer type \a ty with \a parent.
+ *
+ * \deprecated
*/
QBuffer::QBuffer(QBuffer::BufferType ty, QNode *parent)
: QNode(*new QBufferPrivate(), parent)
@@ -360,6 +374,8 @@ void QBuffer::setUsage(QBuffer::UsageType usage)
* \property QBuffer::type
*
* Holds the buffer type.
+ *
+ * \deprecated
*/
QBuffer::BufferType QBuffer::type() const
{
@@ -448,7 +464,6 @@ Qt3DCore::QNodeCreatedChangeBasePtr QBuffer::createNodeCreationChange() const
auto &data = creationChange->data;
Q_D(const QBuffer);
data.data = d->m_data;
- data.type = d->m_type;
data.usage = d->m_usage;
data.functor = d->m_functor;
data.syncData = d->m_syncData;
diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h
index 7cb5acb0a..89b62ab24 100644
--- a/src/render/geometry/qbuffer.h
+++ b/src/render/geometry/qbuffer.h
@@ -95,11 +95,12 @@ public:
};
Q_ENUM(AccessType) // LCOV_EXCL_LINE
- explicit QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = nullptr);
+ explicit QBuffer(Qt3DCore::QNode *parent = nullptr);
+ QT_DEPRECATED explicit QBuffer(BufferType ty, Qt3DCore::QNode *parent = nullptr);
~QBuffer();
UsageType usage() const;
- BufferType type() const;
+ QT_DEPRECATED BufferType type() const;
bool isSyncData() const;
AccessType accessType() const;
@@ -112,7 +113,7 @@ public:
Q_INVOKABLE void updateData(int offset, const QByteArray &bytes);
public Q_SLOTS:
- void setType(BufferType type);
+ QT_DEPRECATED void setType(BufferType type);
void setUsage(UsageType usage);
void setSyncData(bool syncData);
void setAccessType(AccessType access);
diff --git a/src/render/geometry/qbuffer_p.h b/src/render/geometry/qbuffer_p.h
index a722675ab..a342518e0 100644
--- a/src/render/geometry/qbuffer_p.h
+++ b/src/render/geometry/qbuffer_p.h
@@ -80,7 +80,6 @@ public:
struct QBufferData
{
QByteArray data;
- QBuffer::BufferType type;
QBuffer::UsageType usage;
QBufferDataGeneratorPtr functor;
bool syncData;
diff --git a/src/render/geometry/qgeometryrenderer.cpp b/src/render/geometry/qgeometryrenderer.cpp
index 5fcd117f7..a497bab97 100644
--- a/src/render/geometry/qgeometryrenderer.cpp
+++ b/src/render/geometry/qgeometryrenderer.cpp
@@ -58,6 +58,7 @@ QGeometryRendererPrivate::QGeometryRendererPrivate()
, m_indexOffset(0)
, m_firstInstance(0)
, m_firstVertex(0)
+ , m_indexBufferByteOffset(0)
, m_restartIndexValue(-1)
, m_verticesPerPatch(0)
, m_primitiveRestart(false)
@@ -145,6 +146,12 @@ QGeometryRendererPrivate::~QGeometryRendererPrivate()
*/
/*!
+ \qmlproperty int GeometryRenderer::indexBufferByteOffset
+
+ Holds the byte offset into the index buffer.
+ */
+
+/*!
\qmlproperty int GeometryRenderer::restartIndex
Holds the restart index.
@@ -270,6 +277,17 @@ int QGeometryRenderer::firstVertex() const
}
/*!
+ \property QGeometryRenderer::indexBufferByteOffset
+
+ Holds the byte offset into the index buffer.
+ */
+int QGeometryRenderer::indexBufferByteOffset() const
+{
+ Q_D(const QGeometryRenderer);
+ return d->m_indexBufferByteOffset;
+}
+
+/*!
\property QGeometryRenderer::restartIndexValue
Holds the restart index.
@@ -383,6 +401,16 @@ void QGeometryRenderer::setFirstVertex(int firstVertex)
emit firstVertexChanged(firstVertex);
}
+void QGeometryRenderer::setIndexBufferByteOffset(int offset)
+{
+ Q_D(QGeometryRenderer);
+ if (d->m_indexBufferByteOffset == offset)
+ return;
+
+ d->m_indexBufferByteOffset = offset;
+ emit indexBufferByteOffsetChanged(offset);
+}
+
void QGeometryRenderer::setRestartIndexValue(int index)
{
Q_D(QGeometryRenderer);
@@ -483,6 +511,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QGeometryRenderer::createNodeCreationChange(
data.indexOffset = d->m_indexOffset;
data.firstInstance = d->m_firstInstance;
data.firstVertex = d->m_firstVertex;
+ data.indexBufferByteOffset = d->m_indexBufferByteOffset;
data.restartIndexValue = d->m_restartIndexValue;
data.verticesPerPatch = d->m_verticesPerPatch;
data.primitiveRestart = d->m_primitiveRestart;
diff --git a/src/render/geometry/qgeometryrenderer.h b/src/render/geometry/qgeometryrenderer.h
index 28d580990..704e2f89f 100644
--- a/src/render/geometry/qgeometryrenderer.h
+++ b/src/render/geometry/qgeometryrenderer.h
@@ -61,6 +61,7 @@ class QT3DRENDERSHARED_EXPORT QGeometryRenderer : public Qt3DCore::QComponent
Q_PROPERTY(int indexOffset READ indexOffset WRITE setIndexOffset NOTIFY indexOffsetChanged)
Q_PROPERTY(int firstInstance READ firstInstance WRITE setFirstInstance NOTIFY firstInstanceChanged)
Q_PROPERTY(int firstVertex READ firstVertex WRITE setFirstVertex NOTIFY firstVertexChanged)
+ Q_PROPERTY(int indexBufferByteOffset READ indexBufferByteOffset WRITE setIndexBufferByteOffset NOTIFY indexBufferByteOffsetChanged)
Q_PROPERTY(int restartIndexValue READ restartIndexValue WRITE setRestartIndexValue NOTIFY restartIndexValueChanged)
Q_PROPERTY(int verticesPerPatch READ verticesPerPatch WRITE setVerticesPerPatch NOTIFY verticesPerPatchChanged)
Q_PROPERTY(bool primitiveRestartEnabled READ primitiveRestartEnabled WRITE setPrimitiveRestartEnabled NOTIFY primitiveRestartEnabledChanged)
@@ -95,6 +96,7 @@ public:
int indexOffset() const;
int firstInstance() const;
int firstVertex() const;
+ int indexBufferByteOffset() const;
int restartIndexValue() const;
int verticesPerPatch() const;
bool primitiveRestartEnabled() const;
@@ -110,6 +112,7 @@ public Q_SLOTS:
void setIndexOffset(int indexOffset);
void setFirstInstance(int firstInstance);
void setFirstVertex(int firstVertex);
+ void setIndexBufferByteOffset(int offset);
void setRestartIndexValue(int index);
void setVerticesPerPatch(int verticesPerPatch);
void setPrimitiveRestartEnabled(bool enabled);
@@ -122,6 +125,7 @@ Q_SIGNALS:
void indexOffsetChanged(int indexOffset);
void firstInstanceChanged(int firstInstance);
void firstVertexChanged(int firstVertex);
+ void indexBufferByteOffsetChanged(int offset);
void restartIndexValueChanged(int restartIndexValue);
void verticesPerPatchChanged(int verticesPerPatch);
void primitiveRestartEnabledChanged(bool primitiveRestartEnabled);
diff --git a/src/render/geometry/qgeometryrenderer_p.h b/src/render/geometry/qgeometryrenderer_p.h
index 324dc9609..8096b4a6b 100644
--- a/src/render/geometry/qgeometryrenderer_p.h
+++ b/src/render/geometry/qgeometryrenderer_p.h
@@ -75,6 +75,7 @@ public:
int m_indexOffset;
int m_firstInstance;
int m_firstVertex;
+ int m_indexBufferByteOffset;
int m_restartIndexValue;
int m_verticesPerPatch;
bool m_primitiveRestart;
@@ -90,6 +91,7 @@ struct QGeometryRendererData
int indexOffset;
int firstInstance;
int firstVertex;
+ int indexBufferByteOffset;
int restartIndexValue;
int verticesPerPatch;
bool primitiveRestart;
diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp
index cf14ff4ff..9a1f10bc5 100644
--- a/src/render/geometry/qmesh.cpp
+++ b/src/render/geometry/qmesh.cpp
@@ -45,11 +45,23 @@
#include <QFile>
#include <QFileInfo>
#include <QScopedPointer>
-#include <Qt3DRender/private/qgeometryloaderinterface_p.h>
+#include <QMimeDatabase>
+#include <QMimeType>
+#include <QtCore/QBuffer>
+#include <Qt3DRender/QRenderAspect>
+#include <Qt3DCore/QAspectEngine>
#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/qgeometryloaderinterface_p.h>
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DRender/private/qurlhelper_p.h>
#include <Qt3DRender/private/qgeometryloaderfactory_p.h>
+#include <Qt3DRender/private/geometryrenderermanager_p.h>
+
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -62,6 +74,25 @@ QMeshPrivate::QMeshPrivate()
{
}
+QMeshPrivate *QMeshPrivate::get(QMesh *q)
+{
+ return q->d_func();
+}
+
+void QMeshPrivate::setScene(Qt3DCore::QScene *scene)
+{
+ QGeometryRendererPrivate::setScene(scene);
+ updateFunctor();
+}
+
+void QMeshPrivate::updateFunctor()
+{
+ Q_Q(QMesh);
+ Qt3DCore::QAspectEngine *engine = m_scene ? m_scene->engine() : nullptr;
+ if (engine)
+ q->setGeometryFactory(QGeometryFactoryPtr(new MeshLoaderFunctor(q, engine)));
+}
+
/*!
* \qmltype Mesh
* \instantiates Qt3DRender::QMesh
@@ -161,8 +192,7 @@ void QMesh::setSource(const QUrl& source)
if (d->m_source == source)
return;
d->m_source = source;
- // update the functor
- QGeometryRenderer::setGeometryFactory(QGeometryFactoryPtr(new MeshFunctor(d->m_source, d->m_meshName)));
+ d->updateFunctor();
const bool blocked = blockNotifications(true);
emit sourceChanged(source);
blockNotifications(blocked);
@@ -185,8 +215,7 @@ void QMesh::setMeshName(const QString &meshName)
if (d->m_meshName == meshName)
return;
d->m_meshName = meshName;
- // update the functor
- QGeometryRenderer::setGeometryFactory(QGeometryFactoryPtr(new MeshFunctor(d->m_source, d->m_meshName)));
+ d->updateFunctor();
const bool blocked = blockNotifications(true);
emit meshNameChanged(meshName);
blockNotifications(blocked);
@@ -206,51 +235,89 @@ QString QMesh::meshName() const
/*!
* \internal
*/
-MeshFunctor::MeshFunctor(const QUrl &sourcePath, const QString& meshName)
+MeshLoaderFunctor::MeshLoaderFunctor(QMesh *mesh, Qt3DCore::QAspectEngine *engine, const QByteArray &sourceData)
: QGeometryFactory()
- , m_sourcePath(sourcePath)
- , m_meshName(meshName)
+ , m_mesh(mesh->id())
+ , m_sourcePath(mesh->source())
+ , m_meshName(mesh->meshName())
+ , m_engine(engine)
+ , m_sourceData(sourceData)
{
}
/*!
* \internal
*/
-QGeometry *MeshFunctor::operator()()
+QGeometry *MeshLoaderFunctor::operator()()
{
if (m_sourcePath.isEmpty()) {
qCWarning(Render::Jobs) << Q_FUNC_INFO << "Mesh is empty, nothing to load";
return nullptr;
}
- // TO DO: Handle file download if remote url
- QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_sourcePath);
+ QStringList ext;
+ if (!Qt3DCore::QDownloadHelperService::isLocal(m_sourcePath)) {
+ if (m_sourceData.isEmpty()) {
+ if (m_mesh) {
+ auto downloadService = Qt3DCore::QDownloadHelperService::getService(m_engine);
+ Qt3DCore::QDownloadRequestPtr request(new MeshDownloadRequest(m_mesh, m_sourcePath, m_engine));
+ downloadService->submitRequest(request);
+ }
+ return nullptr;
+ }
- QFileInfo finfo(filePath);
- auto ext = finfo.suffix();
- if (ext.isEmpty())
- ext = QLatin1String("obj");
+ QMimeDatabase db;
+ QMimeType mtype = db.mimeTypeForData(m_sourceData);
+ if (mtype.isValid()) {
+ ext = mtype.suffixes();
+ }
+ QFileInfo finfo(m_sourcePath.path());
+ ext << finfo.suffix();
+ ext.removeAll(QLatin1String(""));
+ if (!ext.contains(QLatin1String("obj")))
+ ext << QLatin1String("obj");
+ } else {
+ QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_sourcePath);
+ QFileInfo finfo(filePath);
+ if (finfo.suffix().isEmpty())
+ ext << QLatin1String("obj");
+ else
+ ext << finfo.suffix();
+ }
QScopedPointer<QGeometryLoaderInterface> loader;
-
- loader.reset(qLoadPlugin<QGeometryLoaderInterface, QGeometryLoaderFactory>(geometryLoader(), ext));
+ for (QString e: qAsConst(ext)) {
+ loader.reset(qLoadPlugin<QGeometryLoaderInterface, QGeometryLoaderFactory>(geometryLoader(), e));
+ if (loader)
+ break;
+ }
if (!loader) {
- qCWarning(Render::Jobs, "unsupported format encountered (%s)", qPrintable(ext));
+ qCWarning(Render::Jobs, "unsupported format encountered (%s)", qPrintable(ext.join(QLatin1String(", "))));
return nullptr;
}
- QFile file(filePath);
- if (!file.open(QIODevice::ReadOnly)) {
- qCDebug(Render::Jobs) << "Could not open file" << filePath << "for reading";
- return nullptr;
- }
+ if (m_sourceData.isEmpty()) {
+ QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_sourcePath);
+ QFile file(filePath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCDebug(Render::Jobs) << "Could not open file" << filePath << "for reading";
+ return nullptr;
+ }
- qCDebug(Render::Jobs) << Q_FUNC_INFO << "Loading mesh from" << m_sourcePath << " part:" << m_meshName;
+ if (loader->load(&file, m_meshName))
+ return loader->geometry();
+ qCWarning(Render::Jobs) << Q_FUNC_INFO << "Mesh loading failure for:" << filePath;
+ } else {
+ QT_PREPEND_NAMESPACE(QBuffer) buffer(&m_sourceData);
+ if (!buffer.open(QIODevice::ReadOnly)) {
+ return nullptr;
+ }
- if (loader->load(&file, m_meshName))
- return loader->geometry();
+ if (loader->load(&buffer, m_meshName))
+ return loader->geometry();
- qCWarning(Render::Jobs) << Q_FUNC_INFO << "Mesh loading failure for:" << filePath;
+ qCWarning(Render::Jobs) << Q_FUNC_INFO << "Mesh loading failure for:" << m_sourcePath;
+ }
return nullptr;
}
@@ -258,16 +325,48 @@ QGeometry *MeshFunctor::operator()()
/*!
* \internal
*/
-bool MeshFunctor::operator ==(const QGeometryFactory &other) const
+bool MeshLoaderFunctor::operator ==(const QGeometryFactory &other) const
{
- const MeshFunctor *otherFunctor = functor_cast<MeshFunctor>(&other);
- if (otherFunctor != nullptr) {
- return (otherFunctor->m_sourcePath == m_sourcePath
- && otherFunctor->m_meshName == m_meshName);
- }
+ const MeshLoaderFunctor *otherFunctor = functor_cast<MeshLoaderFunctor>(&other);
+ if (otherFunctor != nullptr)
+ return (otherFunctor->m_sourcePath == m_sourcePath &&
+ otherFunctor->m_sourceData.isEmpty() == m_sourceData.isEmpty() &&
+ otherFunctor->m_meshName == m_meshName &&
+ otherFunctor->m_engine == m_engine);
return false;
}
+/*!
+ * \internal
+ */
+MeshDownloadRequest::MeshDownloadRequest(Qt3DCore::QNodeId mesh, QUrl source, Qt3DCore::QAspectEngine *engine)
+ : Qt3DCore::QDownloadRequest(source)
+ , m_mesh(mesh)
+ , m_engine(engine)
+{
+
+}
+
+void MeshDownloadRequest::onCompleted()
+{
+ if (cancelled() || !succeeded())
+ return;
+
+ QRenderAspectPrivate* d_aspect = QRenderAspectPrivate::findPrivate(m_engine);
+ if (!d_aspect)
+ return;
+
+ Render::GeometryRenderer *renderer = d_aspect->m_nodeManagers->geometryRendererManager()->lookupResource(m_mesh);
+ if (!renderer)
+ return;
+
+ QSharedPointer<MeshLoaderFunctor> functor = qSharedPointerCast<MeshLoaderFunctor>(renderer->geometryFactory());
+ functor->m_sourceData = m_data;
+
+ // mark the component as dirty so that the functor runs again in the correct job
+ d_aspect->m_nodeManagers->geometryRendererManager()->addDirtyGeometryRenderer(m_mesh);
+}
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/geometry/qmesh_p.h b/src/render/geometry/qmesh_p.h
index 23449d22a..1f602ba89 100644
--- a/src/render/geometry/qmesh_p.h
+++ b/src/render/geometry/qmesh_p.h
@@ -51,6 +51,7 @@
// We mean it.
//
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
#include <Qt3DRender/private/qgeometryrenderer_p.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
#include <QUrl>
@@ -67,23 +68,40 @@ public:
QMeshPrivate();
Q_DECLARE_PUBLIC(QMesh)
+ static QMeshPrivate *get(QMesh *q);
+
+ void setScene(Qt3DCore::QScene *scene) override;
+ void updateFunctor();
QUrl m_source;
QString m_meshName;
};
+class Q_AUTOTEST_EXPORT MeshDownloadRequest : public Qt3DCore::QDownloadRequest
+{
+public:
+ MeshDownloadRequest(Qt3DCore::QNodeId mesh, QUrl source, Qt3DCore::QAspectEngine *engine);
+
+ void onCompleted() Q_DECL_OVERRIDE;
-class Q_AUTOTEST_EXPORT MeshFunctor : public QGeometryFactory
+private:
+ Qt3DCore::QNodeId m_mesh;
+ Qt3DCore::QAspectEngine *m_engine;
+};
+
+class Q_AUTOTEST_EXPORT MeshLoaderFunctor : public QGeometryFactory
{
public :
- MeshFunctor(const QUrl &sourcePath, const QString &meshName = QString());
+ MeshLoaderFunctor(QMesh *mesh, Qt3DCore::QAspectEngine *engine, const QByteArray &sourceData = QByteArray());
QGeometry *operator()() Q_DECL_OVERRIDE;
bool operator ==(const QGeometryFactory &other) const Q_DECL_OVERRIDE;
- QT3D_FUNCTOR(MeshFunctor)
+ QT3D_FUNCTOR(MeshLoaderFunctor)
-private:
+ Qt3DCore::QNodeId m_mesh;
QUrl m_sourcePath;
QString m_meshName;
+ Qt3DCore::QAspectEngine *m_engine;
+ QByteArray m_sourceData;
};
diff --git a/src/render/geometry/skeleton.cpp b/src/render/geometry/skeleton.cpp
new file mode 100644
index 000000000..075936f37
--- /dev/null
+++ b/src/render/geometry/skeleton.cpp
@@ -0,0 +1,442 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "skeleton_p.h"
+
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+#include <QCoreApplication>
+#include <QFile>
+#include <QFileInfo>
+
+#include <Qt3DRender/private/abstractrenderer_p.h>
+#include <Qt3DRender/private/gltfskeletonloader_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DRender/private/qurlhelper_p.h>
+#include <Qt3DCore/private/qskeletoncreatedchange_p.h>
+#include <Qt3DCore/private/qskeleton_p.h>
+#include <Qt3DCore/private/qskeletonloader_p.h>
+#include <Qt3DCore/private/qmath3d_p.h>
+#include <Qt3DCore/private/qabstractnodefactory_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+Skeleton::Skeleton()
+ : BackendNode(Qt3DCore::QBackendNode::ReadWrite)
+ , m_status(Qt3DCore::QSkeletonLoader::NotReady)
+ , m_skeletonManager(nullptr)
+ , m_jointManager(nullptr)
+{
+}
+
+void Skeleton::cleanup()
+{
+ m_source.clear();
+ m_status = Qt3DCore::QSkeletonLoader::NotReady;
+ m_createJoints = false;
+ m_rootJointId = Qt3DCore::QNodeId();
+ clearData();
+ setEnabled(false);
+}
+
+void Skeleton::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ Q_ASSERT(m_skeletonManager);
+ m_skeletonHandle = m_skeletonManager->lookupHandle(peerId());
+
+ const auto skeletonCreatedChange = qSharedPointerCast<QSkeletonCreatedChangeBase>(change);
+ switch (skeletonCreatedChange->type()) {
+ case QSkeletonCreatedChangeBase::SkeletonLoader: {
+ const auto loaderTypedChange = qSharedPointerCast<QSkeletonCreatedChange<QSkeletonLoaderData>>(change);
+ const auto &data = loaderTypedChange->data;
+ m_dataType = File;
+ m_source = data.source;
+ m_createJoints = data.createJoints;
+ if (!m_source.isEmpty()) {
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
+ break;
+ }
+
+ case QSkeletonCreatedChangeBase::Skeleton:
+ const auto typedChange = qSharedPointerCast<QSkeletonCreatedChange<QSkeletonData>>(change);
+ const auto &data = typedChange->data;
+ m_dataType = Data;
+ m_rootJointId = data.rootJointId;
+ if (!m_rootJointId.isNull()) {
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
+ break;
+ }
+}
+
+void Skeleton::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ switch (e->type()) {
+ case Qt3DCore::PropertyUpdated: {
+ const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
+ if (change->propertyName() == QByteArrayLiteral("localPoses")) {
+ // When the animation aspect sends us a new set of local poses, all we
+ // need to do is copy them into place. The existing jobs will then update
+ // the skinning matrix palette.
+ m_skeletonData.localPoses = change->value().value<QVector<Qt3DCore::Sqt>>();
+ } else if (change->propertyName() == QByteArrayLiteral("source")) {
+ Q_ASSERT(m_dataType == File);
+ const auto source = change->value().toUrl();
+ if (source != m_source) {
+ m_source = source;
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
+ } else if (change->propertyName() == QByteArrayLiteral("createJointsEnabled")) {
+ m_createJoints = change->value().toBool();
+ } else if (change->propertyName() == QByteArrayLiteral("rootJoint")) {
+ m_rootJointId = change->value().value<QNodeId>();
+
+ // If using a QSkeletonLoader to create frontend QJoints, when those joints are
+ // set on the skeleton, we end up here. In order to allow the subsequent call
+ // to loadSkeleton(), see below, to build the internal data from the frontend
+ // joints rather than from the source url again, we need to change the data type
+ // to Data.
+ m_dataType = Data;
+
+ // If the joint changes, we need to rebuild our internal SkeletonData and
+ // the relationships between joints and skeleton. Mark the skeleton data as
+ // dirty so that we get a loadSkeletonJob executed to process this skeleton.
+ markDirty(AbstractRenderer::SkeletonDataDirty);
+ m_skeletonManager->addDirtySkeleton(SkeletonManager::SkeletonDataDirty, m_skeletonHandle);
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ QBackendNode::sceneChangeEvent(e);
+}
+
+void Skeleton::setStatus(QSkeletonLoader::Status status)
+{
+ if (status != m_status) {
+ m_status = status;
+ Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("status");
+ e->setValue(QVariant::fromValue(m_status));
+ notifyObservers(e);
+ }
+}
+
+void Skeleton::notifyJointCount()
+{
+ Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("jointCount");
+ e->setValue(jointCount());
+ notifyObservers(e);
+}
+
+void Skeleton::notifyJointNamesAndPoses()
+{
+ auto e = QPropertyUpdatedChangePtr::create(peerId());
+ JointNamesAndLocalPoses payload{m_skeletonData.jointNames, m_skeletonData.localPoses};
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::BackendNodes);
+ e->setPropertyName("jointNamesAndLocalPoses");
+ e->setValue(QVariant::fromValue(payload));
+ notifyObservers(e);
+}
+
+void Skeleton::loadSkeleton()
+{
+ qCDebug(Jobs) << Q_FUNC_INFO << m_source;
+ clearData();
+
+ // Load the data
+ switch (m_dataType) {
+ case File:
+ loadSkeletonFromUrl();
+ break;
+
+ case Data:
+ loadSkeletonFromData();
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ }
+
+ // If using a loader inform the frontend of the status change.
+ // Don't bother if asked to create frontend joints though. When
+ // the backend gets notified of those joints we'll update the
+ // status at that point.
+ if (m_dataType == File && !m_createJoints) {
+ if (jointCount() == 0)
+ setStatus(QSkeletonLoader::Error);
+ else
+ setStatus(QSkeletonLoader::Ready);
+ }
+ notifyJointCount();
+ notifyJointNamesAndPoses();
+
+ qCDebug(Jobs) << "Loaded skeleton data:" << *this;
+}
+
+void Skeleton::loadSkeletonFromUrl()
+{
+ // TODO: Handle remote files
+ QString filePath = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_source);
+ QFileInfo info(filePath);
+ if (!info.exists()) {
+ qWarning() << "Could not open skeleton file:" << filePath;
+ setStatus(Qt3DCore::QSkeletonLoader::Error);
+ return;
+ }
+
+ QFile file(filePath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "Could not open skeleton file:" << filePath;
+ setStatus(Qt3DCore::QSkeletonLoader::Error);
+ return;
+ }
+
+ // TODO: Make plugin based for more file type support. For now gltf or native
+ const QString ext = info.suffix();
+ if (ext == QLatin1String("gltf")) {
+ GLTFSkeletonLoader loader;
+ loader.load(&file);
+ m_skeletonData = loader.createSkeleton(m_name);
+
+ // If the user has requested it, create the frontend nodes for the joints
+ // and send them to the (soon to be owning) QSkeletonLoader.
+ if (m_createJoints) {
+ std::unique_ptr<QJoint> rootJoint(createFrontendJoints(m_skeletonData));
+ if (!rootJoint) {
+ qWarning() << "Failed to create frontend joints";
+ setStatus(Qt3DCore::QSkeletonLoader::Error);
+ return;
+ }
+
+ // Move the QJoint tree to the main thread and notify the
+ // corresponding QSkeletonLoader
+ const auto appThread = QCoreApplication::instance()->thread();
+ rootJoint->moveToThread(appThread);
+
+ auto e = QJointChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ e->setPropertyName("rootJoint");
+ e->data = std::move(rootJoint);
+ notifyObservers(e);
+
+ // Clear the skeleton data. It will be recreated from the
+ // frontend joints. A little bit inefficient but ensures
+ // that joints created this way and via QSkeleton go through
+ // the same code path.
+ m_skeletonData = SkeletonData();
+ }
+ } else if (ext == QLatin1String("json")) {
+ // TODO: Support native skeleton type
+ } else {
+ qWarning() << "Unknown skeleton file type:" << ext;
+ setStatus(Qt3DCore::QSkeletonLoader::Error);
+ return;
+ }
+ m_skinningPalette.resize(m_skeletonData.joints.size());
+}
+
+void Skeleton::loadSkeletonFromData()
+{
+ // Recurse down through the joint hierarchy and process it into
+ // the vector of joints used within SkeletonData. The recursion
+ // ensures that a parent always appears before its children in
+ // the vector of JointInfo objects.
+ //
+ // In addition, we set up a mapping from the joint ids to the
+ // index of the corresponding JointInfo object in the vector.
+ // This will allow us to easily update entries in the vector of
+ // JointInfos when a Joint node marks itself as dirty.
+ const int rootParentIndex = -1;
+ processJointHierarchy(m_rootJointId, rootParentIndex, m_skeletonData);
+ m_skinningPalette.resize(m_skeletonData.joints.size());
+}
+
+Qt3DCore::QJoint *Skeleton::createFrontendJoints(const SkeletonData &skeletonData) const
+{
+ if (skeletonData.joints.isEmpty())
+ return nullptr;
+
+ // Create frontend joints from the joint info objects
+ QVector<QJoint *> frontendJoints;
+ const int jointCount = skeletonData.joints.size();
+ frontendJoints.reserve(jointCount);
+ for (int i = 0; i < jointCount; ++i) {
+ const QMatrix4x4 &inverseBindMatrix = skeletonData.joints[i].inverseBindPose;
+ const QString &jointName = skeletonData.jointNames[i];
+ const Qt3DCore::Sqt &localPose = skeletonData.localPoses[i];
+ frontendJoints.push_back(createFrontendJoint(jointName, localPose, inverseBindMatrix));
+ }
+
+ // Now go through and resolve the parent for each joint
+ for (int i = 0; i < frontendJoints.size(); ++i) {
+ const auto parentIndex = skeletonData.joints[i].parentIndex;
+ if (parentIndex == -1)
+ continue;
+
+ // It's not enough to just set up the QObject parent-child relationship.
+ // We need to explicitly add the child to the parent's list of joints so
+ // that information is then propagated to the backend.
+ frontendJoints[parentIndex]->addChildJoint(frontendJoints[i]);
+ }
+
+ return frontendJoints[0];
+}
+
+Qt3DCore::QJoint *Skeleton::createFrontendJoint(const QString &jointName,
+ const Qt3DCore::Sqt &localPose,
+ const QMatrix4x4 &inverseBindMatrix) const
+{
+ auto joint = QAbstractNodeFactory::createNode<QJoint>("QJoint");
+ joint->setTranslation(localPose.translation);
+ joint->setRotation(localPose.rotation);
+ joint->setScale(localPose.scale);
+ joint->setInverseBindMatrix(inverseBindMatrix);
+ joint->setName(jointName);
+ return joint;
+}
+
+void Skeleton::processJointHierarchy(Qt3DCore::QNodeId jointId,
+ int parentJointIndex,
+ SkeletonData &skeletonData)
+{
+ // Lookup the joint, create a JointInfo, and add an entry to the index map
+ Joint *joint = m_renderer->nodeManagers()->jointManager()->lookupResource(jointId);
+ Q_ASSERT(joint);
+ joint->setOwningSkeleton(m_skeletonHandle);
+ const JointInfo jointInfo(joint, parentJointIndex);
+ skeletonData.joints.push_back(jointInfo);
+ skeletonData.localPoses.push_back(joint->localPose());
+ skeletonData.jointNames.push_back(joint->name());
+
+ const int jointIndex = skeletonData.joints.size() - 1;
+ const HJoint jointHandle = m_jointManager->lookupHandle(jointId);
+ skeletonData.jointIndices.insert(jointHandle, jointIndex);
+
+ // Recurse to the children
+ for (const auto childJointId : joint->childJointIds())
+ processJointHierarchy(childJointId, jointIndex, skeletonData);
+}
+
+void Skeleton::clearData()
+{
+ m_name.clear();
+ m_skeletonData.joints.clear();
+ m_skeletonData.localPoses.clear();
+ m_skeletonData.jointNames.clear();
+ m_skeletonData.jointIndices.clear();
+}
+
+// Called from UpdateSkinningPaletteJob
+void Skeleton::setLocalPose(HJoint jointHandle, const Qt3DCore::Sqt &localPose)
+{
+ // Find the corresponding index into the JointInfo vector
+ // and set the local pose
+ const int jointIndex = m_skeletonData.jointIndices.value(jointHandle, -1);
+ Q_ASSERT(jointIndex != -1);
+ m_skeletonData.localPoses[jointIndex] = localPose;
+}
+
+QVector<QMatrix4x4> Skeleton::calculateSkinningMatrixPalette()
+{
+ const QVector<Sqt> &localPoses = m_skeletonData.localPoses;
+ QVector<JointInfo> &joints = m_skeletonData.joints;
+ for (int i = 0; i < m_skeletonData.joints.size(); ++i) {
+ // Calculate the global pose of this joint
+ JointInfo &joint = joints[i];
+ if (joint.parentIndex == -1) {
+ joint.globalPose = localPoses[i].toMatrix();
+ } else {
+ JointInfo &parentJoint = joints[joint.parentIndex];
+ joint.globalPose = parentJoint.globalPose * localPoses[i].toMatrix();
+ }
+
+ m_skinningPalette[i] = joint.globalPose * joint.inverseBindPose;
+ }
+ return m_skinningPalette;
+}
+
+
+SkeletonFunctor::SkeletonFunctor(AbstractRenderer *renderer,
+ SkeletonManager *skeletonManager,
+ JointManager *jointManager)
+ : m_renderer(renderer)
+ , m_skeletonManager(skeletonManager)
+ , m_jointManager(jointManager)
+{
+}
+
+Qt3DCore::QBackendNode *SkeletonFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const
+{
+ Skeleton *backend = m_skeletonManager->getOrCreateResource(change->subjectId());
+ backend->setRenderer(m_renderer);
+ backend->setSkeletonManager(m_skeletonManager);
+ backend->setJointManager(m_jointManager);
+ return backend;
+}
+
+Qt3DCore::QBackendNode *SkeletonFunctor::get(Qt3DCore::QNodeId id) const
+{
+ return m_skeletonManager->lookupResource(id);
+}
+
+void SkeletonFunctor::destroy(Qt3DCore::QNodeId id) const
+{
+ m_skeletonManager->releaseResource(id);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/geometry/skeleton_p.h b/src/render/geometry/skeleton_p.h
new file mode 100644
index 000000000..8907987d9
--- /dev/null
+++ b/src/render/geometry/skeleton_p.h
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_SKELETON_H
+#define QT3DRENDER_RENDER_SKELETON_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/backendnode_p.h>
+#include <Qt3DRender/private/skeletondata_p.h>
+#include <Qt3DRender/private/handle_types_p.h>
+#include <Qt3DCore/qskeletonloader.h>
+
+#include <QtGui/qmatrix4x4.h>
+#include <QDebug>
+
+#if defined(QT_BUILD_INTERNAL)
+class tst_Skeleton;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QJoint;
+}
+
+namespace Qt3DRender {
+namespace Render {
+
+class JointManager;
+class SkeletonManager;
+
+class Q_AUTOTEST_EXPORT Skeleton : public BackendNode
+{
+public:
+ Skeleton();
+
+ void setSkeletonManager(SkeletonManager *skeletonManager) { m_skeletonManager = skeletonManager; }
+ SkeletonManager *skeletonManager() const { return m_skeletonManager; }
+
+ void setJointManager(JointManager *jointManager) { m_jointManager = jointManager; }
+ JointManager *jointManager() const { return m_jointManager; }
+
+ void cleanup();
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+ void setStatus(Qt3DCore::QSkeletonLoader::Status status);
+ Qt3DCore::QSkeletonLoader::Status status() const { return m_status; }
+
+ QUrl source() const { return m_source; }
+
+ void setName(const QString &name) { m_name = name; }
+ QString name() const { return m_name; }
+
+ int jointCount() const { return m_skeletonData.joints.size(); }
+ void notifyJointCount();
+ void notifyJointNamesAndPoses();
+ QVector<JointInfo> joints() const { return m_skeletonData.joints; }
+
+ Qt3DCore::QNodeId rootJointId() const { return m_rootJointId; }
+
+ // Called from jobs
+ void loadSkeleton();
+ void setLocalPose(HJoint jointHandle, const Qt3DCore::Sqt &localPose);
+ QVector<QMatrix4x4> calculateSkinningMatrixPalette();
+
+ // Allow unit tests to set the data type
+#if !defined(QT_BUILD_INTERNAL)
+private:
+#endif
+ enum SkeletonDataType {
+ Unknown,
+ File,
+ Data
+ };
+#if defined(QT_BUILD_INTERNAL)
+public:
+ void setDataType(SkeletonDataType dataType) { m_dataType = dataType; }
+#endif
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ void loadSkeletonFromUrl();
+ void loadSkeletonFromData();
+ Qt3DCore::QJoint *createFrontendJoints(const SkeletonData &skeletonData) const;
+ Qt3DCore::QJoint *createFrontendJoint(const QString &jointName,
+ const Qt3DCore::Sqt &localPose,
+ const QMatrix4x4 &inverseBindMatrix) const;
+ void processJointHierarchy(Qt3DCore::QNodeId jointId, int parentJointIndex, SkeletonData &skeletonData);
+ void clearData();
+
+ QVector<QMatrix4x4> m_skinningPalette;
+
+ // QSkeletonLoader Properties
+ QUrl m_source;
+ Qt3DCore::QSkeletonLoader::Status m_status;
+ bool m_createJoints;
+
+ // QSkeleton properties
+ Qt3DCore::QNodeId m_rootJointId;
+
+ SkeletonDataType m_dataType;
+
+ QString m_name;
+ SkeletonData m_skeletonData;
+ SkeletonManager *m_skeletonManager;
+ JointManager *m_jointManager;
+ HSkeleton m_skeletonHandle; // Our own handle to set on joints
+
+#if defined(QT_BUILD_INTERNAL)
+ friend class ::tst_Skeleton;
+#endif
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+inline QDebug operator<<(QDebug dbg, const Skeleton &skeleton)
+{
+ QDebugStateSaver saver(dbg);
+ dbg << "QNodeId =" << skeleton.peerId() << endl
+ << "Name =" << skeleton.name() << endl;
+ return dbg;
+}
+#endif
+
+class SkeletonFunctor : public Qt3DCore::QBackendNodeMapper
+{
+public:
+ explicit SkeletonFunctor(AbstractRenderer *renderer,
+ SkeletonManager *skeletonManager,
+ JointManager *jointManager);
+ Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const final;
+ Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const final;
+ void destroy(Qt3DCore::QNodeId id) const final;
+
+private:
+ AbstractRenderer *m_renderer;
+ SkeletonManager *m_skeletonManager;
+ JointManager *m_jointManager;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_SKELETON_H
diff --git a/src/render/geometry/skeletondata.cpp b/src/render/geometry/skeletondata.cpp
new file mode 100644
index 000000000..bbb59e82d
--- /dev/null
+++ b/src/render/geometry/skeletondata.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "skeletondata_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+SkeletonData::SkeletonData()
+{
+}
+
+void SkeletonData::reserve(int size)
+{
+ joints.reserve(size);
+ localPoses.reserve(size);
+ jointNames.reserve(size);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/geometry/skeletondata_p.h b/src/render/geometry/skeletondata_p.h
new file mode 100644
index 000000000..b30a3c6d4
--- /dev/null
+++ b/src/render/geometry/skeletondata_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_SKELETONDATA_P_H
+#define QT3DRENDER_RENDER_SKELETONDATA_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/qnodeid.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvector.h>
+#include <Qt3DCore/private/sqt_p.h>
+
+#include <Qt3DRender/private/handle_types_p.h>
+#include <Qt3DRender/private/joint_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+struct Q_AUTOTEST_EXPORT JointInfo
+{
+ JointInfo()
+ : parentIndex(-1)
+ {
+ }
+
+ explicit JointInfo(Joint *joint, int parentJointIndex)
+ : inverseBindPose(joint->inverseBindMatrix())
+ , parentIndex(parentJointIndex)
+ {
+ }
+
+ QMatrix4x4 inverseBindPose;
+ QMatrix4x4 globalPose;
+ int parentIndex;
+};
+
+struct Q_AUTOTEST_EXPORT SkeletonData
+{
+ SkeletonData();
+
+ void reserve(int size);
+
+ QVector<JointInfo> joints;
+ QVector<Qt3DCore::Sqt> localPoses;
+ QVector<QString> jointNames;
+ QHash<HJoint, int> jointIndices;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_SKELETONDATA_P_H
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index 5ac83cac0..9a20c77e7 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -59,6 +59,7 @@
#include <Qt3DRender/private/gltexturemanager_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
#include <Qt3DRender/private/qbuffer_p.h>
+#include <Qt3DRender/private/renderbuffer_p.h>
#include <QOpenGLShaderProgram>
#if !defined(QT_OPENGL_ES_2)
@@ -73,6 +74,7 @@
#endif
#include <Qt3DRender/private/graphicshelperes2_p.h>
#include <Qt3DRender/private/graphicshelperes3_p.h>
+#include <Qt3DRender/private/graphicshelperes3_2_p.h>
#include <QSurface>
#include <QWindow>
@@ -118,22 +120,14 @@ static void logOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage)
namespace {
-GLBuffer::Type bufferTypeToGLBufferType(QBuffer::BufferType type)
+GLBuffer::Type attributeTypeToGLBufferType(QAttribute::AttributeType type)
{
switch (type) {
- case QBuffer::VertexBuffer:
+ case QAttribute::VertexAttribute:
return GLBuffer::ArrayBuffer;
- case QBuffer::IndexBuffer:
+ case QAttribute::IndexAttribute:
return GLBuffer::IndexBuffer;
- case QBuffer::PixelPackBuffer:
- return GLBuffer::PixelPackBuffer;
- case QBuffer::PixelUnpackBuffer:
- return GLBuffer::PixelUnpackBuffer;
- case QBuffer::UniformBuffer:
- return GLBuffer::UniformBuffer;
- case QBuffer::ShaderStorageBuffer:
- return GLBuffer::ShaderStorageBuffer;
- case QBuffer::DrawIndirectBuffer:
+ case QAttribute::DrawIndirectAttribute:
return GLBuffer::DrawIndirectBuffer;
default:
Q_UNREACHABLE();
@@ -476,7 +470,7 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode)
if (!shaderCode.at(i).isEmpty()) {
// Note: logs only return the error but not all the shader code
// we could append it
- if (!shaderProgram->addShaderFromSourceCode(shaderType(type), shaderCode.at(i)))
+ if (!shaderProgram->addCacheableShaderFromSourceCode(shaderType(type), shaderCode.at(i)))
logs += shaderProgram->log();
}
}
@@ -627,20 +621,35 @@ void GraphicsContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId,
void GraphicsContext::bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments)
{
- // Set FBO attachments
+ // Set FBO attachments. These are normally textures, except that on Open GL
+ // ES <= 3.1 we must use a renderbuffer if a combined depth+stencil is
+ // desired since this cannot be achieved neither with a single texture (not
+ // before GLES 3.2) nor with separate textures (no suitable format for
+ // stencil before 3.1 with the appropriate extension).
QSize fboSize;
GLTextureManager *glTextureManager = m_renderer->nodeManagers()->glTextureManager();
const auto attachments_ = attachments.attachments();
for (const Attachment &attachment : attachments_) {
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);
+ if (!m_glHelper->frameBufferNeedsRenderBuffer(attachment)) {
+ 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);
+ }
+ } else {
+ RenderBuffer *renderBuffer = rTex ? rTex->getOrCreateRenderBuffer() : nullptr;
+ if (renderBuffer) {
+ if (fboSize.isEmpty())
+ fboSize = QSize(renderBuffer->width(), renderBuffer->height());
+ else
+ fboSize = QSize(qMin(fboSize.width(), renderBuffer->width()), qMin(fboSize.height(), renderBuffer->height()));
+ m_glHelper->bindFrameBufferAttachment(renderBuffer, attachment);
+ }
}
}
m_renderTargetsSize.insert(fboId, fboSize);
@@ -731,8 +740,13 @@ GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
if (m_gl->isOpenGLES()) {
if (m_gl->format().majorVersion() >= 3) {
- glHelper = new GraphicsHelperES3();
- qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES3 Helper";
+ if (m_gl->format().minorVersion() >= 2) {
+ glHelper = new GraphicsHelperES3_2;
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.2 Helper";
+ } else {
+ glHelper = new GraphicsHelperES3();
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.0 Helper";
+ }
} else {
glHelper = new GraphicsHelperES2();
qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES2 Helper";
@@ -1089,9 +1103,9 @@ GLboolean GraphicsContext::unmapBuffer(GLenum target)
return m_glHelper->unmapBuffer(target);
}
-char *GraphicsContext::mapBuffer(GLenum target)
+char *GraphicsContext::mapBuffer(GLenum target, GLsizeiptr size)
{
- return m_glHelper->mapBuffer(target);
+ return m_glHelper->mapBuffer(target, size);
}
void GraphicsContext::enablei(GLenum cap, GLuint index)
@@ -1203,7 +1217,7 @@ bool GraphicsContext::setParameters(ShaderParameterPack &parameterPack)
int ssboIndex = 0;
for (const BlockToSSBO b : blockToSSBOs) {
Buffer *cpuBuffer = m_renderer->nodeManagers()->bufferManager()->lookupResource(b.m_bufferID);
- GLBuffer *ssbo = glBufferForRenderBuffer(cpuBuffer);
+ GLBuffer *ssbo = glBufferForRenderBuffer(cpuBuffer, GLBuffer::ShaderStorageBuffer);
bindShaderStorageBlock(shader->programId(), b.m_blockIndex, ssboIndex);
// Needed to avoid conflict where the buffer would already
// be bound as a VertexArray
@@ -1218,7 +1232,7 @@ bool GraphicsContext::setParameters(ShaderParameterPack &parameterPack)
int uboIndex = 0;
for (const BlockToUBO &b : blockToUBOs) {
Buffer *cpuBuffer = m_renderer->nodeManagers()->bufferManager()->lookupResource(b.m_bufferID);
- GLBuffer *ubo = glBufferForRenderBuffer(cpuBuffer);
+ GLBuffer *ubo = glBufferForRenderBuffer(cpuBuffer, GLBuffer::UniformBuffer);
bindUniformBlock(shader->programId(), b.m_blockIndex, uboIndex);
// Needed to avoid conflict where the buffer would already
// be bound as a VertexArray
@@ -1247,20 +1261,34 @@ bool GraphicsContext::setParameters(ShaderParameterPack &parameterPack)
return allValid;
}
+void GraphicsContext::readBuffer(GLenum mode)
+{
+ m_glHelper->readBuffer(mode);
+}
+
+void GraphicsContext::drawBuffer(GLenum mode)
+{
+ m_glHelper->drawBuffer(mode);
+}
+
void GraphicsContext::enableAttribute(const VAOVertexAttribute &attr)
{
// Bind buffer within the current VAO
GLBuffer *buf = m_renderer->nodeManagers()->glBufferManager()->data(attr.bufferHandle);
Q_ASSERT(buf);
- bindGLBuffer(buf, attr.bufferType);
+ bindGLBuffer(buf, attr.attributeType);
+
+ // Don't use QOpenGLShaderProgram::setAttributeBuffer() because of QTBUG-43199.
+ // Use the introspection data and set the attribute explicitly
+ m_glHelper->enableVertexAttributeArray(attr.location);
+ m_glHelper->vertexAttributePointer(attr.shaderDataType,
+ attr.location,
+ attr.vertexSize,
+ attr.dataType,
+ GL_TRUE, // TODO: Support normalization property on QAttribute
+ attr.byteStride,
+ reinterpret_cast<const void *>(qintptr(attr.byteOffset)));
- QOpenGLShaderProgram *prog = activeShader();
- prog->enableAttributeArray(attr.location);
- prog->setAttributeBuffer(attr.location,
- attr.dataType,
- attr.byteOffset,
- attr.vertexSize,
- attr.byteStride);
// Done by the helper if it supports it
if (attr.divisor != 0)
@@ -1283,100 +1311,100 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
if (v.storedType() == Int) {
float value = float(*v.constData<int>());
UniformValue floatV(value);
- applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, floatV);
+ applyUniformHelper<UniformType::Float>(description, floatV);
} else {
- applyUniformHelper<UniformType::Float>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Float>(description, v);
}
break;
case UniformType::Vec2:
- applyUniformHelper<UniformType::Vec2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Vec2>(description, v);
break;
case UniformType::Vec3:
- applyUniformHelper<UniformType::Vec3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Vec3>(description, v);
break;
case UniformType::Vec4:
- applyUniformHelper<UniformType::Vec4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Vec4>(description, v);
break;
case UniformType::Double:
- applyUniformHelper<UniformType::Double>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Double>(description, v);
break;
case UniformType::DVec2:
- applyUniformHelper<UniformType::DVec2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::DVec2>(description, v);
break;
case UniformType::DVec3:
- applyUniformHelper<UniformType::DVec3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::DVec3>(description, v);
break;
case UniformType::DVec4:
- applyUniformHelper<UniformType::DVec4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::DVec4>(description, v);
break;
case UniformType::Sampler:
case UniformType::Int:
- applyUniformHelper<UniformType::Int>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Int>(description, v);
break;
case UniformType::IVec2:
- applyUniformHelper<UniformType::IVec2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::IVec2>(description, v);
break;
case UniformType::IVec3:
- applyUniformHelper<UniformType::IVec3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::IVec3>(description, v);
break;
case UniformType::IVec4:
- applyUniformHelper<UniformType::IVec4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::IVec4>(description, v);
break;
case UniformType::UInt:
- applyUniformHelper<UniformType::UInt>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UInt>(description, v);
break;
case UniformType::UIVec2:
- applyUniformHelper<UniformType::UIVec2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UIVec2>(description, v);
break;
case UniformType::UIVec3:
- applyUniformHelper<UniformType::UIVec3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UIVec3>(description, v);
break;
case UniformType::UIVec4:
- applyUniformHelper<UniformType::UIVec4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UIVec4>(description, v);
break;
case UniformType::Bool:
- applyUniformHelper<UniformType::Bool>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Bool>(description, v);
break;
case UniformType::BVec2:
- applyUniformHelper<UniformType::BVec2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::BVec2>(description, v);
break;
case UniformType::BVec3:
- applyUniformHelper<UniformType::BVec3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::BVec3>(description, v);
break;
case UniformType::BVec4:
- applyUniformHelper<UniformType::BVec4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::BVec4>(description, v);
break;
case UniformType::Mat2:
- applyUniformHelper<UniformType::Mat2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat2>(description, v);
break;
case UniformType::Mat3:
- applyUniformHelper<UniformType::Mat3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat3>(description, v);
break;
case UniformType::Mat4:
- applyUniformHelper<UniformType::Mat4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat4>(description, v);
break;
case UniformType::Mat2x3:
- applyUniformHelper<UniformType::Mat2x3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat2x3>(description, v);
break;
case UniformType::Mat3x2:
- applyUniformHelper<UniformType::Mat3x2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat3x2>(description, v);
break;
case UniformType::Mat2x4:
- applyUniformHelper<UniformType::Mat2x4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat2x4>(description, v);
break;
case UniformType::Mat4x2:
- applyUniformHelper<UniformType::Mat4x2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat4x2>(description, v);
break;
case UniformType::Mat3x4:
- applyUniformHelper<UniformType::Mat3x4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat3x4>(description, v);
break;
case UniformType::Mat4x3:
- applyUniformHelper<UniformType::Mat4x3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::Mat4x3>(description, v);
break;
default:
@@ -1385,8 +1413,11 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
}
// Note: needs to be called while VAO is bound
-void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffer, int location)
+void GraphicsContext::specifyAttribute(const Attribute *attribute,
+ Buffer *buffer,
+ const ShaderAttribute *attributeDescription)
{
+ const int location = attributeDescription->m_location;
if (location < 0) {
qCWarning(Backend) << "failed to resolve location for attribute:" << attribute->name();
return;
@@ -1394,7 +1425,8 @@ void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffe
const GLint attributeDataType = glDataTypeFromAttributeDataType(attribute->vertexBaseType());
const HGLBuffer glBufferHandle = m_renderer->nodeManagers()->glBufferManager()->lookupHandle(buffer->peerId());
- const GLBuffer::Type bufferType = bufferTypeToGLBufferType(buffer->type());
+ Q_ASSERT(!glBufferHandle.isNull());
+ const GLBuffer::Type attributeType = attributeTypeToGLBufferType(attribute->attributeType());
int typeSize = 0;
int attrCount = 0;
@@ -1414,13 +1446,14 @@ void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffe
for (int i = 0; i < attrCount; i++) {
VAOVertexAttribute attr;
attr.bufferHandle = glBufferHandle;
- attr.bufferType = bufferType;
+ attr.attributeType = attributeType;
attr.location = location + i;
attr.dataType = attributeDataType;
attr.byteOffset = attribute->byteOffset() + (i * attrCount * typeSize);
attr.vertexSize = attribute->vertexSize() / attrCount;
attr.byteStride = (attribute->byteStride() != 0) ? attribute->byteStride() : (attrCount * attrCount * typeSize);
attr.divisor = attribute->divisor();
+ attr.shaderDataType = attributeDescription->m_type;
enableAttribute(attr);
@@ -1432,9 +1465,7 @@ void GraphicsContext::specifyAttribute(const Attribute *attribute, Buffer *buffe
void GraphicsContext::specifyIndices(Buffer *buffer)
{
- Q_ASSERT(buffer->type() == QBuffer::IndexBuffer);
-
- GLBuffer *buf = glBufferForRenderBuffer(buffer);
+ GLBuffer *buf = glBufferForRenderBuffer(buffer, GLBuffer::IndexBuffer);
if (!bindGLBuffer(buf, GLBuffer::IndexBuffer))
qCWarning(Backend) << Q_FUNC_INFO << "binding index buffer failed";
@@ -1484,19 +1515,71 @@ bool GraphicsContext::hasGLBufferForBuffer(Buffer *buffer)
return (it != m_renderBufferHash.end());
}
+void GraphicsContext::blitFramebuffer(Qt3DCore::QNodeId inputRenderTarget,
+ Qt3DCore::QNodeId outputRenderTarget,
+ QRect inputRect, QRect outputRect,
+ uint defaultFboId,
+ QRenderTargetOutput::AttachmentPoint inputAttachmentPoint,
+ QRenderTargetOutput::AttachmentPoint outputAttachmentPoint,
+ QBlitFramebuffer::InterpolationMethod interpolationMethod)
+{
+ //Find the context side name for the render targets
+ const GLuint inputFboId = m_renderTargets[inputRenderTarget];
+ GLuint outputFboId = defaultFboId;
+ bool outputBufferIsDefault = true;
+ if (!outputRenderTarget.isNull() && m_renderTargets.contains(outputRenderTarget)) {
+ outputFboId = m_renderTargets[outputRenderTarget];
+ outputBufferIsDefault = false;
+ }
+
+ const GLint srcX0 = inputRect.left();
+ const GLint srcY0 = inputRect.top();
+ const GLint srcX1 = srcX0 + inputRect.width();
+ const GLint srcY1 = srcY0 + inputRect.height();
+
+ const GLint dstX0 = outputRect.left();
+ const GLint dstY0 = outputRect.top();
+ const GLint dstX1 = dstX0 + outputRect.width();
+ const GLint dstY1 = dstY0 + outputRect.height();
+
+ //Get the last bounded framebuffers
+ const GLuint lastDrawFboId = boundFrameBufferObject();
+
+ // Activate input framebuffer for reading
+ bindFramebuffer(inputFboId, GraphicsHelperInterface::FBORead);
+
+ // Activate output framebuffer for writing
+ bindFramebuffer(outputFboId, GraphicsHelperInterface::FBODraw);
+
+ //Bind texture
+ readBuffer(GL_COLOR_ATTACHMENT0 + inputAttachmentPoint);
+
+ if (!outputBufferIsDefault)
+ drawBuffer(GL_COLOR_ATTACHMENT0 + outputAttachmentPoint);
+
+ // Blit framebuffer
+ const GLenum mode = interpolationMethod ? GL_NEAREST : GL_LINEAR;
+ m_glHelper->blitFramebuffer(srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ GL_COLOR_BUFFER_BIT, mode);
+
+ // Reset draw buffer
+ bindFramebuffer(lastDrawFboId, GraphicsHelperInterface::FBOReadAndDraw);
+}
+
void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers)
{
m_glHelper->memoryBarrier(barriers);
}
-GLBuffer *GraphicsContext::glBufferForRenderBuffer(Buffer *buf)
+GLBuffer *GraphicsContext::glBufferForRenderBuffer(Buffer *buf, GLBuffer::Type type)
{
if (!m_renderBufferHash.contains(buf->peerId()))
- m_renderBufferHash.insert(buf->peerId(), createGLBufferFor(buf));
+ m_renderBufferHash.insert(buf->peerId(), createGLBufferFor(buf, type));
return m_renderer->nodeManagers()->glBufferManager()->data(m_renderBufferHash.value(buf->peerId()));
}
-HGLBuffer GraphicsContext::createGLBufferFor(Buffer *buffer)
+HGLBuffer GraphicsContext::createGLBufferFor(Buffer *buffer, GLBuffer::Type type)
{
GLBuffer *b = m_renderer->nodeManagers()->glBufferManager()->getOrCreateResource(buffer->peerId());
// b.setUsagePattern(static_cast<QOpenGLBuffer::UsagePattern>(buffer->usage()));
@@ -1504,7 +1587,7 @@ HGLBuffer GraphicsContext::createGLBufferFor(Buffer *buffer)
if (!b->create(this))
qCWarning(Render::Io) << Q_FUNC_INFO << "buffer creation failed";
- if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type())))
+ if (!bindGLBuffer(b, type))
qCWarning(Render::Io) << Q_FUNC_INFO << "buffer binding failed";
return m_renderer->nodeManagers()->glBufferManager()->lookupHandle(buffer->peerId());
@@ -1525,7 +1608,7 @@ bool GraphicsContext::bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type)
void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer)
{
- if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type())))
+ if (!bindGLBuffer(b, GLBuffer::ArrayBuffer)) // We're uploading, the type doesn't matter here
qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed";
// If the buffer is dirty (hence being called here)
// there are two possible cases
@@ -1567,15 +1650,14 @@ void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool rel
if (releaseBuffer) {
b->release(this);
- if (bufferTypeToGLBufferType(buffer->type()) == GLBuffer::ArrayBuffer)
- m_boundArrayBuffer = nullptr;
+ m_boundArrayBuffer = nullptr;
}
qCDebug(Render::Io) << "uploaded buffer size=" << buffer->data().size();
}
QByteArray GraphicsContext::downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b)
{
- if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type())))
+ if (!bindGLBuffer(b, GLBuffer::ArrayBuffer)) // We're downloading, the type doesn't matter here
qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed";
QByteArray data = b->download(this, buffer->data().size());
@@ -1728,10 +1810,10 @@ static void copyGLFramebufferDataToImage(QImage &img, const uchar *srcData, uint
}
}
-QImage GraphicsContext::readFramebuffer(QSize size)
+QImage GraphicsContext::readFramebuffer(const QRect &rect)
{
QImage img;
- const unsigned int area = size.width() * size.height();
+ const unsigned int area = rect.width() * rect.height();
unsigned int bytes;
GLenum format, type;
QImage::Format imageFormat;
@@ -1756,7 +1838,7 @@ QImage GraphicsContext::readFramebuffer(QSize size)
#endif
type = GL_UNSIGNED_BYTE;
bytes = area * 4;
- stride = size.width() * 4;
+ stride = rect.width() * 4;
break;
case QAbstractTexture::SRGB8:
case QAbstractTexture::RGBFormat:
@@ -1772,7 +1854,7 @@ QImage GraphicsContext::readFramebuffer(QSize size)
#endif
type = GL_UNSIGNED_BYTE;
bytes = area * 4;
- stride = size.width() * 4;
+ stride = rect.width() * 4;
break;
#ifndef QT_OPENGL_ES_2
case QAbstractTexture::RG11B10F:
@@ -1780,14 +1862,14 @@ QImage GraphicsContext::readFramebuffer(QSize size)
format = GL_RGB;
type = GL_UNSIGNED_INT_10F_11F_11F_REV;
imageFormat = QImage::Format_RGB30;
- stride = size.width() * 4;
+ stride = rect.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;
+ stride = rect.width() * 4;
break;
case QAbstractTexture::R5G6B5:
bytes = area * 2;
@@ -1795,7 +1877,7 @@ QImage GraphicsContext::readFramebuffer(QSize size)
type = GL_UNSIGNED_SHORT;
internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV;
imageFormat = QImage::Format_RGB16;
- stride = size.width() * 2;
+ stride = rect.width() * 2;
break;
case QAbstractTexture::RGBA16F:
case QAbstractTexture::RGBA16U:
@@ -1805,7 +1887,7 @@ QImage GraphicsContext::readFramebuffer(QSize size)
format = GL_RGBA;
type = GL_FLOAT;
imageFormat = QImage::Format_ARGB32_Premultiplied;
- stride = size.width() * 16;
+ stride = rect.width() * 16;
break;
#endif
default:
@@ -1822,7 +1904,7 @@ QImage GraphicsContext::readFramebuffer(QSize size)
return img;
}
- img = QImage(size.width(), size.height(), imageFormat);
+ img = QImage(rect.width(), rect.height(), imageFormat);
QScopedArrayPointer<uchar> data(new uchar [bytes]);
@@ -1834,7 +1916,7 @@ QImage GraphicsContext::readFramebuffer(QSize size)
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->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, rect.width(), rect.height());
gl->glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
const GLenum status = gl->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
@@ -1845,13 +1927,13 @@ QImage GraphicsContext::readFramebuffer(QSize size)
return img;
}
- m_glHelper->blitFramebuffer(0, 0, size.width(), size.height(),
- 0, 0, size.width(), size.height(),
+ m_glHelper->blitFramebuffer(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(),
+ 0, 0, rect.width(), rect.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());
+ gl->glReadPixels(0,0,rect.width(), rect.height(), format, type, data.data());
- copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat);
+ copyGLFramebufferDataToImage(img, data.data(), stride, rect.width(), rect.height(), m_renderTargetFormat);
gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
gl->glDeleteRenderbuffers(1, &rb);
@@ -1859,8 +1941,8 @@ QImage GraphicsContext::readFramebuffer(QSize size)
gl->glDeleteFramebuffers(1, &fbo);
} else {
// 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);
+ m_gl->functions()->glReadPixels(rect.x(), rect.y(), rect.width(), rect.height(), format, type, data.data());
+ copyGLFramebufferDataToImage(img, data.data(), stride, rect.width(), rect.height(), m_renderTargetFormat);
}
return img;
diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h
index 79089a31e..b07a11c7e 100644
--- a/src/render/graphicshelpers/graphicscontext_p.h
+++ b/src/render/graphicshelpers/graphicscontext_p.h
@@ -71,6 +71,8 @@
#include <Qt3DRender/private/shadercache_p.h>
#include <Qt3DRender/private/uniform_p.h>
#include <Qt3DRender/private/graphicshelperinterface_p.h>
+#include <Qt3DRender/private/qblitframebuffer_p.h>
+#include <qmath.h>
QT_BEGIN_NAMESPACE
@@ -157,24 +159,36 @@ public:
void setRenderer(Renderer *renderer);
- void specifyAttribute(const Attribute *attribute, Buffer *buffer, int attributeLocation);
+ void specifyAttribute(const Attribute *attribute,
+ Buffer *buffer,
+ const ShaderAttribute *attributeDescription);
void specifyIndices(Buffer *buffer);
void updateBuffer(Buffer *buffer);
QByteArray downloadBufferContent(Buffer *buffer);
void releaseBuffer(Qt3DCore::QNodeId bufferId);
bool hasGLBufferForBuffer(Buffer *buffer);
+ void blitFramebuffer(Qt3DCore::QNodeId outputRenderTarget, Qt3DCore::QNodeId inputRenderTarget,
+ QRect inputRect,
+ QRect outputRect, uint defaultFboId,
+ QRenderTargetOutput::AttachmentPoint inputAttachmentPoint,
+ QRenderTargetOutput::AttachmentPoint outputAttachmentPoint,
+ QBlitFramebuffer::InterpolationMethod interpolationMethod);
+
void memoryBarrier(QMemoryBarrier::Operations barriers);
bool setParameters(ShaderParameterPack &parameterPack);
+ void readBuffer(GLenum mode);
+ void drawBuffer(GLenum mode);
+
/**
* @brief glBufferFor - given a client-side (CPU) buffer, provide the
* context-specific object. Initial call will create the buffer.
* @param buf
* @return
*/
- GLBuffer *glBufferForRenderBuffer(Buffer *buf);
+ GLBuffer *glBufferForRenderBuffer(Buffer *buf, GLBuffer::Type type);
/**
* @brief activateTexture - make a texture active on a hardware unit
@@ -212,7 +226,7 @@ public:
void disablei(GLenum cap, GLuint index);
void disablePrimitiveRestart();
void dispatchCompute(int x, int y, int z);
- char * mapBuffer(GLenum target);
+ char * mapBuffer(GLenum target, GLsizeiptr size);
GLboolean unmapBuffer(GLenum target);
void drawArrays(GLenum primitiveType, GLint first, GLsizei count);
void drawArraysIndirect(GLenum mode,void *indirect);
@@ -242,7 +256,7 @@ public:
bool supportsDrawBuffersBlend() const;
bool supportsVAO() const { return m_supportsVAO; }
- QImage readFramebuffer(QSize size);
+ QImage readFramebuffer(const QRect &rect);
private:
void initialize();
@@ -256,7 +270,7 @@ private:
void bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments);
void activateDrawBuffers(const AttachmentPack &attachments);
- HGLBuffer createGLBufferFor(Buffer *buffer);
+ HGLBuffer createGLBufferFor(Buffer *buffer, GLBuffer::Type type);
void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false);
QByteArray downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b);
bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type);
@@ -317,13 +331,14 @@ private:
struct VAOVertexAttribute
{
HGLBuffer bufferHandle;
- GLBuffer::Type bufferType;
+ GLBuffer::Type attributeType;
int location;
GLint dataType;
uint byteOffset;
uint vertexSize;
uint byteStride;
uint divisor;
+ GLenum shaderDataType;
};
using VAOIndexAttribute = HGLBuffer;
@@ -334,7 +349,7 @@ private:
void applyUniform(const ShaderUniform &description, const UniformValue &v);
template<UniformType>
- void applyUniformHelper(int, int, const UniformValue &) const
+ void applyUniformHelper(const ShaderUniform &, const UniformValue &) const
{
Q_ASSERT_X(false, Q_FUNC_INFO, "Uniform: Didn't provide specialized apply() implementation");
}
@@ -342,13 +357,14 @@ private:
#define QT3D_UNIFORM_TYPE_PROTO(UniformTypeEnum, BaseType, Func) \
template<> \
-void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, int count, const UniformValue &value) const;
+void GraphicsContext::applyUniformHelper<UniformTypeEnum>(const ShaderUniform &description, const UniformValue &value) const;
#define QT3D_UNIFORM_TYPE_IMPL(UniformTypeEnum, BaseType, Func) \
template<> \
- void GraphicsContext::applyUniformHelper<UniformTypeEnum>(int location, int count, const UniformValue &value) const \
+ void GraphicsContext::applyUniformHelper<UniformTypeEnum>(const ShaderUniform &description, const UniformValue &value) const \
{ \
- m_glHelper->Func(location, count, value.constData<BaseType>()); \
+ const int count = qMin(description.m_size, int(value.byteSize() / description.m_rawByteSize)); \
+ m_glHelper->Func(description.m_location, count, value.constData<BaseType>()); \
}
diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp
index f92941e98..676363b73 100644
--- a/src/render/graphicshelpers/graphicshelperes2.cpp
+++ b/src/render/graphicshelpers/graphicshelperes2.cpp
@@ -41,6 +41,7 @@
#include <Qt3DRender/private/renderlogging_p.h>
#include <private/attachmentpack_p.h>
#include <private/qgraphicsutils_p.h>
+#include <private/renderbuffer_p.h>
#include <QtGui/private/qopenglextensions_p.h>
QT_BEGIN_NAMESPACE
@@ -208,6 +209,9 @@ QVector<ShaderUniform> GraphicsHelperES2::programUniformsAndLocations(GLuint pro
uniformName[sizeof(uniformName) - 1] = '\0';
uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
uniforms.append(uniform);
}
return uniforms;
@@ -257,6 +261,43 @@ void GraphicsHelperES2::vertexAttribDivisor(GLuint index, GLuint divisor)
Q_UNUSED(divisor);
}
+void GraphicsHelperES2::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperES2::readBuffer(GLenum mode)
+{
+ Q_UNUSED(mode)
+ qWarning() << "glReadBuffer not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+void GraphicsHelperES2::drawBuffer(GLenum mode)
+{
+ Q_UNUSED(mode);
+ qWarning() << "glDrawBuffer is not supported with OpenGL ES 2";
+}
+
void GraphicsHelperES2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -355,6 +396,13 @@ bool GraphicsHelperES2::checkFrameBufferComplete()
return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
+bool GraphicsHelperES2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ // Use a renderbuffer for combined depth+stencil attachments since this is
+ // problematic before GLES 3.2. Keep using textures for everything else.
+ return attachment.m_point == QRenderTargetOutput::DepthStencil;
+}
+
void GraphicsHelperES2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
GLenum attr = GL_COLOR_ATTACHMENT0;
@@ -385,6 +433,20 @@ void GraphicsHelperES2::bindFrameBufferAttachment(QOpenGLTexture *texture, const
texture->release();
}
+void GraphicsHelperES2::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ if (attachment.m_point != QRenderTargetOutput::DepthStencil) {
+ qCritical() << "Renderbuffers only supported for combined depth-stencil, but got attachment point"
+ << attachment.m_point;
+ return;
+ }
+
+ renderBuffer->bind();
+ m_funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->renderBufferId());
+ m_funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->renderBufferId());
+ renderBuffer->release();
+}
+
bool GraphicsHelperES2::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
@@ -528,6 +590,11 @@ void GraphicsHelperES2::enablePrimitiveRestart(int)
{
}
+void GraphicsHelperES2::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
void GraphicsHelperES2::disablePrimitiveRestart()
{
}
@@ -601,9 +668,10 @@ void GraphicsHelperES2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
qWarning() << "Compute Shaders are not supported by ES 2.0 (since ES 3.1)";
}
-char *GraphicsHelperES2::mapBuffer(GLenum target)
+char *GraphicsHelperES2::mapBuffer(GLenum target, GLsizeiptr size)
{
Q_UNUSED(target);
+ Q_UNUSED(size);
qWarning() << "Map buffer is not a core requirement for ES 2.0";
return nullptr;
}
diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h
index 9255c1fda..eade3514a 100644
--- a/src/render/graphicshelpers/graphicshelperes2_p.h
+++ b/src/render/graphicshelpers/graphicshelperes2_p.h
@@ -72,7 +72,9 @@ public:
void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE;
void bindBufferBase(GLenum target, GLuint index, GLuint buffer) Q_DECL_OVERRIDE;
void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) Q_DECL_OVERRIDE;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) Q_DECL_OVERRIDE;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE;
@@ -91,7 +93,7 @@ public:
void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void disablePrimitiveRestart() Q_DECL_OVERRIDE;
void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE;
- char *mapBuffer(GLenum target) Q_DECL_OVERRIDE;
+ char *mapBuffer(GLenum target, GLsizeiptr size) Q_DECL_OVERRIDE;
GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE;
void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE;
void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE;
@@ -104,6 +106,7 @@ public:
void enableClipPlane(int clipPlane) Q_DECL_OVERRIDE;
void enablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void enablePrimitiveRestart(int primitiveRestartIndex) Q_DECL_OVERRIDE;
+ void enableVertexAttributeArray(int location) Q_DECL_OVERRIDE;
void frontFace(GLenum mode) Q_DECL_OVERRIDE;
QSize getRenderBufferDimensions(GLuint renderBufferId) Q_DECL_OVERRIDE;
QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) Q_DECL_OVERRIDE;
@@ -125,6 +128,9 @@ public:
uint uniformByteSize(const ShaderUniform &description) Q_DECL_OVERRIDE;
void useProgram(GLuint programId) Q_DECL_OVERRIDE;
void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) Q_DECL_OVERRIDE;
+ void readBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ void drawBuffer(GLenum mode) Q_DECL_OVERRIDE;
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelperes3.cpp b/src/render/graphicshelpers/graphicshelperes3.cpp
index fcd0a2ad2..813c627b8 100644
--- a/src/render/graphicshelpers/graphicshelperes3.cpp
+++ b/src/render/graphicshelpers/graphicshelperes3.cpp
@@ -40,6 +40,8 @@
#include "graphicshelperes3_p.h"
#include <private/attachmentpack_p.h>
+#include <private/qgraphicsutils_p.h>
+#include <private/renderlogging_p.h>
#include <QOpenGLExtraFunctions>
QT_BEGIN_NAMESPACE
@@ -60,6 +62,82 @@ QT_BEGIN_NAMESPACE
#ifndef GL_SAMPLER_2D_ARRAY_SHADOW
#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
#endif
+#ifndef GL_FLOAT_MAT2x3
+#define GL_FLOAT_MAT2x3 0x8B65
+#endif
+#ifndef GL_FLOAT_MAT2x4
+#define GL_FLOAT_MAT2x4 0x8B66
+#endif
+#ifndef GL_FLOAT_MAT3x2
+#define GL_FLOAT_MAT3x2 0x8B67
+#endif
+#ifndef GL_FLOAT_MAT3x4
+#define GL_FLOAT_MAT3x4 0x8B68
+#endif
+#ifndef GL_FLOAT_MAT4x2
+#define GL_FLOAT_MAT4x2 0x8B69
+#endif
+#ifndef GL_FLOAT_MAT4x3
+#define GL_FLOAT_MAT4x3 0x8B6A
+#endif
+#ifndef GL_UNSIGNED_INT_VEC2
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#endif
+#ifndef GL_UNSIGNED_INT_VEC3
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#endif
+#ifndef GL_UNSIGNED_INT_VEC4
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#endif
+#ifndef GL_INT_SAMPLER_2D
+#define GL_INT_SAMPLER_2D 0x8DCA
+#endif
+#ifndef GL_INT_SAMPLER_3D
+#define GL_INT_SAMPLER_3D 0x8DCB
+#endif
+#ifndef GL_INT_SAMPLER_CUBE
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#endif
+#ifndef GL_INT_SAMPLER_2D_ARRAY
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_2D
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_3D
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_CUBE
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_2D_ARRAY
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#endif
+
+#ifndef GL_ACTIVE_UNIFORM_BLOCKS
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#endif
+#ifndef GL_UNIFORM_BLOCK_INDEX
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#endif
+#ifndef GL_UNIFORM_OFFSET
+#define GL_UNIFORM_OFFSET 0x8A3B
+#endif
+#ifndef GL_UNIFORM_ARRAY_STRIDE
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#endif
+#ifndef GL_UNIFORM_MATRIX_STRIDE
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#endif
+#ifndef GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#endif
+#ifndef GL_UNIFORM_BLOCK_BINDING
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#endif
+#ifndef GL_UNIFORM_BLOCK_DATA_SIZE
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#endif
namespace Qt3DRender {
namespace Render {
@@ -106,6 +184,59 @@ void GraphicsHelperES3::vertexAttribDivisor(GLuint index, GLuint divisor)
m_extraFuncs->glVertexAttribDivisor(index, divisor);
}
+void GraphicsHelperES3::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_extraFuncs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperES3::readBuffer(GLenum mode)
+{
+ m_extraFuncs->glReadBuffer(mode);
+}
+
+void GraphicsHelperES3::drawBuffer(GLenum mode)
+{
+ Q_UNUSED(mode);
+ qWarning() << "glDrawBuffer is not supported with OpenGL ES 3";
+}
+
void GraphicsHelperES3::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
GLenum attr = GL_COLOR_ATTACHMENT0;
@@ -142,6 +273,8 @@ bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature
case RenderBufferDimensionRetrieval:
case MRT:
case BlitFramebuffer:
+ case UniformBufferObject:
+ case MapBuffer:
return true;
default:
return false;
@@ -176,6 +309,265 @@ void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, G
m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
+void GraphicsHelperES3::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ m_extraFuncs->glBindBufferBase(target, index, buffer);
+}
+
+void GraphicsHelperES3::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ m_extraFuncs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding);
+}
+
+void GraphicsHelperES3::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ char *bufferData = buffer.data();
+
+ switch (description.m_type) {
+
+ case GL_FLOAT: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_FLOAT_VEC2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_FLOAT_VEC3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_FLOAT_VEC4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 3);
+ break;
+ }
+
+ case GL_INT: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_INT_VEC2: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_INT_VEC3: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_INT_VEC4: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_UNSIGNED_INT: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC2: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC3: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC4: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_BOOL: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_BOOL_VEC2: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_BOOL_VEC3: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_BOOL_VEC4: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ // note: only GLES 3.0 supported types, not the same as OpenGL proper
+ // (also, no MS samplers before ES 3.1)
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ {
+ Q_ASSERT(description.m_size == 1);
+ int value = v.toInt();
+ QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
+ break;
+ }
+
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name;
+ break;
+ }
+}
+
+char *GraphicsHelperES3::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ return static_cast<char*>(m_extraFuncs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+}
+
+GLboolean GraphicsHelperES3::unmapBuffer(GLenum target)
+{
+ return m_extraFuncs->glUnmapBuffer(target);
+}
+
+QVector<ShaderUniform> GraphicsHelperES3::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; i++) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_MATRIX_STRIDE, &uniform.m_matrixStride);
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ qCDebug(Render::Rendering) << uniform.m_name << "size" << uniform.m_size
+ << " offset" << uniform.m_offset
+ << " rawSize" << uniform.m_rawByteSize;
+ }
+
+ return uniforms;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperES3::programUniformBlocks(GLuint programId)
+{
+ QVector<ShaderUniformBlock> blocks;
+ GLint nbrActiveUniformsBlocks = 0;
+ m_extraFuncs->glGetProgramiv(programId, GL_ACTIVE_UNIFORM_BLOCKS, &nbrActiveUniformsBlocks);
+ blocks.reserve(nbrActiveUniformsBlocks);
+ for (GLint i = 0; i < nbrActiveUniformsBlocks; i++) {
+ QByteArray uniformBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderUniformBlock uniformBlock;
+ m_extraFuncs->glGetActiveUniformBlockName(programId, i, 256, &length, uniformBlockName.data());
+ uniformBlock.m_name = QString::fromUtf8(uniformBlockName.left(length));
+ uniformBlock.m_index = i;
+ m_extraFuncs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &uniformBlock.m_activeUniformsCount);
+ m_extraFuncs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_BINDING, &uniformBlock.m_binding);
+ m_extraFuncs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_DATA_SIZE, &uniformBlock.m_size);
+ blocks.append(uniformBlock);
+ }
+ return blocks;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/graphicshelpers/graphicshelperes3_2.cpp b/src/render/graphicshelpers/graphicshelperes3_2.cpp
new file mode 100644
index 000000000..6290d091d
--- /dev/null
+++ b/src/render/graphicshelpers/graphicshelperes3_2.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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 "graphicshelperes3_2_p.h"
+#include <QOpenGLExtraFunctions>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <private/attachmentpack_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperES3_2::GraphicsHelperES3_2()
+{
+}
+
+GraphicsHelperES3_2::~GraphicsHelperES3_2()
+{
+}
+
+bool GraphicsHelperES3_2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ // This is first ES version where we have glFramebufferTexture, so
+ // attaching a D24S8 texture to the combined depth-stencil attachment point
+ // should work.
+ return false;
+}
+
+void GraphicsHelperES3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_COLOR_ATTACHMENT0;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::DepthStencil)
+ attr = GL_DEPTH_STENCIL_ATTACHMENT;
+ else
+ qCritical() << "Unsupported FBO attachment OpenGL ES 3.2";
+
+ const QOpenGLTexture::Target target = texture->target();
+
+ texture->bind();
+ 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_extraFuncs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
+ texture->release();
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/graphicshelpers/graphicshelperes3_2_p.h b/src/render/graphicshelpers/graphicshelperes3_2_p.h
new file mode 100644
index 000000000..018db6481
--- /dev/null
+++ b/src/render/graphicshelpers/graphicshelperes3_2_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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_GRAPHICSHELPERES3_2_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERES3_2_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/graphicshelperes3_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsHelperES3_2 : public GraphicsHelperES3
+{
+public:
+ GraphicsHelperES3_2();
+ ~GraphicsHelperES3_2();
+
+ // QGraphicHelperInterface interface
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERES3_2_H
diff --git a/src/render/graphicshelpers/graphicshelperes3_p.h b/src/render/graphicshelpers/graphicshelperes3_p.h
index 7520328d4..84a906b49 100644
--- a/src/render/graphicshelpers/graphicshelperes3_p.h
+++ b/src/render/graphicshelpers/graphicshelperes3_p.h
@@ -63,16 +63,26 @@ class GraphicsHelperES3 : public GraphicsHelperES2
{
public:
GraphicsHelperES3();
- virtual ~GraphicsHelperES3();
+ ~GraphicsHelperES3();
// 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;
- virtual bool supportsFeature(Feature feature) const Q_DECL_OVERRIDE;
- virtual void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) Q_DECL_OVERRIDE;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) 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;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) Q_DECL_OVERRIDE;
+ void drawBuffers(GLsizei n, const int *bufs) Q_DECL_OVERRIDE;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) Q_DECL_OVERRIDE;
+ virtual void readBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ virtual void drawBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
+ char *mapBuffer(GLenum target, GLsizeiptr size) Q_DECL_OVERRIDE;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE;
+ bool supportsFeature(Feature feature) const Q_DECL_OVERRIDE;
+ GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) Q_DECL_OVERRIDE;
UniformType uniformTypeFromGLType(GLenum glType) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp
index 001176cd4..6da8a9b6f 100644
--- a/src/render/graphicshelpers/graphicshelpergl2.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl2.cpp
@@ -43,7 +43,7 @@
#include <private/attachmentpack_p.h>
#include <QtOpenGLExtensions/QOpenGLExtensions>
#include <private/qgraphicsutils_p.h>
-#include <QDebug>
+#include <Qt3DRender/private/renderlogging_p.h>
QT_BEGIN_NAMESPACE
@@ -178,6 +178,9 @@ QVector<ShaderUniform> GraphicsHelperGL2::programUniformsAndLocations(GLuint pro
uniformName[sizeof(uniformName) - 1] = '\0';
uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
uniform.m_rawByteSize = uniformByteSize(uniform);
uniforms.append(uniform);
}
@@ -228,6 +231,47 @@ void GraphicsHelperGL2::vertexAttribDivisor(GLuint index,
Q_UNUSED(divisor);
}
+void GraphicsHelperGL2::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperGL2::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL2::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
void GraphicsHelperGL2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -313,6 +357,12 @@ bool GraphicsHelperGL2::checkFrameBufferComplete()
return false;
}
+bool GraphicsHelperGL2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
void GraphicsHelperGL2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
if (m_fboFuncs != nullptr) {
@@ -349,6 +399,13 @@ void GraphicsHelperGL2::bindFrameBufferAttachment(QOpenGLTexture *texture, const
}
}
+void GraphicsHelperGL2::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
bool GraphicsHelperGL2::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
@@ -565,6 +622,11 @@ void GraphicsHelperGL2::enablePrimitiveRestart(int)
{
}
+void GraphicsHelperGL2::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
void GraphicsHelperGL2::disablePrimitiveRestart()
{
}
@@ -633,8 +695,9 @@ void GraphicsHelperGL2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
qWarning() << "Compute Shaders are not supported by OpenGL 2.0 (since OpenGL 4.3)";
}
-char *GraphicsHelperGL2::mapBuffer(GLenum target)
+char *GraphicsHelperGL2::mapBuffer(GLenum target, GLsizeiptr size)
{
+ Q_UNUSED(size);
return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
}
diff --git a/src/render/graphicshelpers/graphicshelpergl2_p.h b/src/render/graphicshelpers/graphicshelpergl2_p.h
index d7573cf8c..1a7af544c 100644
--- a/src/render/graphicshelpers/graphicshelpergl2_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl2_p.h
@@ -72,7 +72,9 @@ public:
void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE;
void bindBufferBase(GLenum target, GLuint index, GLuint buffer) Q_DECL_OVERRIDE;
void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) Q_DECL_OVERRIDE;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) Q_DECL_OVERRIDE;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE;
@@ -91,7 +93,7 @@ public:
void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void disablePrimitiveRestart() Q_DECL_OVERRIDE;
void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE;
- char *mapBuffer(GLenum target) Q_DECL_OVERRIDE;
+ char *mapBuffer(GLenum target, GLsizeiptr size) Q_DECL_OVERRIDE;
GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE;
void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE;
void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE;
@@ -104,6 +106,7 @@ public:
void enableClipPlane(int clipPlane) Q_DECL_OVERRIDE;
void enablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void enablePrimitiveRestart(int primitiveRestartIndex) Q_DECL_OVERRIDE;
+ void enableVertexAttributeArray(int location) Q_DECL_OVERRIDE;
void frontFace(GLenum mode) Q_DECL_OVERRIDE;
QSize getRenderBufferDimensions(GLuint renderBufferId) Q_DECL_OVERRIDE;
QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) Q_DECL_OVERRIDE;
@@ -125,6 +128,9 @@ public:
uint uniformByteSize(const ShaderUniform &description) Q_DECL_OVERRIDE;
void useProgram(GLuint programId) Q_DECL_OVERRIDE;
void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) Q_DECL_OVERRIDE;
+ void readBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ void drawBuffer(GLenum mode) Q_DECL_OVERRIDE;
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
index 24b788fd4..a35c4e37f 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_2.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
@@ -207,6 +207,9 @@ QVector<ShaderUniform> GraphicsHelperGL3_2::programUniformsAndLocations(GLuint p
uniformName[sizeof(uniformName) - 1] = '\0';
uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
@@ -279,6 +282,58 @@ void GraphicsHelperGL3_2::vertexAttribDivisor(GLuint index, GLuint divisor)
qCWarning(Render::Rendering) << "Vertex attribute divisor not available with OpenGL 3.2 core";
}
+void GraphicsHelperGL3_2::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_funcs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperGL3_2::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL3_2::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
void GraphicsHelperGL3_2::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -378,6 +433,12 @@ bool GraphicsHelperGL3_2::checkFrameBufferComplete()
return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
+bool GraphicsHelperGL3_2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
void GraphicsHelperGL3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
@@ -403,6 +464,13 @@ void GraphicsHelperGL3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, con
texture->release();
}
+void GraphicsHelperGL3_2::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
@@ -820,6 +888,11 @@ void GraphicsHelperGL3_2::enablePrimitiveRestart(int primitiveRestartIndex)
m_funcs->glEnable(GL_PRIMITIVE_RESTART);
}
+void GraphicsHelperGL3_2::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
void GraphicsHelperGL3_2::disablePrimitiveRestart()
{
m_funcs->glDisable(GL_PRIMITIVE_RESTART);
@@ -893,9 +966,9 @@ void GraphicsHelperGL3_2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
qWarning() << "Compute Shaders are not supported by OpenGL 3.2 (since OpenGL 4.3)";
}
-char *GraphicsHelperGL3_2::mapBuffer(GLenum target)
+char *GraphicsHelperGL3_2::mapBuffer(GLenum target, GLsizeiptr size)
{
- return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+ return static_cast<char*>(m_funcs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
}
GLboolean GraphicsHelperGL3_2::unmapBuffer(GLenum target)
diff --git a/src/render/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
index 82b21a304..adb2942aa 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_2_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
@@ -74,7 +74,9 @@ public:
void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE;
void bindBufferBase(GLenum target, GLuint index, GLuint buffer) Q_DECL_OVERRIDE;
void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) Q_DECL_OVERRIDE;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) Q_DECL_OVERRIDE;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE;
@@ -93,7 +95,7 @@ public:
void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void disablePrimitiveRestart() Q_DECL_OVERRIDE;
void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE;
- char *mapBuffer(GLenum target) Q_DECL_OVERRIDE;
+ char *mapBuffer(GLenum target, GLsizeiptr size) Q_DECL_OVERRIDE;
GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE;
void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE;
void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE;
@@ -106,6 +108,7 @@ public:
void enableClipPlane(int clipPlane) Q_DECL_OVERRIDE;
void enablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void enablePrimitiveRestart(int primitiveRestartIndex) Q_DECL_OVERRIDE;
+ void enableVertexAttributeArray(int location) Q_DECL_OVERRIDE;
void frontFace(GLenum mode) Q_DECL_OVERRIDE;
QSize getRenderBufferDimensions(GLuint renderBufferId) Q_DECL_OVERRIDE;
QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) Q_DECL_OVERRIDE;
@@ -127,6 +130,9 @@ public:
uint uniformByteSize(const ShaderUniform &description) Q_DECL_OVERRIDE;
void useProgram(GLuint programId) Q_DECL_OVERRIDE;
void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) Q_DECL_OVERRIDE;
+ void readBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ void drawBuffer(GLenum mode) Q_DECL_OVERRIDE;
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp
index 7bbc333f7..40c2bafeb 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp
@@ -206,6 +206,9 @@ QVector<ShaderUniform> GraphicsHelperGL3_3::programUniformsAndLocations(GLuint p
uniformName[sizeof(uniformName) - 1] = '\0';
uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
@@ -276,6 +279,48 @@ void GraphicsHelperGL3_3::vertexAttribDivisor(GLuint index, GLuint divisor)
m_funcs->glVertexAttribDivisor(index, divisor);
}
+void GraphicsHelperGL3_3::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_funcs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ }
+}
+
+void GraphicsHelperGL3_3::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL3_3::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
void GraphicsHelperGL3_3::blendEquation(GLenum mode)
{
m_funcs->glBlendEquation(mode);
@@ -375,6 +420,12 @@ bool GraphicsHelperGL3_3::checkFrameBufferComplete()
return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
+bool GraphicsHelperGL3_3::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
void GraphicsHelperGL3_3::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
@@ -400,6 +451,13 @@ void GraphicsHelperGL3_3::bindFrameBufferAttachment(QOpenGLTexture *texture, con
texture->release();
}
+void GraphicsHelperGL3_3::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
@@ -817,6 +875,11 @@ void GraphicsHelperGL3_3::enablePrimitiveRestart(int primitiveRestartIndex)
m_funcs->glEnable(GL_PRIMITIVE_RESTART);
}
+void GraphicsHelperGL3_3::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
void GraphicsHelperGL3_3::disablePrimitiveRestart()
{
m_funcs->glDisable(GL_PRIMITIVE_RESTART);
@@ -890,9 +953,9 @@ void GraphicsHelperGL3_3::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
qWarning() << "Compute Shaders are not supported by OpenGL 3.3 (since OpenGL 4.3)";
}
-char *GraphicsHelperGL3_3::mapBuffer(GLenum target)
+char *GraphicsHelperGL3_3::mapBuffer(GLenum target, GLsizeiptr size)
{
- return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+ return static_cast<char*>(m_funcs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
}
GLboolean GraphicsHelperGL3_3::unmapBuffer(GLenum target)
diff --git a/src/render/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/graphicshelpers/graphicshelpergl3_3_p.h
index a315c5ab1..d36386a73 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_3_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_3_p.h
@@ -74,7 +74,9 @@ public:
void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE;
void bindBufferBase(GLenum target, GLuint index, GLuint buffer) Q_DECL_OVERRIDE;
void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) Q_DECL_OVERRIDE;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) Q_DECL_OVERRIDE;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE;
@@ -93,7 +95,7 @@ public:
void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void disablePrimitiveRestart() Q_DECL_OVERRIDE;
void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE;
- char *mapBuffer(GLenum target) Q_DECL_OVERRIDE;
+ char *mapBuffer(GLenum target, GLsizeiptr size) Q_DECL_OVERRIDE;
GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE;
void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE;
void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE;
@@ -106,6 +108,7 @@ public:
void enableClipPlane(int clipPlane) Q_DECL_OVERRIDE;
void enablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void enablePrimitiveRestart(int primitiveRestartIndex) Q_DECL_OVERRIDE;
+ void enableVertexAttributeArray(int location) Q_DECL_OVERRIDE;
void frontFace(GLenum mode) Q_DECL_OVERRIDE;
QSize getRenderBufferDimensions(GLuint renderBufferId) Q_DECL_OVERRIDE;
QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) Q_DECL_OVERRIDE;
@@ -127,6 +130,9 @@ public:
uint uniformByteSize(const ShaderUniform &description) Q_DECL_OVERRIDE;
void useProgram(GLuint programId) Q_DECL_OVERRIDE;
void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) Q_DECL_OVERRIDE;
+ void readBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ void drawBuffer(GLenum mode) Q_DECL_OVERRIDE;
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp
index 2c2e71cef..ce1b8ac2b 100644
--- a/src/render/graphicshelpers/graphicshelpergl4.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl4.cpp
@@ -249,6 +249,9 @@ QVector<ShaderUniform> GraphicsHelperGL4::programUniformsAndLocations(GLuint pro
uniformName[sizeof(uniformName) - 1] = '\0';
uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
@@ -338,6 +341,65 @@ void GraphicsHelperGL4::vertexAttribDivisor(GLuint index, GLuint divisor)
m_funcs->glVertexAttribDivisor(index, divisor);
}
+void GraphicsHelperGL4::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_funcs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ case GL_DOUBLE:
+ case GL_DOUBLE_VEC2:
+ case GL_DOUBLE_VEC3:
+ case GL_DOUBLE_VEC4:
+ m_funcs->glVertexAttribLPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperGL4::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL4::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
@@ -631,6 +693,12 @@ bool GraphicsHelperGL4::checkFrameBufferComplete()
return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
+bool GraphicsHelperGL4::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
void GraphicsHelperGL4::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
{
GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
@@ -656,6 +724,13 @@ void GraphicsHelperGL4::bindFrameBufferAttachment(QOpenGLTexture *texture, const
texture->release();
}
+void GraphicsHelperGL4::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
@@ -1069,6 +1144,11 @@ void GraphicsHelperGL4::enablePrimitiveRestart(int primitiveRestartIndex)
m_funcs->glEnable(GL_PRIMITIVE_RESTART);
}
+void GraphicsHelperGL4::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
void GraphicsHelperGL4::disablePrimitiveRestart()
{
m_funcs->glDisable(GL_PRIMITIVE_RESTART);
@@ -1139,9 +1219,9 @@ void GraphicsHelperGL4::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
m_funcs->glDispatchCompute(wx, wy, wz);
}
-char *GraphicsHelperGL4::mapBuffer(GLenum target)
+char *GraphicsHelperGL4::mapBuffer(GLenum target, GLsizeiptr size)
{
- return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+ return static_cast<char*>(m_funcs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
}
GLboolean GraphicsHelperGL4::unmapBuffer(GLenum target)
diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h
index 0dd767ccb..b38d0876c 100644
--- a/src/render/graphicshelpers/graphicshelpergl4_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl4_p.h
@@ -72,7 +72,9 @@ public:
void alphaTest(GLenum mode1, GLenum mode2) Q_DECL_OVERRIDE;
void bindBufferBase(GLenum target, GLuint index, GLuint buffer) Q_DECL_OVERRIDE;
void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) Q_DECL_OVERRIDE;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) Q_DECL_OVERRIDE;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) Q_DECL_OVERRIDE;
void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) Q_DECL_OVERRIDE;
void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) Q_DECL_OVERRIDE;
void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) Q_DECL_OVERRIDE;
@@ -91,7 +93,7 @@ public:
void disablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void disablePrimitiveRestart() Q_DECL_OVERRIDE;
void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) Q_DECL_OVERRIDE;
- char *mapBuffer(GLenum target) Q_DECL_OVERRIDE;
+ char *mapBuffer(GLenum target, GLsizeiptr size) Q_DECL_OVERRIDE;
GLboolean unmapBuffer(GLenum target) Q_DECL_OVERRIDE;
void drawArrays(GLenum primitiveType, GLint first, GLsizei count) Q_DECL_OVERRIDE;
void drawArraysIndirect(GLenum mode,void *indirect) Q_DECL_OVERRIDE;
@@ -104,6 +106,7 @@ public:
void enableClipPlane(int clipPlane) Q_DECL_OVERRIDE;
void enablei(GLenum cap, GLuint index) Q_DECL_OVERRIDE;
void enablePrimitiveRestart(int primitiveRestartIndex) Q_DECL_OVERRIDE;
+ void enableVertexAttributeArray(int location) Q_DECL_OVERRIDE;
void frontFace(GLenum mode) Q_DECL_OVERRIDE;
QSize getRenderBufferDimensions(GLuint renderBufferId) Q_DECL_OVERRIDE;
QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) Q_DECL_OVERRIDE;
@@ -125,6 +128,9 @@ public:
uint uniformByteSize(const ShaderUniform &description) Q_DECL_OVERRIDE;
void useProgram(GLuint programId) Q_DECL_OVERRIDE;
void vertexAttribDivisor(GLuint index, GLuint divisor) Q_DECL_OVERRIDE;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) Q_DECL_OVERRIDE;
+ void readBuffer(GLenum mode) Q_DECL_OVERRIDE;
+ void drawBuffer(GLenum mode) Q_DECL_OVERRIDE;
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelperinterface_p.h b/src/render/graphicshelpers/graphicshelperinterface_p.h
index 109457711..e41325cb7 100644
--- a/src/render/graphicshelpers/graphicshelperinterface_p.h
+++ b/src/render/graphicshelpers/graphicshelperinterface_p.h
@@ -64,6 +64,7 @@ namespace Qt3DRender {
namespace Render {
struct Attachment;
+class RenderBuffer;
class GraphicsHelperInterface
{
@@ -94,7 +95,9 @@ public:
virtual void alphaTest(GLenum mode1, GLenum mode2) = 0;
virtual void bindBufferBase(GLenum target, GLuint index, GLuint buffer) = 0;
virtual void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) = 0;
+ virtual bool frameBufferNeedsRenderBuffer(const Attachment &attachment) = 0;
virtual void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) = 0;
+ virtual void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) = 0;
virtual void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) = 0;
virtual void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) = 0;
virtual void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
@@ -113,7 +116,7 @@ public:
virtual void disablei(GLenum cap, GLuint index) = 0;
virtual void disablePrimitiveRestart() = 0;
virtual void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) = 0;
- virtual char *mapBuffer(GLenum target) = 0;
+ virtual char *mapBuffer(GLenum target, GLsizeiptr size) = 0;
virtual GLboolean unmapBuffer(GLenum target) = 0;
virtual void drawArrays(GLenum primitiveType, GLint first, GLsizei count) = 0;
virtual void drawArraysIndirect(GLenum mode,void *indirect) = 0;
@@ -126,6 +129,7 @@ public:
virtual void enableClipPlane(int clipPlane) = 0;
virtual void enablei(GLenum cap, GLuint index) = 0;
virtual void enablePrimitiveRestart(int primitiveRestartIndex) = 0;
+ virtual void enableVertexAttributeArray(int location) = 0;
virtual void frontFace(GLenum mode) = 0;
virtual QSize getRenderBufferDimensions(GLuint renderBufferId) = 0;
virtual QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) = 0;
@@ -147,6 +151,9 @@ public:
virtual uint uniformByteSize(const ShaderUniform &description) = 0;
virtual void useProgram(GLuint programId) = 0;
virtual void vertexAttribDivisor(GLuint index, GLuint divisor) = 0;
+ virtual void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) = 0;
+ virtual void readBuffer(GLenum mode) = 0;
+ virtual void drawBuffer(GLenum mode) = 0;
virtual void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) = 0;
virtual void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) = 0;
diff --git a/src/render/graphicshelpers/graphicshelpers.pri b/src/render/graphicshelpers/graphicshelpers.pri
index e9c5c1bc8..ff529ba44 100644
--- a/src/render/graphicshelpers/graphicshelpers.pri
+++ b/src/render/graphicshelpers/graphicshelpers.pri
@@ -7,6 +7,7 @@ HEADERS += \
$$PWD/graphicshelperinterface_p.h \
$$PWD/graphicshelperes2_p.h \
$$PWD/graphicshelperes3_p.h \
+ $$PWD/graphicshelperes3_2_p.h \
$$PWD/graphicshelpergl2_p.h \
$$PWD/graphicshelpergl3_3_p.h \
$$PWD/graphicshelpergl4_p.h \
@@ -16,6 +17,7 @@ SOURCES += \
$$PWD/graphicscontext.cpp \
$$PWD/graphicshelperes2.cpp \
$$PWD/graphicshelperes3.cpp \
+ $$PWD/graphicshelperes3_2.cpp \
$$PWD/graphicshelpergl2.cpp \
$$PWD/graphicshelpergl3_3.cpp \
$$PWD/graphicshelpergl4.cpp \
diff --git a/src/render/io/glbuffer.cpp b/src/render/io/glbuffer.cpp
index 4918f9a56..f1b860f03 100644
--- a/src/render/io/glbuffer.cpp
+++ b/src/render/io/glbuffer.cpp
@@ -142,7 +142,7 @@ void GLBuffer::update(GraphicsContext *ctx, const void *data, uint size, int off
QByteArray GLBuffer::download(GraphicsContext *ctx, uint size)
{
- char *gpu_ptr = ctx->mapBuffer(m_lastTarget);
+ char *gpu_ptr = ctx->mapBuffer(m_lastTarget, size);
QByteArray data;
if (gpu_ptr != nullptr) {
data.resize(size);
diff --git a/src/render/io/qsceneimporter_p.h b/src/render/io/qsceneimporter_p.h
index e76eb8780..8f83231c3 100644
--- a/src/render/io/qsceneimporter_p.h
+++ b/src/render/io/qsceneimporter_p.h
@@ -86,7 +86,8 @@ public:
virtual ~QSceneImporter();
virtual void setSource(const QUrl &source) = 0;
- virtual bool isFileTypeSupported(const QUrl &source) const = 0;
+ virtual void setData(const QByteArray& data, const QString &basePath) = 0;
+ virtual bool areFileTypesSupported(const QStringList &extensions) const = 0;
virtual Qt3DCore::QEntity *scene(const QString &id = QString()) = 0;
virtual Qt3DCore::QEntity *node(const QString &id) = 0;
diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp
index cf1ca4736..7ae6f9473 100644
--- a/src/render/io/scene.cpp
+++ b/src/render/io/scene.cpp
@@ -42,6 +42,7 @@
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
#include <Qt3DRender/qsceneloader.h>
#include <Qt3DRender/private/qsceneloader_p.h>
#include <Qt3DRender/private/scenemanager_p.h>
@@ -81,7 +82,10 @@ void Scene::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change
const auto &data = typedChange->data;
m_source = data.source;
Q_ASSERT(m_sceneManager);
- m_sceneManager->addSceneData(m_source, peerId());
+ if (Qt3DCore::QDownloadHelperService::isLocal(m_source))
+ m_sceneManager->addSceneData(m_source, peerId());
+ else
+ m_sceneManager->startSceneDownload(m_source, peerId());
}
void Scene::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
@@ -90,7 +94,10 @@ void Scene::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("source")) {
m_source = propertyChange->value().toUrl();
- m_sceneManager->addSceneData(m_source, peerId());
+ if (Qt3DCore::QDownloadHelperService::isLocal(m_source))
+ m_sceneManager->addSceneData(m_source, peerId());
+ else
+ m_sceneManager->startSceneDownload(m_source, peerId());
}
}
markDirty(AbstractRenderer::AllDirty);
diff --git a/src/render/io/scenemanager.cpp b/src/render/io/scenemanager.cpp
index 8e6af8c40..784751857 100644
--- a/src/render/io/scenemanager.cpp
+++ b/src/render/io/scenemanager.cpp
@@ -45,16 +45,31 @@ namespace Qt3DRender {
namespace Render {
SceneManager::SceneManager() : Qt3DCore::QResourceManager<Scene,
- Qt3DCore::QNodeId,
- 8,
- Qt3DCore::ObjectLevelLockingPolicy>()
+ Qt3DCore::QNodeId,
+ 8,
+ Qt3DCore::ObjectLevelLockingPolicy>()
+ , m_service(nullptr)
{
}
-void SceneManager::addSceneData(const QUrl &source, Qt3DCore::QNodeId sceneUuid)
+SceneManager::~SceneManager()
+{
+}
+
+void SceneManager::setDownloadService(Qt3DCore::QDownloadHelperService *service)
+{
+ m_service = service;
+}
+
+void SceneManager::addSceneData(const QUrl &source,
+ Qt3DCore::QNodeId sceneUuid,
+ const QByteArray &data)
{
LoadSceneJobPtr newJob(new LoadSceneJob(source, sceneUuid));
+ if (!data.isEmpty())
+ newJob->setData(data);
+
// We cannot run two jobs that use the same scene loader plugin
// in two different threads at the same time
if (!m_pendingJobs.isEmpty())
@@ -69,6 +84,43 @@ QVector<LoadSceneJobPtr> SceneManager::pendingSceneLoaderJobs()
return std::move(m_pendingJobs);
}
+void SceneManager::startSceneDownload(const QUrl &source, Qt3DCore::QNodeId sceneUuid)
+{
+ if (!m_service)
+ return;
+ SceneDownloaderPtr request = SceneDownloaderPtr::create(source, sceneUuid, this);
+ m_pendingDownloads << request;
+ m_service->submitRequest(request);
+}
+
+void SceneManager::clearSceneDownload(SceneDownloader *downloader)
+{
+ for (auto it = m_pendingDownloads.begin(); it != m_pendingDownloads.end(); ++it) {
+ if ((*it).data() == downloader) {
+ m_pendingDownloads.erase(it);
+ return;
+ }
+ }
+}
+
+
+SceneDownloader::SceneDownloader(const QUrl &source, Qt3DCore::QNodeId sceneComponent, SceneManager *manager)
+ : Qt3DCore::QDownloadRequest(source)
+ , m_sceneComponent(sceneComponent)
+ , m_manager(manager)
+{
+
+}
+
+void SceneDownloader::onCompleted()
+{
+ if (!m_manager)
+ return;
+ if (succeeded())
+ m_manager->addSceneData(url(), m_sceneComponent, m_data);
+ m_manager->clearSceneDownload(this);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/io/scenemanager_p.h b/src/render/io/scenemanager_p.h
index 941b90a4d..d7dd8c752 100644
--- a/src/render/io/scenemanager_p.h
+++ b/src/render/io/scenemanager_p.h
@@ -52,6 +52,7 @@
//
#include <Qt3DCore/private/qresourcemanager_p.h>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
#include <Qt3DRender/private/scene_p.h>
#include <Qt3DCore/qnodeid.h>
#include <Qt3DRender/private/loadscenejob_p.h>
@@ -65,6 +66,22 @@ class QEntity;
namespace Qt3DRender {
namespace Render {
+class SceneManager;
+
+class SceneDownloader : public Qt3DCore::QDownloadRequest {
+public:
+ SceneDownloader(const QUrl &source, Qt3DCore::QNodeId sceneComponent, SceneManager* manager);
+
+ void onCompleted() Q_DECL_OVERRIDE;
+
+private:
+ Qt3DCore::QNodeId m_sceneComponent;
+ SceneManager* m_manager;
+};
+
+typedef QSharedPointer<SceneDownloader> SceneDownloaderPtr;
+
+
class Q_AUTOTEST_EXPORT SceneManager : public Qt3DCore::QResourceManager<
Scene,
Qt3DCore::QNodeId,
@@ -73,12 +90,21 @@ class Q_AUTOTEST_EXPORT SceneManager : public Qt3DCore::QResourceManager<
{
public:
SceneManager();
+ ~SceneManager();
- void addSceneData(const QUrl &source, Qt3DCore::QNodeId sceneUuid);
+ void setDownloadService(Qt3DCore::QDownloadHelperService *service);
+
+ void addSceneData(const QUrl &source, Qt3DCore::QNodeId sceneUuid,
+ const QByteArray &data = QByteArray());
QVector<LoadSceneJobPtr> pendingSceneLoaderJobs();
+ void startSceneDownload(const QUrl &source, Qt3DCore::QNodeId sceneUuid);
+ void clearSceneDownload(SceneDownloader *downloader);
+
private:
+ Qt3DCore::QDownloadHelperService *m_service;
QVector<LoadSceneJobPtr> m_pendingJobs;
+ QVector<SceneDownloaderPtr> m_pendingDownloads;
};
} // namespace Render
diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp
index 7bbab307c..e81836502 100644
--- a/src/render/jobs/calcboundingvolumejob.cpp
+++ b/src/render/jobs/calcboundingvolumejob.cpp
@@ -216,30 +216,28 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
return;
}
- if (positionAttribute) {
- Buffer *buf = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
- // No point in continuing if the positionAttribute doesn't have a suitable buffer
- if (!buf) {
- qWarning() << "ObjectPicker position Attribute not referencing a valid buffer";
- return;
- }
+ Buffer *buf = manager->lookupResource<Buffer, BufferManager>(positionAttribute->bufferId());
+ // No point in continuing if the positionAttribute doesn't have a suitable buffer
+ if (!buf) {
+ qWarning() << "ObjectPicker position Attribute not referencing a valid buffer";
+ return;
+ }
- // Buf will be set to not dirty once it's loaded
- // in a job executed after this one
- // We need to recompute the bounding volume
- // If anything in the GeometryRenderer has changed
- if (buf->isDirty() ||
- node->isBoundingVolumeDirty() ||
- positionAttribute->isDirty() ||
- geom->isDirty() ||
- gRenderer->isDirty()) {
-
- BoundingVolumeCalculator reader(manager);
- if (reader.apply(positionAttribute)) {
- node->localBoundingVolume()->setCenter(reader.result().center());
- node->localBoundingVolume()->setRadius(reader.result().radius());
- node->unsetBoundingVolumeDirty();
- }
+ // Buf will be set to not dirty once it's loaded
+ // in a job executed after this one
+ // We need to recompute the bounding volume
+ // If anything in the GeometryRenderer has changed
+ if (buf->isDirty() ||
+ node->isBoundingVolumeDirty() ||
+ positionAttribute->isDirty() ||
+ geom->isDirty() ||
+ gRenderer->isDirty()) {
+
+ BoundingVolumeCalculator reader(manager);
+ if (reader.apply(positionAttribute)) {
+ node->localBoundingVolume()->setCenter(reader.result().center());
+ node->localBoundingVolume()->setRadius(reader.result().radius());
+ node->unsetBoundingVolumeDirty();
}
}
}
diff --git a/src/render/jobs/computefilteredboundingvolumejob.cpp b/src/render/jobs/computefilteredboundingvolumejob.cpp
new file mode 100644
index 000000000..d8a7b5094
--- /dev/null
+++ b/src/render/jobs/computefilteredboundingvolumejob.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "computefilteredboundingvolumejob_p.h"
+
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/job_common_p.h>
+
+#include <QThread>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+namespace {
+
+void expandWorldBoundingVolume(Qt3DRender::Render::Sphere *sphere,
+ Qt3DRender::Render::Entity *node,
+ Qt3DRender::Render::Entity *excludeSubTree)
+{
+ Qt3DRender::Render::Sphere childSphere(*node->worldBoundingVolume());
+ // Go to the nodes that have the most depth
+ const auto children = node->children();
+ for (Entity *c : children) {
+ if (c != excludeSubTree)
+ expandWorldBoundingVolume(&childSphere, c, excludeSubTree);
+ }
+ sphere->expandToContain(childSphere);
+}
+
+} // namespace
+
+ComputeFilteredBoundingVolumeJob::ComputeFilteredBoundingVolumeJob()
+ : m_root(nullptr)
+ , m_ignoreSubTree(nullptr)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0);
+}
+
+void ComputeFilteredBoundingVolumeJob::setRoot(Entity *root)
+{
+ m_root = root;
+}
+
+void ComputeFilteredBoundingVolumeJob::ignoreSubTree(Entity *node)
+{
+ m_ignoreSubTree = node;
+}
+
+void ComputeFilteredBoundingVolumeJob::run()
+{
+ qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread();
+
+ if (!m_root)
+ return;
+ if (!m_ignoreSubTree) {
+ finished(*m_root->worldBoundingVolumeWithChildren());
+ return;
+ }
+
+ bool isFilterChildOfRoot = false;
+ Entity *parent = m_ignoreSubTree->parent();
+ while (parent) {
+ if (parent == m_root) {
+ isFilterChildOfRoot = true;
+ break;
+ }
+ parent = parent->parent();
+ }
+ if (!isFilterChildOfRoot) {
+ finished(*m_root->worldBoundingVolumeWithChildren());
+ return;
+ }
+
+ Qt3DRender::Render::Sphere sphere;
+ expandWorldBoundingVolume(&sphere, m_root, m_ignoreSubTree);
+ finished(sphere);
+
+ qCDebug(Jobs) << "Exiting" << Q_FUNC_INFO << QThread::currentThread();
+}
+
+void ComputeFilteredBoundingVolumeJob::finished(const Qt3DRender::Render::Sphere &sphere)
+{
+ Q_UNUSED(sphere);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/computefilteredboundingvolumejob_p.h b/src/render/jobs/computefilteredboundingvolumejob_p.h
new file mode 100644
index 000000000..d7681e604
--- /dev/null
+++ b/src/render/jobs/computefilteredboundingvolumejob_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_COMPUTEFILTEREDBOUNDINGVOLUMEJOB_H
+#define QT3DRENDER_RENDER_COMPUTEFILTEREDBOUNDINGVOLUMEJOB_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 <private/qt3drender_global_p.h>
+
+#include <QtCore/QSharedPointer>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class Entity;
+class Sphere;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT ComputeFilteredBoundingVolumeJob : public Qt3DCore::QAspectJob
+{
+public:
+ ComputeFilteredBoundingVolumeJob();
+
+ void setRoot(Entity *root);
+ void ignoreSubTree(Entity *node);
+ void run() Q_DECL_OVERRIDE;
+
+protected:
+ virtual void finished(const Qt3DRender::Render::Sphere &sphere);
+
+private:
+ Entity *m_root;
+ Entity *m_ignoreSubTree;
+};
+
+typedef QSharedPointer<ComputeFilteredBoundingVolumeJob> ComputeFilteredBoundingVolumeJobPtr;
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_COMPUTEFILTEREDBOUNDINGVOLUMEJOB_H
diff --git a/src/render/jobs/filterlayerentityjob.cpp b/src/render/jobs/filterlayerentityjob.cpp
index 5e1add275..902338be7 100644
--- a/src/render/jobs/filterlayerentityjob.cpp
+++ b/src/render/jobs/filterlayerentityjob.cpp
@@ -42,6 +42,7 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/layerfilternode_p.h>
QT_BEGIN_NAMESPACE
@@ -51,61 +52,203 @@ namespace Render {
namespace {
int layerFilterJobCounter = 0;
+
+// TO DO: This will be moved to a dedicated job with smarter
+// heuristics in a later commit
+void addLayerIdToEntityChildren(const QVector<Entity *> &children,
+ const Qt3DCore::QNodeId layerId)
+{
+ for (Entity *child : children) {
+ child->addRecursiveLayerId(layerId);
+ addLayerIdToEntityChildren(child->children(), layerId);
+ }
+}
+
+void updateEntityLayers(NodeManagers *manager)
+{
+ EntityManager *entityManager = manager->renderNodesManager();
+
+ const QVector<HEntity> handles = entityManager->activeHandles();
+
+ // Clear list of recursive layerIds
+ for (const HEntity handle : handles) {
+ Entity *entity = entityManager->data(handle);
+ entity->clearRecursiveLayerIds();
+ }
+
+ LayerManager *layerManager = manager->layerManager();
+
+ // Set recursive layerIds on children
+ for (const HEntity handle : handles) {
+ Entity *entity = entityManager->data(handle);
+ const Qt3DCore::QNodeIdVector entityLayers = entity->componentsUuid<Layer>();
+
+ for (const Qt3DCore::QNodeId layerId : entityLayers) {
+ Layer *layer = layerManager->lookupResource(layerId);
+ if (layer->recursive()) {
+ // Find all children of the entity and add the layers to them
+ addLayerIdToEntityChildren(entity->children(), layerId);
+ }
+ }
+ }
+}
+
} // anonymous
FilterLayerEntityJob::FilterLayerEntityJob()
: Qt3DCore::QAspectJob()
, m_manager(nullptr)
- , m_hasLayerFilter(false)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++);
}
+
void FilterLayerEntityJob::run()
{
m_filteredEntities.clear();
- if (m_hasLayerFilter) { // LayerFilter set -> filter
- LayerManager *layerManager = m_manager->layerManager();
-
- // Remove layerIds which are not active/enabled
- for (auto i = m_layerIds.size() - 1; i >= 0; --i) {
- Layer *backendLayer = layerManager->lookupResource(m_layerIds.at(i));
- if (backendLayer == nullptr || !backendLayer->isEnabled())
- m_layerIds.removeAt(i);
- }
-
+ if (hasLayerFilter()) { // LayerFilter set -> filter
+ updateEntityLayers(m_manager);
filterLayerAndEntity();
} else { // No LayerFilter set -> retrieve all
selectAllEntities();
}
}
-// Note: we assume that m_layerIds contains only enabled layers
-// -> meaning that if an Entity references such a layer, it's enabled
+// We accept the entity if it contains any of the layers that are in the layer filter
+void FilterLayerEntityJob::filterAcceptAnyMatchingLayers(Entity *entity,
+ const Qt3DCore::QNodeIdVector &layerIds)
+{
+ const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
+
+ for (const Qt3DCore::QNodeId id : entityLayers) {
+ const bool layerAccepted = layerIds.contains(id);
+
+ if (layerAccepted) {
+ m_filteredEntities.push_back(entity);
+ break;
+ }
+ }
+}
+
+// We accept the entity if it contains all the layers that are in the layer
+// filter
+void FilterLayerEntityJob::filterAcceptAllMatchingLayers(Entity *entity,
+ const Qt3DCore::QNodeIdVector &layerIds)
+{
+ const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
+ int layersAccepted = 0;
+
+ for (const Qt3DCore::QNodeId id : entityLayers) {
+ if (layerIds.contains(id))
+ ++layersAccepted;
+ }
+
+ if (layersAccepted == layerIds.size())
+ m_filteredEntities.push_back(entity);
+}
+
+// We discard the entity if it contains any of the layers that are in the layer
+// filter
+// In other words that means we select an entity if one of its layers is not on
+// the layer filter
+void FilterLayerEntityJob::filterDiscardAnyMatchingLayers(Entity *entity,
+ const Qt3DCore::QNodeIdVector &layerIds)
+{
+ const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
+ bool entityCanBeDiscarded = false;
+
+ for (const Qt3DCore::QNodeId id : entityLayers) {
+ if (layerIds.contains(id)) {
+ entityCanBeDiscarded = true;
+ break;
+ }
+ }
+
+ if (!entityCanBeDiscarded)
+ m_filteredEntities.push_back(entity);
+}
+
+// We discard the entity if it contains all of the layers that are in the layer
+// filter
+// In other words that means we select an entity if none of its layers are on
+// the layer filter
+void FilterLayerEntityJob::filterDiscardAllMatchingLayers(Entity *entity,
+ const Qt3DCore::QNodeIdVector &layerIds)
+{
+ const Qt3DCore::QNodeIdVector entityLayers = entity->layerIds();
+
+ int containedLayers = 0;
+
+ for (const Qt3DCore::QNodeId id : layerIds) {
+ if (entityLayers.contains(id))
+ ++containedLayers;
+ }
+
+ if (containedLayers != layerIds.size())
+ m_filteredEntities.push_back(entity);
+}
+
void FilterLayerEntityJob::filterLayerAndEntity()
{
EntityManager *entityManager = m_manager->renderNodesManager();
const QVector<HEntity> handles = entityManager->activeHandles();
+ QVector<Entity *> entitiesToFilter;
+ entitiesToFilter.reserve(handles.size());
+
for (const HEntity handle : handles) {
Entity *entity = entityManager->data(handle);
- if (!entity->isTreeEnabled())
- continue;
+ if (entity->isTreeEnabled())
+ entitiesToFilter.push_back(entity);
+ }
- const Qt3DCore::QNodeIdVector entityLayers = entity->componentsUuid<Layer>();
+ FrameGraphManager *frameGraphManager = m_manager->frameGraphManager();
+ LayerManager *layerManager = m_manager->layerManager();
+
+ for (const Qt3DCore::QNodeId layerFilterId : m_layerFilterIds) {
+ LayerFilterNode *layerFilter = static_cast<LayerFilterNode *>(frameGraphManager->lookupNode(layerFilterId));
+ Qt3DCore::QNodeIdVector layerIds = layerFilter->layerIds();
+
+ // Remove layerIds which are not active/enabled
+ for (int i = layerIds.size() - 1; i >= 0; --i) {
+ Layer *backendLayer = layerManager->lookupResource(layerIds.at(i));
+ if (backendLayer == nullptr || !backendLayer->isEnabled())
+ layerIds.removeAt(i);
+ }
- // An Entity is positively filtered if it contains at least one Layer component with the same id as the
- // layers selected by the LayerFilter
+ const QLayerFilter::FilterMode filterMode = layerFilter->filterMode();
- for (const Qt3DCore::QNodeId id : entityLayers) {
- if (m_layerIds.contains(id)) {
- m_filteredEntities.push_back(entity);
+ // Perform filtering
+ for (Entity *entity : entitiesToFilter) {
+ switch (filterMode) {
+ case QLayerFilter::AcceptAnyMatchingLayers: {
+ filterAcceptAnyMatchingLayers(entity, layerIds);
+ break;
+ }
+ case QLayerFilter::AcceptAllMatchingLayers: {
+ filterAcceptAllMatchingLayers(entity, layerIds);
+ break;
+ }
+ case QLayerFilter::DiscardAnyMatchingLayers: {
+ filterDiscardAnyMatchingLayers(entity, layerIds);
break;
}
+ case QLayerFilter::DiscardAllMatchingLayers: {
+ filterDiscardAllMatchingLayers(entity, layerIds);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ }
}
+
+ // Entities to filter for the next frame are the filtered result of the
+ // current LayerFilter
+ entitiesToFilter = std::move(m_filteredEntities);
}
+ m_filteredEntities = std::move(entitiesToFilter);
}
// No layer filter -> retrieve all entities
diff --git a/src/render/jobs/filterlayerentityjob_p.h b/src/render/jobs/filterlayerentityjob_p.h
index 50b988ce4..4e4619a25 100644
--- a/src/render/jobs/filterlayerentityjob_p.h
+++ b/src/render/jobs/filterlayerentityjob_p.h
@@ -54,6 +54,7 @@
#include <Qt3DCore/qaspectjob.h>
#include <Qt3DCore/qnodeid.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <Qt3DRender/qlayerfilter.h>
QT_BEGIN_NAMESPACE
@@ -70,24 +71,27 @@ public:
FilterLayerEntityJob();
inline void setManager(NodeManagers *manager) Q_DECL_NOEXCEPT { m_manager = manager; }
- inline void setLayers(const Qt3DCore::QNodeIdVector &layerIds) Q_DECL_NOEXCEPT { m_layerIds = layerIds; }
- inline void setHasLayerFilter(bool hasLayerFilter) Q_DECL_NOEXCEPT { m_hasLayerFilter = hasLayerFilter; }
+ inline void setLayerFilters(const Qt3DCore::QNodeIdVector &layerIds) Q_DECL_NOEXCEPT { m_layerFilterIds = layerIds; }
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; }
+ inline bool hasLayerFilter() const Q_DECL_NOTHROW { return !m_layerFilterIds.isEmpty(); }
+ inline Qt3DCore::QNodeIdVector layerFilters() const { return m_layerFilterIds; }
// QAspectJob interface
void run() Q_DECL_FINAL;
+ void filterAcceptAnyMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds);
+ void filterAcceptAllMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds);
+ void filterDiscardAnyMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds);
+ void filterDiscardAllMatchingLayers(Entity *entity, const Qt3DCore::QNodeIdVector &layerIds);
+
private:
void filterLayerAndEntity();
void selectAllEntities();
NodeManagers *m_manager;
- Qt3DCore::QNodeIdVector m_layerIds;
+ Qt3DCore::QNodeIdVector m_layerFilterIds;
QVector<Entity *> m_filteredEntities;
- bool m_hasLayerFilter;
};
typedef QSharedPointer<FilterLayerEntityJob> FilterLayerEntityJobPtr;
diff --git a/src/render/jobs/filterproximitydistancejob.cpp b/src/render/jobs/filterproximitydistancejob.cpp
new file mode 100644
index 000000000..b07997336
--- /dev/null
+++ b/src/render/jobs/filterproximitydistancejob.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "filterproximitydistancejob_p.h"
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/proximityfilter_p.h>
+#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/sphere_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+
+FilterProximityDistanceJob::FilterProximityDistanceJob()
+ : m_manager(nullptr)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::ProximityFiltering, 0);
+}
+
+void FilterProximityDistanceJob::run()
+{
+ Q_ASSERT(m_manager != nullptr);
+ m_filteredEntities.clear();
+
+ // Fill m_filteredEntities
+ // If no filtering needs to be done, this will be the output value
+ // otherwise it will be used as the base list of entities to filter
+ selectAllEntities();
+
+ if (hasProximityFilter()) {
+ QVector<Entity *> entitiesToFilter = std::move(m_filteredEntities);
+ FrameGraphManager *frameGraphManager = m_manager->frameGraphManager();
+ EntityManager *entityManager = m_manager->renderNodesManager();
+
+ for (const Qt3DCore::QNodeId proximityFilterId : qAsConst(m_proximityFilterIds)) {
+ ProximityFilter *proximityFilter = static_cast<ProximityFilter *>(frameGraphManager->lookupNode(proximityFilterId));
+ m_targetEntity = entityManager->lookupResource(proximityFilter->entityId());
+ m_distanceThresholdSquared = proximityFilter->distanceThreshold();
+ m_distanceThresholdSquared *= m_distanceThresholdSquared;
+
+ // We can't filter, select nothings
+ if (m_targetEntity == nullptr || m_distanceThresholdSquared <= 0.0f) {
+ m_filteredEntities.clear();
+ return;
+ }
+ // Otherwise we filter
+ filterEntities(entitiesToFilter);
+
+ // And we make the filtered subset be the list of entities to filter
+ // for the next loop
+ entitiesToFilter = std::move(m_filteredEntities);
+ }
+ m_filteredEntities = std::move(entitiesToFilter);
+ }
+}
+
+void FilterProximityDistanceJob::selectAllEntities()
+{
+ EntityManager *entityManager = m_manager->renderNodesManager();
+ const QVector<HEntity> handles = entityManager->activeHandles();
+
+ m_filteredEntities.reserve(handles.size());
+ for (const HEntity handle : handles) {
+ Entity *e = entityManager->data(handle);
+ m_filteredEntities.push_back(e);
+ }
+}
+
+void FilterProximityDistanceJob::filterEntities(const QVector<Entity *> &entitiesToFilter)
+{
+ const Sphere *target = m_targetEntity->worldBoundingVolumeWithChildren();
+
+ for (Entity *entity : entitiesToFilter) {
+ // Note: The target entity is always selected as distance will be 0
+
+ // Retrieve center of bounding volume for entity
+ const Sphere *s = entity->worldBoundingVolumeWithChildren();
+
+ // If distance between entity and target is less than threshold, we keep the entity
+ if ((s->center() - target->center()).lengthSquared() <= m_distanceThresholdSquared)
+ m_filteredEntities.push_back(entity);
+ }
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/filterproximitydistancejob_p.h b/src/render/jobs/filterproximitydistancejob_p.h
new file mode 100644
index 000000000..50b5f6f55
--- /dev/null
+++ b/src/render/jobs/filterproximitydistancejob_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_FILTERPROXIMITYDISTANCEJOB_P_H
+#define QT3DRENDER_RENDER_FILTERPROXIMITYDISTANCEJOB_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 Qt3DRender {
+
+namespace Render {
+
+class Entity;
+class NodeManagers;
+
+class Q_AUTOTEST_EXPORT FilterProximityDistanceJob : public Qt3DCore::QAspectJob
+{
+public:
+ FilterProximityDistanceJob();
+
+ inline void setManager(NodeManagers *manager) { m_manager = manager; }
+ inline void setProximityFilterIds(const Qt3DCore::QNodeIdVector &proximityFilterIds) { m_proximityFilterIds = proximityFilterIds; }
+ inline bool hasProximityFilter() const { return !m_proximityFilterIds.empty(); }
+
+ // QAspectJob interface
+ void run() Q_DECL_FINAL;
+ QVector<Entity *> filteredEntities() const { return m_filteredEntities; }
+
+#if defined (QT_BUILD_INTERNAL)
+ // For unit testing
+ inline Qt3DCore::QNodeIdVector proximityFilterIds() const { return m_proximityFilterIds; }
+ inline NodeManagers *manager() const { return m_manager; }
+#endif
+
+private:
+ void selectAllEntities();
+ void filterEntities(const QVector<Entity *> &entitiesToFilter);
+
+ NodeManagers *m_manager;
+ Qt3DCore::QNodeIdVector m_proximityFilterIds;
+ Entity *m_targetEntity;
+ float m_distanceThresholdSquared;
+ QVector<Entity *> m_filteredEntities;
+};
+
+typedef QSharedPointer<FilterProximityDistanceJob> FilterProximityDistanceJobPtr;
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_FILTERPROXIMITYDISTANCEJOB_P_H
diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h
index 332b62547..56c4346ed 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -99,7 +99,11 @@ namespace JobTypes {
UpdateMeshTriangleList,
FilterCompatibleTechniques,
UpdateLevelOfDetail,
- SyncTextureLoading
+ SyncTextureLoading,
+ LoadSkeleton,
+ UpdateSkinningPalette,
+ ProximityFiltering,
+ SyncFilterEntityByLayer
};
} // JobTypes
diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri
index 010914f88..745af6d85 100644
--- a/src/render/jobs/jobs.pri
+++ b/src/render/jobs/jobs.pri
@@ -11,6 +11,7 @@ HEADERS += \
$$PWD/calcboundingvolumejob_p.h \
$$PWD/pickboundingvolumejob_p.h \
$$PWD/calcgeometrytrianglevolumes_p.h \
+ $$PWD/computefilteredboundingvolumejob_p.h \
$$PWD/job_common_p.h \
$$PWD/filterlayerentityjob_p.h \
$$PWD/filterentitybycomponentjob_p.h \
@@ -29,7 +30,10 @@ HEADERS += \
$$PWD/pickboundingvolumeutils_p.h \
$$PWD/filtercompatibletechniquejob_p.h \
$$PWD/updatetreeenabledjob_p.h \
- $$PWD/sendbuffercapturejob_p.h
+ $$PWD/sendbuffercapturejob_p.h \
+ $$PWD/loadskeletonjob_p.h \
+ $$PWD/updateskinningpalettejob_p.h \
+ $$PWD/filterproximitydistancejob_p.h
SOURCES += \
$$PWD/updateworldtransformjob.cpp \
@@ -42,6 +46,7 @@ SOURCES += \
$$PWD/calcboundingvolumejob.cpp \
$$PWD/pickboundingvolumejob.cpp \
$$PWD/calcgeometrytrianglevolumes.cpp \
+ $$PWD/computefilteredboundingvolumejob.cpp \
$$PWD/filterlayerentityjob.cpp \
$$PWD/materialparametergathererjob.cpp \
$$PWD/renderviewbuilderjob.cpp \
@@ -57,5 +62,8 @@ SOURCES += \
$$PWD/pickboundingvolumeutils.cpp \
$$PWD/filtercompatibletechniquejob.cpp \
$$PWD/updatetreeenabledjob.cpp \
- $$PWD/sendbuffercapturejob.cpp
+ $$PWD/sendbuffercapturejob.cpp \
+ $$PWD/loadskeletonjob.cpp \
+ $$PWD/updateskinningpalettejob.cpp \
+ $$PWD/filterproximitydistancejob.cpp
diff --git a/src/render/jobs/loadscenejob.cpp b/src/render/jobs/loadscenejob.cpp
index 9b3374627..5be733a4d 100644
--- a/src/render/jobs/loadscenejob.cpp
+++ b/src/render/jobs/loadscenejob.cpp
@@ -44,8 +44,12 @@
#include <Qt3DCore/qentity.h>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/qsceneimporter_p.h>
+#include <Qt3DRender/private/qurlhelper_p.h>
#include <Qt3DRender/qsceneloader.h>
+#include <QFileInfo>
+#include <QMimeDatabase>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -60,6 +64,11 @@ LoadSceneJob::LoadSceneJob(const QUrl &source, Qt3DCore::QNodeId m_sceneComponen
SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadScene, 0);
}
+void LoadSceneJob::setData(const QByteArray &data)
+{
+ m_data = data;
+}
+
NodeManagers *LoadSceneJob::nodeManagers() const
{
return m_managers;
@@ -95,20 +104,54 @@ void LoadSceneJob::run()
// Perform the loading only if the source wasn't explicitly set to empty
if (!m_source.isEmpty()) {
finalStatus = QSceneLoader::Error;
- for (QSceneImporter *sceneImporter : qAsConst(m_sceneImporters)) {
- if (!sceneImporter->isFileTypeSupported(m_source))
- continue;
-
- // If the file type is supported -> enter Loading status
- scene->setStatus(QSceneLoader::Loading);
-
- // File type is supported, try to load it
- sceneImporter->setSource(m_source);
- sceneSubTree = sceneImporter->scene();
- if (sceneSubTree != nullptr) {
- // Successfully built a subtree
- finalStatus = QSceneLoader::Ready;
- break;
+
+ if (m_data.isEmpty()) {
+ const QString path = QUrlHelper::urlToLocalFileOrQrc(m_source);
+ QFileInfo finfo(path);
+ if (finfo.exists()) {
+ QStringList extensions(finfo.suffix());
+
+ for (QSceneImporter *sceneImporter : qAsConst(m_sceneImporters)) {
+ if (!sceneImporter->areFileTypesSupported(extensions))
+ continue;
+
+ // If the file type is supported -> enter Loading status
+ scene->setStatus(QSceneLoader::Loading);
+
+ // File type is supported, try to load it
+ sceneImporter->setSource(m_source);
+ sceneSubTree = sceneImporter->scene();
+ if (sceneSubTree != nullptr) {
+ // Successfully built a subtree
+ finalStatus = QSceneLoader::Ready;
+ break;
+ }
+ }
+ }
+ } else {
+ QStringList extensions;
+ QMimeDatabase db;
+ QMimeType mtype = db.mimeTypeForData(m_data);
+ if (mtype.isValid()) {
+ extensions = mtype.suffixes();
+ }
+
+ QString basePath = m_source.adjusted(QUrl::RemoveFilename).toString();
+ for (QSceneImporter *sceneImporter : qAsConst(m_sceneImporters)) {
+ if (!sceneImporter->areFileTypesSupported(extensions))
+ continue;
+
+ // If the file type is supported -> enter Loading status
+ scene->setStatus(QSceneLoader::Loading);
+
+ // File type is supported, try to load it
+ sceneImporter->setData(m_data, basePath);
+ sceneSubTree = sceneImporter->scene();
+ if (sceneSubTree != nullptr) {
+ // Successfully built a subtree
+ finalStatus = QSceneLoader::Ready;
+ break;
+ }
}
}
}
diff --git a/src/render/jobs/loadscenejob_p.h b/src/render/jobs/loadscenejob_p.h
index 7538c6eb0..5217c6f43 100644
--- a/src/render/jobs/loadscenejob_p.h
+++ b/src/render/jobs/loadscenejob_p.h
@@ -70,6 +70,7 @@ class Q_AUTOTEST_EXPORT LoadSceneJob : public Qt3DCore::QAspectJob
{
public:
explicit LoadSceneJob(const QUrl &source, Qt3DCore::QNodeId sceneComponent);
+ void setData(const QByteArray &data);
void setNodeManagers(NodeManagers *managers) { m_managers = managers; }
void setSceneImporters(const QList<QSceneImporter *> sceneImporters) { m_sceneImporters = sceneImporters; }
@@ -82,6 +83,7 @@ public:
private:
QUrl m_source;
+ QByteArray m_data;
Qt3DCore::QNodeId m_sceneComponent;
NodeManagers *m_managers;
QList<QSceneImporter *> m_sceneImporters;
diff --git a/src/render/jobs/loadskeletonjob.cpp b/src/render/jobs/loadskeletonjob.cpp
new file mode 100644
index 000000000..34060312f
--- /dev/null
+++ b/src/render/jobs/loadskeletonjob.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "loadskeletonjob_p.h"
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/job_common_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+LoadSkeletonJob::LoadSkeletonJob(const HSkeleton &handle)
+ : QAspectJob()
+ , m_handle(handle)
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadSkeleton, 0);
+}
+
+LoadSkeletonJob::~LoadSkeletonJob()
+{
+}
+
+void LoadSkeletonJob::run()
+{
+ Skeleton *skeleton = m_nodeManagers->skeletonManager()->data(m_handle);
+ if (skeleton != nullptr)
+ skeleton->loadSkeleton();
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/loadskeletonjob_p.h b/src/render/jobs/loadskeletonjob_p.h
new file mode 100644
index 000000000..2cd9fa8bf
--- /dev/null
+++ b/src/render/jobs/loadskeletonjob_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_LOADSKELETONJOB_P_H
+#define QT3DRENDER_RENDER_LOADSKELETONJOB_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 <QtCore/qsharedpointer.h>
+
+#include <Qt3DRender/private/handle_types_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class NodeManagers;
+
+class LoadSkeletonJob : public Qt3DCore::QAspectJob
+{
+public:
+ explicit LoadSkeletonJob(const HSkeleton &handle);
+ ~LoadSkeletonJob();
+
+ void setNodeManagers(NodeManagers *nodeManagers) { m_nodeManagers = nodeManagers; }
+
+protected:
+ void run() override;
+ HSkeleton m_handle;
+ NodeManagers *m_nodeManagers;
+};
+
+typedef QSharedPointer<LoadSkeletonJob> LoadSkeletonJobPtr;
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_LOADSKELETONJOB_P_H
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 19c9932f5..df78f8f0a 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -39,17 +39,20 @@
#include "pickboundingvolumejob_p.h"
#include "qpicktriangleevent.h"
+#include "qpicklineevent.h"
+#include "qpickpointevent.h"
+#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/objectpicker_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
-
#include <Qt3DRender/private/rendersettings_p.h>
-#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/qpickevent_p.h>
+#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
QT_BEGIN_NAMESPACE
@@ -60,8 +63,6 @@ namespace Render {
namespace {
-typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList;
-
void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
{
switch (event.button()) {
@@ -223,18 +224,16 @@ bool PickBoundingVolumeJob::runHelper()
// 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
- // 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 trianglePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::TrianglePicking);
+ const bool edgePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::LinePicking);
+ const bool pointPickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::PointPicking);
+ const bool primitivePickingRequested = pointPickingRequested | edgePickingRequested | trianglePickingRequested;
const bool allHitsRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks);
const bool frontFaceRequested =
m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace;
const bool backFaceRequested =
m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace;
-
- // Select the best reduction function based on the settings
- const ReducerFunction reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+ const float pickWorldSpaceTolerance = m_renderSettings->pickWorldSpaceTolerance();
// For each mouse event
for (const QMouseEvent &event : mouseEvents) {
@@ -248,7 +247,7 @@ bool PickBoundingVolumeJob::runHelper()
// For each triplet of Viewport / Camera and Area
for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) {
- HitList sphereHits;
+ PickingUtils::HitList sphereHits;
QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId);
PickingUtils::HierarchicalEntityPicker entityPicker(ray);
@@ -259,10 +258,26 @@ bool PickBoundingVolumeJob::runHelper()
gathererFunctor.m_backFaceRequested = backFaceRequested;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
- sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entityPicker.entities(),
- gathererFunctor, reducerOp);
- } else {
- sphereHits = entityPicker.hits();
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ }
+ if (edgePickingRequested) {
+ PickingUtils::LineCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ }
+ if (pointPickingRequested) {
+ PickingUtils::PointCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ }
+ if (!primitivePickingRequested) {
+ sphereHits << entityPicker.hits();
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
if (!allHitsRequested)
sphereHits = { sphereHits.front() };
@@ -270,8 +285,7 @@ bool PickBoundingVolumeJob::runHelper()
}
// Dispatch events based on hit results
- dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers,
- trianglePickingRequested, allHitsRequested);
+ dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, allHitsRequested);
}
}
@@ -300,11 +314,10 @@ void PickBoundingVolumeJob::run()
}
void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
- const PickingUtils::CollisionVisitor::HitList &sphereHits,
+ const PickingUtils::HitList &sphereHits,
QPickEvent::Buttons eventButton,
int eventButtons,
int eventModifiers,
- bool trianglePickingRequested,
bool allHitsRequested)
{
ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
@@ -343,15 +356,39 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
localIntersection = entity->worldTransform()->inverted() * hit.m_intersection;
QPickEventPtr pickEvent;
- if (trianglePickingRequested) {
- pickEvent = QSharedPointer<QPickTriangleEvent>::create(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, hit.m_uvw);
- QPickEventPrivate::get(pickEvent.data())->m_entity = hit.m_entityId;
- } else {
- pickEvent = QSharedPointer<QPickEvent>::create(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
- eventButton, eventButtons, eventModifiers);
+ switch (hit.m_type) {
+ case QCollisionQueryResult::Hit::Triangle:
+ pickEvent = QPickTriangleEventPtr::create(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
+ hit.m_primitiveIndex,
+ hit.m_vertexIndex[0],
+ hit.m_vertexIndex[1],
+ hit.m_vertexIndex[2],
+ eventButton, eventButtons,
+ eventModifiers, hit.m_uvw);
+ break;
+ case QCollisionQueryResult::Hit::Edge:
+ pickEvent = QPickLineEventPtr::create(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
+ hit.m_primitiveIndex,
+ hit.m_vertexIndex[0], hit.m_vertexIndex[1],
+ eventButton, eventButtons, eventModifiers);
+ break;
+ case QCollisionQueryResult::Hit::Point:
+ pickEvent = QPickPointEventPtr::create(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
+ hit.m_vertexIndex[0],
+ eventButton, eventButtons, eventModifiers);
+ break;
+ case QCollisionQueryResult::Hit::Entity:
+ pickEvent = QPickEventPtr::create(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
+ eventButton, eventButtons, eventModifiers);
+ break;
+ default:
+ Q_UNREACHABLE();
}
+ Qt3DRender::QPickEventPrivate::get(pickEvent.data())->m_entity = hit.m_entityId;
switch (event.type()) {
case QEvent::MouseButtonPress: {
// Store pressed object handle
@@ -424,20 +461,6 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
}
}
-void PickBoundingVolumeJob::viewMatrixForCamera(Qt3DCore::QNodeId cameraId,
- QMatrix4x4 &viewMatrix,
- QMatrix4x4 &projectionMatrix) const
-{
- Render::CameraLens *lens = nullptr;
- Entity *camNode = m_manager->renderNodesManager()->lookupResource(cameraId);
- if (camNode != nullptr &&
- (lens = camNode->renderComponent<CameraLens>()) != nullptr &&
- lens->isEnabled()) {
- viewMatrix = *camNode->worldTransform();
- projectionMatrix = lens->projection();
- }
-}
-
QRect PickBoundingVolumeJob::windowViewport(const QSize &area, const QRectF &relativeViewport) const
{
if (area.isValid()) {
@@ -458,7 +481,7 @@ RayCasting::QRay3D PickBoundingVolumeJob::rayForViewportAndCamera(const QSize &a
{
QMatrix4x4 viewMatrix;
QMatrix4x4 projectionMatrix;
- viewMatrixForCamera(cameraId, viewMatrix, projectionMatrix);
+ Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), cameraId, viewMatrix, projectionMatrix);
const QRect viewport = windowViewport(area, relativeViewport);
// In GL the y is inverted compared to Qt
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index 5239c5c6c..d3f270d35 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -56,7 +56,6 @@
#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 <QKeyEvent>
@@ -76,6 +75,10 @@ class Renderer;
class NodeManagers;
class RenderSettings;
+namespace PickingUtils {
+typedef QVector<RayCasting::QCollisionQueryResult::Hit> HitList;
+}
+
class Q_AUTOTEST_EXPORT PickBoundingVolumeJob : public Qt3DCore::QAspectJob
{
public:
@@ -102,11 +105,11 @@ public:
protected:
void run() Q_DECL_FINAL;
- void dispatchPickEvents(const QMouseEvent &event, const PickingUtils::CollisionVisitor::HitList &sphereHits,
+ void dispatchPickEvents(const QMouseEvent &event,
+ const PickingUtils::HitList &sphereHits,
QPickEvent::Buttons eventButton,
int eventButtons,
int eventModifiers,
- bool trianglePickingRequested,
bool allHitsRequested);
private:
@@ -121,9 +124,6 @@ private:
QList<QKeyEvent> m_pendingKeyEvents;
- void viewMatrixForCamera(Qt3DCore::QNodeId cameraId,
- QMatrix4x4 &viewMatrix,
- QMatrix4x4 &projectionMatrix) const;
QRect windowViewport(const QSize &area, const QRectF &relativeViewport) const;
RayCasting::QRay3D rayForViewportAndCamera(const QSize &area,
const QPoint &pos,
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index 70f0b7f95..5a32f0203 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "pickboundingvolumeutils_p.h"
+#include <Qt3DRender/private/geometryrenderer_p.h>
#include <Qt3DRender/private/framegraphnode_p.h>
#include <Qt3DRender/private/cameralens_p.h>
#include <Qt3DRender/private/cameraselectornode_p.h>
@@ -47,6 +48,9 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/segmentsvisitor_p.h>
+#include <Qt3DRender/private/pointsvisitor_p.h>
#include <vector>
@@ -112,7 +116,8 @@ QVector<ViewportCameraAreaTriplet> ViewportCameraAreaGatherer::gather(FrameGraph
return vcaTriplets;
}
-bool PickingUtils::ViewportCameraAreaGatherer::isUnique(const QVector<ViewportCameraAreaTriplet> &vcaTriplets, const ViewportCameraAreaTriplet &vca) const
+bool 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)
@@ -149,7 +154,35 @@ QVector<Entity *> EntityGatherer::entities() const
return m_entities;
}
-void CollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c)
+
+class TriangleCollisionVisitor : public TrianglesVisitor
+{
+public:
+ HitList hits;
+
+ TriangleCollisionVisitor(NodeManagers* manager, const Entity *root, const RayCasting::QRay3D& ray,
+ bool frontFaceRequested, bool backFaceRequested)
+ : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0)
+ , m_frontFaceRequested(frontFaceRequested), m_backFaceRequested(backFaceRequested)
+ {
+ }
+
+private:
+ const Entity *m_root;
+ RayCasting::QRay3D m_ray;
+ uint m_triangleIndex;
+ bool m_frontFaceRequested;
+ bool m_backFaceRequested;
+
+ void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b,
+ uint cndx, const QVector3D &c) Q_DECL_OVERRIDE;
+ bool intersectsSegmentTriangle(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b,
+ uint cndx, const QVector3D &c);
+};
+
+void TriangleCollisionVisitor::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;
@@ -165,15 +198,16 @@ void CollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVe
m_triangleIndex++;
}
-bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c)
+bool TriangleCollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a, uint bndx, const QVector3D &b, uint cndx, const QVector3D &c)
{
float t = 0.0f;
QVector3D uvw;
bool intersected = Render::intersectsSegmentTriangle(m_ray, a, b, c, uvw, t);
if (intersected) {
QCollisionQueryResult::Hit queryResult;
+ queryResult.m_type = QCollisionQueryResult::Hit::Triangle;
queryResult.m_entityId = m_root->peerId();
- queryResult.m_triangleIndex = m_triangleIndex;
+ queryResult.m_primitiveIndex = m_triangleIndex;
queryResult.m_vertexIndex[0] = andx;
queryResult.m_vertexIndex[1] = bndx;
queryResult.m_vertexIndex[2] = cndx;
@@ -185,6 +219,204 @@ bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a,
return intersected;
}
+class LineCollisionVisitor : public SegmentsVisitor
+{
+public:
+ HitList hits;
+
+ LineCollisionVisitor(NodeManagers* manager, const Entity *root, const RayCasting::QRay3D& ray,
+ float pickWorldSpaceTolerance)
+ : SegmentsVisitor(manager), m_root(root), m_ray(ray)
+ , m_segmentIndex(0), m_pickWorldSpaceTolerance(pickWorldSpaceTolerance)
+ {
+ }
+
+private:
+ const Entity *m_root;
+ RayCasting::QRay3D m_ray;
+ uint m_segmentIndex;
+ float m_pickWorldSpaceTolerance;
+
+ void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b) Q_DECL_OVERRIDE;
+ bool intersectsSegmentSegment(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b);
+ bool rayToLineSegment(const QVector3D& lineStart,const QVector3D& lineEnd,
+ float &distance, QVector3D &intersection) const;
+};
+
+void LineCollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b)
+{
+ const QMatrix4x4 &mat = *m_root->worldTransform();
+ const QVector3D tA = mat * a;
+ const QVector3D tB = mat * b;
+
+ intersectsSegmentSegment(andx, tA, bndx, tB);
+
+ m_segmentIndex++;
+}
+
+bool LineCollisionVisitor::intersectsSegmentSegment(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b)
+{
+ float distance = 0.f;
+ QVector3D intersection;
+ bool res = rayToLineSegment(a, b, distance, intersection);
+ if (res) {
+ QCollisionQueryResult::Hit queryResult;
+ queryResult.m_type = QCollisionQueryResult::Hit::Edge;
+ queryResult.m_entityId = m_root->peerId();
+ queryResult.m_primitiveIndex = m_segmentIndex;
+ queryResult.m_vertexIndex[0] = andx;
+ queryResult.m_vertexIndex[1] = bndx;
+ queryResult.m_intersection = intersection;
+ queryResult.m_distance = m_ray.projectedDistance(queryResult.m_intersection);
+ hits.push_back(queryResult);
+ return true;
+ }
+ return false;
+}
+
+bool LineCollisionVisitor::rayToLineSegment(const QVector3D& lineStart,const QVector3D& lineEnd,
+ float &distance, QVector3D &intersection) const
+{
+ const float epsilon = 0.00000001f;
+
+ const QVector3D u = m_ray.direction() * m_ray.distance();
+ const QVector3D v = lineEnd - lineStart;
+ const QVector3D w = m_ray.origin() - lineStart;
+ const float a = QVector3D::dotProduct(u, u);
+ const float b = QVector3D::dotProduct(u, v);
+ const float c = QVector3D::dotProduct(v, v);
+ const float d = QVector3D::dotProduct(u, w);
+ const float e = QVector3D::dotProduct(v, w);
+ const float D = a * c - b * b;
+ float sc, sN, sD = D;
+ float tc, tN, tD = D;
+
+ if (D < epsilon) {
+ sN = 0.0;
+ sD = 1.0;
+ tN = e;
+ tD = c;
+ } else {
+ sN = (b * e - c * d);
+ tN = (a * e - b * d);
+ if (sN < 0.0) {
+ sN = 0.0;
+ tN = e;
+ tD = c;
+ }
+ }
+
+ if (tN < 0.0) {
+ tN = 0.0;
+ if (-d < 0.0)
+ sN = 0.0;
+ else {
+ sN = -d;
+ sD = a;
+ }
+ } else if (tN > tD) {
+ tN = tD;
+ if ((-d + b) < 0.0)
+ sN = 0;
+ else {
+ sN = (-d + b);
+ sD = a;
+ }
+ }
+
+ sc = (qAbs(sN) < epsilon ? 0.0f : sN / sD);
+ tc = (qAbs(tN) < epsilon ? 0.0f : tN / tD);
+
+ const QVector3D dP = w + (sc * u) - (tc * v);
+ const float f = dP.length();
+ if (f < m_pickWorldSpaceTolerance) {
+ distance = sc * u.length();
+ intersection = lineStart + v * tc;
+ return true;
+ }
+ return false;
+}
+
+class PointCollisionVisitor : public PointsVisitor
+{
+public:
+ HitList hits;
+
+ PointCollisionVisitor(NodeManagers* manager, const Entity *root, const RayCasting::QRay3D& ray,
+ float pickWorldSpaceTolerance)
+ : PointsVisitor(manager), m_root(root), m_ray(ray)
+ , m_pointIndex(0), m_pickWorldSpaceTolerance(pickWorldSpaceTolerance)
+ {
+ }
+
+private:
+ const Entity *m_root;
+ RayCasting::QRay3D m_ray;
+ uint m_pointIndex;
+ float m_pickWorldSpaceTolerance;
+
+ void visit(uint ndx, const QVector3D &p) Q_DECL_OVERRIDE;
+
+ double pointToRayDistance(const QVector3D &a, QVector3D &p)
+ {
+ const QVector3D v = a - m_ray.origin();
+ const double t = QVector3D::dotProduct(v, m_ray.direction());
+ p = m_ray.origin() + t * m_ray.direction();
+ return (p - a).length();
+ }
+};
+
+
+void PointCollisionVisitor::visit(uint ndx, const QVector3D &p)
+{
+ const QMatrix4x4 &mat = *m_root->worldTransform();
+ const QVector3D tP = mat * p;
+ QVector3D intersection;
+
+ float d = pointToRayDistance(tP, intersection);
+ if (d < m_pickWorldSpaceTolerance) {
+ QCollisionQueryResult::Hit queryResult;
+ queryResult.m_type = QCollisionQueryResult::Hit::Point;
+ queryResult.m_entityId = m_root->peerId();
+ queryResult.m_primitiveIndex = m_pointIndex;
+ queryResult.m_vertexIndex[0] = ndx;
+ queryResult.m_intersection = intersection;
+ queryResult.m_distance = d;
+ hits.push_back(queryResult);
+ }
+
+ m_pointIndex++;
+}
+
+HitList reduceToFirstHit(HitList &result, const 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;
+}
+
+HitList reduceToAllHits(HitList &results, const HitList &intermediate)
+{
+ if (!intermediate.empty())
+ results << intermediate;
+ return results;
+}
+
AbstractCollisionGathererFunctor::AbstractCollisionGathererFunctor()
: m_manager(nullptr)
{ }
@@ -192,7 +424,7 @@ AbstractCollisionGathererFunctor::AbstractCollisionGathererFunctor()
AbstractCollisionGathererFunctor::~AbstractCollisionGathererFunctor()
{ }
-AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor::operator ()(const Entity *entity) const
+HitList AbstractCollisionGathererFunctor::operator ()(const Entity *entity) const
{
HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
@@ -207,44 +439,62 @@ AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor::
ObjectPicker *objectPicker = m_manager->objectPickerManager()->data(objectPickerHandle);
if (objectPicker == nullptr || !objectPicker->isEnabled())
- return result_type(); // don't bother picking entities that don't
- // have an object picker, or if it's disabled
+ return {}; // don't bother picking entities that don't
+ // have an object picker, or if it's disabled
- RayCasting::QRayCastingService rayCasting;
+ return pick(entity);
+}
- return pick(&rayCasting, entity);
+bool AbstractCollisionGathererFunctor::rayHitsEntity(const Entity *entity) const
+{
+ QRayCastingService rayCasting;
+ const QCollisionQueryResult::Hit queryResult = rayCasting.query(m_ray, entity->worldBoundingVolume());
+ return queryResult.m_distance >= 0.f;
}
-void AbstractCollisionGathererFunctor::sortHits(CollisionVisitor::HitList &results)
+void AbstractCollisionGathererFunctor::sortHits(HitList &results)
{
- auto compareHitsDistance = [](const CollisionVisitor::HitList::value_type &a,
- const CollisionVisitor::HitList::value_type &b) {
+ auto compareHitsDistance = [](const HitList::value_type &a,
+ const HitList::value_type &b) {
return a.m_distance < b.m_distance;
};
std::sort(results.begin(), results.end(), compareHitsDistance);
}
-AbstractCollisionGathererFunctor::result_type EntityCollisionGathererFunctor::pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
+HitList EntityCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
+{
+ const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+ return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp);
+}
+
+HitList EntityCollisionGathererFunctor::pick(const Entity *entity) const
{
- result_type result;
+ HitList result;
- const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
+ QRayCastingService rayCasting;
+ 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(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
+HitList TriangleCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
+{
+ const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+ return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp);
+}
+
+HitList TriangleCollisionGathererFunctor::pick(const Entity *entity) const
{
- result_type result;
+ HitList result;
GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
if (!gRenderer)
return result;
- if (rayHitsEntity(rayCasting, entity)) {
- CollisionVisitor visitor(m_manager, entity, m_ray, m_frontFaceRequested, m_backFaceRequested);
+ if (rayHitsEntity(entity)) {
+ TriangleCollisionVisitor visitor(m_manager, entity, m_ray, m_frontFaceRequested, m_backFaceRequested);
visitor.apply(gRenderer, entity->peerId());
result = visitor.hits;
@@ -254,36 +504,55 @@ AbstractCollisionGathererFunctor::result_type TriangleCollisionGathererFunctor::
return result;
}
-bool TriangleCollisionGathererFunctor::rayHitsEntity(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const
+HitList LineCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
{
- const QCollisionQueryResult::Hit queryResult = rayCasting->query(m_ray, entity->worldBoundingVolume());
- return queryResult.m_distance >= 0.f;
+ const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+ return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp);
}
-CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate)
+HitList LineCollisionGathererFunctor::pick(const Entity *entity) const
{
- 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;
- }
- }
+ HitList result;
- while (result.size() > 1)
- result.pop_back();
+ GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
+ if (!gRenderer)
+ return result;
+
+ if (rayHitsEntity(entity)) {
+ LineCollisionVisitor visitor(m_manager, entity, m_ray, m_pickWorldSpaceTolerance);
+ visitor.apply(gRenderer, entity->peerId());
+ result = visitor.hits;
+ sortHits(result);
}
+
return result;
}
-CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate)
+HitList PointCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
{
- if (!intermediate.empty())
- results << intermediate;
- return results;
+ const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+ return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp);
+}
+
+HitList PointCollisionGathererFunctor::pick(const Entity *entity) const
+{
+ HitList result;
+
+ GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
+ if (!gRenderer)
+ return result;
+
+ if (gRenderer->primitiveType() != Qt3DRender::QGeometryRenderer::Points)
+ return result;
+
+ if (rayHitsEntity(entity)) {
+ PointCollisionVisitor visitor(m_manager, entity, m_ray, m_pickWorldSpaceTolerance);
+ visitor.apply(gRenderer, entity->peerId());
+ result = visitor.hits;
+ sortHits(result);
+ }
+
+ return result;
}
HierarchicalEntityPicker::HierarchicalEntityPicker(const QRay3D &ray)
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index 08615c094..6e2532ea5 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -53,7 +53,6 @@
#include <Qt3DCore/QNodeId>
#include <Qt3DRender/private/qray3d_p.h>
-#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/qraycastingservice_p.h>
@@ -69,6 +68,7 @@ namespace Render {
class Entity;
class Renderer;
class FrameGraphNode;
+class NodeManagers;
namespace PickingUtils {
@@ -108,33 +108,7 @@ private:
mutable bool m_needsRefresh;
};
-class Q_AUTOTEST_EXPORT CollisionVisitor : public TrianglesVisitor
-{
-public:
- typedef QVector<RayCasting::QCollisionQueryResult::Hit> HitList;
- HitList hits;
-
- CollisionVisitor(NodeManagers* manager, const Entity *root, const RayCasting::QRay3D& ray,
- bool frontFaceRequested, bool backFaceRequested)
- : TrianglesVisitor(manager), m_root(root), m_ray(ray), m_triangleIndex(0)
- , m_frontFaceRequested(frontFaceRequested), m_backFaceRequested(backFaceRequested)
- {
- }
-
-private:
- const Entity *m_root;
- RayCasting::QRay3D m_ray;
- uint m_triangleIndex;
- bool m_frontFaceRequested;
- bool m_backFaceRequested;
-
- void visit(uint andx, const QVector3D &a,
- uint bndx, const QVector3D &b,
- uint cndx, const QVector3D &c) Q_DECL_OVERRIDE;
- bool intersectsSegmentTriangle(uint andx, const QVector3D &a,
- uint bndx, const QVector3D &b,
- uint cndx, const QVector3D &c);
-};
+typedef QVector<RayCasting::QCollisionQueryResult::Hit> HitList;
class Q_AUTOTEST_EXPORT HierarchicalEntityPicker
{
@@ -142,12 +116,12 @@ public:
explicit HierarchicalEntityPicker(const RayCasting::QRay3D &ray);
bool collectHits(Entity *root);
- inline CollisionVisitor::HitList hits() const { return m_hits; }
+ inline HitList hits() const { return m_hits; }
inline QVector<Entity *> entities() const { return m_entities; }
private:
RayCasting::QRay3D m_ray;
- CollisionVisitor::HitList m_hits;
+ HitList m_hits;
QVector<Entity *> m_entities;
};
@@ -159,17 +133,21 @@ struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
NodeManagers *m_manager;
RayCasting::QRay3D m_ray;
+ virtual HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) = 0;
+
// This define is required to work with QtConcurrent
- typedef CollisionVisitor::HitList result_type;
- result_type operator ()(const Entity *entity) const;
- virtual result_type pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const = 0;
+ typedef HitList result_type;
+ HitList operator ()(const Entity *entity) const;
+ virtual HitList pick(const Entity *entity) const = 0;
- static void sortHits(CollisionVisitor::HitList &results);
+ bool rayHitsEntity(const Entity *entity) const;
+ static void sortHits(HitList &results);
};
struct Q_AUTOTEST_EXPORT EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor
{
- result_type pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE;
+ HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) Q_DECL_OVERRIDE;
+ HitList pick(const Entity *entity) const Q_DECL_OVERRIDE;
};
struct Q_AUTOTEST_EXPORT TriangleCollisionGathererFunctor : public AbstractCollisionGathererFunctor
@@ -177,17 +155,25 @@ struct Q_AUTOTEST_EXPORT TriangleCollisionGathererFunctor : public AbstractColli
bool m_frontFaceRequested;
bool m_backFaceRequested;
- result_type pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const Q_DECL_OVERRIDE;
-
- bool rayHitsEntity(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const;
+ HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) Q_DECL_OVERRIDE;
+ HitList pick(const Entity *entity) const Q_DECL_OVERRIDE;
};
-Q_AUTOTEST_EXPORT QVector<Entity *> gatherEntities(Entity *entity, QVector<Entity *> entities);
+struct Q_AUTOTEST_EXPORT LineCollisionGathererFunctor : public AbstractCollisionGathererFunctor
+{
+ float m_pickWorldSpaceTolerance;
+
+ HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) Q_DECL_OVERRIDE;
+ HitList pick(const Entity *entity) const Q_DECL_OVERRIDE;
+};
-Q_AUTOTEST_EXPORT CollisionVisitor::HitList reduceToFirstHit(CollisionVisitor::HitList &result, const CollisionVisitor::HitList &intermediate);
+struct Q_AUTOTEST_EXPORT PointCollisionGathererFunctor : public AbstractCollisionGathererFunctor
+{
+ float m_pickWorldSpaceTolerance;
-// Unordered
-Q_AUTOTEST_EXPORT CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, const CollisionVisitor::HitList &intermediate);
+ HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) Q_DECL_OVERRIDE;
+ HitList pick(const Entity *entity) const Q_DECL_OVERRIDE;
+};
} // PickingUtils
diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp
index 05e99314e..cf23e572f 100644
--- a/src/render/jobs/renderviewjobutils.cpp
+++ b/src/render/jobs/renderviewjobutils.cpp
@@ -67,6 +67,7 @@
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/memorybarrier_p.h>
+#include <Qt3DRender/private/blitframebuffer_p.h>
QT_BEGIN_NAMESPACE
@@ -118,8 +119,11 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
break;
case FrameGraphNode::LayerFilter: // Can be set multiple times in the tree
- rv->setHasLayerFilter(true);
- rv->appendLayerFilter(static_cast<const LayerFilterNode *>(node)->layerIds());
+ rv->appendLayerFilter(static_cast<const LayerFilterNode *>(node)->peerId());
+ break;
+
+ case FrameGraphNode::ProximityFilter: // Can be set multiple times in the tree
+ rv->appendProximityFilterId(node->peerId());
break;
case FrameGraphNode::RenderPassFilter:
@@ -232,8 +236,8 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
auto *renderCapture = const_cast<Render::RenderCapture *>(
static_cast<const Render::RenderCapture *>(node));
if (rv->renderCaptureNodeId().isNull() && renderCapture->wasCaptureRequested()) {
- renderCapture->acknowledgeCaptureRequest();
rv->setRenderCaptureNodeId(renderCapture->peerId());
+ rv->setRenderCaptureRequest(renderCapture->takeCaptureRequest());
}
break;
}
@@ -252,6 +256,22 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
break;
}
+ case FrameGraphNode::BlitFramebuffer: {
+ const Render::BlitFramebuffer *blitFramebufferNode =
+ static_cast<const Render::BlitFramebuffer *>(node);
+ rv->setHasBlitFramebufferInfo(true);
+ BlitFramebufferInfo bfbInfo;
+ bfbInfo.sourceRenderTargetId = blitFramebufferNode->sourceRenderTargetId();
+ bfbInfo.destinationRenderTargetId = blitFramebufferNode->destinationRenderTargetId();
+ bfbInfo.sourceRect = blitFramebufferNode->sourceRect();
+ bfbInfo.destinationRect = blitFramebufferNode->destinationRect();
+ bfbInfo.sourceAttachmentPoint = blitFramebufferNode->sourceAttachmentPoint();
+ bfbInfo.destinationAttachmentPoint = blitFramebufferNode->destinationAttachmentPoint();
+ bfbInfo.interpolationMethod = blitFramebufferNode->interpolationMethod();
+ rv->setBlitFrameBufferInfo(bfbInfo);
+ break;
+ }
+
default:
// Should never get here
qCWarning(Backend) << "Unhandled FrameGraphNode type";
diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp
index 24891f9b8..8b604229a 100644
--- a/src/render/jobs/updatelevelofdetailjob.cpp
+++ b/src/render/jobs/updatelevelofdetailjob.cpp
@@ -43,6 +43,7 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
QT_BEGIN_NAMESPACE
@@ -95,22 +96,6 @@ void UpdateLevelOfDetailJob::run()
updateEntityLod(m_root);
}
-bool UpdateLevelOfDetailJob::viewMatrixForCamera(const Qt3DCore::QNodeId &cameraId,
- QMatrix4x4 &viewMatrix,
- QMatrix4x4 &projectionMatrix) const
-{
- Render::CameraLens *lens = nullptr;
- Entity *camNode = m_manager->renderNodesManager()->lookupResource(cameraId);
- if (camNode != nullptr &&
- (lens = camNode->renderComponent<CameraLens>()) != nullptr &&
- lens->isEnabled()) {
- viewMatrix = *camNode->worldTransform();
- projectionMatrix = lens->projection();
- return true;
- }
- return false;
-}
-
QRect UpdateLevelOfDetailJob::windowViewport(const QSize &area, const QRectF &relativeViewport) const
{
if (area.isValid()) {
@@ -157,7 +142,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDe
{
QMatrix4x4 viewMatrix;
QMatrix4x4 projectionMatrix;
- if (!viewMatrixForCamera(lod->camera(), viewMatrix, projectionMatrix))
+ if (!Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), lod->camera(), viewMatrix, projectionMatrix))
return;
const QVector<qreal> thresholds = lod->thresholds();
@@ -186,7 +171,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOf
{
QMatrix4x4 viewMatrix;
QMatrix4x4 projectionMatrix;
- if (!viewMatrixForCamera(lod->camera(), viewMatrix, projectionMatrix))
+ if (!Render::CameraLens::viewMatrixForCamera(m_manager->renderNodesManager(), lod->camera(), viewMatrix, projectionMatrix))
return;
PickingUtils::ViewportCameraAreaGatherer vcaGatherer(lod->camera());
diff --git a/src/render/jobs/updatelevelofdetailjob_p.h b/src/render/jobs/updatelevelofdetailjob_p.h
index 30fe3004d..c29501a09 100644
--- a/src/render/jobs/updatelevelofdetailjob_p.h
+++ b/src/render/jobs/updatelevelofdetailjob_p.h
@@ -51,9 +51,9 @@
// We mean it.
//
-#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DCore/QAspectJob>
+#include <Qt3DCore/QNodeId>
#include <Qt3DRender/private/qt3drender_global_p.h>
-#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
QT_BEGIN_NAMESPACE
@@ -64,6 +64,7 @@ namespace Render {
class Entity;
class NodeManagers;
class LevelOfDetail;
+class FrameGraphNode;
class QT3DRENDERSHARED_PRIVATE_EXPORT UpdateLevelOfDetailJob : public Qt3DCore::QAspectJob
{
@@ -83,7 +84,6 @@ private:
void updateEntityLod(Entity *entity);
void updateEntityLodByDistance(Entity *entity, LevelOfDetail *lod);
void updateEntityLodByScreenArea(Entity *entity, LevelOfDetail *lod);
- bool viewMatrixForCamera(const Qt3DCore::QNodeId &cameraId, QMatrix4x4 &viewMatrix, QMatrix4x4 &projectionMatrix) const;
QRect windowViewport(const QSize &area, const QRectF &relativeViewport) const;
NodeManagers *m_manager;
diff --git a/src/render/jobs/updateskinningpalettejob.cpp b/src/render/jobs/updateskinningpalettejob.cpp
new file mode 100644
index 000000000..9cb80c42b
--- /dev/null
+++ b/src/render/jobs/updateskinningpalettejob.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "updateskinningpalettejob_p.h"
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/handle_types_p.h>
+#include <Qt3DRender/private/job_common_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+UpdateSkinningPaletteJob::UpdateSkinningPaletteJob()
+ : Qt3DCore::QAspectJob()
+ , m_root()
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateSkinningPalette, 0);
+}
+
+UpdateSkinningPaletteJob::~UpdateSkinningPaletteJob()
+{
+}
+
+void UpdateSkinningPaletteJob::run()
+{
+ // TODO: Decompose this job across several jobs, say one per skeleton so
+ // that it can be done in parallel
+
+ // Update the local pose transforms of JointInfo's in Skeletons from
+ // the set of dirty joints.
+ for (const auto jointHandle : m_dirtyJoints) {
+ Joint *joint = m_nodeManagers->jointManager()->data(jointHandle);
+ Q_ASSERT(joint);
+ Skeleton *skeleton = m_nodeManagers->skeletonManager()->data(joint->owningSkeleton());
+ Q_ASSERT(skeleton);
+ if (skeleton->isEnabled() && joint->isEnabled())
+ skeleton->setLocalPose(jointHandle, joint->localPose());
+ }
+
+ // Find all the armature components and update their skinning palettes
+ QVector<HArmature> dirtyArmatures;
+ findDirtyArmatures(m_root, dirtyArmatures);
+
+ // Update the skeleton for each dirty armature
+ auto armatureManager = m_nodeManagers->armatureManager();
+ auto skeletonManager = m_nodeManagers->skeletonManager();
+ for (const auto armatureHandle : qAsConst(dirtyArmatures)) {
+ auto armature = armatureManager->data(armatureHandle);
+ Q_ASSERT(armature);
+
+ auto skeletonId = armature->skeletonId();
+ auto skeleton = skeletonManager->lookupResource(skeletonId);
+ Q_ASSERT(skeleton);
+
+ const QVector<QMatrix4x4> skinningPalette = skeleton->calculateSkinningMatrixPalette();
+ armature->skinningPaletteUniform().setData(skinningPalette);
+ }
+}
+
+void UpdateSkinningPaletteJob::findDirtyArmatures(Entity *entity,
+ QVector<HArmature> &armatures) const
+{
+ // Just return all enabled armatures found on entities for now
+ // TODO: Be smarter about limiting which armatures we update. For e.g. only
+ // those with skeletons that have changed and only those that are within view
+ // of one or more renderviews.
+ const auto armatureHandle = entity->componentHandle<Armature, 16>();
+ if (!armatureHandle.isNull() && !armatures.contains(armatureHandle))
+ armatures.push_back(armatureHandle);
+
+ for (const auto child : entity->children())
+ findDirtyArmatures(child, armatures);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/updateskinningpalettejob_p.h b/src/render/jobs/updateskinningpalettejob_p.h
new file mode 100644
index 000000000..9e230f143
--- /dev/null
+++ b/src/render/jobs/updateskinningpalettejob_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_UPDATESKINNINGPALETTEJOB_P_H
+#define QT3DRENDER_RENDER_UPDATESKINNINGPALETTEJOB_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 <QtCore/qsharedpointer.h>
+
+#include <Qt3DRender/private/handle_types_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class NodeManagers;
+
+class UpdateSkinningPaletteJob : public Qt3DCore::QAspectJob
+{
+public:
+ explicit UpdateSkinningPaletteJob();
+ ~UpdateSkinningPaletteJob();
+
+ void setRoot(Entity *root) { m_root = root; }
+ void setManagers(NodeManagers *nodeManagers) { m_nodeManagers = nodeManagers; }
+
+ void setDirtyJoints(const QVector<HJoint> dirtyJoints) { m_dirtyJoints = dirtyJoints; }
+ void clearDirtyJoints() { m_dirtyJoints.clear(); }
+
+protected:
+ void run() override;
+ void findDirtyArmatures(Entity *entity, QVector<HArmature> &armatures) const;
+ NodeManagers *m_nodeManagers;
+ Entity *m_root;
+ QVector<HJoint> m_dirtyJoints;
+};
+
+typedef QSharedPointer<UpdateSkinningPaletteJob> UpdateSkinningPaletteJobPtr;
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_UPDATESKINNINGPALETTEJOB_P_H
diff --git a/src/render/lights/qspotlight.h b/src/render/lights/qspotlight.h
index 8497740db..8902708a3 100644
--- a/src/render/lights/qspotlight.h
+++ b/src/render/lights/qspotlight.h
@@ -61,7 +61,6 @@ public:
explicit QSpotLight(Qt3DCore::QNode *parent = nullptr);
~QSpotLight();
- QVector3D attenuation() const;
QVector3D localDirection() const;
float cutOffAngle() const;
diff --git a/src/render/materialsystem/materialsystem.pri b/src/render/materialsystem/materialsystem.pri
index b6e9ead03..c464d6b99 100644
--- a/src/render/materialsystem/materialsystem.pri
+++ b/src/render/materialsystem/materialsystem.pri
@@ -19,10 +19,13 @@ HEADERS += \
$$PWD/qshaderdata_p.h \
$$PWD/qshaderprogram.h \
$$PWD/qshaderprogram_p.h \
+ $$PWD/qshaderprogrambuilder.h \
+ $$PWD/qshaderprogrambuilder_p.h \
$$PWD/qtechnique.h \
$$PWD/qtechnique_p.h \
$$PWD/renderpass_p.h \
$$PWD/shader_p.h \
+ $$PWD/shaderbuilder_p.h \
$$PWD/shaderdata_p.h \
$$PWD/technique_p.h \
$$PWD/qgraphicsapifilter.h \
@@ -42,11 +45,16 @@ SOURCES += \
$$PWD/qrenderpass.cpp \
$$PWD/qshaderdata.cpp \
$$PWD/qshaderprogram.cpp \
+ $$PWD/qshaderprogrambuilder.cpp \
$$PWD/qtechnique.cpp \
$$PWD/renderpass.cpp \
$$PWD/shader.cpp \
+ $$PWD/shaderbuilder.cpp \
$$PWD/shaderdata.cpp \
$$PWD/technique.cpp \
$$PWD/qgraphicsapifilter.cpp \
$$PWD/shadercache.cpp \
$$PWD/techniquemanager.cpp
+
+RESOURCES += \
+ $$PWD/materialsystem.qrc
diff --git a/src/render/materialsystem/materialsystem.qrc b/src/render/materialsystem/materialsystem.qrc
new file mode 100644
index 000000000..69a6a1022
--- /dev/null
+++ b/src/render/materialsystem/materialsystem.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>prototypes/default.json</file>
+ </qresource>
+</RCC>
diff --git a/src/render/materialsystem/parameter.cpp b/src/render/materialsystem/parameter.cpp
index 6671e4943..f00df3c90 100644
--- a/src/render/materialsystem/parameter.cpp
+++ b/src/render/materialsystem/parameter.cpp
@@ -87,10 +87,13 @@ void Parameter::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (propertyChange->propertyName() == QByteArrayLiteral("name")) {
m_name = propertyChange->value().toString();
m_nameId = StringToInt::lookupId(m_name);
+ markDirty(AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty);
} else if (propertyChange->propertyName() == QByteArrayLiteral("value")) {
m_uniformValue = UniformValue::fromVariant(propertyChange->value());
+ markDirty(AbstractRenderer::ParameterDirty);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) {
+ markDirty(AbstractRenderer::MaterialDirty | AbstractRenderer::ParameterDirty);
}
- markDirty(AbstractRenderer::AllDirty);
}
BackendNode::sceneChangeEvent(e);
diff --git a/src/render/materialsystem/prototypes/default.json b/src/render/materialsystem/prototypes/default.json
new file mode 100644
index 000000000..535f144d7
--- /dev/null
+++ b/src/render/materialsystem/prototypes/default.json
@@ -0,0 +1,592 @@
+{
+ "input": {
+ "outputs": [
+ "value"
+ ],
+ "parameters": {
+ "name": "defaultName",
+ "qualifier": {
+ "type": "QShaderLanguage::StorageQualifier",
+ "value": "QShaderLanguage::Input"
+ },
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $value = $name;",
+ "headerSnippets": [ "$qualifier highp $type $name;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $value = $name;",
+ "headerSnippets": [ "$qualifier $type $name;" ]
+ }
+ ]
+ },
+ "constant": {
+ "outputs": [
+ "value"
+ ],
+ "parameters": {
+ "constant": "0.0",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Float"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $value = $type($constant);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $value = $type($constant);"
+ }
+ ]
+ },
+ "sampleTexture": {
+ "inputs": [
+ "coord"
+ ],
+ "outputs": [
+ "color"
+ ],
+ "parameters": {
+ "name": "defaultName"
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec4 $color = texture2D($name, $coord);",
+ "headerSnippets": [ "uniform sampler2D $name;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "vec4 $color = texture($name, $coord);",
+ "headerSnippets": [ "uniform sampler2D $name;" ]
+ }
+ ]
+ },
+ "fragColor": {
+ "inputs": [
+ "fragColor"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "gl_FragColor = $fragColor;"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "fragColor = $fragColor;",
+ "headerSnippets": [ "out vec4 fragColor;" ]
+ }
+ ]
+ },
+ "eyePosition": {
+ "outputs": [
+ "eyePosition"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec3 $eyePosition = eyePosition;",
+ "headerSnippets": [ "uniform highp vec3 eyePosition;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "vec3 $eyePosition = eyePosition;",
+ "headerSnippets": [ "uniform vec3 eyePosition;" ]
+ }
+ ]
+ },
+ "time": {
+ "outputs": [
+ "time"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp float $time = time;",
+ "headerSnippets": [ "uniform highp float time;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "float $time = time;",
+ "headerSnippets": [ "uniform float time;" ]
+ }
+ ]
+ },
+ "transpose": {
+ "inputs": [
+ "input"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Mat3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = transpose($input);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = transpose($input);"
+ }
+ ]
+ },
+ "normalize": {
+ "inputs": [
+ "input"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = normalize($input);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = normalize($input);"
+ }
+ ]
+ },
+ "subtract": {
+ "inputs": [
+ "minuend",
+ "subtrahend"
+ ],
+ "outputs": [
+ "difference"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $difference = $minuend - $subtrahend;"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $difference = $minuend - $subtrahend;"
+ }
+ ]
+ },
+ "add": {
+ "inputs": [
+ "first",
+ "second"
+ ],
+ "outputs": [
+ "sum"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $sum = $first + $second;"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $sum = $first + $second;"
+ }
+ ]
+ },
+ "multiply": {
+ "inputs": [
+ "first",
+ "second"
+ ],
+ "outputs": [
+ "product"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $product = $first * $second;"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $product = $first * $second;"
+ }
+ ]
+ },
+ "swizzle": {
+ "inputs": [
+ "input"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "fields": "x",
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = $input.$fields;"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = $input.$fields;"
+ }
+ ]
+ },
+ "worldSpaceToTangentSpaceMatrix": {
+ "inputs": [
+ "worldNormal",
+ "worldTangent"
+ ],
+ "outputs": [
+ "matrix"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp mat3 $matrix = calcWorldSpaceToTangentSpaceMatrix($worldNormal, $worldTangent);",
+ "headerSnippets": [ "#pragma include :/shaders/es2/coordinatesystems.inc" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "mat3 $matrix = calcWorldSpaceToTangentSpaceMatrix($worldNormal, $worldTangent);",
+ "headerSnippets": [ "#pragma include :/shaders/gl3/coordinatesystems.inc" ]
+ }
+ ]
+ },
+ "phongFunction": {
+ "inputs": [
+ "ambient",
+ "diffuse",
+ "specular",
+ "shininess",
+ "worldPosition",
+ "worldView",
+ "worldNormal"
+ ],
+ "outputs": [
+ "outputColor"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec4 $outputColor = phongFunction($ambient, $diffuse, $specular, $shininess, $worldPosition, $worldView, $worldNormal);",
+ "headerSnippets": [ "#pragma include :/shaders/es2/phong.inc.frag" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "vec4 $outputColor = phongFunction($ambient, $diffuse, $specular, $shininess, $worldPosition, $worldView, $worldNormal);",
+ "headerSnippets": [ "#pragma include :/shaders/gl3/phong.inc.frag" ]
+ }
+ ]
+ },
+ "metalRoughFunction": {
+ "inputs": [
+ "baseColor",
+ "metalness",
+ "roughness",
+ "ambientOcclusion",
+ "worldPosition",
+ "worldView",
+ "worldNormal"
+ ],
+ "outputs": [
+ "outputColor"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 1
+ },
+ "substitution": "vec4 $outputColor = metalRoughFunction($baseColor, $metalness, $roughness, $ambientOcclusion, $worldPosition, $worldView, $worldNormal);",
+ "headerSnippets": [ "#pragma include :/shaders/gl3/metalrough.inc.frag" ]
+ }
+ ]
+ },
+ "join2": {
+ "inputs": [
+ "first",
+ "second"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec2"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = $type($first, $second);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = $type($first, $second);"
+ }
+ ]
+ },
+ "join3": {
+ "inputs": [
+ "first",
+ "second",
+ "third"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = $type($first, $second, $third);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = $type($first, $second, $third);"
+ }
+ ]
+ },
+ "join4": {
+ "inputs": [
+ "first",
+ "second",
+ "third",
+ "fourth"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec4"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = $type($first, $second, $third, $fourth);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = $type($first, $second, $third, $fourth);"
+ }
+ ]
+ },
+ "cast": {
+ "inputs": [
+ "input"
+ ],
+ "outputs": [
+ "output"
+ ],
+ "parameters": {
+ "type": {
+ "type": "QShaderLanguage::VariableType",
+ "value": "QShaderLanguage::Vec3"
+ }
+ },
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp $type $output = $type($input);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 0
+ },
+ "substitution": "$type $output = $type($input);"
+ }
+ ]
+ }
+}
+
diff --git a/src/render/materialsystem/qshaderprogram_p.h b/src/render/materialsystem/qshaderprogram_p.h
index 6bdde68f1..92520c3c8 100644
--- a/src/render/materialsystem/qshaderprogram_p.h
+++ b/src/render/materialsystem/qshaderprogram_p.h
@@ -64,12 +64,6 @@ public:
QShaderProgramPrivate();
Q_DECLARE_PUBLIC(QShaderProgram)
- QString m_vertexSourceFile;
- QString m_tessControlSourceFile;
- QString m_tessEvalSourceFile;
- QString m_geometrySourceFile;
- QString m_fragmentSourceFile;
- QString m_computeSourceFile;
QByteArray m_vertexShaderCode;
QByteArray m_tessControlShaderCode;
QByteArray m_tessEvalShaderCode;
diff --git a/src/render/materialsystem/qshaderprogrambuilder.cpp b/src/render/materialsystem/qshaderprogrambuilder.cpp
new file mode 100644
index 000000000..9318f96af
--- /dev/null
+++ b/src/render/materialsystem/qshaderprogrambuilder.cpp
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qshaderprogrambuilder.h"
+#include "qshaderprogrambuilder_p.h"
+#include "qshaderprogram.h"
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DRender/private/qurlhelper_p.h>
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QUrl>
+
+/*!
+ \class Qt3DRender::QShaderProgramBuilder
+ \inmodule Qt3DRender
+ \brief Generates a Shader Program content from loaded graphs.
+ \inherits Qt3DCore::QNode
+ \since 5.10
+
+ A shader program builder consists of several different shader graphs
+ used to generate shader code.
+*/
+
+/*!
+ \qmltype ShaderProgramBuilder
+ \instantiates Qt3DRender::QShaderProgramBuilder
+ \inqmlmodule Qt3D.Render
+ \brief Generates a Shader Program content from loaded graphs.
+ \since 5.10
+
+ A shader program builder consists of several different shader graphs
+ used to generate shader code.
+*/
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+QShaderProgramBuilderPrivate::QShaderProgramBuilderPrivate()
+ : QNodePrivate(),
+ m_shaderProgram(nullptr)
+{
+}
+
+QShaderProgramBuilder::QShaderProgramBuilder(QNode *parent)
+ : QNode(*new QShaderProgramBuilderPrivate, parent)
+{
+}
+
+QShaderProgramBuilder::~QShaderProgramBuilder()
+{
+}
+
+/*! \internal */
+QShaderProgramBuilder::QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, QNode *parent)
+ : QNode(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty string ShaderProgramBuilder::shaderProgram
+
+ Holds the shader program on which this builder generates code.
+*/
+/*!
+ \property QShaderProgramBuilder::shaderProgram
+
+ Holds the shader program on which this builder generates code.
+*/
+void QShaderProgramBuilder::setShaderProgram(QShaderProgram *program)
+{
+ Q_D(QShaderProgramBuilder);
+ if (program != d->m_shaderProgram) {
+
+ if (d->m_shaderProgram)
+ d->unregisterDestructionHelper(d->m_shaderProgram);
+
+ // We need to add it as a child of the current node if it has been declared inline
+ // Or not previously added as a child of the current node so that
+ // 1) The backend gets notified about it's creation
+ // 2) When the current node is destroyed, it gets destroyed as well
+ if (program && !program->parent())
+ program->setParent(this);
+ d->m_shaderProgram = program;
+
+ // Ensures proper bookkeeping
+ if (d->m_shaderProgram)
+ d->registerDestructionHelper(d->m_shaderProgram, &QShaderProgramBuilder::setShaderProgram, d->m_shaderProgram);
+
+ emit shaderProgramChanged(program);
+ }
+}
+
+QShaderProgram *QShaderProgramBuilder::shaderProgram() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_shaderProgram;
+}
+
+/*!
+ \qmlproperty stringlist ShaderProgramBuilder::enabledLayers
+
+ Holds the list of layers this builder will activate on the shader graphs
+ during code generation.
+*/
+/*!
+ \property QShaderProgramBuilder::enabledLayers
+
+ Holds the list of layers this builder will activate on the shader graphs
+ during code generation.
+*/
+void QShaderProgramBuilder::setEnabledLayers(const QStringList &layers)
+{
+ Q_D(QShaderProgramBuilder);
+ if (layers != d->m_enabledLayers) {
+ d->m_enabledLayers = layers;
+ emit enabledLayersChanged(layers);
+ }
+}
+
+QStringList QShaderProgramBuilder::enabledLayers() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_enabledLayers;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::vertexShaderGraph
+
+ Holds the URL to the vertex shader graph used by this shader program builder.
+*/
+/*!
+ \property QShaderProgramBuilder::vertexShaderGraph
+
+ Holds the URL to the vertex shader graph used by this shader program builder.
+*/
+void QShaderProgramBuilder::setVertexShaderGraph(const QUrl &vertexShaderGraph)
+{
+ Q_D(QShaderProgramBuilder);
+ if (vertexShaderGraph != d->m_vertexShaderGraph) {
+ d->m_vertexShaderGraph = vertexShaderGraph;
+ emit vertexShaderGraphChanged(vertexShaderGraph);
+ }
+}
+
+QUrl QShaderProgramBuilder::vertexShaderGraph() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_vertexShaderGraph;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::tessellationControlShaderGraph
+
+ Holds the URL to the tesselation control shader graph used by this shader program builder.
+*/
+/*!
+ \property QShaderProgramBuilder::tessellationControlShaderGraph
+
+ Holds the URL to the tesselation control shader graph used by this shader program builder.
+*/
+void QShaderProgramBuilder::setTessellationControlShaderGraph(const QUrl &tessellationControlShaderGraph)
+{
+ Q_D(QShaderProgramBuilder);
+ if (tessellationControlShaderGraph != d->m_tessControlShaderGraph) {
+ d->m_tessControlShaderGraph = tessellationControlShaderGraph;
+ emit tessellationControlShaderGraphChanged(tessellationControlShaderGraph);
+ }
+}
+
+QUrl QShaderProgramBuilder::tessellationControlShaderGraph() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_tessControlShaderGraph;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::tessellationEvaluationShaderGraph
+
+ Holds the URL to the tesselation evaluation shader graph used by this shader program builder.
+*/
+/*!
+ \property QShaderProgramBuilder::tessellationEvaluationShaderGraph
+
+ Holds the URL to the tesselation evaluation shader graph used by this shader program builder.
+*/
+void QShaderProgramBuilder::setTessellationEvaluationShaderGraph(const QUrl &tessellationEvaluationShaderGraph)
+{
+ Q_D(QShaderProgramBuilder);
+ if (tessellationEvaluationShaderGraph != d->m_tessEvalShaderGraph) {
+ d->m_tessEvalShaderGraph = tessellationEvaluationShaderGraph;
+ emit tessellationEvaluationShaderGraphChanged(tessellationEvaluationShaderGraph);
+ }
+}
+
+QUrl QShaderProgramBuilder::tessellationEvaluationShaderGraph() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_tessEvalShaderGraph;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::geometryShaderGraph
+
+ Holds the URL to the geometry shader graph used by this shader program builder.
+*/
+/*!
+ \property QShaderProgramBuilder::geometryShaderGraph
+
+ Holds the URL to the geometry shader graph used by this shader program builder.
+*/
+void QShaderProgramBuilder::setGeometryShaderGraph(const QUrl &geometryShaderGraph)
+{
+ Q_D(QShaderProgramBuilder);
+ if (geometryShaderGraph != d->m_geometryShaderGraph) {
+ d->m_geometryShaderGraph = geometryShaderGraph;
+ emit geometryShaderGraphChanged(geometryShaderGraph);
+ }
+}
+
+QUrl QShaderProgramBuilder::geometryShaderGraph() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_geometryShaderGraph;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::fragmentShaderGraph
+
+ Holds the URL to the fragment shader graph used by this shader program builder.
+*/
+/*!
+ \property QShaderProgramBuilder::fragmentShaderGraph
+
+ Holds the URL to the fragment shader graph used by this shader program builder.
+*/
+void QShaderProgramBuilder::setFragmentShaderGraph(const QUrl &fragmentShaderGraph)
+{
+ Q_D(QShaderProgramBuilder);
+ if (fragmentShaderGraph != d->m_fragmentShaderGraph) {
+ d->m_fragmentShaderGraph = fragmentShaderGraph;
+ emit fragmentShaderGraphChanged(fragmentShaderGraph);
+ }
+}
+
+QUrl QShaderProgramBuilder::fragmentShaderGraph() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_fragmentShaderGraph;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::computeShaderGraph
+
+ Holds the URL to the compute shader graph used by this shader program builder.
+*/
+/*!
+ \property QShaderProgramBuilder::computeShaderGraph
+
+ Holds the URL to the compute shader graph used by this shader program builder.
+*/
+void QShaderProgramBuilder::setComputeShaderGraph(const QUrl &computeShaderGraph)
+{
+ Q_D(QShaderProgramBuilder);
+ if (computeShaderGraph != d->m_computeShaderGraph) {
+ d->m_computeShaderGraph = computeShaderGraph;
+ emit computeShaderGraphChanged(computeShaderGraph);
+ }
+}
+
+QUrl QShaderProgramBuilder::computeShaderGraph() const
+{
+ Q_D(const QShaderProgramBuilder);
+ return d->m_computeShaderGraph;
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QShaderProgramBuilder::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QShaderProgramBuilderData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QShaderProgramBuilder);
+ data.shaderProgramId = d->m_shaderProgram ? d->m_shaderProgram->id() : Qt3DCore::QNodeId();
+ data.enabledLayers = d->m_enabledLayers;
+ data.vertexShaderGraph = d->m_vertexShaderGraph;
+ data.tessellationControlShaderGraph = d->m_tessControlShaderGraph;
+ data.tessellationEvaluationShaderGraph = d->m_tessEvalShaderGraph;
+ data.geometryShaderGraph = d->m_geometryShaderGraph;
+ data.fragmentShaderGraph = d->m_fragmentShaderGraph;
+ data.computeShaderGraph = d->m_computeShaderGraph;
+ return creationChange;
+}
+
+} // of namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/materialsystem/qshaderprogrambuilder.h b/src/render/materialsystem/qshaderprogrambuilder.h
new file mode 100644
index 000000000..d8903232a
--- /dev/null
+++ b/src/render/materialsystem/qshaderprogrambuilder.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QSHADERPROGRAMBUILDER_H
+#define QT3DRENDER_QSHADERPROGRAMBUILDER_H
+
+#include <Qt3DCore/qnode.h>
+#include <Qt3DRender/qt3drender_global.h>
+
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QShaderProgram;
+class QShaderProgramBuilderPrivate;
+
+class QT3DRENDERSHARED_EXPORT QShaderProgramBuilder : public Qt3DCore::QNode
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QShaderProgram* shaderProgram READ shaderProgram WRITE setShaderProgram NOTIFY shaderProgramChanged)
+ Q_PROPERTY(QStringList enabledLayers READ enabledLayers WRITE setEnabledLayers NOTIFY enabledLayersChanged)
+ Q_PROPERTY(QUrl vertexShaderGraph READ vertexShaderGraph WRITE setVertexShaderGraph NOTIFY vertexShaderGraphChanged)
+ Q_PROPERTY(QUrl tessellationControlShaderGraph READ tessellationControlShaderGraph WRITE setTessellationControlShaderGraph NOTIFY tessellationControlShaderGraphChanged)
+ Q_PROPERTY(QUrl tessellationEvaluationShaderGraph READ tessellationEvaluationShaderGraph WRITE setTessellationEvaluationShaderGraph NOTIFY tessellationEvaluationShaderGraphChanged)
+ Q_PROPERTY(QUrl geometryShaderGraph READ geometryShaderGraph WRITE setGeometryShaderGraph NOTIFY geometryShaderGraphChanged)
+ Q_PROPERTY(QUrl fragmentShaderGraph READ fragmentShaderGraph WRITE setFragmentShaderGraph NOTIFY fragmentShaderGraphChanged)
+ Q_PROPERTY(QUrl computeShaderGraph READ computeShaderGraph WRITE setComputeShaderGraph NOTIFY computeShaderGraphChanged)
+
+public:
+ explicit QShaderProgramBuilder(Qt3DCore::QNode *parent = nullptr);
+ ~QShaderProgramBuilder();
+
+ QShaderProgram *shaderProgram() const;
+ QStringList enabledLayers() const;
+ QUrl vertexShaderGraph() const;
+ QUrl tessellationControlShaderGraph() const;
+ QUrl tessellationEvaluationShaderGraph() const;
+ QUrl geometryShaderGraph() const;
+ QUrl fragmentShaderGraph() const;
+ QUrl computeShaderGraph() const;
+
+public Q_SLOTS:
+ void setShaderProgram(Qt3DRender::QShaderProgram *program);
+ void setEnabledLayers(const QStringList &layers);
+ void setVertexShaderGraph(const QUrl &vertexShaderGraph);
+ void setTessellationControlShaderGraph(const QUrl &tessellationControlShaderGraph);
+ void setTessellationEvaluationShaderGraph(const QUrl &tessellationEvaluationShaderGraph);
+ void setGeometryShaderGraph(const QUrl &geometryShaderGraph);
+ void setFragmentShaderGraph(const QUrl &fragmentShaderGraph);
+ void setComputeShaderGraph(const QUrl &computeShaderGraph);
+
+Q_SIGNALS:
+ void shaderProgramChanged(Qt3DRender::QShaderProgram *shaderProgram);
+ void enabledLayersChanged(const QStringList &layers);
+ void vertexShaderGraphChanged(const QUrl &vertexShaderGraph);
+ void tessellationControlShaderGraphChanged(const QUrl &tessellationControlShaderGraph);
+ void tessellationEvaluationShaderGraphChanged(const QUrl &tessellationEvaluationShaderGraph);
+ void geometryShaderGraphChanged(const QUrl &geometryShaderGraph);
+ void fragmentShaderGraphChanged(const QUrl &fragmentShaderGraph);
+ void computeShaderGraphChanged(const QUrl &computeShaderGraph);
+
+protected:
+ explicit QShaderProgramBuilder(QShaderProgramBuilderPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QShaderProgramBuilder)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSHADERPROGRAMBUILDER_H
diff --git a/src/render/materialsystem/qshaderprogrambuilder_p.h b/src/render/materialsystem/qshaderprogrambuilder_p.h
new file mode 100644
index 000000000..e1b470229
--- /dev/null
+++ b/src/render/materialsystem/qshaderprogrambuilder_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QSHADERPROGRAMBUILDER_P_H
+#define QT3DRENDER_QSHADERPROGRAMBUILDER_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 <private/qnode_p.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
+
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QShaderProgramBuilderPrivate : public Qt3DCore::QNodePrivate
+{
+public:
+ QShaderProgramBuilderPrivate();
+
+ Q_DECLARE_PUBLIC(QShaderProgramBuilder)
+ QShaderProgram *m_shaderProgram;
+ QStringList m_enabledLayers;
+ QUrl m_vertexShaderGraph;
+ QUrl m_tessControlShaderGraph;
+ QUrl m_tessEvalShaderGraph;
+ QUrl m_geometryShaderGraph;
+ QUrl m_fragmentShaderGraph;
+ QUrl m_computeShaderGraph;
+};
+
+struct QShaderProgramBuilderData
+{
+ Qt3DCore::QNodeId shaderProgramId;
+ QStringList enabledLayers;
+ QUrl vertexShaderGraph;
+ QUrl tessellationControlShaderGraph;
+ QUrl tessellationEvaluationShaderGraph;
+ QUrl geometryShaderGraph;
+ QUrl fragmentShaderGraph;
+ QUrl computeShaderGraph;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QSHADERPROGRAMBUILDER_P_H
diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp
index 915ca1d54..d42b0dda7 100644
--- a/src/render/materialsystem/shader.cpp
+++ b/src/render/materialsystem/shader.cpp
@@ -117,6 +117,7 @@ void Shader::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang
m_shaderCode[QShaderProgram::Compute] = data.computeShaderCode;
m_isLoaded = false;
updateDNA();
+ markDirty(AbstractRenderer::ShadersDirty);
}
void Shader::setGraphicsContext(GraphicsContext *context)
@@ -161,36 +162,36 @@ QVector<QByteArray> Shader::shaderCode() const
return m_shaderCode;
}
+void Shader::setShaderCode(QShaderProgram::ShaderType type, const QByteArray &code)
+{
+ if (code == m_shaderCode[type])
+ return;
+
+ m_shaderCode[type] = code;
+ m_isLoaded = false;
+ setStatus(QShaderProgram::NotReady);
+ updateDNA();
+ markDirty(AbstractRenderer::ShadersDirty);
+}
+
void Shader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == PropertyUpdated) {
QPropertyUpdatedChangePtr propertyChange = e.staticCast<QPropertyUpdatedChange>();
QVariant propertyValue = propertyChange->value();
- if (propertyChange->propertyName() == QByteArrayLiteral("vertexShaderCode")) {
- m_shaderCode[QShaderProgram::Vertex] = propertyValue.toByteArray();
- m_isLoaded = false;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("fragmentShaderCode")) {
- m_shaderCode[QShaderProgram::Fragment] = propertyValue.toByteArray();
- m_isLoaded = false;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationControlShaderCode")) {
- m_shaderCode[QShaderProgram::TessellationControl] = propertyValue.toByteArray();
- m_isLoaded = false;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationEvaluationShaderCode")) {
- m_shaderCode[QShaderProgram::TessellationEvaluation] = propertyValue.toByteArray();
- m_isLoaded = false;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("geometryShaderCode")) {
- m_shaderCode[QShaderProgram::Geometry] = propertyValue.toByteArray();
- m_isLoaded = false;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("computeShaderCode")) {
- m_shaderCode[QShaderProgram::Compute] = propertyValue.toByteArray();
- m_isLoaded = false;
- }
- if (!m_isLoaded) {
- setStatus(QShaderProgram::NotReady);
- updateDNA();
- }
- markDirty(AbstractRenderer::AllDirty);
+ if (propertyChange->propertyName() == QByteArrayLiteral("vertexShaderCode"))
+ setShaderCode(QShaderProgram::Vertex, propertyValue.toByteArray());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("fragmentShaderCode"))
+ setShaderCode(QShaderProgram::Fragment, propertyValue.toByteArray());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationControlShaderCode"))
+ setShaderCode(QShaderProgram::TessellationControl, propertyValue.toByteArray());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationEvaluationShaderCode"))
+ setShaderCode(QShaderProgram::TessellationEvaluation, propertyValue.toByteArray());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("geometryShaderCode"))
+ setShaderCode(QShaderProgram::Geometry, propertyValue.toByteArray());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("computeShaderCode"))
+ setShaderCode(QShaderProgram::Compute, propertyValue.toByteArray());
}
BackendNode::sceneChangeEvent(e);
diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h
index b5127f5ec..a5fdc7cd9 100644
--- a/src/render/materialsystem/shader_p.h
+++ b/src/render/materialsystem/shader_p.h
@@ -97,6 +97,7 @@ public:
QVector<QString> uniformBlockNames() const;
QVector<QString> storageBlockNames() const;
QVector<QByteArray> shaderCode() const;
+ void setShaderCode(QShaderProgram::ShaderType type, const QByteArray &code);
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
bool isLoaded() const { QMutexLocker lock(&m_mutex); return m_isLoaded; }
diff --git a/src/render/materialsystem/shaderbuilder.cpp b/src/render/materialsystem/shaderbuilder.cpp
new file mode 100644
index 000000000..da1e6a713
--- /dev/null
+++ b/src/render/materialsystem/shaderbuilder.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "shaderbuilder_p.h"
+
+#include <Qt3DRender/private/qshaderprogrambuilder_p.h>
+#include <Qt3DRender/private/qurlhelper_p.h>
+
+#include <QtGui/private/qshaderformat_p.h>
+#include <QtGui/private/qshadergraphloader_p.h>
+#include <QtGui/private/qshadergenerator_p.h>
+#include <QtGui/private/qshadernodesloader_p.h>
+
+#include <QFile>
+#include <QFileInfo>
+#include <QUrl>
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(materialsystem);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class GlobalShaderPrototypes
+{
+public:
+ GlobalShaderPrototypes()
+ {
+ initResources();
+ setPrototypesFile(QStringLiteral(":/prototypes/default.json"));
+ }
+
+ QString prototypesFile() const
+ {
+ return m_fileName;
+ }
+
+ void setPrototypesFile(const QString &fileName)
+ {
+ m_fileName = fileName;
+ load();
+ }
+
+ QHash<QString, QShaderNode> prototypes() const
+ {
+ return m_prototypes;
+ }
+
+private:
+ void load()
+ {
+ QFile file(m_fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Couldn't open file:" << m_fileName;
+ return;
+ }
+
+ QShaderNodesLoader loader;
+ loader.setDevice(&file);
+ loader.load();
+ m_prototypes = loader.nodes();
+ }
+
+ QString m_fileName;
+ QHash<QString, QShaderNode> m_prototypes;
+};
+
+Q_GLOBAL_STATIC(GlobalShaderPrototypes, qt3dGlobalShaderPrototypes)
+
+using namespace Qt3DCore;
+
+namespace Qt3DRender {
+namespace Render {
+
+QString ShaderBuilder::getPrototypesFile()
+{
+ return qt3dGlobalShaderPrototypes->prototypesFile();
+}
+
+void ShaderBuilder::setPrototypesFile(const QString &file)
+{
+ qt3dGlobalShaderPrototypes->setPrototypesFile(file);
+}
+
+QStringList ShaderBuilder::getPrototypeNames()
+{
+ return qt3dGlobalShaderPrototypes->prototypes().keys();
+}
+
+ShaderBuilder::ShaderBuilder()
+ : BackendNode(ReadWrite)
+{
+}
+
+ShaderBuilder::~ShaderBuilder()
+{
+}
+
+void ShaderBuilder::cleanup()
+{
+ m_shaderProgramId = Qt3DCore::QNodeId();
+ m_enabledLayers.clear();
+ m_graphs.clear();
+ m_dirtyTypes.clear();
+ QBackendNode::setEnabled(false);
+}
+
+Qt3DCore::QNodeId ShaderBuilder::shaderProgramId() const
+{
+ return m_shaderProgramId;
+}
+
+QStringList ShaderBuilder::enabledLayers() const
+{
+ return m_enabledLayers;
+}
+
+
+void ShaderBuilder::setEnabledLayers(const QStringList &layers)
+{
+ if (m_enabledLayers == layers)
+ return;
+
+ m_enabledLayers = layers;
+
+ for (const auto type : m_graphs.keys()) {
+ if (!m_graphs.value(type).isEmpty())
+ m_dirtyTypes.insert(type);
+ }
+}
+
+GraphicsApiFilterData ShaderBuilder::graphicsApi() const
+{
+ return m_graphicsApi;
+}
+
+void ShaderBuilder::setGraphicsApi(const GraphicsApiFilterData &graphicsApi)
+{
+ if (m_graphicsApi == graphicsApi)
+ return;
+
+ m_graphicsApi = graphicsApi;
+ for (const auto type : m_graphs.keys()) {
+ if (!m_graphs.value(type).isEmpty())
+ m_dirtyTypes.insert(type);
+ }
+}
+
+QUrl ShaderBuilder::shaderGraph(ShaderBuilder::ShaderType type) const
+{
+ return m_graphs.value(type);
+}
+
+void ShaderBuilder::setShaderGraph(ShaderBuilder::ShaderType type, const QUrl &url)
+{
+ if (url != m_graphs.value(type)) {
+ m_graphs.insert(type, url);
+ m_dirtyTypes.insert(type);
+ }
+}
+
+QByteArray ShaderBuilder::shaderCode(ShaderBuilder::ShaderType type) const
+{
+ return m_codes.value(type);
+}
+
+bool ShaderBuilder::isShaderCodeDirty(ShaderBuilder::ShaderType type) const
+{
+ return m_dirtyTypes.contains(type);
+}
+
+static QByteArray deincludify(const QByteArray &contents, const QString &filePath);
+
+static QByteArray deincludify(const QString &filePath)
+{
+ QFile f(filePath);
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning() << "Could not read shader source file:" << f.fileName();
+ return QByteArray();
+ }
+
+ QByteArray contents = f.readAll();
+ return deincludify(contents, filePath);
+}
+
+static QByteArray deincludify(const QByteArray &contents, const QString &filePath)
+{
+ QByteArrayList lines = contents.split('\n');
+ const QByteArray includeDirective = QByteArrayLiteral("#pragma include");
+ for (int i = 0; i < lines.count(); ++i) {
+ const auto line = lines[i].simplified();
+ if (line.startsWith(includeDirective)) {
+ const QString includePartialPath = QString::fromUtf8(line.mid(includeDirective.count() + 1));
+
+ QString includePath = QFileInfo(includePartialPath).isAbsolute() ? includePartialPath
+ : QFileInfo(filePath).absolutePath() + QLatin1Char('/') + includePartialPath;
+ if (qEnvironmentVariableIsSet("QT3D_GLSL100_WORKAROUND")) {
+ QString candidate = includePath + QLatin1String("100");
+ if (QFile::exists(candidate))
+ includePath = candidate;
+ }
+ lines.removeAt(i);
+ QByteArray includedContents = deincludify(includePath);
+ lines.insert(i, includedContents);
+ QString lineDirective = QString(QStringLiteral("#line %1")).arg(i + 2);
+ lines.insert(i + 1, lineDirective.toUtf8());
+ }
+ }
+
+ return lines.join('\n');
+}
+
+void ShaderBuilder::generateCode(ShaderBuilder::ShaderType type)
+{
+ const auto graphPath = QUrlHelper::urlToLocalFileOrQrc(shaderGraph(type));
+ QFile file(graphPath);
+ if (!file.open(QFile::ReadOnly)) {
+ qWarning() << "Couldn't open file:" << graphPath;
+ return;
+ }
+
+ auto graphLoader = QShaderGraphLoader();
+ graphLoader.setPrototypes(qt3dGlobalShaderPrototypes->prototypes());
+ graphLoader.setDevice(&file);
+ graphLoader.load();
+
+ if (graphLoader.status() == QShaderGraphLoader::Error)
+ return;
+
+ const auto graph = graphLoader.graph();
+
+ auto format = QShaderFormat();
+ format.setApi(m_graphicsApi.m_api == QGraphicsApiFilter::OpenGLES ? QShaderFormat::OpenGLES
+ : m_graphicsApi.m_profile == QGraphicsApiFilter::CoreProfile ? QShaderFormat::OpenGLCoreProfile
+ : m_graphicsApi.m_profile == QGraphicsApiFilter::CompatibilityProfile ? QShaderFormat::OpenGLCompatibilityProfile
+ : QShaderFormat::OpenGLNoProfile);
+ format.setVersion(QVersionNumber(m_graphicsApi.m_major, m_graphicsApi.m_minor));
+ format.setExtensions(m_graphicsApi.m_extensions);
+ format.setVendor(m_graphicsApi.m_vendor);
+
+ auto generator = QShaderGenerator();
+ generator.format = format;
+ generator.graph = graph;
+
+ const auto code = generator.createShaderCode(m_enabledLayers);
+ m_codes.insert(type, deincludify(code, graphPath + QStringLiteral(".glsl")));
+ m_dirtyTypes.remove(type);
+}
+
+void ShaderBuilder::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
+{
+ if (e->type() == PropertyUpdated) {
+ QPropertyUpdatedChangePtr propertyChange = e.staticCast<QPropertyUpdatedChange>();
+ QVariant propertyValue = propertyChange->value();
+
+ if (propertyChange->propertyName() == QByteArrayLiteral("shaderProgram"))
+ m_shaderProgramId = propertyValue.value<Qt3DCore::QNodeId>();
+ else if (propertyChange->propertyName() == QByteArrayLiteral("enabledLayers"))
+ setEnabledLayers(propertyValue.toStringList());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("vertexShaderGraph"))
+ setShaderGraph(Vertex, propertyValue.toUrl());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationControlShaderGraph"))
+ setShaderGraph(TessellationControl, propertyValue.toUrl());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("tessellationEvaluationShaderGraph"))
+ setShaderGraph(TessellationEvaluation, propertyValue.toUrl());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("geometryShaderGraph"))
+ setShaderGraph(Geometry, propertyValue.toUrl());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("fragmentShaderGraph"))
+ setShaderGraph(Fragment, propertyValue.toUrl());
+ else if (propertyChange->propertyName() == QByteArrayLiteral("computeShaderGraph"))
+ setShaderGraph(Compute, propertyValue.toUrl());
+
+ markDirty(AbstractRenderer::ShadersDirty);
+ }
+ BackendNode::sceneChangeEvent(e);
+}
+
+void ShaderBuilder::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
+{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QShaderProgramBuilderData>>(change);
+ const auto &data = typedChange->data;
+
+ m_shaderProgramId = data.shaderProgramId;
+ m_enabledLayers = data.enabledLayers;
+ setShaderGraph(Vertex, data.vertexShaderGraph);
+ setShaderGraph(TessellationControl, data.tessellationControlShaderGraph);
+ setShaderGraph(TessellationEvaluation, data.tessellationEvaluationShaderGraph);
+ setShaderGraph(Geometry, data.geometryShaderGraph);
+ setShaderGraph(Fragment, data.fragmentShaderGraph);
+ setShaderGraph(Compute, data.computeShaderGraph);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/materialsystem/shaderbuilder_p.h b/src/render/materialsystem/shaderbuilder_p.h
new file mode 100644
index 000000000..9fff5df97
--- /dev/null
+++ b/src/render/materialsystem/shaderbuilder_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_SHADERBUILDER_H
+#define QT3DRENDER_RENDER_SHADERBUILDER_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/backendnode_p.h>
+#include <Qt3DRender/private/qgraphicsapifilter_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Q_AUTOTEST_EXPORT ShaderBuilder : public BackendNode
+{
+public:
+ enum ShaderType {
+ Vertex = 0,
+ TessellationControl,
+ TessellationEvaluation,
+ Geometry,
+ Fragment,
+ Compute
+ };
+
+ static QString getPrototypesFile();
+ static void setPrototypesFile(const QString &file);
+ static QStringList getPrototypeNames();
+
+ ShaderBuilder();
+ ~ShaderBuilder();
+ void cleanup();
+
+ Qt3DCore::QNodeId shaderProgramId() const;
+ QStringList enabledLayers() const;
+
+ GraphicsApiFilterData graphicsApi() const;
+ void setGraphicsApi(const GraphicsApiFilterData &graphicsApi);
+
+ QUrl shaderGraph(ShaderType type) const;
+ void setShaderGraph(ShaderType type, const QUrl &url);
+
+ QByteArray shaderCode(ShaderType type) const;
+ bool isShaderCodeDirty(ShaderType type) const;
+
+ void generateCode(ShaderType type);
+
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
+
+private:
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ void setEnabledLayers(const QStringList &layers);
+
+ GraphicsApiFilterData m_graphicsApi;
+ Qt3DCore::QNodeId m_shaderProgramId;
+ QStringList m_enabledLayers;
+ QHash<ShaderType, QUrl> m_graphs;
+ QHash<ShaderType, QByteArray> m_codes;
+ QSet<ShaderType> m_dirtyTypes;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_SHADERBUILDER_H
diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri
index c4c188a82..23d65c6f2 100644
--- a/src/render/picking/picking.pri
+++ b/src/render/picking/picking.pri
@@ -4,6 +4,8 @@ HEADERS += \
$$PWD/qobjectpicker.h \
$$PWD/qpickevent.h \
$$PWD/qpickevent_p.h \
+ $$PWD/qpicklineevent.h \
+ $$PWD/qpickpointevent.h \
$$PWD/qpicktriangleevent.h \
$$PWD/objectpicker_p.h \
$$PWD/pickeventfilter_p.h \
@@ -12,6 +14,8 @@ HEADERS += \
SOURCES += \
$$PWD/qobjectpicker.cpp \
$$PWD/qpickevent.cpp \
+ $$PWD/qpicklineevent.cpp \
+ $$PWD/qpickpointevent.cpp \
$$PWD/qpicktriangleevent.cpp \
$$PWD/objectpicker.cpp \
$$PWD/pickeventfilter.cpp
diff --git a/src/render/picking/qpicklineevent.cpp b/src/render/picking/qpicklineevent.cpp
new file mode 100644
index 000000000..5b9ef0d76
--- /dev/null
+++ b/src/render/picking/qpicklineevent.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qpicklineevent.h"
+#include "qpickevent_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QPickLineEventPrivate : public QPickEventPrivate
+{
+public:
+ QPickLineEventPrivate()
+ : QPickEventPrivate()
+ , m_edgeIndex(0)
+ , m_vertex1Index(0)
+ , m_vertex2Index(0)
+ {
+ }
+
+ uint m_edgeIndex;
+ uint m_vertex1Index;
+ uint m_vertex2Index;
+};
+
+/*!
+ \class Qt3DRender::QPickLineEvent
+ \inmodule Qt3DRender
+
+ \brief The QPickLineEvent class holds information when a segment of a line is picked
+
+ \sa QPickEvent
+ \since 5.10
+*/
+
+/*!
+ * \qmltype PickLineEvent
+ * \instantiates Qt3DRender::QPickLineEvent
+ * \inqmlmodule Qt3D.Render
+ * \brief PickLineEvent holds information when a segment of a line is picked.
+ * \sa ObjectPicker
+ */
+
+
+/*!
+ \fn Qt3DRender::QPickLineEvent::QPickLineEvent()
+ Constructs a new QPickEvent.
+ */
+QPickLineEvent::QPickLineEvent()
+ : QPickEvent(*new QPickLineEventPrivate())
+{
+}
+
+QPickLineEvent::QPickLineEvent(const QPointF &position, const QVector3D &worldIntersection,
+ const QVector3D &localIntersection, float distance,
+ uint edgeIndex, uint vertex1Index, uint vertex2Index,
+ QPickEvent::Buttons button, int buttons, int modifiers)
+ : QPickEvent(*new QPickLineEventPrivate())
+{
+ Q_D(QPickLineEvent);
+ d->m_position = position;
+ d->m_distance = distance;
+ d->m_worldIntersection = worldIntersection;
+ d->m_localIntersection = localIntersection;
+ d->m_edgeIndex = edgeIndex;
+ d->m_vertex1Index = vertex1Index;
+ d->m_vertex2Index = vertex2Index;
+ d->m_button = button;
+ d->m_buttons = buttons;
+ d->m_modifiers = modifiers;
+}
+
+/*! \internal */
+QPickLineEvent::~QPickLineEvent()
+{
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickLineEvent::triangleIndex
+ Specifies the triangle index of the event
+*/
+/*!
+ \property Qt3DRender::QPickLineEvent::edgeIndex
+ Specifies the index of the edge that was picked
+ */
+/*!
+ * \brief QPickLineEvent::edgeIndex
+ * Returns the index of the picked edge
+ */
+uint QPickLineEvent::edgeIndex() const
+{
+ Q_D(const QPickLineEvent);
+ return d->m_edgeIndex;
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickLineEvent::vertex1Index
+ Specifies the index of the first point of the picked edge
+*/
+/*!
+ \property Qt3DRender::QPickLineEvent::vertex1Index
+ Specifies the index of the first point of the picked edge
+ */
+/*!
+ * \brief QPickLineEvent::vertex1Index
+ * Returns the index of the first point of the picked edge
+ */
+uint QPickLineEvent::vertex1Index() const
+{
+ Q_D(const QPickLineEvent);
+ return d->m_vertex1Index;
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickLineEvent::vertex2Index
+ Specifies the index of the second point of the picked edge
+*/
+/*!
+ \property Qt3DRender::QPickLineEvent::vertex2Index
+ Specifies the index of the second point of the picked edge
+ */
+/*!
+ * \brief QPickLineEvent::vertex2Index
+ * Returns the index of the second point of the picked triangle
+ */
+uint QPickLineEvent::vertex2Index() const
+{
+ Q_D(const QPickLineEvent);
+ return d->m_vertex2Index;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
diff --git a/src/render/picking/qpicklineevent.h b/src/render/picking/qpicklineevent.h
new file mode 100644
index 000000000..09697ad22
--- /dev/null
+++ b/src/render/picking/qpicklineevent.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 QT3DRENDER_QPICKLINEEVENT_H
+#define QT3DRENDER_QPICKLINEEVENT_H
+
+#include <Qt3DRender/qpickevent.h>
+#include <QtCore/qsharedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+class QPickLineEventPrivate;
+
+class QT3DRENDERSHARED_EXPORT QPickLineEvent : public QPickEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(uint edgeIndex READ edgeIndex CONSTANT)
+ Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT)
+ Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT)
+public:
+ QPickLineEvent();
+ QPickLineEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance,
+ uint edgeIndex, uint vertex1Index, uint vertex2Index, Buttons button, int buttons, int modifiers);
+ ~QPickLineEvent();
+
+public:
+ uint edgeIndex() const;
+ uint vertex1Index() const;
+ uint vertex2Index() const;
+
+private:
+ Q_DECLARE_PRIVATE(QPickLineEvent)
+};
+
+typedef QSharedPointer<QPickLineEvent> QPickLineEventPtr;
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QPICKLINEEVENT_H
diff --git a/src/render/picking/qpickpointevent.cpp b/src/render/picking/qpickpointevent.cpp
new file mode 100644
index 000000000..295860e75
--- /dev/null
+++ b/src/render/picking/qpickpointevent.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qpickpointevent.h"
+#include "qpickevent_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QPickPointEventPrivate : public QPickEventPrivate
+{
+public:
+ QPickPointEventPrivate()
+ : QPickEventPrivate()
+ , m_pointIndex(0)
+ {
+ }
+
+ uint m_pointIndex;
+};
+
+/*!
+ \class Qt3DRender::QPickPointEvent
+ \inmodule Qt3DRender
+
+ \brief The QPickPointEvent class holds information when a segment of a point cloud is picked
+
+ \sa QPickEvent
+ \since 5.10
+*/
+
+/*!
+ * \qmltype PickPointEvent
+ * \instantiates Qt3DRender::QPickPointEvent
+ * \inqmlmodule Qt3D.Render
+ * \brief PickPointEvent holds information when a segment of a point cloud is picked.
+ * \sa ObjectPicker
+ */
+
+
+/*!
+ \fn Qt3DRender::QPickPointEvent::QPickPointEvent()
+ Constructs a new QPickPointEvent.
+ */
+QPickPointEvent::QPickPointEvent()
+ : QPickEvent(*new QPickPointEventPrivate())
+{
+}
+
+QPickPointEvent::QPickPointEvent(const QPointF &position, const QVector3D &worldIntersection,
+ const QVector3D &localIntersection, float distance,
+ uint pointIndex,
+ QPickEvent::Buttons button, int buttons, int modifiers)
+ : QPickEvent(*new QPickPointEventPrivate())
+{
+ Q_D(QPickPointEvent);
+ d->m_position = position;
+ d->m_distance = distance;
+ d->m_worldIntersection = worldIntersection;
+ d->m_localIntersection = localIntersection;
+ d->m_pointIndex = pointIndex;
+ d->m_button = button;
+ d->m_buttons = buttons;
+ d->m_modifiers = modifiers;
+}
+
+/*! \internal */
+QPickPointEvent::~QPickPointEvent()
+{
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickPointEvent::pointIndex
+ Specifies the index of the point that was picked
+*/
+/*!
+ \property Qt3DRender::QPickPointEvent::pointIndex
+ Specifies the index of the point that was picked
+ */
+/*!
+ * \brief QPickPointEvent::pointIndex
+ * Returns the index of the picked point
+ */
+uint QPickPointEvent::pointIndex() const
+{
+ Q_D(const QPickPointEvent);
+ return d->m_pointIndex;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
diff --git a/src/render/picking/qpickpointevent.h b/src/render/picking/qpickpointevent.h
new file mode 100644
index 000000000..f298f64b9
--- /dev/null
+++ b/src/render/picking/qpickpointevent.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 QT3DRENDER_QPICKPOINTEVENT_H
+#define QT3DRENDER_QPICKPOINTEVENT_H
+
+#include <Qt3DRender/qpickevent.h>
+#include <QtCore/qsharedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+class QPickPointEventPrivate;
+
+class QT3DRENDERSHARED_EXPORT QPickPointEvent : public QPickEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(uint pointIndex READ pointIndex CONSTANT)
+public:
+ QPickPointEvent();
+ QPickPointEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance,
+ uint pointIndex, Buttons button, int buttons, int modifiers);
+ ~QPickPointEvent();
+
+public:
+ uint pointIndex() const;
+
+private:
+ Q_DECLARE_PRIVATE(QPickPointEvent)
+};
+
+typedef QSharedPointer<QPickPointEvent> QPickPointEventPtr;
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QPICKPOINTEVENT_H
diff --git a/src/render/picking/qpicktriangleevent.h b/src/render/picking/qpicktriangleevent.h
index 7655a0b94..f116af288 100644
--- a/src/render/picking/qpicktriangleevent.h
+++ b/src/render/picking/qpicktriangleevent.h
@@ -41,6 +41,7 @@
#define QT3DRENDER_QPICKTRIANGLEEVENT_H
#include <Qt3DRender/qpickevent.h>
+#include <QtCore/qsharedpointer.h>
QT_BEGIN_NAMESPACE
@@ -75,6 +76,8 @@ private:
Q_DECLARE_PRIVATE(QPickTriangleEvent)
};
+typedef QSharedPointer<QPickTriangleEvent> QPickTriangleEventPtr;
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h
index e13dda74a..1a430e019 100644
--- a/src/render/raycasting/qcollisionqueryresult_p.h
+++ b/src/render/raycasting/qcollisionqueryresult_p.h
@@ -69,9 +69,17 @@ class QT3DRENDERSHARED_EXPORT QCollisionQueryResult
{
public:
struct Hit {
+ enum HitType {
+ Entity,
+ Point,
+ Edge,
+ Triangle
+ };
+
Hit()
- : m_distance(-1.f)
- , m_triangleIndex(0)
+ : m_type(Entity)
+ , m_distance(-1.f)
+ , m_primitiveIndex(0)
{
m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0;
}
@@ -85,9 +93,10 @@ public:
}
Qt3DCore::QNodeId m_entityId;
+ HitType m_type;
QVector3D m_intersection;
float m_distance;
- uint m_triangleIndex;
+ uint m_primitiveIndex;
uint m_vertexIndex[3];
QVector3D m_uvw;
};
diff --git a/src/render/renderstates/qlinewidth.cpp b/src/render/renderstates/qlinewidth.cpp
new file mode 100644
index 000000000..f5ef04ebb
--- /dev/null
+++ b/src/render/renderstates/qlinewidth.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 "qlinewidth.h"
+#include "qlinewidth_p.h"
+
+#include <Qt3DRender/private/qrenderstatecreatedchange_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+/*!
+ \class Qt3DRender::QLineWidth
+ \inmodule Qt3DRender
+ \since 5.10
+ \brief Specifies the width of rasterized lines.
+ */
+
+/*!
+ \qmltype LineWidth
+ \since 5.10
+ \inherits RenderState
+ \instantiates Qt3DRender::QLineWidth
+ \inqmlmodule Qt3D.Render
+
+ \brief Specifies the width of rasterized lines.
+ */
+
+/*!
+ \qmlproperty real LineWidth::value
+ Specifies the width value to be used.
+*/
+
+/*!
+ \property QLineWidth::value
+ Specifies the width value to be used.
+*/
+
+QLineWidth::QLineWidth(Qt3DCore::QNode *parent)
+ : QRenderState(*new QLineWidthPrivate(1.0f), parent)
+{
+}
+
+QLineWidth::~QLineWidth()
+{
+}
+
+float QLineWidth::value() const
+{
+ Q_D(const QLineWidth);
+ return d->m_value;
+}
+
+void QLineWidth::setValue(float width)
+{
+ Q_D(QLineWidth);
+ d->m_value = width;
+ emit valueChanged(width);
+}
+
+bool QLineWidth::smooth() const
+{
+ Q_D(const QLineWidth);
+ return d->m_smooth;
+}
+
+void QLineWidth::setSmooth(bool enabled)
+{
+ Q_D(QLineWidth);
+ if (d->m_smooth != enabled) {
+ d->m_smooth = enabled;
+ emit smoothChanged(enabled);
+ }
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QLineWidth::createNodeCreationChange() const
+{
+ auto creationChange = QRenderStateCreatedChangePtr<QLineWidthData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QLineWidth);
+ data.value = d->m_value;
+ data.smooth = d->m_smooth;
+ return creationChange;
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/renderstates/qlinewidth.h b/src/render/renderstates/qlinewidth.h
new file mode 100644
index 000000000..08b395982
--- /dev/null
+++ b/src/render/renderstates/qlinewidth.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_QLINEWIDTH_H
+#define QT3DRENDER_QLINEWIDTH_H
+
+#include <Qt3DRender/qrenderstate.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QLineWidthPrivate;
+
+class QT3DRENDERSHARED_EXPORT QLineWidth : public QRenderState
+{
+ Q_OBJECT
+ Q_PROPERTY(float value READ value WRITE setValue NOTIFY valueChanged)
+ Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged)
+
+public:
+ explicit QLineWidth(Qt3DCore::QNode *parent = nullptr);
+ ~QLineWidth();
+
+ float value() const;
+ bool smooth() const;
+
+public Q_SLOTS:
+ void setValue(float value);
+ void setSmooth(bool enabled);
+
+Q_SIGNALS:
+ void valueChanged(float value);
+ void smoothChanged(bool enabled);
+
+private:
+ Q_DECLARE_PRIVATE(QLineWidth)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QTRENDER_QLINEWIDTH_H
diff --git a/src/render/renderstates/qlinewidth_p.h b/src/render/renderstates/qlinewidth_p.h
new file mode 100644
index 000000000..bffa9ac1e
--- /dev/null
+++ b/src/render/renderstates/qlinewidth_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QLINEWIDTH_P_H
+#define QT3DRENDER_QLINEWIDTH_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 <Qt3DRender/private/qrenderstate_p.h>
+#include <Qt3DRender/qlinewidth.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QLineWidthPrivate : public QRenderStatePrivate
+{
+public:
+ QLineWidthPrivate(float value)
+ : QRenderStatePrivate(Render::LineWidthMask)
+ , m_value(value)
+ , m_smooth(false)
+ {}
+
+ float m_value;
+ bool m_smooth;
+
+ Q_DECLARE_PUBLIC(QLineWidth)
+};
+
+struct QLineWidthData
+{
+ float value;
+ bool smooth;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QLINEWIDTH_P_H
diff --git a/src/render/renderstates/renderstates.cpp b/src/render/renderstates/renderstates.cpp
index d5f0f46e7..d5e12aeab 100644
--- a/src/render/renderstates/renderstates.cpp
+++ b/src/render/renderstates/renderstates.cpp
@@ -306,6 +306,29 @@ void StencilMask::updateProperty(const char *name, const QVariant &value)
else if (name == QByteArrayLiteral("backOutputMask")) std::get<1>(m_values) = value.toInt();
}
+#ifndef GL_LINE_SMOOTH
+#define GL_LINE_SMOOTH 0x0B20
+#endif
+
+void LineWidth::apply(GraphicsContext *gc) const
+{
+ if (std::get<1>(m_values))
+ gc->openGLContext()->functions()->glEnable(GL_LINE_SMOOTH);
+ else
+ gc->openGLContext()->functions()->glDisable(GL_LINE_SMOOTH);
+
+ gc->activateGLHelper();
+ gc->openGLContext()->functions()->glLineWidth(std::get<0>(m_values));
+}
+
+void LineWidth::updateProperty(const char *name, const QVariant &value)
+{
+ if (name == QByteArrayLiteral("value"))
+ std::get<0>(m_values) = value.toFloat();
+ else if (name == QByteArrayLiteral("smooth"))
+ std::get<1>(m_values) = value.toBool();
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/renderstates/renderstates.pri b/src/render/renderstates/renderstates.pri
index 76497d310..7418ce162 100644
--- a/src/render/renderstates/renderstates.pri
+++ b/src/render/renderstates/renderstates.pri
@@ -27,6 +27,7 @@ HEADERS += \
$$PWD/qseamlesscubemap.h \
$$PWD/qdepthtest.h \
$$PWD/qnodepthmask.h \
+ $$PWD/qlinewidth.h \
$$PWD/qalphatest_p.h \
$$PWD/qblendequation_p.h \
$$PWD/qblendequationarguments_p.h \
@@ -43,6 +44,7 @@ HEADERS += \
$$PWD/qstenciloperationarguments_p.h \
$$PWD/qstenciltest_p.h \
$$PWD/qstenciltestarguments_p.h \
+ $$PWD/qlinewidth_p.h \
$$PWD/renderstatenode_p.h \
$$PWD/qmultisampleantialiasing.h \
$$PWD/statemask_p.h \
@@ -73,6 +75,7 @@ SOURCES += \
$$PWD/qpointsize.cpp \
$$PWD/qseamlesscubemap.cpp \
$$PWD/qnodepthmask.cpp \
+ $$PWD/qlinewidth.cpp \
$$PWD/qrenderstatecreatedchange.cpp \
$$PWD/renderstatenode.cpp \
$$PWD/qmultisampleantialiasing.cpp \
diff --git a/src/render/renderstates/renderstates_p.h b/src/render/renderstates/renderstates_p.h
index da6fe3b10..2b1af1c4c 100644
--- a/src/render/renderstates/renderstates_p.h
+++ b/src/render/renderstates/renderstates_p.h
@@ -190,6 +190,13 @@ public:
void updateProperty(const char *name, const QVariant &value) Q_DECL_OVERRIDE;
};
+class Q_AUTOTEST_EXPORT LineWidth : public GenericState<LineWidth, LineWidthMask, GLfloat, bool>
+{
+public:
+ void apply(GraphicsContext *gc) const Q_DECL_FINAL;
+ void updateProperty(const char *name, const QVariant &value) Q_DECL_OVERRIDE;
+};
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/renderstates/renderstateset.cpp b/src/render/renderstates/renderstateset.cpp
index afe900997..4166d41b0 100644
--- a/src/render/renderstates/renderstateset.cpp
+++ b/src/render/renderstates/renderstateset.cpp
@@ -86,6 +86,8 @@
#include <Qt3DRender/private/qstenciloperationarguments_p.h>
#include <Qt3DRender/qstencilmask.h>
#include <Qt3DRender/private/qstencilmask_p.h>
+#include <Qt3DRender/qlinewidth.h>
+#include <Qt3DRender/private/qlinewidth_p.h>
QT_BEGIN_NAMESPACE
@@ -230,6 +232,9 @@ void RenderStateSet::resetMasked(StateMaskSet maskOfStatesToReset, GraphicsConte
if (maskOfStatesToReset & StencilOpMask)
funcs->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ if (maskOfStatesToReset & LineWidthMask)
+ funcs->glLineWidth(1.0f);
}
bool RenderStateSet::contains(const StateVariant &ds) const
@@ -368,6 +373,12 @@ StateVariant RenderStateSet::initializeStateFromPeer(const Qt3DRender::QRenderSt
data.backOutputMask);
}
+ case LineWidthMask: {
+ const auto typedChange = qSharedPointerCast<Qt3DRender::QRenderStateCreatedChange<QLineWidthData>>(change);
+ const auto &data = typedChange->data;
+ return RenderStateSet::createState<LineWidth>(data.value, data.smooth);
+ }
+
// TODO: Fix Dithering state
case DitheringStateMask:
default:
diff --git a/src/render/renderstates/statemask_p.h b/src/render/renderstates/statemask_p.h
index 16d229f8d..1f3305747 100644
--- a/src/render/renderstates/statemask_p.h
+++ b/src/render/renderstates/statemask_p.h
@@ -80,6 +80,7 @@ enum StateMask
SeamlessCubemapMask = 1 << 16,
MSAAEnabledStateMask = 1 << 17,
BlendEquationArgumentsMask = 1 << 18,
+ LineWidthMask = 1 << 19,
};
} // namespace Render
diff --git a/src/render/renderstates/statevariant.cpp b/src/render/renderstates/statevariant.cpp
index f472d9920..0db9b5a3c 100644
--- a/src/render/renderstates/statevariant.cpp
+++ b/src/render/renderstates/statevariant.cpp
@@ -105,6 +105,9 @@ void StateVariant::apply(GraphicsContext *gc) const
case StencilWriteStateMask:
data.stencilMask.apply(gc);
return;
+ case LineWidthMask:
+ data.lineWidth.apply(gc);
+ return;
default:
Q_UNREACHABLE();
}
@@ -136,6 +139,7 @@ RenderStateImpl *StateVariant::state()
case SeamlessCubemapMask:
case StencilOpMask:
case StencilWriteStateMask:
+ case LineWidthMask:
return &data.blendEquationArguments;
default:
Q_UNREACHABLE();
@@ -168,6 +172,7 @@ const RenderStateImpl *StateVariant::constState() const
case SeamlessCubemapMask:
case StencilOpMask:
case StencilWriteStateMask:
+ case LineWidthMask:
return &data.blendEquationArguments;
default:
Q_UNREACHABLE();
diff --git a/src/render/renderstates/statevariant_p.h b/src/render/renderstates/statevariant_p.h
index 7f118d229..393e4156c 100644
--- a/src/render/renderstates/statevariant_p.h
+++ b/src/render/renderstates/statevariant_p.h
@@ -83,6 +83,7 @@ struct Q_AUTOTEST_EXPORT StateVariant
SeamlessCubemap seamlessCubemap;
StencilOp stencilOp;
StencilMask stencilMask;
+ LineWidth lineWidth;
u_Data()
{
diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp
index 2571e99bd..11cc1544f 100644
--- a/src/render/texture/gltexture.cpp
+++ b/src/render/texture/gltexture.cpp
@@ -50,6 +50,7 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/qabstracttexture_p.h>
+#include <Qt3DRender/private/renderbuffer_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qpropertynodeaddedchange.h>
#include <Qt3DCore/qpropertynoderemovedchange.h>
@@ -67,6 +68,7 @@ GLTexture::GLTexture(TextureDataManager *texDataMgr,
bool unique)
: m_unique(unique)
, m_gl(nullptr)
+ , m_renderBuffer(nullptr)
, m_textureDataManager(texDataMgr)
, m_textureImageDataManager(texImgDataMgr)
, m_dataFunctor(texGen)
@@ -97,6 +99,9 @@ void GLTexture::destroyGLTexture()
{
delete m_gl;
m_gl = nullptr;
+ delete m_renderBuffer;
+ m_renderBuffer = nullptr;
+
m_dirtyFlags.store(0);
destroyResources();
@@ -219,6 +224,41 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture()
return m_gl;
}
+RenderBuffer *GLTexture::getOrCreateRenderBuffer()
+{
+ QMutexLocker locker(&m_textureMutex);
+
+ if (m_dataFunctor && !m_textureData) {
+ m_textureData = m_textureDataManager->getData(m_dataFunctor);
+ if (m_textureData) {
+ if (m_properties.target != QAbstractTexture::TargetAutomatic)
+ qWarning() << "[Qt3DRender::GLTexture] [renderbuffer] When a texture provides a generator, it's target is expected to be TargetAutomatic";
+
+ m_properties.width = m_textureData->width();
+ m_properties.height = m_textureData->height();
+ m_properties.format = m_textureData->format();
+
+ setDirtyFlag(Properties);
+ } else {
+ qWarning() << "[Qt3DRender::GLTexture] [renderbuffer] No QTextureData generated from Texture Generator yet. Texture will be invalid for this frame";
+ return nullptr;
+ }
+ }
+
+ if (testDirtyFlag(Properties)) {
+ delete m_renderBuffer;
+ m_renderBuffer = nullptr;
+ }
+
+ if (!m_renderBuffer)
+ m_renderBuffer = new RenderBuffer(m_properties.width, m_properties.height, m_properties.format);
+
+ setDirtyFlag(Properties, false);
+ setDirtyFlag(Parameters, false);
+
+ return m_renderBuffer;
+}
+
void GLTexture::setParameters(const TextureParameters &params)
{
QMutexLocker locker(&m_textureMutex);
@@ -290,20 +330,24 @@ void GLTexture::setImages(const QVector<Image> &images)
void GLTexture::setGenerator(const QTextureGeneratorPtr &generator)
{
- if (m_dataFunctor != generator) {
- if (m_dataFunctor)
- m_textureDataManager->releaseData(m_dataFunctor, this);
+ // Note: we do not compare if the generator is different
+ // as in some cases we may want to reset the same generator to force a reload
+ // e.g when using remote urls for textures
+ if (m_dataFunctor)
+ m_textureDataManager->releaseData(m_dataFunctor, this);
- m_textureData.reset();
- m_dataFunctor = generator;
+ m_textureData.reset();
+ m_dataFunctor = generator;
- if (m_dataFunctor) {
- m_textureDataManager->requestData(m_dataFunctor, this);
- requestUpload();
- }
+ if (m_dataFunctor) {
+ m_textureDataManager->requestData(m_dataFunctor, this);
+ requestUpload();
}
}
+// Return nullptr if
+// - context cannot be obtained
+// - texture hasn't yet been loaded
QOpenGLTexture *GLTexture::buildGLTexture()
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
@@ -313,7 +357,9 @@ QOpenGLTexture *GLTexture::buildGLTexture()
}
if (m_actualTarget == QAbstractTexture::TargetAutomatic) {
- qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point";
+ // If the target is automatic at this point, it means that the texture
+ // hasn't been loaded yet (case of remote urls) and that loading failed
+ // and that target format couldn't be deduced
return nullptr;
}
diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h
index 294732b2a..a8f5705e8 100644
--- a/src/render/texture/gltexture_p.h
+++ b/src/render/texture/gltexture_p.h
@@ -72,6 +72,7 @@ namespace Render {
class TextureImageManager;
class TextureDataManager;
class TextureImageDataManager;
+class RenderBuffer;
/**
* @brief
@@ -85,6 +86,12 @@ class TextureImageDataManager;
*
* A GLTexture can be unique though. In that case, it will not be shared
* between QTextures, but private to one QTexture only.
+ *
+ * A GLTexture can also represent an OpenGL renderbuffer object. This is used
+ * only in certain special cases, mainly to provide a packed depth-stencil
+ * renderbuffer suitable as an FBO attachment with OpenGL ES 3.1 and earlier.
+ * Such a GLTexture will have no texture object under the hood, and therefore
+ * the only valid operation is getOrCreateRenderBuffer().
*/
class Q_AUTOTEST_EXPORT GLTexture
{
@@ -136,6 +143,13 @@ public:
QOpenGLTexture* getOrCreateGLTexture();
/**
+ * @brief
+ * Returns the RenderBuffer for this GLTexture. If this is the first
+ * call, the OpenGL renderbuffer object will be created.
+ */
+ RenderBuffer *getOrCreateRenderBuffer();
+
+ /**
* @brief Make sure to call this before calling the dtor
*/
void destroyGLTexture();
@@ -205,6 +219,7 @@ private:
QAtomicInt m_dirtyFlags;
QMutex m_textureMutex;
QOpenGLTexture *m_gl;
+ RenderBuffer *m_renderBuffer;
TextureDataManager *m_textureDataManager;
TextureImageDataManager *m_textureImageDataManager;
diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp
index 9e9d7e4f0..76886f438 100644
--- a/src/render/texture/qabstracttexture.cpp
+++ b/src/render/texture/qabstracttexture.cpp
@@ -69,6 +69,11 @@ QAbstractTexturePrivate::QAbstractTexturePrivate()
{
}
+QTextureGeneratorPtr QAbstractTexturePrivate::dataFunctor() const
+{
+ return m_dataFunctor;
+}
+
void QAbstractTexturePrivate::setDataFunctor(const QTextureGeneratorPtr &generator)
{
if (generator != m_dataFunctor) {
@@ -909,6 +914,41 @@ Qt3DCore::QNodeCreatedChangeBasePtr QAbstractTexture::createNodeCreationChange()
return creationChange;
}
+void QAbstractTexture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ switch (change->type()) {
+ case PropertyUpdated: {
+ Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (propertyChange->propertyName() == QByteArrayLiteral("width")) {
+ bool blocked = blockNotifications(true);
+ setWidth(propertyChange->value().toInt());
+ blockNotifications(blocked);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("height")) {
+ bool blocked = blockNotifications(true);
+ setHeight(propertyChange->value().toInt());
+ blockNotifications(blocked);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("depth")) {
+ bool blocked = blockNotifications(true);
+ setDepth(propertyChange->value().toInt());
+ blockNotifications(blocked);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("layers")) {
+ bool blocked = blockNotifications(true);
+ setLayers(propertyChange->value().toInt());
+ blockNotifications(blocked);
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("format")) {
+ bool blocked = blockNotifications(true);
+ setFormat(static_cast<QAbstractTexture::TextureFormat>(propertyChange->value().toInt()));
+ blockNotifications(blocked);
+ }
+ // TODO handle target changes, it's a CONSTANT property but can be affected by loader
+ break;
+ }
+ default:
+ break;
+ };
+}
+
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/texture/qabstracttexture.h b/src/render/texture/qabstracttexture.h
index 53868b319..5a1106787 100644
--- a/src/render/texture/qabstracttexture.h
+++ b/src/render/texture/qabstracttexture.h
@@ -332,6 +332,7 @@ protected:
explicit QAbstractTexture(Qt3DCore::QNode *parent = nullptr);
explicit QAbstractTexture(Target target, Qt3DCore::QNode *parent = nullptr);
explicit QAbstractTexture(QAbstractTexturePrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
void setStatus(Status status);
diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h
index c245a78af..a27ae3729 100644
--- a/src/render/texture/qabstracttexture_p.h
+++ b/src/render/texture/qabstracttexture_p.h
@@ -87,6 +87,7 @@ public :
int m_layers;
int m_samples;
+ QTextureGeneratorPtr dataFunctor() const;
void setDataFunctor(const QTextureGeneratorPtr &generator);
private:
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index 442c92d74..8dde9f9ac 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -44,7 +44,18 @@
#include "qtexture.h"
#include "qtexture_p.h"
#include <QFileInfo>
+#include <QMimeDatabase>
+#include <QMimeType>
+#include <QtCore/QBuffer>
#include <qendian.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qaspectengine.h>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
+#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/texture_p.h>
+#include <Qt3DRender/private/qurlhelper_p.h>
QT_BEGIN_NAMESPACE
@@ -418,15 +429,25 @@ const struct DX10Format
{ DXGI_FORMAT_BC7_UNORM_SRGB, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::SRGB_BP_UNorm, QOpenGLTexture::NoPixelType, 16, true } },
};
+struct PkmHeader
+{
+ char magic[4];
+ char version[2];
+ quint16 textureType;
+ quint16 paddedWidth;
+ quint16 paddedHeight;
+ quint16 width;
+ quint16 height;
+};
+
enum CompressedFormatExtension {
None = 0,
DDS,
PKM
};
-CompressedFormatExtension texturedCompressedFormat(const QString &source)
+CompressedFormatExtension texturedCompressedFormat(const QString &suffix)
{
- const QString suffix = QFileInfo(source).suffix().toLower();
if (suffix == QStringLiteral("pkm"))
return PKM;
if (suffix == QStringLiteral("dds"))
@@ -434,50 +455,102 @@ CompressedFormatExtension texturedCompressedFormat(const QString &source)
return None;
}
-QTextureImageDataPtr setPkmFile(const QString &source)
+QTextureImageDataPtr setPkmFile(QIODevice *source)
{
QTextureImageDataPtr imageData;
- QFile f(source);
- if (!f.open(QIODevice::ReadOnly)) {
- qWarning() << "Failed to open" << source;
+
+ PkmHeader header;
+ if ((source->read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header)
+ || (qstrncmp(header.magic, "PKM ", 4) != 0))
+ return imageData;
+
+ QOpenGLTexture::TextureFormat format = QOpenGLTexture::NoFormat;
+ int blockSize = 0;
+
+ if (header.version[0] == '2' && header.version[1] == '0') {
+ switch (qFromBigEndian(header.textureType)) {
+ case 0:
+ format = QOpenGLTexture::RGB8_ETC1;
+ blockSize = 8;
+ break;
+
+ case 1:
+ format = QOpenGLTexture::RGB8_ETC2;
+ blockSize = 8;
+ break;
+
+ case 3:
+ format = QOpenGLTexture::RGBA8_ETC2_EAC;
+ blockSize = 16;
+ break;
+
+ case 4:
+ format = QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2;
+ blockSize = 8;
+ break;
+
+ case 5:
+ format = QOpenGLTexture::R11_EAC_UNorm;
+ blockSize = 8;
+ break;
+
+ case 6:
+ format = QOpenGLTexture::RG11_EAC_UNorm;
+ blockSize = 16;
+ break;
+
+ case 7:
+ format = QOpenGLTexture::R11_EAC_SNorm;
+ blockSize = 8;
+ break;
+
+ case 8:
+ format = QOpenGLTexture::RG11_EAC_SNorm;
+ blockSize = 16;
+ break;
+ }
+ } else {
+ format = QOpenGLTexture::RGB8_ETC1;
+ blockSize = 8;
+ }
+
+ if (format == QOpenGLTexture::NoFormat) {
+ qWarning() << "Unrecognized compression format in" << source;
return imageData;
}
- // ETC1 in PKM, as generated by f.ex. Android's etc1tool
- static const char pkmMagic[] = { 'P', 'K', 'M', ' ', '1', '0' };
- const int pkmHeaderSize = 6 + 2 + 4 * 2;
- const QByteArray header = f.read(pkmHeaderSize);
- if (header.size() >= pkmHeaderSize && !qstrncmp(header.constData(), pkmMagic, 6)) {
- imageData = QTextureImageDataPtr::create();
- imageData->setTarget(QOpenGLTexture::Target2D);
- imageData->setFormat(QOpenGLTexture::RGB8_ETC1); // may get changed to RGB8_ETC2 later on
- // get the extended (multiple of 4) width and height
- imageData->setWidth(qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2))));
- imageData->setHeight(qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2 + 2))));
- imageData->setDepth(1);
- const QByteArray data = f.readAll();
- if (data.size() < (imageData->width() / 4) * (imageData->height() / 4) * 8)
- qWarning() << "Unexpected end of ETC1 data in" << source;
- const bool isCompressed = true;
- const int blockSize = 8;
- imageData->setPixelFormat(QOpenGLTexture::RGBA);
- imageData->setPixelType(QOpenGLTexture::UInt8);
- imageData->setData(data, blockSize, isCompressed);
+ // get the extended (multiple of 4) width and height
+ const int width = qFromBigEndian(header.paddedWidth);
+ const int height = qFromBigEndian(header.paddedHeight);
+
+ const QByteArray data = source->readAll();
+ if (data.size() != (width / 4) * (height / 4) * blockSize) {
+ qWarning() << "Unexpected data size in" << source;
+ return imageData;
}
+
+ imageData = QTextureImageDataPtr::create();
+ imageData->setTarget(QOpenGLTexture::Target2D);
+ imageData->setFormat(format);
+ imageData->setWidth(width);
+ imageData->setHeight(height);
+ imageData->setLayers(1);
+ imageData->setDepth(1);
+ imageData->setFaces(1);
+ imageData->setMipLevels(1);
+ imageData->setPixelFormat(QOpenGLTexture::NoSourceFormat);
+ imageData->setPixelType(QOpenGLTexture::NoPixelType);
+ imageData->setData(data, blockSize, true);
+
return imageData;
}
-QTextureImageDataPtr setDdsFile(const QString &source)
+QTextureImageDataPtr setDdsFile(QIODevice *source)
{
QTextureImageDataPtr imageData;
- QFile f(source);
- if (!f.open(QIODevice::ReadOnly)) {
- qWarning() << "Failed to open" << source;
- return imageData;
- }
DdsHeader header;
- if ((f.read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header)
+ if ((source->read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header)
|| (qstrncmp(header.magic, "DDS ", 4) != 0))
return imageData;
@@ -490,7 +563,7 @@ QTextureImageDataPtr setDdsFile(const QString &source)
if (fourCC == DdsFourCC<'D', 'X', '1', '0'>::value) {
// DX10 texture
DdsDX10Header dx10Header;
- if (f.read(reinterpret_cast<char *>(&dx10Header), sizeof dx10Header) != sizeof dx10Header)
+ if (source->read(reinterpret_cast<char *>(&dx10Header), sizeof dx10Header) != sizeof dx10Header)
return imageData;
layers = qFromLittleEndian(dx10Header.arraySize);
@@ -582,13 +655,13 @@ QTextureImageDataPtr setDdsFile(const QString &source)
// data
const int dataSize = layers * layerSize;
- const QByteArray data = f.read(dataSize);
+ const QByteArray data = source->read(dataSize);
if (data.size() < dataSize) {
qWarning() << "Unexpected end of data in" << source;
return imageData;
}
- if (!f.atEnd())
+ if (!source->atEnd())
qWarning() << "Unrecognized data in" << source;
imageData = QTextureImageDataPtr::create();
@@ -626,26 +699,39 @@ QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool
#endif
) {
const QString source = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(url);
- const CompressedFormatExtension formatExtension = texturedCompressedFormat(source);
- switch (formatExtension) {
- case DDS:
- textureData = setDdsFile(source);
- break;
- case PKM:
- textureData = setPkmFile(source);
- break;
- default:
- QImage img;
- if (img.load(source)) {
- textureData = QTextureImageDataPtr::create();
- textureData->setImage(mirrored ? img.mirrored() : img);
- }
- break;
- }
+ QFile f(source);
+ if (!f.open(QIODevice::ReadOnly))
+ qWarning() << "Failed to open" << source;
+ else
+ textureData = loadTextureData(&f, QFileInfo(source).suffix().toLower(), allow3D, mirrored);
+ }
+ return textureData;
+}
- if (!allow3D && textureData && (textureData->layers() > 1 || textureData->depth() > 1))
- qWarning() << "Texture data has a 3rd dimension which wasn't expected";
+QTextureImageDataPtr TextureLoadingHelper::loadTextureData(QIODevice *data, const QString& suffix,
+ bool allow3D, bool mirrored)
+{
+ QTextureImageDataPtr textureData;
+ const CompressedFormatExtension formatExtension = texturedCompressedFormat(suffix);
+ switch (formatExtension) {
+ case DDS:
+ textureData = setDdsFile(data);
+ break;
+ case PKM:
+ textureData = setPkmFile(data);
+ break;
+ default: {
+ QImage img;
+ if (img.load(data, suffix.toLatin1())) {
+ textureData = QTextureImageDataPtr::create();
+ textureData->setImage(mirrored ? img.mirrored() : img);
+ }
+ break;
}
+ }
+
+ if (!allow3D && textureData && (textureData->layers() > 1 || textureData->depth() > 1))
+ qWarning() << "Texture data has a 3rd dimension which wasn't expected";
return textureData;
}
@@ -653,8 +739,48 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
{
QTextureDataPtr generatedData = QTextureDataPtr::create();
m_status = QAbstractTexture::Loading;
+ QTextureImageDataPtr textureData;
- const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored);
+ QRenderAspectPrivate *d_aspect = QRenderAspectPrivate::findPrivate(m_engine);
+ Render::Texture *texture = d_aspect ? d_aspect->m_nodeManagers->textureManager()->lookupResource(m_texture) : nullptr;
+ if (texture)
+ texture->notifyStatus(m_status);
+
+ if (!Qt3DCore::QDownloadHelperService::isLocal(m_url)) {
+ if (m_sourceData.isEmpty()) {
+ // first time around, trigger a download
+ if (m_texture) {
+ auto downloadService = Qt3DCore::QDownloadHelperService::getService(m_engine);
+ Qt3DCore::QDownloadRequestPtr request(new TextureDownloadRequest(m_texture, m_url,
+ m_engine));
+ downloadService->submitRequest(request);
+ }
+ return generatedData;
+ }
+
+ // second time around, we have the data
+ QT_PREPEND_NAMESPACE(QBuffer) buffer(&m_sourceData);
+ if (buffer.open(QIODevice::ReadOnly)) {
+ QString suffix = m_url.toString();
+ suffix = suffix.right(suffix.length() - suffix.lastIndexOf('.'));
+
+ QStringList ext(suffix);
+
+ QMimeDatabase db;
+ QMimeType mtype = db.mimeTypeForData(m_sourceData);
+ if (mtype.isValid()) {
+ ext << mtype.suffixes();
+ }
+
+ for (QString s: qAsConst(ext)) {
+ textureData = TextureLoadingHelper::loadTextureData(&buffer, suffix, true, m_mirrored);
+ if (textureData && textureData->data().length() > 0)
+ break;
+ }
+ }
+ } else {
+ textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored);
+ }
// Update any properties explicitly set by the user
if (m_format != QAbstractTexture::NoFormat && m_format != QAbstractTexture::Automatic)
@@ -668,13 +794,51 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
generatedData->setDepth(textureData->depth());
generatedData->setLayers(textureData->layers());
generatedData->addImageData(textureData);
+
+ if (texture)
+ texture->updateFromData(generatedData);
+
m_status = QAbstractTexture::Ready;
} else {
m_status = QAbstractTexture::Error;
}
+
+ if (texture)
+ texture->notifyStatus(m_status);
return generatedData;
}
+TextureDownloadRequest::TextureDownloadRequest(Qt3DCore::QNodeId texture, const QUrl& source,
+ Qt3DCore::QAspectEngine *engine)
+ : Qt3DCore::QDownloadRequest(source)
+ , m_texture(texture)
+ , m_engine(engine)
+{
+
+}
+
+// Executed in download thread
+void TextureDownloadRequest::onCompleted()
+{
+ if (cancelled() || !succeeded())
+ return;
+
+ QRenderAspectPrivate* d_aspect = QRenderAspectPrivate::findPrivate(m_engine);
+ if (!d_aspect)
+ return;
+
+ Render::Texture *texture = d_aspect->m_nodeManagers->textureManager()->lookupResource(m_texture);
+ if (!texture)
+ return;
+
+ QSharedPointer<QTextureFromSourceGenerator> functor =
+ qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator());
+ functor->m_sourceData = m_data;
+
+ // mark the component as dirty so that the functor runs again in the correct job
+ texture->addDirtyFlag(Render::Texture::DirtyDataGenerator);
+}
+
/*!
\class Qt3DRender::QTexture1D
\inmodule Qt3DRender
@@ -901,10 +1065,17 @@ QTextureLoaderPrivate::QTextureLoaderPrivate()
{
}
+void QTextureLoaderPrivate::setScene(Qt3DCore::QScene *scene)
+{
+ QAbstractTexturePrivate::setScene(scene);
+ updateGenerator();
+}
+
void QTextureLoaderPrivate::updateGenerator()
{
Q_Q(QTextureLoader);
- setDataFunctor(QTextureFromSourceGeneratorPtr::create(q));
+ Qt3DCore::QAspectEngine *engine = m_scene ? m_scene->engine() : nullptr;
+ setDataFunctor(QTextureFromSourceGeneratorPtr::create(q, engine, m_id));
}
/*!
@@ -1033,11 +1204,15 @@ void QTextureLoader::setMirrored(bool mirrored)
* instance with properties passed in via \a textureLoader
* \param url
*/
-QTextureFromSourceGenerator::QTextureFromSourceGenerator(QTextureLoader *textureLoader)
+QTextureFromSourceGenerator::QTextureFromSourceGenerator(QTextureLoader *textureLoader,
+ Qt3DCore::QAspectEngine *engine,
+ Qt3DCore::QNodeId textureId)
: QTextureGenerator()
- , m_status(QAbstractTexture::None)
, m_url()
+ , m_status(QAbstractTexture::None)
, m_mirrored()
+ , m_texture(textureId)
+ , m_engine(engine)
, m_format(QAbstractTexture::RGBA8_UNorm)
{
Q_ASSERT(textureLoader);
@@ -1066,6 +1241,7 @@ bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) co
return (otherFunctor != nullptr &&
otherFunctor->m_url == m_url &&
otherFunctor->m_mirrored == m_mirrored &&
+ otherFunctor->m_engine == m_engine &&
otherFunctor->m_format == m_format);
}
@@ -1082,5 +1258,3 @@ bool QTextureFromSourceGenerator::isMirrored() const
} // namespace Qt3DRender
QT_END_NAMESPACE
-
-
diff --git a/src/render/texture/qtexture_p.h b/src/render/texture/qtexture_p.h
index 2cdb4c689..490eed487 100644
--- a/src/render/texture/qtexture_p.h
+++ b/src/render/texture/qtexture_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
+#include <Qt3DCore/QNodeId>
+#include <Qt3DCore/private/qdownloadhelperservice_p.h>
#include <Qt3DRender/private/qabstracttexture_p.h>
#include <Qt3DRender/qtexturegenerator.h>
#include <Qt3DRender/qtexture.h>
@@ -67,16 +69,32 @@ public:
Q_DECLARE_PUBLIC(QTextureLoader)
+ void setScene(Qt3DCore::QScene *scene) override;
void updateGenerator();
QUrl m_source;
bool m_mirrored;
};
+class Q_AUTOTEST_EXPORT TextureDownloadRequest : public Qt3DCore::QDownloadRequest
+{
+public:
+ TextureDownloadRequest(Qt3DCore::QNodeId texture, const QUrl &url, Qt3DCore::QAspectEngine *engine);
+
+ void onCompleted() Q_DECL_OVERRIDE;
+
+private:
+ Qt3DCore::QNodeId m_texture;
+ Qt3DCore::QAspectEngine *m_engine;
+};
+
class Q_AUTOTEST_EXPORT QTextureFromSourceGenerator : public QTextureGenerator
{
public:
- explicit QTextureFromSourceGenerator(QTextureLoader *textureLoader);
+ explicit QTextureFromSourceGenerator(QTextureLoader *textureLoader,
+ Qt3DCore::QAspectEngine *engine,
+ Qt3DCore::QNodeId textureId);
+
QTextureDataPtr operator ()() Q_DECL_OVERRIDE;
bool operator ==(const QTextureGenerator &other) const Q_DECL_OVERRIDE;
inline QAbstractTexture::Status status() const { return m_status; }
@@ -87,10 +105,16 @@ public:
bool isMirrored() const;
private:
- QAbstractTexture::Status m_status;
+ friend class TextureDownloadRequest;
+
QUrl m_url;
+ QAbstractTexture::Status m_status;
bool m_mirrored;
+ QByteArray m_sourceData;
+ Qt3DCore::QNodeId m_texture;
+ Qt3DCore::QAspectEngine *m_engine;
+
// Options that can be overridden on TextureLoader when loading
QAbstractTexture::TextureFormat m_format;
};
@@ -100,6 +124,8 @@ class Q_AUTOTEST_EXPORT TextureLoadingHelper
{
public:
static QTextureImageDataPtr loadTextureData(const QUrl &source, bool allow3D, bool mirrored);
+ static QTextureImageDataPtr loadTextureData(QIODevice *data, const QString& suffix,
+ bool allow3D, bool mirrored);
};
} // namespace Qt3DRender
diff --git a/src/render/texture/qtextureimagedata.cpp b/src/render/texture/qtextureimagedata.cpp
index c9057608e..c31f272a8 100644
--- a/src/render/texture/qtextureimagedata.cpp
+++ b/src/render/texture/qtextureimagedata.cpp
@@ -370,7 +370,7 @@ void QTextureImageData::setImage(const QImage &image)
Q_ASSERT_X(glImage.bytesPerLine() == (glImage.width() * glImage.depth() + 7) / 8,
"QTextureImageData::setImage", "glImage is not packed"); // QTBUG-48330
d->m_blockSize = 4;
- QByteArray imageBytes((const char*) glImage.constBits(), glImage.byteCount());
+ QByteArray imageBytes((const char*) glImage.constBits(), glImage.sizeInBytes());
setData(imageBytes, d->m_blockSize, false);
d->m_format = QOpenGLTexture::RGBA8_UNorm;
d->m_pixelFormat = QOpenGLTexture::RGBA;
diff --git a/src/render/texture/renderbuffer.cpp b/src/render/texture/renderbuffer.cpp
new file mode 100644
index 000000000..bc5050f73
--- /dev/null
+++ b/src/render/texture/renderbuffer.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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 "renderbuffer_p.h"
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFunctions>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+RenderBuffer::RenderBuffer(int width, int height, QAbstractTexture::TextureFormat format)
+ : m_size(width, height),
+ m_format(format),
+ m_renderBuffer(0),
+ m_context(nullptr)
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx) {
+ qWarning("Renderbuffer requires an OpenGL context");
+ return;
+ }
+
+ m_context = ctx;
+ QOpenGLFunctions *f = ctx->functions();
+ f->glGenRenderbuffers(1, &m_renderBuffer);
+ if (!m_renderBuffer)
+ return;
+
+ f->glBindRenderbuffer(GL_RENDERBUFFER, m_renderBuffer);
+ while (f->glGetError() != GL_NO_ERROR) { }
+ f->glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
+ GLint err = f->glGetError();
+ if (err != GL_NO_ERROR)
+ qWarning("Failed to set renderbuffer storage: error 0x%x", err);
+ f->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+}
+
+RenderBuffer::~RenderBuffer()
+{
+ if (m_renderBuffer) {
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+
+ // Ignore the fact that renderbuffers are sharable resources and let's
+ // just expect that the context is the same as when the resource was
+ // created. QOpenGLTexture suffers from the same limitation anyway, and
+ // this is unlikely to become an issue within Qt 3D.
+ if (ctx == m_context) {
+ ctx->functions()->glDeleteRenderbuffers(1, &m_renderBuffer);
+ } else {
+ qWarning("Wrong current context; renderbuffer not destroyed");
+ }
+ }
+}
+
+void RenderBuffer::bind()
+{
+ if (!m_renderBuffer)
+ return;
+
+ m_context->functions()->glBindRenderbuffer(GL_RENDERBUFFER, m_renderBuffer);
+}
+
+void RenderBuffer::release()
+{
+ if (!m_context)
+ return;
+
+ m_context->functions()->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/texture/renderbuffer_p.h b/src/render/texture/renderbuffer_p.h
new file mode 100644
index 000000000..7dc62492a
--- /dev/null
+++ b/src/render/texture/renderbuffer_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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_RENDERBUFFER_P_H
+#define QT3DRENDER_RENDER_RENDERBUFFER_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 <Qt3DRender/qabstracttexture.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT RenderBuffer
+{
+public:
+ RenderBuffer(int width, int height, QAbstractTexture::TextureFormat format);
+ ~RenderBuffer();
+
+ int width() const { return m_size.width(); }
+ int height() const { return m_size.height(); }
+ QSize size() const { return m_size; }
+ QAbstractTexture::TextureFormat format() const { return m_format; }
+ GLuint renderBufferId() const { return m_renderBuffer; }
+
+ void bind();
+ void release();
+
+private:
+ QSize m_size;
+ QAbstractTexture::TextureFormat m_format;
+ GLuint m_renderBuffer;
+ QOpenGLContext *m_context;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RENDERBUFFER_P_H
diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp
index 13991ec4a..b4587d3e0 100644
--- a/src/render/texture/texture.cpp
+++ b/src/render/texture/texture.cpp
@@ -81,11 +81,19 @@ void Texture::setTextureImageManager(TextureImageManager *manager)
void Texture::addDirtyFlag(DirtyFlags flags)
{
+ QMutexLocker lock(&m_flagsMutex);
m_dirty |= flags;
}
+Texture::DirtyFlags Texture::dirtyFlags()
+{
+ QMutexLocker lock(&m_flagsMutex);
+ return m_dirty;
+}
+
void Texture::unsetDirty()
{
+ QMutexLocker lock(&m_flagsMutex);
m_dirty = Texture::NotDirty;
}
@@ -242,10 +250,77 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
addDirtyFlag(dirty);
- markDirty(AbstractRenderer::AllDirty);
+ markDirty(AbstractRenderer::TexturesDirty);
BackendNode::sceneChangeEvent(e);
}
+void Texture::notifyStatus(QAbstractTexture::Status status)
+{
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("status");
+ change->setValue(status);
+ notifyObservers(change);
+}
+
+void Texture::updateFromData(QTextureDataPtr data)
+{
+ if (data->width() != m_properties.width) {
+ m_properties.width = data->width();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("width");
+ change->setValue(data->width());
+ notifyObservers(change);
+ }
+
+ if (data->height() != m_properties.height) {
+ m_properties.height = data->height();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("height");
+ change->setValue(data->height());
+ notifyObservers(change);
+ }
+
+ if (data->depth() != m_properties.depth) {
+ m_properties.depth = data->depth();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("depth");
+ change->setValue(data->depth());
+ notifyObservers(change);
+ }
+
+ if (data->layers() != m_properties.layers) {
+ m_properties.layers = data->layers();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("layers");
+ change->setValue(data->layers());
+ notifyObservers(change);
+ }
+
+ if (data->format() != m_properties.format) {
+ m_properties.format = data->format();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("format");
+ change->setValue(data->format());
+ notifyObservers(change);
+ }
+
+ if (data->target() != m_properties.target) {
+ // TODO frontend property is actually constant
+ m_properties.target = data->target();
+ auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ change->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ change->setPropertyName("target");
+ change->setValue(data->target());
+ notifyObservers(change);
+ }
+}
+
bool Texture::isValid() const
{
for (const auto handle : m_textureImages) {
diff --git a/src/render/texture/texture.pri b/src/render/texture/texture.pri
index bd5c34e72..17855d943 100644
--- a/src/render/texture/texture.pri
+++ b/src/render/texture/texture.pri
@@ -23,7 +23,8 @@ HEADERS += \
$$PWD/qpaintedtextureimage_p.h \
$$PWD/gltexture_p.h \
$$PWD/gltexturemanager_p.h \
- $$PWD/apitexturemanager_p.h
+ $$PWD/apitexturemanager_p.h \
+ $$PWD/renderbuffer_p.h
SOURCES += \
$$PWD/qabstracttextureimage.cpp \
@@ -37,4 +38,5 @@ SOURCES += \
$$PWD/qtexturedata.cpp \
$$PWD/qtexturegenerator.cpp \
$$PWD/qpaintedtextureimage.cpp \
- $$PWD/gltexture.cpp
+ $$PWD/gltexture.cpp \
+ $$PWD/renderbuffer.cpp
diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h
index 4fe4e2c7c..325d1567f 100644
--- a/src/render/texture/texture_p.h
+++ b/src/render/texture/texture_p.h
@@ -54,7 +54,7 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/handle_types_p.h>
#include <Qt3DRender/qtexture.h>
-#include <Qt3DRender/qtextureimagedata.h>
+#include <Qt3DRender/qtexturedata.h>
#include <Qt3DRender/qtexturegenerator.h>
#include <QOpenGLContext>
#include <QMutex>
@@ -143,7 +143,7 @@ public:
void setTextureImageManager(TextureImageManager *manager);
void addDirtyFlag(DirtyFlags flags);
- inline DirtyFlags dirtyFlags() const { return m_dirty; }
+ DirtyFlags dirtyFlags();
void unsetDirty();
void addTextureImage(Qt3DCore::QNodeId id);
@@ -157,6 +157,9 @@ public:
inline const QVector<HTextureImage>& textureImages() const { return m_textureImages; }
inline const QTextureGeneratorPtr& dataGenerator() const { return m_dataFunctor; }
+ void notifyStatus(QAbstractTexture::Status status);
+ void updateFromData(QTextureDataPtr data);
+
bool isValid() const;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -169,6 +172,7 @@ private:
QVector<HTextureImage> m_textureImages;
TextureImageManager *m_textureImageManager;
+ QMutex m_flagsMutex;
};
class TextureFunctor : public Qt3DCore::QBackendNodeMapper
diff --git a/src/src.pro b/src/src.pro
index a965d7946..cd07486e9 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -13,7 +13,7 @@ src_logic.depends = src_core
src_input.subdir = $$PWD/input
src_input.target = sub-input
-src_input.depends = src_render
+src_input.depends = src_core
src_animation.subdir = $$PWD/animation
src_animation.target = sub-animation
@@ -27,7 +27,7 @@ qtHaveModule(quick) {
# Quick3D libs
src_quick3d_core.subdir = $$PWD/quick3d/quick3d
src_quick3d_core.target = sub-quick3d-core
- src_quick3d_core.depends = src_core src_input
+ src_quick3d_core.depends = src_core
src_quick3d_render.subdir = $$PWD/quick3d/quick3drender
src_quick3d_render.target = sub-quick3d-render
@@ -60,7 +60,7 @@ qtHaveModule(quick) {
src_quick3d_imports_scene3d.file = $$PWD/quick3d/imports/scene3d/importsscene3d.pro
src_quick3d_imports_scene3d.target = sub-quick3d-imports-scene3d
- src_quick3d_imports_scene3d.depends = src_quick3d_render src_input
+ src_quick3d_imports_scene3d.depends = src_quick3d_render
src_quick3d_imports_input.file = $$PWD/quick3d/imports/input/importsinput.pro
src_quick3d_imports_input.target = sub-quick3d-imports-input
@@ -102,30 +102,56 @@ qtHaveModule(quick) {
SUBDIRS += \
src_core \
- src_render \
- src_logic \
- src_input \
- src_animation \
- src_extras \
- src_plugins_sceneparsers \
- src_plugins_geometryloaders \
doc
+QT_FOR_CONFIG += 3dcore
+include($$OUT_PWD/core/qt3dcore-config.pri)
+
+qtConfig(qt3d-input): SUBDIRS += src_input
+qtConfig(qt3d-logic): SUBDIRS += src_logic
+qtConfig(qt3d-render): SUBDIRS += src_render
+qtConfig(qt3d-animation): SUBDIRS += src_animation
+qtConfig(qt3d-extras) {
+ SUBDIRS += \
+ src_extras \
+ src_plugins_sceneparsers \
+ src_plugins_geometryloaders
+}
+
qtHaveModule(quick) {
SUBDIRS += \
src_quick3d_core \
- src_quick3d_core_imports \
- src_quick3d_render \
- src_quick3d_input \
- src_quick3d_animation \
- src_quick3d_extras \
- src_quick3d_imports_render \
- src_quick3d_imports_scene3d \
- src_quick3d_imports_input \
- src_quick3d_imports_logic \
- src_quick3d_imports_animation \
- src_quick3d_imports_extras \
- src_plugins_render \
- src_quick3d_scene2d \
- src_quick3d_imports_scene2d
+ src_quick3d_core_imports
+
+ qtConfig(qt3d-input) {
+ SUBDIRS += \
+ src_quick3d_input \
+ src_quick3d_imports_input
+ }
+ qtConfig(qt3d-logic): SUBDIRS += src_quick3d_imports_logic
+ qtConfig(qt3d-render) {
+ SUBDIRS += \
+ src_quick3d_render \
+ src_quick3d_imports_render \
+ src_quick3d_imports_scene3d
+
+ qtConfig(qt3d-input) {
+ src_quick3d_imports_scene3d.depends += src_input
+ SUBDIRS += \
+ src_quick3d_scene2d \
+ src_quick3d_imports_scene2d
+ }
+ qtConfig(qt3d-logic): src_quick3d_imports_scene3d.depends += src_logic
+ }
+ qtConfig(qt3d-animation) {
+ SUBDIRS += \
+ src_quick3d_animation \
+ src_quick3d_imports_animation
+ }
+ qtConfig(qt3d-extras) {
+ SUBDIRS += \
+ src_quick3d_extras \
+ src_quick3d_imports_extras \
+ src_plugins_render
+ }
}
diff --git a/tests/auto/animation/animation.pro b/tests/auto/animation/animation.pro
index 421ecfdd5..1226f9498 100644
--- a/tests/auto/animation/animation.pro
+++ b/tests/auto/animation/animation.pro
@@ -13,7 +13,10 @@ SUBDIRS += \
qkeyframeanimation \
qmorphinganimation \
qmorphtarget \
- qvertexblendanimation
+ qvertexblendanimation \
+ qclock \
+ qskeletonmapping \
+ qcallbackmapping
qtConfig(private_tests) {
SUBDIRS += \
@@ -35,5 +38,7 @@ qtConfig(private_tests) {
clipblendvalue \
animationutils \
qabstractanimation \
+ clock \
+ skeleton \
findrunningclipanimatorsjob
}
diff --git a/tests/auto/animation/animationutils/animationutils.qrc b/tests/auto/animation/animationutils/animationutils.qrc
index ddaeab7f1..0b499ed76 100644
--- a/tests/auto/animation/animationutils/animationutils.qrc
+++ b/tests/auto/animation/animationutils/animationutils.qrc
@@ -4,5 +4,6 @@
<file>clip2.json</file>
<file>clip3.json</file>
<file>clip4.json</file>
+ <file>clip5.json</file>
</qresource>
</RCC>
diff --git a/tests/auto/animation/animationutils/clip5.json b/tests/auto/animation/animationutils/clip5.json
new file mode 100644
index 000000000..50a848f03
--- /dev/null
+++ b/tests/auto/animation/animationutils/clip5.json
@@ -0,0 +1,1401 @@
+{
+ "animations": [
+ {
+ "animationName": "SkeletonAction",
+ "channels": [
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Rotation W",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -4.371138828673793e-08
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -4.371138828673793e-08
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -4.371138828673793e-08
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ -0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ -0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -1.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -1.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -1.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Rotation",
+ "jointIndex": 0
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Location X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Location",
+ "jointIndex": 0
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Scale X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Scale",
+ "jointIndex": 0
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Rotation W",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -4.371138828673793e-08
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -4.371138828673793e-08
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -4.371138828673793e-08
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ -0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ -0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -1.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -1.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -1.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Rotation",
+ "jointIndex": 1
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Location X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Location",
+ "jointIndex": 1
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Scale X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Scale",
+ "jointIndex": 1
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Rotation W",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -4.371138828673793e-08
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -4.371138828673793e-08
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -4.371138828673793e-08
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ -0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ -0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -1.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -1.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -1.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Rotation",
+ "jointIndex": 2
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Location X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Location",
+ "jointIndex": 2
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Scale X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Scale",
+ "jointIndex": 2
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Rotation W",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -4.371138828673793e-08
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -4.371138828673793e-08
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -4.371138828673793e-08
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ -0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ -0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ -1.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ -1.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ -1.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Rotation",
+ "jointIndex": 3
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Location X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Location",
+ "jointIndex": 3
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Scale X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 5.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.9597616195678711,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9597616195678711,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.4583333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.4985717137654622,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.4180949529012046,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Scale",
+ "jointIndex": 3
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/auto/animation/animationutils/tst_animationutils.cpp b/tests/auto/animation/animationutils/tst_animationutils.cpp
index 36e954a85..5ec8c7d60 100644
--- a/tests/auto/animation/animationutils/tst_animationutils.cpp
+++ b/tests/auto/animation/animationutils/tst_animationutils.cpp
@@ -30,6 +30,7 @@
#include <Qt3DAnimation/private/animationclip_p.h>
#include <Qt3DAnimation/private/animationutils_p.h>
#include <Qt3DAnimation/private/blendedclipanimator_p.h>
+#include <Qt3DAnimation/private/clock_p.h>
#include <Qt3DAnimation/private/channelmapper_p.h>
#include <Qt3DAnimation/private/channelmapping_p.h>
#include <Qt3DAnimation/private/clipblendvalue_p.h>
@@ -51,6 +52,7 @@ using namespace Qt3DAnimation::Animation;
Q_DECLARE_METATYPE(Qt3DAnimation::Animation::Handler*)
Q_DECLARE_METATYPE(QVector<ChannelMapping *>)
+Q_DECLARE_METATYPE(Clock *)
Q_DECLARE_METATYPE(ChannelMapper *)
Q_DECLARE_METATYPE(AnimationClip *)
Q_DECLARE_METATYPE(QVector<MappingData>)
@@ -61,6 +63,7 @@ Q_DECLARE_METATYPE(ClipEvaluationData)
Q_DECLARE_METATYPE(ClipAnimator *)
Q_DECLARE_METATYPE(BlendedClipAnimator *)
Q_DECLARE_METATYPE(QVector<ChannelNameAndType>)
+Q_DECLARE_METATYPE(QVector<AnimationCallbackAndValue>)
namespace {
@@ -122,6 +125,12 @@ bool fuzzyCompare(float x1, float x2)
}
}
+class DummyCallback : public Qt3DAnimation::QAnimationCallback
+{
+public:
+ void valueChanged(const QVariant &) override { }
+};
+
} // anonymous
@@ -140,11 +149,25 @@ public:
auto channelMappingId = Qt3DCore::QNodeId::createId();
ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(channelMappingId);
setPeerId(channelMapping, channelMappingId);
+ channelMapping->setHandler(handler);
channelMapping->setTargetId(targetId);
channelMapping->setProperty(property);
channelMapping->setPropertyName(propertyName);
channelMapping->setChannelName(channelName);
channelMapping->setType(type);
+ channelMapping->setMappingType(ChannelMapping::ChannelMappingType);
+ return channelMapping;
+ }
+
+ ChannelMapping *createChannelMapping(Handler *handler,
+ const Qt3DCore::QNodeId skeletonId)
+ {
+ auto channelMappingId = Qt3DCore::QNodeId::createId();
+ ChannelMapping *channelMapping = handler->channelMappingManager()->getOrCreateResource(channelMappingId);
+ setPeerId(channelMapping, channelMappingId);
+ channelMapping->setHandler(handler);
+ channelMapping->setSkeletonId(skeletonId);
+ channelMapping->setMappingType(ChannelMapping::SkeletonMappingType);
return channelMapping;
}
@@ -238,9 +261,19 @@ public:
return node;
}
+ Skeleton *createSkeleton(Handler *handler, int jointCount)
+ {
+ auto skeletonId = Qt3DCore::QNodeId::createId();
+ Skeleton *skeleton = handler->skeletonManager()->getOrCreateResource(skeletonId);
+ setPeerId(skeleton, skeletonId);
+ skeleton->setJointCount(jointCount);
+ return skeleton;
+ }
+
private Q_SLOTS:
void checkBuildPropertyMappings_data()
{
+ QTest::addColumn<Handler *>("handler");
QTest::addColumn<QVector<ChannelMapping *>>("channelMappings");
QTest::addColumn<QVector<ChannelNameAndType>>("channelNamesAndTypes");
QTest::addColumn<QVector<ComponentIndices>>("channelComponentIndices");
@@ -248,12 +281,14 @@ private Q_SLOTS:
// Single ChannelMapping
{
- auto channelMapping = new ChannelMapping();
- channelMapping->setChannelName("Location");
- channelMapping->setTargetId(Qt3DCore::QNodeId::createId());
- channelMapping->setProperty(QLatin1String("translation"));
- channelMapping->setPropertyName("translation");
- channelMapping->setType(static_cast<int>(QVariant::Vector3D));
+ Handler *handler = new Handler();
+
+ auto channelMapping = createChannelMapping(handler,
+ QLatin1String("Location"),
+ Qt3DCore::QNodeId::createId(),
+ QLatin1String("translation"),
+ "translation",
+ static_cast<int>(QVariant::Vector3D));
QVector<ChannelMapping *> channelMappings = { channelMapping };
@@ -289,6 +324,7 @@ private Q_SLOTS:
QVector<MappingData> expectedResults = { expectedMapping };
QTest::newRow("single mapping")
+ << handler
<< channelMappings
<< channelNamesAndTypes
<< channelComponentIndices
@@ -297,40 +333,42 @@ private Q_SLOTS:
// Multiple ChannelMappings
{
- auto locationMapping = new ChannelMapping();
- locationMapping->setChannelName("Location");
- locationMapping->setTargetId(Qt3DCore::QNodeId::createId());
- locationMapping->setProperty(QLatin1String("translation"));
- locationMapping->setPropertyName("translation");
- locationMapping->setType(static_cast<int>(QVariant::Vector3D));
-
- auto metalnessMapping = new ChannelMapping();
- metalnessMapping->setChannelName("Metalness");
- metalnessMapping->setTargetId(Qt3DCore::QNodeId::createId());
- metalnessMapping->setProperty(QLatin1String("metalness"));
- metalnessMapping->setPropertyName("metalness");
- metalnessMapping->setType(static_cast<int>(QVariant::Double));
-
- auto baseColorMapping = new ChannelMapping();
- baseColorMapping->setChannelName("BaseColor");
- baseColorMapping->setTargetId(Qt3DCore::QNodeId::createId());
- baseColorMapping->setProperty(QLatin1String("baseColor"));
- baseColorMapping->setPropertyName("baseColor");
- baseColorMapping->setType(static_cast<int>(QVariant::Vector3D));
-
- auto roughnessMapping = new ChannelMapping();
- roughnessMapping->setChannelName("Roughness");
- roughnessMapping->setTargetId(Qt3DCore::QNodeId::createId());
- roughnessMapping->setProperty(QLatin1String("roughness"));
- roughnessMapping->setPropertyName("roughness");
- roughnessMapping->setType(static_cast<int>(QVariant::Double));
-
- auto rotationMapping = new ChannelMapping();
- rotationMapping->setChannelName("Rotation");
- rotationMapping->setTargetId(Qt3DCore::QNodeId::createId());
- rotationMapping->setProperty(QLatin1String("rotation"));
- rotationMapping->setPropertyName("rotation");
- rotationMapping->setType(static_cast<int>(QVariant::Quaternion));
+ Handler *handler = new Handler();
+
+ auto locationMapping = createChannelMapping(handler,
+ QLatin1String("Location"),
+ Qt3DCore::QNodeId::createId(),
+ QLatin1String("translation"),
+ "translation",
+ static_cast<int>(QVariant::Vector3D));
+
+ auto metalnessMapping = createChannelMapping(handler,
+ QLatin1String("Metalness"),
+ Qt3DCore::QNodeId::createId(),
+ QLatin1String("metalness"),
+ "metalness",
+ static_cast<int>(QVariant::Double));
+
+ auto baseColorMapping = createChannelMapping(handler,
+ QLatin1String("BaseColor"),
+ Qt3DCore::QNodeId::createId(),
+ QLatin1String("baseColor"),
+ "baseColor",
+ static_cast<int>(QVariant::Vector3D));
+
+ auto roughnessMapping = createChannelMapping(handler,
+ QLatin1String("Roughness"),
+ Qt3DCore::QNodeId::createId(),
+ QLatin1String("roughness"),
+ "roughness",
+ static_cast<int>(QVariant::Double));
+
+ auto rotationMapping = createChannelMapping(handler,
+ QLatin1String("Rotation"),
+ Qt3DCore::QNodeId::createId(),
+ QLatin1String("rotation"),
+ "rotation",
+ static_cast<int>(QVariant::Quaternion));
QVector<ChannelMapping *> channelMappings
= { locationMapping, metalnessMapping,
@@ -399,6 +437,77 @@ private Q_SLOTS:
expectedRotationMapping };
QTest::newRow("multiple mappings")
+ << handler
+ << channelMappings
+ << channelNamesAndTypes
+ << channelComponentIndices
+ << expectedResults;
+ }
+
+ // Single skeleton mapping
+ {
+ Handler *handler = new Handler();
+ const int jointCount = 4;
+ auto skeleton = createSkeleton(handler, jointCount);
+ auto channelMapping = createChannelMapping(handler, skeleton->peerId());
+
+ QVector<ChannelMapping *> channelMappings = { channelMapping };
+
+ // Create a few channels in the format description
+ QVector<ChannelNameAndType> channelNamesAndTypes;
+ for (int i = 0; i < jointCount; ++i) {
+ channelNamesAndTypes.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D), i });
+ channelNamesAndTypes.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion), i });
+ channelNamesAndTypes.push_back({ QLatin1String("Scale"), static_cast<int>(QVariant::Vector3D), i });
+ }
+
+ // And the matching indices
+ QVector<ComponentIndices> channelComponentIndices;
+ channelComponentIndices.push_back({ 0, 1, 2 });
+ channelComponentIndices.push_back({ 3, 4, 5, 6 });
+ channelComponentIndices.push_back({ 7, 8, 9 });
+
+ channelComponentIndices.push_back({ 10, 11, 12 });
+ channelComponentIndices.push_back({ 13, 14, 15, 16 });
+ channelComponentIndices.push_back({ 17, 18, 19 });
+
+ channelComponentIndices.push_back({ 20, 21, 22 });
+ channelComponentIndices.push_back({ 23, 24, 25, 26 });
+ channelComponentIndices.push_back({ 27, 28, 29 });
+
+ channelComponentIndices.push_back({ 30, 31, 32 });
+ channelComponentIndices.push_back({ 33, 34, 35, 36 });
+ channelComponentIndices.push_back({ 37, 38, 39 });
+
+ QVector<MappingData> expectedResults;
+ int componentIndicesIndex = 0;
+ for (int i = 0; i < jointCount; ++i) {
+ MappingData locationMapping;
+ locationMapping.targetId = channelMapping->skeletonId();
+ locationMapping.propertyName = "translation";
+ locationMapping.type = static_cast<int>(QVariant::Vector3D);
+ locationMapping.channelIndices = channelComponentIndices[componentIndicesIndex++];
+ locationMapping.jointIndex = i;
+
+ MappingData rotationMapping;
+ rotationMapping.targetId = channelMapping->skeletonId();
+ rotationMapping.propertyName = "rotation";
+ rotationMapping.type = static_cast<int>(QVariant::Quaternion);
+ rotationMapping.channelIndices = channelComponentIndices[componentIndicesIndex++];
+ rotationMapping.jointIndex = i;
+
+ MappingData scaleMapping;
+ scaleMapping.targetId = channelMapping->skeletonId();
+ scaleMapping.propertyName = "scale";
+ scaleMapping.type = static_cast<int>(QVariant::Vector3D);
+ scaleMapping.channelIndices = channelComponentIndices[componentIndicesIndex++];
+ scaleMapping.jointIndex = i;
+
+ expectedResults << locationMapping << rotationMapping << scaleMapping;
+ }
+
+ QTest::newRow("single skeleton mapping")
+ << handler
<< channelMappings
<< channelNamesAndTypes
<< channelComponentIndices
@@ -409,6 +518,7 @@ private Q_SLOTS:
void checkBuildPropertyMappings()
{
// GIVEN
+ QFETCH(Handler *, handler);
QFETCH(QVector<ChannelMapping *>, channelMappings);
QFETCH(QVector<ChannelNameAndType>, channelNamesAndTypes);
QFETCH(QVector<ComponentIndices>, channelComponentIndices);
@@ -426,6 +536,7 @@ private Q_SLOTS:
const auto expectedMapping = expectedResults[i];
QCOMPARE(actualMapping.targetId, expectedMapping.targetId);
+ QCOMPARE(actualMapping.jointIndex, expectedMapping.jointIndex);
QCOMPARE(actualMapping.propertyName, expectedMapping.propertyName);
QCOMPARE(actualMapping.type, expectedMapping.type);
QCOMPARE(actualMapping.channelIndices.size(), expectedMapping.channelIndices.size());
@@ -433,338 +544,142 @@ private Q_SLOTS:
QCOMPARE(actualMapping.channelIndices[j], expectedMapping.channelIndices[j]);
}
}
+
+ // Cleanup
+ delete handler;
}
- void checkLocalTimeFromGlobalTime_data()
+ void checkLocalTimeFromElapsedTime_data()
{
- QTest::addColumn<double>("globalTime");
- QTest::addColumn<double>("globalStartTime");
+ QTest::addColumn<double>("elapsedTime");
+ QTest::addColumn<double>("currentTime");
QTest::addColumn<double>("playbackRate");
QTest::addColumn<double>("duration");
QTest::addColumn<int>("loopCount");
+ QTest::addColumn<int>("currentLoop");
QTest::addColumn<double>("expectedLocalTime");
QTest::addColumn<int>("expectedCurrentLoop");
- double globalTime;
- double globalStartTime;
+ double elapsedTime;
+ double currentTime;
double playbackRate;
double duration;
int loopCount;
+ int currentLoop;
double expectedLocalTime;
int expectedCurrentLoop;
- globalTime = 0.0;
- globalStartTime = 0.0;
+ elapsedTime = 0.0;
+ currentTime = 0.0;
playbackRate = 1.0;
duration = 1.0;
loopCount = 1;
+ currentLoop = 0;
expectedLocalTime = 0.0;
expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 0")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ QTest::newRow("simple, t_current = 0, t_elapsed = 0, loop_current = 0")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
- globalTime = 0.5;
- globalStartTime = 0.0;
+ elapsedTime = 0.5;
+ currentTime = 0.0;
playbackRate = 1.0;
duration = 1.0;
loopCount = 1;
+ currentLoop = 0;
expectedLocalTime = 0.5;
expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 0.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ QTest::newRow("simple, t_current = 0, t_elapsed = 0.5, loop_current = 0")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
- globalTime = 1.0;
- globalStartTime = 0.0;
+ elapsedTime = 1.5;
+ currentTime = 0.0;
playbackRate = 1.0;
duration = 1.0;
loopCount = 1;
+ currentLoop = 0;
expectedLocalTime = 1.0;
expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 1.0")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedLocalTime << expectedCurrentLoop;
-
- globalTime = -0.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 1;
- expectedLocalTime = 0.0;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = -0.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ QTest::newRow("simple, t_current = 0, t_elapsed = 1.5, loop_current = 0")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
- globalTime = 1.5;
- globalStartTime = 0.0;
+ elapsedTime = 0.5;
+ currentTime = 0.6;
playbackRate = 1.0;
duration = 1.0;
loopCount = 1;
+ currentLoop = 0;
expectedLocalTime = 1.0;
expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 1.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ QTest::newRow("simple, t_current = 0.5, t_elapsed = 0.6, loop_current = 0")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
- globalTime = 0.5;
- globalStartTime = 0.0;
+ elapsedTime = 0.5;
+ currentTime = 0.6;
playbackRate = 1.0;
duration = 1.0;
loopCount = 2;
- expectedLocalTime = 0.5;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, loopCount = 2, t_global = 0.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedLocalTime << expectedCurrentLoop;
-
- globalTime = 1.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 2;
- expectedLocalTime = 0.5;
+ currentLoop = 0;
+ expectedLocalTime = 0.1;
expectedCurrentLoop = 1;
- QTest::newRow("simple, loopCount = 2, t_global = 1.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ QTest::newRow("simple, t_current = 0.5, t_elapsed = 0.6, loop_current = 0, loop_count = 2")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
- globalTime = 3.5;
- globalStartTime = 0.0;
+ elapsedTime = 0.5;
+ currentTime = 0.6;
playbackRate = 1.0;
- duration = 2.0;
- loopCount = 2;
- expectedLocalTime = 1.5;
- expectedCurrentLoop = 1;
- QTest::newRow("duration = 2, loopCount = 2, t_global = 3.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedLocalTime << expectedCurrentLoop;
-
- globalTime = 4.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 2.0;
+ duration = 1.0;
loopCount = 2;
- expectedLocalTime = 2.0;
- expectedCurrentLoop = 1;
- QTest::newRow("duration = 2, loopCount = 2, t_global = 4.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ currentLoop = 1;
+ expectedLocalTime = 1.0;
+ expectedCurrentLoop = 1; // We clamp at end of final loop
+ QTest::newRow("simple, t_current = 0.5, t_elapsed = 0.6, loop_current = 1, loop_count = 2")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
- globalTime = 1.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
+ elapsedTime = 0.5;
+ currentTime = 0.6;
+ playbackRate = 0.1;
duration = 1.0;
- loopCount = -1;
- expectedLocalTime = 0.5;
+ loopCount = 2;
+ currentLoop = 1;
+ expectedLocalTime = 0.65;
expectedCurrentLoop = 1;
- QTest::newRow("simple, loopCount = inf, t_global = 1.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedLocalTime << expectedCurrentLoop;
-
- globalTime = 10.2;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = -1;
- expectedLocalTime = 0.2;
- expectedCurrentLoop = 10;
- QTest::newRow("simple, loopCount = inf, t_global = 10.2")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
+ QTest::newRow("simple, t_current = 0.5, t_elapsed = 0.6, loop_current = 1, loop_count = 2")
+ << elapsedTime << currentTime << playbackRate << duration << loopCount << currentLoop
<< expectedLocalTime << expectedCurrentLoop;
}
- void checkLocalTimeFromGlobalTime()
+ void checkLocalTimeFromElapsedTime()
{
// GIVEN
- QFETCH(double, globalTime);
- QFETCH(double, globalStartTime);
+ QFETCH(double, elapsedTime);
+ QFETCH(double, currentTime);
QFETCH(double, playbackRate);
QFETCH(double, duration);
QFETCH(int, loopCount);
+ QFETCH(int, currentLoop);
QFETCH(double, expectedLocalTime);
QFETCH(int, expectedCurrentLoop);
// WHEN
- int actualCurrentLoop = 0;
- double actualLocalTime = localTimeFromGlobalTime(globalTime,
- globalStartTime,
- playbackRate,
- duration,
- loopCount,
- actualCurrentLoop);
+ int actualCurrentLoop = currentLoop;
+ double actualLocalTime = localTimeFromElapsedTime(currentTime,
+ elapsedTime,
+ playbackRate,
+ duration,
+ loopCount,
+ actualCurrentLoop);
// THEN
QCOMPARE(actualCurrentLoop, expectedCurrentLoop);
QCOMPARE(actualLocalTime, expectedLocalTime);
}
- void checkPhaseFromGlobalTime_data()
- {
- QTest::addColumn<double>("globalTime");
- QTest::addColumn<double>("globalStartTime");
- QTest::addColumn<double>("playbackRate");
- QTest::addColumn<double>("duration");
- QTest::addColumn<int>("loopCount");
- QTest::addColumn<double>("expectedPhase");
- QTest::addColumn<int>("expectedCurrentLoop");
-
- double globalTime;
- double globalStartTime;
- double playbackRate;
- double duration;
- int loopCount;
- double expectedPhase;
- int expectedCurrentLoop;
-
- globalTime = 0.0;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 1;
- expectedPhase = 0.0;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 0")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 0.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 1;
- expectedPhase = 0.5;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 0.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 1.0;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 1;
- expectedPhase = 1.0;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 1.0")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = -0.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 1;
- expectedPhase = 0.0;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = -0.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 1.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 1;
- expectedPhase = 1.0;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, t_global = 1.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 0.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 2;
- expectedPhase = 0.5;
- expectedCurrentLoop = 0;
- QTest::newRow("simple, loopCount = 2, t_global = 0.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 1.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = 2;
- expectedPhase = 0.5;
- expectedCurrentLoop = 1;
- QTest::newRow("simple, loopCount = 2, t_global = 1.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 3.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 2.0;
- loopCount = 2;
- expectedPhase = 0.75;
- expectedCurrentLoop = 1;
- QTest::newRow("duration = 2, loopCount = 2, t_global = 3.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 4.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 2.0;
- loopCount = 2;
- expectedPhase = 1.0;
- expectedCurrentLoop = 1;
- QTest::newRow("duration = 2, loopCount = 2, t_global = 4.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 1.5;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = -1;
- expectedPhase = 0.5;
- expectedCurrentLoop = 1;
- QTest::newRow("simple, loopCount = inf, t_global = 1.5")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
-
- globalTime = 10.2;
- globalStartTime = 0.0;
- playbackRate = 1.0;
- duration = 1.0;
- loopCount = -1;
- expectedPhase = 0.2;
- expectedCurrentLoop = 10;
- QTest::newRow("simple, loopCount = inf, t_global = 10.2")
- << globalTime << globalStartTime << playbackRate << duration << loopCount
- << expectedPhase << expectedCurrentLoop;
- }
-
- void checkPhaseFromGlobalTime()
- {
- // GIVEN
- QFETCH(double, globalTime);
- QFETCH(double, globalStartTime);
- QFETCH(double, playbackRate);
- QFETCH(double, duration);
- QFETCH(int, loopCount);
- QFETCH(double, expectedPhase);
- QFETCH(int, expectedCurrentLoop);
-
- // WHEN
- int actualCurrentLoop = 0;
- double actualPhase = phaseFromGlobalTime(globalTime,
- globalStartTime,
- playbackRate,
- duration,
- loopCount,
- actualCurrentLoop);
-
- // THEN
- QCOMPARE(actualCurrentLoop, expectedCurrentLoop);
- QCOMPARE(actualPhase, expectedPhase);
- }
-
void checkPreparePropertyChanges_data()
{
QTest::addColumn<Qt3DCore::QNodeId>("animatorId");
@@ -1034,6 +949,117 @@ private Q_SLOTS:
}
}
+ void checkPrepareCallbacks_data()
+ {
+ QTest::addColumn<QVector<MappingData>>("mappingData");
+ QTest::addColumn<QVector<float>>("channelResults");
+ QTest::addColumn<QVector<AnimationCallbackAndValue> >("expectedValues");
+
+ QVector<MappingData> mappingData;
+ QVector<float> channelResults;
+ QVector<AnimationCallbackAndValue> expectedValues;
+
+ // vec3
+ {
+ DummyCallback callback; // safe since the object is never used, just the address
+ MappingData mapping;
+ mapping.targetId = Qt3DCore::QNodeId::createId();
+ mapping.propertyName = "translation";
+ mapping.type = static_cast<int>(QVariant::Vector3D);
+ mapping.channelIndices = QVector<int>() << 0 << 1 << 2;
+ mapping.callback = &callback;
+ mapping.callbackFlags = 0;
+ mappingData.push_back(mapping);
+ channelResults = QVector<float>() << 1.0f << 2.0f << 3.0f;
+
+ AnimationCallbackAndValue cbv;
+ cbv.callback = mapping.callback;
+ cbv.flags = mapping.callbackFlags;
+ cbv.value = QVariant::fromValue<QVector3D>(QVector3D(1.0f, 2.0f, 3.0f));
+ expectedValues.push_back(cbv);
+
+ QTest::newRow("vec3 translation, no flags") << mappingData << channelResults << expectedValues;
+
+ mappingData.clear();
+ channelResults.clear();
+ expectedValues.clear();
+ }
+
+ // double
+ {
+ DummyCallback callback;
+ MappingData mapping;
+ mapping.targetId = Qt3DCore::QNodeId::createId();
+ mapping.propertyName = "something";
+ mapping.type = static_cast<int>(QVariant::Double);
+ mapping.channelIndices = QVector<int>() << 0;
+ mapping.callback = &callback;
+ mapping.callbackFlags = 0;
+ mappingData.push_back(mapping);
+ channelResults = QVector<float>() << 1.0f;
+
+ AnimationCallbackAndValue cbv;
+ cbv.callback = mapping.callback;
+ cbv.flags = mapping.callbackFlags;
+ cbv.value = QVariant(double(1.0));
+ expectedValues.push_back(cbv);
+
+ QTest::newRow("double, no flags") << mappingData << channelResults << expectedValues;
+
+ mappingData.clear();
+ channelResults.clear();
+ expectedValues.clear();
+ }
+
+ // float, set a flag
+ {
+ DummyCallback callback;
+ MappingData mapping;
+ mapping.targetId = Qt3DCore::QNodeId::createId();
+ mapping.propertyName = "opacity";
+ mapping.type = static_cast<int>(QMetaType::Float);
+ mapping.channelIndices = QVector<int>() << 0;
+ mapping.callback = &callback;
+ mapping.callbackFlags = Qt3DAnimation::QAnimationCallback::OnThreadPool;
+ mappingData.push_back(mapping);
+ channelResults = QVector<float>() << 0.5f;
+
+ AnimationCallbackAndValue cbv;
+ cbv.callback = mapping.callback;
+ cbv.flags = mapping.callbackFlags;
+ cbv.value = QVariant(float(0.5f));
+ expectedValues.push_back(cbv);
+
+ QTest::newRow("float, OnThreadPool") << mappingData << channelResults << expectedValues;
+
+ mappingData.clear();
+ channelResults.clear();
+ expectedValues.clear();
+ }
+ }
+
+ void checkPrepareCallbacks()
+ {
+ // GIVEN
+ QFETCH(QVector<MappingData>, mappingData);
+ QFETCH(QVector<float>, channelResults);
+ QFETCH(QVector<AnimationCallbackAndValue>, expectedValues);
+
+ // WHEN
+ QVector<AnimationCallbackAndValue> callbacks = prepareCallbacks(mappingData, channelResults);
+
+ // THEN
+ QCOMPARE(callbacks.size(), expectedValues.size());
+ for (int i = 0; i < callbacks.size(); ++i) {
+ auto expected = expectedValues[i];
+ auto actual = callbacks[i];
+
+ QCOMPARE(actual.callback, expected.callback);
+ QCOMPARE(actual.flags, expected.flags);
+ QCOMPARE(actual.value, expected.value);
+ }
+ }
+
void checkEvaluateClipAtLocalTime_data()
{
QTest::addColumn<Handler *>("handler");
@@ -1284,6 +1310,31 @@ private Q_SLOTS:
QVector<char> suffixes;
QVector<int> expectedResults;
+ // already sorted vec3, no component names, with and without offset
+ {
+ channel = Channel();
+ channel.name = QLatin1String("Location");
+ channel.channelComponents.resize(3);
+ // leave 'name' empty
+
+ dataType = static_cast<int>(QVariant::Vector3D);
+ offset = 0;
+ // suffixes expected to be ignored
+ expectedResults = (QVector<int>() << 0 << 1 << 2);
+
+ QTest::newRow("vec3 location, pre-sorted, no component names, offset = 0")
+ << channel << dataType << offset << suffixes << expectedResults;
+
+ expectedResults.clear();
+
+ offset = 4;
+ expectedResults = (QVector<int>() << 4 << 5 << 6);
+ QTest::newRow("vec3 location, pre-sorted, no component names, offset = 4")
+ << channel << dataType << offset << suffixes << expectedResults;
+
+ expectedResults.clear();
+ }
+
// vec3 with and without offset
{
channel = Channel();
@@ -1622,6 +1673,7 @@ private Q_SLOTS:
AnimationClip *clip;
AnimatorEvaluationData animatorData;
ClipEvaluationData clipData;
+ auto* clock = new Clock;
{
handler = new Handler();
@@ -1629,11 +1681,13 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 1;
auto animator = createClipAnimator(handler, globalStartTimeNS, loops);
- const qint64 globalTimeNS = 0;
- animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere
+ animator->setCurrentLoop(0);
+ clipData.currentLoop = animator->currentLoop();
+ const qint64 elapsedTimeNS = 0;
+ animatorData = evaluationDataForAnimator(animator, clock, elapsedTimeNS); // Tested elsewhere
- clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime,
- animatorData.startTime,
+ clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime,
+ animatorData.elapsedTime,
animatorData.playbackRate,
clip->duration(),
animatorData.loopCount,
@@ -1650,18 +1704,20 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 1;
auto animator = createClipAnimator(handler, globalStartTimeNS, loops);
- const qint64 globalTimeNS = (clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip
- animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere
+ animator->setCurrentLoop(0);
+ clipData.currentLoop = animator->currentLoop();
+ const qint64 elapsedTimeNS = (clip->duration()+1)*1e09; // +1 to ensure beyond end
+ animatorData = evaluationDataForAnimator(animator, nullptr, elapsedTimeNS); // Tested elsewhere
- clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime,
- animatorData.startTime,
+ clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime,
+ animatorData.elapsedTime,
animatorData.playbackRate,
clip->duration(),
animatorData.loopCount,
clipData.currentLoop); // Tested elsewhere
clipData.isFinalFrame = true;
- QTest::newRow("clip1.json, globalTime = duration")
+ QTest::newRow("clip1.json, elapsedTime = duration + 1")
<< handler << clip << animatorData << clipData;
}
@@ -1671,18 +1727,43 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 0; // Infinite loops
auto animator = createClipAnimator(handler, globalStartTimeNS, loops);
- const qint64 globalTimeNS = 2.0 * clip->duration() * 1.0e9;
- animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere
+ animator->setCurrentLoop(0);
+ clipData.currentLoop = animator->currentLoop();
+ const qint64 elapsedTimeNS = 2.0 * clip->duration() * 1.0e9;
+ animatorData = evaluationDataForAnimator(animator, clock, elapsedTimeNS); // Tested elsewhere
- clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime,
- animatorData.startTime,
+ clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime,
+ animatorData.elapsedTime,
animatorData.playbackRate,
clip->duration(),
animatorData.loopCount,
clipData.currentLoop); // Tested elsewhere
clipData.isFinalFrame = false;
- QTest::newRow("clip1.json, globalTime = 2 * duration, loops = infinite")
+ QTest::newRow("clip1.json, elapsedTime = 2 * duration, loops = infinite")
+ << handler << clip << animatorData << clipData;
+ }
+
+ {
+ handler = new Handler();
+ clip = createAnimationClipLoader(handler, QUrl("qrc:/clip1.json"));
+ const qint64 globalStartTimeNS = 0;
+ const int loops = 2;
+ auto animator = createClipAnimator(handler, globalStartTimeNS, loops);
+ animator->setCurrentLoop(0);
+ clipData.currentLoop = animator->currentLoop();
+ const qint64 elapsedTimeNS = (2.0 * clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip
+ animatorData = evaluationDataForAnimator(animator, nullptr, elapsedTimeNS); // Tested elsewhere
+
+ clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime,
+ animatorData.elapsedTime,
+ animatorData.playbackRate,
+ clip->duration(),
+ animatorData.loopCount,
+ clipData.currentLoop); // Tested elsewhere
+ clipData.isFinalFrame = true;
+
+ QTest::newRow("clip1.json, elapsedTime = 2 * duration + 1, loops = 2")
<< handler << clip << animatorData << clipData;
}
@@ -1692,18 +1773,20 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 2;
auto animator = createClipAnimator(handler, globalStartTimeNS, loops);
- const qint64 globalTimeNS = (2.0 * clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip
- animatorData = evaluationDataForAnimator(animator, globalTimeNS); // Tested elsewhere
+ animator->setCurrentLoop(1);
+ clipData.currentLoop = animator->currentLoop();
+ const qint64 elapsedTimeNS = (clip->duration() + 1.0) * 1.0e9; // +1 to ensure beyond end of clip
+ animatorData = evaluationDataForAnimator(animator, nullptr, elapsedTimeNS); // Tested elsewhere
- clipData.localTime = localTimeFromGlobalTime(animatorData.globalTime,
- animatorData.startTime,
+ clipData.localTime = localTimeFromElapsedTime(animatorData.currentTime,
+ animatorData.elapsedTime,
animatorData.playbackRate,
clip->duration(),
animatorData.loopCount,
clipData.currentLoop); // Tested elsewhere
clipData.isFinalFrame = true;
- QTest::newRow("clip1.json, globalTime = 2 * duration + 1, loops = 2")
+ QTest::newRow("clip1.json, elapsedTime = duration + 1, loops = 2, current_loop = 1")
<< handler << clip << animatorData << clipData;
}
}
@@ -1732,12 +1815,12 @@ private Q_SLOTS:
{
QTest::addColumn<Handler *>("handler");
QTest::addColumn<ClipAnimator *>("animator");
- QTest::addColumn<qint64>("globalTimeNS");
+ QTest::addColumn<qint64>("elapsedTime");
QTest::addColumn<AnimatorEvaluationData>("expectedAnimatorData");
Handler *handler;
ClipAnimator *animator;
- qint64 globalTimeNS;
+ qint64 elapsedTimeNS;
AnimatorEvaluationData expectedAnimatorData;
{
@@ -1745,15 +1828,14 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 1;
animator = createClipAnimator(handler, globalStartTimeNS, loops);
- globalTimeNS = 0;
+ elapsedTimeNS = 0;
expectedAnimatorData.loopCount = loops;
expectedAnimatorData.playbackRate = 1.0; // hard-wired for now
- expectedAnimatorData.startTime = 0.0;
- expectedAnimatorData.globalTime = 0.0;
+ expectedAnimatorData.elapsedTime = 0.0;
- QTest::newRow("globalStartTime = 0, globalTime = 0, loops = 1")
- << handler << animator << globalTimeNS << expectedAnimatorData;
+ QTest::newRow("globalStartTime = 0, elapsedTime = 0, loops = 1")
+ << handler << animator << elapsedTimeNS << expectedAnimatorData;
}
{
@@ -1761,15 +1843,14 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 5;
animator = createClipAnimator(handler, globalStartTimeNS, loops);
- globalTimeNS = 0;
+ elapsedTimeNS = 0;
expectedAnimatorData.loopCount = loops;
expectedAnimatorData.playbackRate = 1.0; // hard-wired for now
- expectedAnimatorData.startTime = 0.0;
- expectedAnimatorData.globalTime = 0.0;
+ expectedAnimatorData.elapsedTime = 0.0;
- QTest::newRow("globalStartTime = 0, globalTime = 0, loops = 5")
- << handler << animator << globalTimeNS << expectedAnimatorData;
+ QTest::newRow("globalStartTime = 0, elapsedTime = 0, loops = 5")
+ << handler << animator << elapsedTimeNS << expectedAnimatorData;
}
{
@@ -1777,15 +1858,14 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 0;
const int loops = 1;
animator = createClipAnimator(handler, globalStartTimeNS, loops);
- globalTimeNS = 5000000000;
+ elapsedTimeNS = 5000000000;
expectedAnimatorData.loopCount = loops;
expectedAnimatorData.playbackRate = 1.0; // hard-wired for now
- expectedAnimatorData.startTime = 0.0;
- expectedAnimatorData.globalTime = 5.0;
+ expectedAnimatorData.elapsedTime = 5.0;
- QTest::newRow("globalStartTime = 0, globalTime = 5, loops = 1")
- << handler << animator << globalTimeNS << expectedAnimatorData;
+ QTest::newRow("globalStartTime = 0, elapsedTime = 5, loops = 1")
+ << handler << animator << elapsedTimeNS << expectedAnimatorData;
}
{
@@ -1793,15 +1873,14 @@ private Q_SLOTS:
const qint64 globalStartTimeNS = 3000000000;
const int loops = 1;
animator = createClipAnimator(handler, globalStartTimeNS, loops);
- globalTimeNS = 5000000000;
+ elapsedTimeNS = 2000000000;
expectedAnimatorData.loopCount = loops;
expectedAnimatorData.playbackRate = 1.0; // hard-wired for now
- expectedAnimatorData.startTime = 3.0;
- expectedAnimatorData.globalTime = 5.0;
+ expectedAnimatorData.elapsedTime = 2.0;
- QTest::newRow("globalStartTime = 3, globalTime = 5, loops = 1")
- << handler << animator << globalTimeNS << expectedAnimatorData;
+ QTest::newRow("globalStartTime = 3, elapsedTime = 2, loops = 1")
+ << handler << animator << elapsedTimeNS << expectedAnimatorData;
}
}
@@ -1810,17 +1889,16 @@ private Q_SLOTS:
// GIVEN
QFETCH(Handler *, handler);
QFETCH(ClipAnimator *, animator);
- QFETCH(qint64, globalTimeNS);
+ QFETCH(qint64, elapsedTime);
QFETCH(AnimatorEvaluationData, expectedAnimatorData);
// WHEN
- AnimatorEvaluationData actualAnimatorData = evaluationDataForAnimator(animator, globalTimeNS);
+ AnimatorEvaluationData actualAnimatorData = evaluationDataForAnimator(animator, nullptr, elapsedTime);
// THEN
QCOMPARE(actualAnimatorData.loopCount, expectedAnimatorData.loopCount);
QVERIFY(fuzzyCompare(actualAnimatorData.playbackRate, expectedAnimatorData.playbackRate) == true);
- QVERIFY(fuzzyCompare(actualAnimatorData.startTime, expectedAnimatorData.startTime) == true);
- QVERIFY(fuzzyCompare(actualAnimatorData.globalTime, expectedAnimatorData.globalTime) == true);
+ QVERIFY(fuzzyCompare(actualAnimatorData.elapsedTime, expectedAnimatorData.elapsedTime) == true);
// Cleanup
delete handler;
@@ -2304,6 +2382,27 @@ private Q_SLOTS:
QTest::addRow("Multiple channels with repeats") << handler << channelMapper << expectedResults;
}
+
+ {
+ auto handler = new Handler();
+ const int jointCount = 10;
+ auto skeleton = createSkeleton(handler, jointCount);
+ auto channelMapping = createChannelMapping(handler, skeleton->peerId());
+ QVector<ChannelMapping *> channelMappings;
+ channelMappings.push_back(channelMapping);
+
+ auto channelMapper = createChannelMapper(handler,
+ QVector<Qt3DCore::QNodeId>() << channelMapping->peerId());
+
+ QVector<ChannelNameAndType> expectedResults;
+ for (int i = 0; i < jointCount; ++i) {
+ expectedResults.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D), i });
+ expectedResults.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion), i });
+ expectedResults.push_back({ QLatin1String("Scale"), static_cast<int>(QVariant::Vector3D), i });
+ }
+
+ QTest::addRow("Skeleton, 10 joints") << handler << channelMapper << expectedResults;
+ }
}
void checkBuildRequiredChannelsAndTypes()
@@ -2369,6 +2468,35 @@ private Q_SLOTS:
QTest::newRow("vec3 location, quaterion rotation, pbr metal-rough") << allChannels << expectedResults;
}
+
+ {
+ QVector<ChannelNameAndType> allChannels;
+ const int jointCount = 4;
+ for (int i = 0; i < jointCount; ++i) {
+ allChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D), i });
+ allChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion), i });
+ allChannels.push_back({ QLatin1String("Scale"), static_cast<int>(QVariant::Vector3D), i });
+ }
+
+ QVector<ComponentIndices> expectedResults;
+ expectedResults.push_back({ 0, 1, 2 });
+ expectedResults.push_back({ 3, 4, 5, 6 });
+ expectedResults.push_back({ 7, 8, 9 });
+
+ expectedResults.push_back({ 10, 11, 12 });
+ expectedResults.push_back({ 13, 14, 15, 16 });
+ expectedResults.push_back({ 17, 18, 19 });
+
+ expectedResults.push_back({ 20, 21, 22 });
+ expectedResults.push_back({ 23, 24, 25, 26 });
+ expectedResults.push_back({ 27, 28, 29 });
+
+ expectedResults.push_back({ 30, 31, 32 });
+ expectedResults.push_back({ 33, 34, 35, 36 });
+ expectedResults.push_back({ 37, 38, 39 });
+
+ QTest::newRow("skeleton, 4 joints") << allChannels << expectedResults;
+ }
}
void checkAssignChannelComponentIndices()
@@ -2517,6 +2645,54 @@ private Q_SLOTS:
QTest::newRow("location, rotation, albedo (missing), metal-rough")
<< targetChannels << targetIndices << clip << expectedResults;
}
+
+ {
+ QVector<ChannelNameAndType> targetChannels;
+ const int jointCount = 4;
+ for (int i = 0; i < jointCount; ++i) {
+ targetChannels.push_back({ QLatin1String("Location"), static_cast<int>(QVariant::Vector3D), i });
+ targetChannels.push_back({ QLatin1String("Rotation"), static_cast<int>(QVariant::Quaternion), i });
+ targetChannels.push_back({ QLatin1String("Scale"), static_cast<int>(QVariant::Vector3D), i });
+ }
+
+ QVector<ComponentIndices> targetIndices;
+ targetIndices.push_back({ 0, 1, 2 });
+ targetIndices.push_back({ 3, 4, 5, 6 });
+ targetIndices.push_back({ 7, 8, 9 });
+
+ targetIndices.push_back({ 10, 11, 12 });
+ targetIndices.push_back({ 13, 14, 15, 16 });
+ targetIndices.push_back({ 17, 18, 19 });
+
+ targetIndices.push_back({ 20, 21, 22 });
+ targetIndices.push_back({ 23, 24, 25, 26 });
+ targetIndices.push_back({ 27, 28, 29 });
+
+ targetIndices.push_back({ 30, 31, 32 });
+ targetIndices.push_back({ 33, 34, 35, 36 });
+ targetIndices.push_back({ 37, 38, 39 });
+
+ auto *clip = new AnimationClip();
+ clip->setDataType(AnimationClip::File);
+ clip->setSource(QUrl("qrc:/clip5.json"));
+ clip->loadAnimation();
+
+ ComponentIndices expectedResults = { 4, 6, 5, // Location, joint 0 (y/z swapped in clip5.json)
+ 0, 1, 3, 2, // Rotation, joint 0 (y/z swapped in clip5.json)
+ 7, 8, 9, // Scale, joint 0
+ 14, 16, 15, // Location, joint 1 (y/z swapped in clip5.json)
+ 10, 11, 13, 12, // Rotation, joint 1 (y/z swapped in clip5.json)
+ 17, 18, 19, // Scale, joint 1
+ 24, 26, 25, // Location, joint 2 (y/z swapped in clip5.json)
+ 20, 21, 23, 22, // Rotation, joint 2 (y/z swapped in clip5.json)
+ 27, 28, 29, // Scale, joint 2
+ 34, 36, 35, // Location, joint 3 (y/z swapped in clip5.json)
+ 30, 31, 33, 32, // Rotation, joint 3 (y/z swapped in clip5.json)
+ 37, 38, 39 }; // Scale, joint 3
+
+ QTest::newRow("skeleton (SQT), 4 joints")
+ << targetChannels << targetIndices << clip << expectedResults;
+ }
}
void checkGenerateClipFormatIndices()
diff --git a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp
index 3265de167..c0e1581f9 100644
--- a/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp
+++ b/tests/auto/animation/blendedclipanimator/tst_blendedclipanimator.cpp
@@ -63,7 +63,8 @@ private Q_SLOTS:
QCOMPARE(backendBlendedClipAnimator.blendTreeRootId(), Qt3DCore::QNodeId());
QCOMPARE(backendBlendedClipAnimator.mapperId(), Qt3DCore::QNodeId());
QCOMPARE(backendBlendedClipAnimator.isRunning(), false);
- QCOMPARE(backendBlendedClipAnimator.startTime(), 0);
+ QCOMPARE(backendBlendedClipAnimator.lastLocalTime(), 0.0);
+ QCOMPARE(backendBlendedClipAnimator.nsSincePreviousFrame(0), 0);
QCOMPARE(backendBlendedClipAnimator.currentLoop(), 0);
QCOMPARE(backendBlendedClipAnimator.loops(), 1);
@@ -82,6 +83,7 @@ private Q_SLOTS:
backendBlendedClipAnimator.setMapperId(Qt3DCore::QNodeId::createId());
backendBlendedClipAnimator.setRunning(true);
backendBlendedClipAnimator.setStartTime(28);
+ backendBlendedClipAnimator.setLastLocalTime(0.28);
backendBlendedClipAnimator.cleanup();
// THEN
@@ -89,7 +91,8 @@ private Q_SLOTS:
QCOMPARE(backendBlendedClipAnimator.blendTreeRootId(), Qt3DCore::QNodeId());
QCOMPARE(backendBlendedClipAnimator.mapperId(), Qt3DCore::QNodeId());
QCOMPARE(backendBlendedClipAnimator.isRunning(), false);
- QCOMPARE(backendBlendedClipAnimator.startTime(), 0);
+ QCOMPARE(backendBlendedClipAnimator.lastLocalTime(), 0.0);
+ QCOMPARE(backendBlendedClipAnimator.nsSincePreviousFrame(0), 0);
QCOMPARE(backendBlendedClipAnimator.currentLoop(), 0);
QCOMPARE(backendBlendedClipAnimator.loops(), 1);
}
diff --git a/tests/auto/animation/channelmapping/tst_channelmapping.cpp b/tests/auto/animation/channelmapping/tst_channelmapping.cpp
index 478406336..a947d4a2d 100644
--- a/tests/auto/animation/channelmapping/tst_channelmapping.cpp
+++ b/tests/auto/animation/channelmapping/tst_channelmapping.cpp
@@ -31,8 +31,10 @@
#include <Qt3DAnimation/private/handler_p.h>
#include <Qt3DAnimation/private/channelmapping_p.h>
#include <Qt3DAnimation/qchannelmapping.h>
+#include <Qt3DAnimation/qskeletonmapping.h>
#include <Qt3DAnimation/private/qchannelmapping_p.h>
#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/qskeleton.h>
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
@@ -66,6 +68,23 @@ private Q_SLOTS:
QCOMPARE(backendMapping.channelName(), mapping.channelName());
QCOMPARE(backendMapping.targetId(), mapping.target()->id());
QCOMPARE(backendMapping.property(), mapping.property());
+ QCOMPARE(backendMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::ChannelMappingType);
+
+ // GIVEN
+ Qt3DAnimation::Animation::ChannelMapping backendSkeletonMapping;
+ backendSkeletonMapping.setHandler(&handler);
+ Qt3DAnimation::QSkeletonMapping skeletonMapping;
+ auto skeleton = new Qt3DCore::QSkeleton;
+ skeletonMapping.setSkeleton(skeleton);
+
+ // WHEN
+ simulateInitialization(&skeletonMapping, &backendSkeletonMapping);
+
+ // THEN
+ QCOMPARE(backendSkeletonMapping.peerId(), skeletonMapping.id());
+ QCOMPARE(backendSkeletonMapping.isEnabled(), skeletonMapping.isEnabled());
+ QCOMPARE(backendSkeletonMapping.skeletonId(), skeletonMapping.skeleton()->id());
+ QCOMPARE(backendSkeletonMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::SkeletonMappingType);
}
void checkInitialAndCleanedUpState()
@@ -81,6 +100,8 @@ private Q_SLOTS:
QCOMPARE(backendMapping.channelName(), QString());
QCOMPARE(backendMapping.targetId(), Qt3DCore::QNodeId());
QCOMPARE(backendMapping.property(), QString());
+ QCOMPARE(backendMapping.skeletonId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::ChannelMappingType);
// GIVEN
Qt3DAnimation::QChannelMapping mapping;
@@ -91,6 +112,7 @@ private Q_SLOTS:
// WHEN
simulateInitialization(&mapping, &backendMapping);
+ backendMapping.setSkeletonId(Qt3DCore::QNodeId::createId());
backendMapping.cleanup();
// THEN
@@ -98,6 +120,8 @@ private Q_SLOTS:
QCOMPARE(backendMapping.channelName(), QString());
QCOMPARE(backendMapping.targetId(), Qt3DCore::QNodeId());
QCOMPARE(backendMapping.property(), QString());
+ QCOMPARE(backendMapping.skeletonId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendMapping.mappingType(), Qt3DAnimation::Animation::ChannelMapping::ChannelMappingType);
}
void checkPropertyChanges()
@@ -146,6 +170,16 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendMapping.property(), property);
+
+ // WHEN
+ const auto skeletonId = Qt3DCore::QNodeId::createId();
+ updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
+ updateChange->setPropertyName("skeleton");
+ updateChange->setValue(QVariant::fromValue(skeletonId));
+ backendMapping.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendMapping.skeletonId(), skeletonId);
}
};
diff --git a/tests/auto/animation/clipanimator/tst_clipanimator.cpp b/tests/auto/animation/clipanimator/tst_clipanimator.cpp
index e837a2a82..168cba050 100644
--- a/tests/auto/animation/clipanimator/tst_clipanimator.cpp
+++ b/tests/auto/animation/clipanimator/tst_clipanimator.cpp
@@ -30,6 +30,7 @@
#include <Qt3DAnimation/private/clipanimator_p.h>
#include <Qt3DAnimation/qanimationcliploader.h>
#include <Qt3DAnimation/qclipanimator.h>
+#include <Qt3DAnimation/qclock.h>
#include <Qt3DCore/private/qnode_p.h>
#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
@@ -50,8 +51,10 @@ private Q_SLOTS:
backendAnimator.setHandler(&handler);
Qt3DAnimation::QClipAnimator animator;
auto clip = new Qt3DAnimation::QAnimationClipLoader();
+ auto clock = new Qt3DAnimation::QClock();
animator.setClip(clip);
+ animator.setClock(clock);
animator.setLoopCount(10);
// WHEN
@@ -61,6 +64,7 @@ private Q_SLOTS:
QCOMPARE(backendAnimator.peerId(), animator.id());
QCOMPARE(backendAnimator.isEnabled(), animator.isEnabled());
QCOMPARE(backendAnimator.clipId(), clip->id());
+ QCOMPARE(backendAnimator.clockId(), clock->id());
QCOMPARE(backendAnimator.isRunning(), animator.isRunning());
QCOMPARE(backendAnimator.loops(), animator.loopCount());
}
@@ -76,23 +80,28 @@ private Q_SLOTS:
QVERIFY(backendAnimator.peerId().isNull());
QCOMPARE(backendAnimator.isEnabled(), false);
QCOMPARE(backendAnimator.clipId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendAnimator.clockId(), Qt3DCore::QNodeId());
QCOMPARE(backendAnimator.isRunning(), false);
QCOMPARE(backendAnimator.loops(), 1);
// GIVEN
Qt3DAnimation::QClipAnimator animator;
auto clip = new Qt3DAnimation::QAnimationClipLoader();
+ auto clock = new Qt3DAnimation::QClock();
animator.setClip(clip);
+ animator.setClock(clock);
animator.setRunning(true);
animator.setLoopCount(25);
// WHEN
simulateInitialization(&animator, &backendAnimator);
backendAnimator.setClipId(Qt3DCore::QNodeId::createId());
+ backendAnimator.setClockId(Qt3DCore::QNodeId::createId());
backendAnimator.cleanup();
// THEN
QCOMPARE(backendAnimator.clipId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendAnimator.clockId(), Qt3DCore::QNodeId());
QCOMPARE(backendAnimator.isEnabled(), false);
QCOMPARE(backendAnimator.isRunning(), false);
QCOMPARE(backendAnimator.loops(), 1);
@@ -126,6 +135,16 @@ private Q_SLOTS:
QCOMPARE(backendAnimator.clipId(), newClip->id());
// WHEN
+ auto clock = new Qt3DAnimation::QClock();
+ updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
+ updateChange->setPropertyName("clock");
+ updateChange->setValue(QVariant::fromValue(clock->id()));
+ backendAnimator.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendAnimator.clockId(), clock->id());
+
+ // WHEN
updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
updateChange->setPropertyName("running");
updateChange->setValue(true);
diff --git a/tests/auto/animation/clock/clock.pro b/tests/auto/animation/clock/clock.pro
new file mode 100644
index 000000000..26b7a4b21
--- /dev/null
+++ b/tests/auto/animation/clock/clock.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_clock
+
+QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_clock.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/animation/clock/tst_clock.cpp b/tests/auto/animation/clock/tst_clock.cpp
new file mode 100644
index 000000000..a81adfe7b
--- /dev/null
+++ b/tests/auto/animation/clock/tst_clock.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DAnimation/qclock.h>
+#include <Qt3DAnimation/private/clock_p.h>
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include <qbackendnodetester.h>
+#include <testpostmanarbiter.h>
+
+class tst_Clock: public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ Qt3DAnimation::Animation::Clock backendClock;
+ Qt3DAnimation::QClock clock;
+
+ clock.setPlaybackRate(10.5);
+
+ // WHEN
+ simulateInitialization(&clock, &backendClock);
+
+ // THEN
+ QCOMPARE(backendClock.playbackRate(), clock.playbackRate());
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ Qt3DAnimation::Animation::Clock backendClock;
+
+ // THEN
+ QCOMPARE(backendClock.playbackRate(), 1.0);
+
+ // GIVEN
+ Qt3DAnimation::QClock clock;
+ clock.setPlaybackRate(10.5);
+
+ // WHEN
+ simulateInitialization(&clock, &backendClock);
+ backendClock.cleanup();
+
+ // THEN
+ QCOMPARE(backendClock.playbackRate(), 1.0);
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DAnimation::Animation::Clock backendClock;
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendClock.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendClock.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const double newPlaybackRateValue = 2.0;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("playbackRate");
+ change->setValue(newPlaybackRateValue);
+ backendClock.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendClock.playbackRate(), newPlaybackRateValue);
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Clock)
+
+#include "tst_clock.moc"
diff --git a/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp b/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp
index 79d18b7cf..ce37ffc76 100644
--- a/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp
+++ b/tests/auto/animation/findrunningclipanimatorsjob/tst_findrunningclipanimatorsjob.cpp
@@ -72,6 +72,7 @@ public:
channelMapping->setPropertyName(propertyName);
channelMapping->setChannelName(channelName);
channelMapping->setType(type);
+ channelMapping->setMappingType(ChannelMapping::ChannelMappingType);
return channelMapping;
}
diff --git a/tests/auto/animation/qcallbackmapping/qcallbackmapping.pro b/tests/auto/animation/qcallbackmapping/qcallbackmapping.pro
new file mode 100644
index 000000000..2ec002878
--- /dev/null
+++ b/tests/auto/animation/qcallbackmapping/qcallbackmapping.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qcallbackmapping
+
+QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_qcallbackmapping.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp b/tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp
new file mode 100644
index 000000000..6a1c8da8c
--- /dev/null
+++ b/tests/auto/animation/qcallbackmapping/tst_qcallbackmapping.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DAnimation/qcallbackmapping.h>
+#include <Qt3DAnimation/private/qcallbackmapping_p.h>
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <testpostmanarbiter.h>
+
+class DummyCallback : public Qt3DAnimation::QAnimationCallback
+{
+public:
+ void valueChanged(const QVariant &) override { }
+};
+
+class tst_QCallbackMapping : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DAnimation::QCallbackMapping mapping;
+
+ // THEN
+ QCOMPARE(mapping.channelName(), QString());
+ QCOMPARE(mapping.callback(), static_cast<Qt3DAnimation::QAnimationCallback *>(nullptr));
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DAnimation::QCallbackMapping mapping;
+
+ {
+ // WHEN
+ QSignalSpy spy(&mapping, SIGNAL(channelNameChanged(QString)));
+ const QString newValue(QStringLiteral("Rotation"));
+ mapping.setChannelName(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(mapping.channelName(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ mapping.setChannelName(newValue);
+
+ // THEN
+ QCOMPARE(mapping.channelName(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ auto newValue = new DummyCallback();
+ mapping.setCallback(QVariant::Quaternion, newValue);
+
+ // THEN - no signals for callback
+ QCOMPARE(mapping.callback(), newValue);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DAnimation::QCallbackMapping mapping;
+ auto callback = new DummyCallback();
+
+ mapping.setChannelName(QStringLiteral("Location"));
+ mapping.setCallback(QVariant::Vector3D, callback);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QCallbackMappingData>>(creationChanges.first());
+ const Qt3DAnimation::QCallbackMappingData data = creationChangeData->data;
+
+ QCOMPARE(mapping.id(), creationChangeData->subjectId());
+ QCOMPARE(mapping.isEnabled(), true);
+ QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::CallbackMapping);
+ QCOMPARE(mapping.channelName(), data.channelName);
+ QCOMPARE(mapping.callback(), data.callback);
+ QCOMPARE(QVariant::Vector3D, data.type);
+ }
+
+ // WHEN
+ mapping.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QCallbackMappingData>>(creationChanges.first());
+ const Qt3DAnimation::QCallbackMappingData data = creationChangeData->data;
+
+ QCOMPARE(mapping.id(), creationChangeData->subjectId());
+ QCOMPARE(mapping.isEnabled(), false);
+ QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::CallbackMapping);
+ QCOMPARE(mapping.channelName(), data.channelName);
+ QCOMPARE(mapping.callback(), data.callback);
+ QCOMPARE(QVariant::Vector3D, data.type);
+ }
+ }
+
+ void checkPropertyUpdateChanges()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DAnimation::QCallbackMapping mapping;
+ arbiter.setArbiterOnNode(&mapping);
+
+ {
+ // WHEN
+ mapping.setChannelName(QStringLiteral("Scale"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "channelName");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().toString(), mapping.channelName());
+
+ arbiter.events.clear();
+
+ // WHEN
+ mapping.setChannelName(QStringLiteral("Scale"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ {
+ // WHEN
+ auto callback = new DummyCallback();
+ mapping.setCallback(QVariant::Vector3D, callback, Qt3DAnimation::QAnimationCallback::OnThreadPool);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 3);
+ auto change = arbiter.events.at(0).staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "type");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().toInt(), QVariant::Vector3D);
+
+ change = arbiter.events.at(1).staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "callback");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(reinterpret_cast<DummyCallback *>(change->value().value<void *>()), callback);
+
+ change = arbiter.events.at(2).staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "callbackFlags");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().toInt(), static_cast<int>(Qt3DAnimation::QAnimationCallback::OnThreadPool));
+
+ arbiter.events.clear();
+
+ // WHEN
+ mapping.setCallback(QVariant::Vector3D, callback, Qt3DAnimation::QAnimationCallback::OnThreadPool);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+};
+
+QTEST_MAIN(tst_QCallbackMapping)
+
+#include "tst_qcallbackmapping.moc"
diff --git a/tests/auto/animation/qchannelmapping/tst_qchannelmapping.cpp b/tests/auto/animation/qchannelmapping/tst_qchannelmapping.cpp
index 9d356de4c..cab5fda6f 100644
--- a/tests/auto/animation/qchannelmapping/tst_qchannelmapping.cpp
+++ b/tests/auto/animation/qchannelmapping/tst_qchannelmapping.cpp
@@ -29,6 +29,7 @@
#include <QtTest/QTest>
#include <Qt3DAnimation/qchannelmapping.h>
#include <Qt3DAnimation/private/qchannelmapping_p.h>
+#include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qnodecreatedchange.h>
@@ -142,13 +143,14 @@ private Q_SLOTS:
{
QCOMPARE(creationChanges.size(), 2); // 1 for mapping, 1 for target
- const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QChannelMappingData>>(creationChanges.first());
+ const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QChannelMappingData>>(creationChanges.first());
const Qt3DAnimation::QChannelMappingData data = creationChangeData->data;
QCOMPARE(mapping.id(), creationChangeData->subjectId());
QCOMPARE(mapping.isEnabled(), true);
QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::ChannelMapping);
QCOMPARE(mapping.channelName(), data.channelName);
QCOMPARE(mapping.target()->id(), data.targetId);
QCOMPARE(mapping.property(), data.property);
@@ -166,13 +168,14 @@ private Q_SLOTS:
{
QCOMPARE(creationChanges.size(), 2); // 1 for mapping, 1 for target
- const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QChannelMappingData>>(creationChanges.first());
+ const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QChannelMappingData>>(creationChanges.first());
const Qt3DAnimation::QChannelMappingData data = creationChangeData->data;
QCOMPARE(mapping.id(), creationChangeData->subjectId());
QCOMPARE(mapping.isEnabled(), false);
QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::ChannelMapping);
QCOMPARE(mapping.channelName(), data.channelName);
QCOMPARE(mapping.target()->id(), data.targetId);
QCOMPARE(mapping.property(), data.property);
diff --git a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp
index 1ed4b8f13..6a46b7008 100644
--- a/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp
+++ b/tests/auto/animation/qclipanimator/tst_qclipanimator.cpp
@@ -30,6 +30,7 @@
#include <QtTest/QTest>
#include <Qt3DAnimation/qanimationcliploader.h>
#include <Qt3DAnimation/qchannelmapper.h>
+#include <Qt3DAnimation/qclock.h>
#include <Qt3DAnimation/qclipanimator.h>
#include <Qt3DAnimation/private/qanimationclip_p.h>
#include <Qt3DAnimation/private/qclipanimator_p.h>
@@ -49,6 +50,7 @@ private Q_SLOTS:
{
qRegisterMetaType<Qt3DAnimation::QAbstractAnimationClip*>();
qRegisterMetaType<Qt3DAnimation::QChannelMapper*>();
+ qRegisterMetaType<Qt3DAnimation::QClock*>();
}
void checkDefaultConstruction()
@@ -59,6 +61,7 @@ private Q_SLOTS:
// THEN
QCOMPARE(animator.clip(), static_cast<Qt3DAnimation::QAbstractAnimationClip *>(nullptr));
QCOMPARE(animator.channelMapper(), static_cast<Qt3DAnimation::QChannelMapper *>(nullptr));
+ QCOMPARE(animator.clock(), static_cast<Qt3DAnimation::QClock*>(nullptr));
QCOMPARE(animator.loopCount(), 1);
}
@@ -111,6 +114,27 @@ private Q_SLOTS:
{
// WHEN
+ QSignalSpy spy(&animator, SIGNAL(clockChanged(Qt3DAnimation::QClock *)));
+ auto clock = new Qt3DAnimation::QClock();
+ animator.setClock(clock);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(animator.clock(), clock);
+ QCOMPARE(clock->parent(), &animator);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ animator.setClock(clock);
+
+ // THEN
+ QCOMPARE(animator.clock(), clock);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
QSignalSpy spy(&animator, SIGNAL(loopCountChanged(int)));
const int newValue = 5;
animator.setLoopCount(newValue);
@@ -138,6 +162,8 @@ private Q_SLOTS:
animator.setClip(clip);
auto mapper = new Qt3DAnimation::QChannelMapper();
animator.setChannelMapper(mapper);
+ auto clock = new Qt3DAnimation::QClock();
+ animator.setClock(clock);
// WHEN
QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
@@ -148,7 +174,7 @@ private Q_SLOTS:
// THEN
{
- QCOMPARE(creationChanges.size(), 3);
+ QCOMPARE(creationChanges.size(), 4);
const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QClipAnimatorData>>(creationChanges.first());
const Qt3DAnimation::QClipAnimatorData data = creationChangeData->data;
@@ -159,6 +185,7 @@ private Q_SLOTS:
QCOMPARE(animator.metaObject(), creationChangeData->metaObject());
QCOMPARE(animator.clip()->id(), data.clipId);
QCOMPARE(animator.channelMapper()->id(), data.mapperId);
+ QCOMPARE(animator.clock()->id(), data.clockId);
QCOMPARE(animator.loopCount(), data.loops);
}
@@ -171,7 +198,7 @@ private Q_SLOTS:
// THEN
{
- QCOMPARE(creationChanges.size(), 3);
+ QCOMPARE(creationChanges.size(), 4);
const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QClipAnimatorData>>(creationChanges.first());
@@ -240,6 +267,32 @@ private Q_SLOTS:
QCOMPARE(arbiter.events.size(), 0);
}
+ // GIVEN
+ auto clock = new Qt3DAnimation::QClock;
+ {
+ // WHEN
+ animator.setClock(clock);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "clock");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), clock->id());
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ animator.setClock(clock);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
{
// WHEN
animator.setLoopCount(10);
diff --git a/tests/auto/animation/qclock/qclock.pro b/tests/auto/animation/qclock/qclock.pro
new file mode 100644
index 000000000..2b1194860
--- /dev/null
+++ b/tests/auto/animation/qclock/qclock.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qclock
+
+QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_qclock.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/animation/qclock/tst_qclock.cpp b/tests/auto/animation/qclock/tst_qclock.cpp
new file mode 100644
index 000000000..34c70da7b
--- /dev/null
+++ b/tests/auto/animation/qclock/tst_qclock.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DAnimation/qclock.h>
+#include <Qt3DAnimation/private/qclock_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <testpostmanarbiter.h>
+
+class tst_QClock : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DAnimation::QClock*>();
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DAnimation::QClock clock;
+
+ // THEN
+ QCOMPARE(clock.playbackRate(), 1.0);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DAnimation::QClock clock;
+
+ // WHEN
+ QSignalSpy spy(&clock, SIGNAL(playbackRateChanged(double)));
+ const double newValue = 5.5;
+ clock.setPlaybackRate(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(clock.playbackRate(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ clock.setPlaybackRate(newValue);
+
+ // THEN
+ QCOMPARE(clock.playbackRate(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DAnimation::QClock clock;
+ clock.setPlaybackRate(10.f);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clock);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QClockData>>(creationChanges.first());
+ const Qt3DAnimation::QClockData data = creationChangeData->data;
+
+ QCOMPARE(clock.id(), creationChangeData->subjectId());
+ QCOMPARE(clock.isEnabled(), true);
+ QCOMPARE(clock.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(clock.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(clock.playbackRate(), data.playbackRate);
+ }
+
+ // WHEN
+ clock.setEnabled(false);
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&clock);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DAnimation::QClockData>>(creationChanges.first());
+
+ QCOMPARE(clock.id(), creationChangeData->subjectId());
+ QCOMPARE(clock.isEnabled(), false);
+ QCOMPARE(clock.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(clock.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkPropertyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DAnimation::QClock clock;
+ arbiter.setArbiterOnNode(&clock);
+
+ {
+ // WHEN
+ clock.setPlaybackRate(10.5);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "playbackRate");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<double>(), clock.playbackRate());
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ clock.setPlaybackRate(10.5f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+};
+
+QTEST_MAIN(tst_QClock)
+
+#include "tst_qclock.moc"
diff --git a/tests/auto/animation/qskeletonmapping/qskeletonmapping.pro b/tests/auto/animation/qskeletonmapping/qskeletonmapping.pro
new file mode 100644
index 000000000..c00252557
--- /dev/null
+++ b/tests/auto/animation/qskeletonmapping/qskeletonmapping.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qskeletonmapping
+
+QT += 3dcore 3dcore-private 3danimation 3danimation-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_qskeletonmapping.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/animation/qskeletonmapping/tst_qskeletonmapping.cpp b/tests/auto/animation/qskeletonmapping/tst_qskeletonmapping.cpp
new file mode 100644
index 000000000..452292e9e
--- /dev/null
+++ b/tests/auto/animation/qskeletonmapping/tst_qskeletonmapping.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DAnimation/qskeletonmapping.h>
+#include <Qt3DAnimation/private/qskeletonmapping_p.h>
+#include <Qt3DCore/qskeleton.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qentity.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <testpostmanarbiter.h>
+
+class tst_QSkeletonMapping : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void initTestCase()
+ {
+ qRegisterMetaType<Qt3DCore::QAbstractSkeleton*>();
+ }
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DAnimation::QSkeletonMapping mapping;
+
+ // THEN
+ QCOMPARE(mapping.skeleton(), static_cast<Qt3DCore::QAbstractSkeleton *>(nullptr));
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DAnimation::QSkeletonMapping mapping;
+
+ {
+ // WHEN
+ QSignalSpy spy(&mapping, SIGNAL(skeletonChanged(Qt3DCore::QAbstractSkeleton*)));
+ auto newValue = new Qt3DCore::QSkeleton();
+ mapping.setSkeleton(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(mapping.skeleton(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ mapping.setSkeleton(newValue);
+
+ // THEN
+ QCOMPARE(mapping.skeleton(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DAnimation::QSkeletonMapping mapping;
+ auto target = new Qt3DCore::QSkeleton;
+
+ mapping.setSkeleton(target);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // 1 for mapping, 1 for skeleton
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QSkeletonMappingData>>(creationChanges.first());
+ const Qt3DAnimation::QSkeletonMappingData data = creationChangeData->data;
+
+ QCOMPARE(mapping.id(), creationChangeData->subjectId());
+ QCOMPARE(mapping.isEnabled(), true);
+ QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::SkeletonMapping);
+ QCOMPARE(mapping.skeleton()->id(), data.skeletonId);
+ }
+
+ // WHEN
+ mapping.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&mapping);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // 1 for mapping, 1 for skeleton
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DAnimation::QChannelMappingCreatedChange<Qt3DAnimation::QSkeletonMappingData>>(creationChanges.first());
+ const Qt3DAnimation::QSkeletonMappingData data = creationChangeData->data;
+
+ QCOMPARE(mapping.id(), creationChangeData->subjectId());
+ QCOMPARE(mapping.isEnabled(), false);
+ QCOMPARE(mapping.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(mapping.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(creationChangeData->type(), Qt3DAnimation::QChannelMappingCreatedChangeBase::SkeletonMapping);
+ QCOMPARE(mapping.skeleton()->id(), data.skeletonId);
+ }
+ }
+
+ void checkPropertyUpdateChanges()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DAnimation::QSkeletonMapping mapping;
+ arbiter.setArbiterOnNode(&mapping);
+
+ {
+ // WHEN
+ auto target = new Qt3DCore::QSkeleton();
+ mapping.setSkeleton(target);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "skeleton");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), mapping.skeleton()->id());
+
+ arbiter.events.clear();
+
+ // WHEN
+ mapping.setSkeleton(target);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+};
+
+QTEST_MAIN(tst_QSkeletonMapping)
+
+#include "tst_qskeletonmapping.moc"
diff --git a/tests/auto/animation/skeleton/skeleton.pro b/tests/auto/animation/skeleton/skeleton.pro
new file mode 100644
index 000000000..b36278bdf
--- /dev/null
+++ b/tests/auto/animation/skeleton/skeleton.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_skeleton
+
+QT += core-private 3dcore 3dcore-private 3danimation 3danimation-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_skeleton.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/animation/skeleton/tst_skeleton.cpp b/tests/auto/animation/skeleton/tst_skeleton.cpp
new file mode 100644
index 000000000..9e3cfef6d
--- /dev/null
+++ b/tests/auto/animation/skeleton/tst_skeleton.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qskeleton.h>
+#include <Qt3DAnimation/private/skeleton_p.h>
+#include <Qt3DAnimation/private/handler_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include <qbackendnodetester.h>
+#include <testpostmanarbiter.h>
+
+using namespace Qt3DCore;
+using namespace Qt3DAnimation;
+using namespace Qt3DAnimation::Animation;
+
+class tst_Skeleton : public QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ Handler handler;
+ Skeleton backendSkeleton;
+ backendSkeleton.setHandler(&handler);
+ QSkeleton skeleton;
+ auto rootJoint = new QJoint();
+ rootJoint->setName(QLatin1String("rootJoint"));
+ auto childJoint = new QJoint();
+ childJoint->setName(QLatin1String("childJoint"));
+ rootJoint->addChildJoint(childJoint);
+ skeleton.setRootJoint(rootJoint);
+
+ // WHEN
+ simulateInitialization(&skeleton, &backendSkeleton);
+
+ // THEN - nothing mirrored from frontend
+ QCOMPARE(backendSkeleton.peerId(), skeleton.id());
+ QCOMPARE(backendSkeleton.isEnabled(), skeleton.isEnabled());
+ QCOMPARE(backendSkeleton.jointNames().size(), 0);
+ QCOMPARE(backendSkeleton.jointLocalPoses().size(), 0);
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ Handler handler;
+ Skeleton backendSkeleton;
+ backendSkeleton.setHandler(&handler);
+
+ // THEN
+ QVERIFY(backendSkeleton.peerId().isNull());
+ QCOMPARE(backendSkeleton.isEnabled(), false);
+ QCOMPARE(backendSkeleton.jointNames().size(), 0);
+ QCOMPARE(backendSkeleton.jointLocalPoses().size(), 0);
+
+ // GIVEN
+ const QVector<QString> names = (QVector<QString>()
+ << QLatin1String("root")
+ << QLatin1String("child1")
+ << QLatin1String("child2"));
+ const QVector<Sqt> localPoses = (QVector<Sqt>() << Sqt() << Sqt() << Sqt());
+
+ // WHEN
+ backendSkeleton.setJointNames(names);
+ backendSkeleton.setJointLocalPoses(localPoses);
+ backendSkeleton.cleanup();
+
+ // THEN
+ QCOMPARE(backendSkeleton.isEnabled(), false);
+ QCOMPARE(backendSkeleton.jointNames().size(), 0);
+ QCOMPARE(backendSkeleton.jointLocalPoses().size(), 0);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Handler handler;
+ Skeleton backendSkeleton;
+ backendSkeleton.setHandler(&handler);
+ QPropertyUpdatedChangePtr updateChange;
+
+ // WHEN
+ updateChange = QPropertyUpdatedChangePtr::create(QNodeId());
+ updateChange->setPropertyName("enabled");
+ updateChange->setValue(true);
+ backendSkeleton.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendSkeleton.isEnabled(), true);
+
+ // GIVEN
+ const QVector<QString> names = (QVector<QString>()
+ << QLatin1String("root")
+ << QLatin1String("child1")
+ << QLatin1String("child2"));
+ const QVector<Sqt> localPoses = (QVector<Sqt>() << Sqt() << Sqt() << Sqt());
+
+ // WHEN
+ JointNamesAndLocalPoses namesAndPoses;
+ namesAndPoses.names = names;
+ namesAndPoses.localPoses = localPoses;
+
+ updateChange = QPropertyUpdatedChangePtr::create(QNodeId());
+ updateChange->setPropertyName("jointNamesAndLocalPoses");
+ updateChange->setValue(QVariant::fromValue(namesAndPoses));
+ backendSkeleton.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendSkeleton.jointNames(), names);
+ QCOMPARE(backendSkeleton.jointLocalPoses(), localPoses);
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Skeleton)
+
+#include "tst_skeleton.moc"
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index cc7e5590a..2d7ec9cb3 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -3,15 +3,17 @@ TEMPLATE = subdirs
SUBDIRS = \
coretest \
core \
- render \
- quick3d \
- cmake \
- input \
- animation \
- extras
+ cmake
installed_cmake.depends = cmake
+QT_FOR_CONFIG += 3dcore
+qtConfig(qt3d-render): SUBDIRS += render
+qtConfig(qt3d-input): SUBDIRS += input
+qtConfig(qt3d-animation): SUBDIRS += animation
+qtConfig(qt3d-extras): SUBDIRS += extras
+qtConfig(qt3d-render):qtConfig(qt3d-input): SUBDIRS += quick3d
+
for(subdir, SUBDIRS) {
!equals(subdir, coretest) {
$${subdir}.depends += coretest
diff --git a/tests/auto/core/aspectcommanddebugger/tst_aspectcommanddebugger.cpp b/tests/auto/core/aspectcommanddebugger/tst_aspectcommanddebugger.cpp
index 1bcaced2c..f13fa2e03 100644
--- a/tests/auto/core/aspectcommanddebugger/tst_aspectcommanddebugger.cpp
+++ b/tests/auto/core/aspectcommanddebugger/tst_aspectcommanddebugger.cpp
@@ -29,16 +29,13 @@
#include <QtTest/QTest>
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
-#ifdef QT3D_JOBS_RUN_STATS
using namespace Qt3DCore::Debug;
-#endif
class tst_AspectCommandDebugger : public QObject
{
Q_OBJECT
private slots:
-#ifdef QT3D_JOBS_RUN_STATS
void checkReadBufferInitialState()
{
// GIVEN
@@ -92,7 +89,6 @@ private slots:
QCOMPARE(buffer.size(), 16 * 1024);
QCOMPARE(hugeFakeData, QByteArray(buffer.buffer.constData(), 1024 * 16));
}
-#endif
};
QTEST_APPLESS_MAIN(tst_AspectCommandDebugger)
diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro
index 3595755d6..25440ce0e 100644
--- a/tests/auto/core/core.pro
+++ b/tests/auto/core/core.pro
@@ -11,14 +11,27 @@ SUBDIRS = \
qaspectjob \
qchangearbiter \
qscene \
- qservicelocator
+ qservicelocator \
+ qjoint \
+ qskeletonloader \
+ qskeleton \
+ qarmature
qtConfig(private_tests) {
SUBDIRS += \
- qentity \
- qframeallocator \
- qtransform \
- threadpooler \
- aspectcommanddebugger \
- qpostman
+ qentity \
+ qframeallocator \
+ qtransform \
+ threadpooler \
+ qpostman \
+ vector4d_base \
+ vector3d_base
+
+ QT_FOR_CONFIG += 3dcore-private
+ qtConfig(qt3d-profile-jobs): SUBDIRS += aspectcommanddebugger
+ qtConfig(qt3d-simd-sse2) {
+ SUBDIRS += \
+ vector4d_sse \
+ vector3d_sse
+ }
}
diff --git a/tests/auto/core/qarmature/qarmature.pro b/tests/auto/core/qarmature/qarmature.pro
new file mode 100644
index 000000000..1d4769310
--- /dev/null
+++ b/tests/auto/core/qarmature/qarmature.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qarmature
+
+QT += core-private 3dcore 3dcore-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qarmature.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/core/qarmature/tst_qarmature.cpp b/tests/auto/core/qarmature/tst_qarmature.cpp
new file mode 100644
index 000000000..f624b998f
--- /dev/null
+++ b/tests/auto/core/qarmature/tst_qarmature.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** 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: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/qarmature.h>
+#include <Qt3DCore/private/qarmature_p.h>
+#include <Qt3DCore/qskeleton.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+
+#include "testpostmanarbiter.h"
+
+using namespace Qt3DCore;
+
+class tst_QArmature: public QObject
+{
+ Q_OBJECT
+public:
+ tst_QArmature()
+ {
+ qRegisterMetaType<Qt3DCore::QAbstractSkeleton*>();
+ }
+
+private Q_SLOTS:
+
+ void checkCreationChange_data()
+ {
+ QTest::addColumn<QArmature *>("armature");
+
+ QArmature *defaultConstructed = new QArmature();
+ QTest::newRow("defaultConstructed") << defaultConstructed;
+
+ QArmature *armatureWithSkeleton = new QArmature();
+ armatureWithSkeleton->setSkeleton(new QSkeleton());
+ QTest::newRow("skeletonWithOneJoint") << armatureWithSkeleton;
+ }
+
+ void checkCreationChange()
+ {
+ // GIVEN
+ QFETCH(QArmature *, armature);
+
+ // WHEN
+ QNodeCreatedChangeGenerator creationChangeGenerator(armature);
+ QVector<QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges();
+
+ const int skeletonCount = armature->skeleton() ? 1 : 0;
+
+ // THEN
+ QCOMPARE(creationChanges.size(), 1 + skeletonCount);
+
+ const auto creationChangeData = qSharedPointerCast<QNodeCreatedChange<QArmatureData>>(creationChanges.first());
+ const QArmatureData &data = creationChangeData->data;
+
+ // THEN
+ QCOMPARE(armature->id(), creationChangeData->subjectId());
+ QCOMPARE(armature->isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(armature->metaObject(), creationChangeData->metaObject());
+ if (armature->skeleton()) {
+ QCOMPARE(armature->skeleton()->id(), data.skeletonId);
+ }
+ }
+
+ void checkPropertyUpdates()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ QScopedPointer<QArmature> armature(new QArmature());
+ arbiter.setArbiterOnNode(armature.data());
+
+ // WHEN
+ QSkeleton *skeleton = new QSkeleton(armature.data());
+ QCoreApplication::processEvents();
+ arbiter.events.clear();
+
+ armature->setSkeleton(skeleton);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "skeleton");
+ QCOMPARE(change->value().value<QNodeId>(), skeleton->id());
+ QCOMPARE(change->type(), PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ armature->setSkeleton(nullptr);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "skeleton");
+ QCOMPARE(change->value().value<QNodeId>(), QNodeId());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ void checkSkeletonBookkeeping()
+ {
+ // GIVEN
+ QScopedPointer<QArmature> armature(new QArmature);
+ {
+ // WHEN
+ QSkeleton skeleton;
+ armature->setSkeleton(&skeleton);
+
+ // THEN
+ QCOMPARE(skeleton.parent(), armature.data());
+ QCOMPARE(armature->skeleton(), &skeleton);
+ }
+ // THEN (Should not crash and parameter be unset)
+ QVERIFY(armature->skeleton() == nullptr);
+
+ {
+ // WHEN
+ QArmature someOtherArmature;
+ QScopedPointer<QSkeleton> skeleton(new QSkeleton(&someOtherArmature));
+ armature->setSkeleton(skeleton.data());
+
+ // THEN
+ QCOMPARE(skeleton->parent(), &someOtherArmature);
+ QCOMPARE(armature->skeleton(), skeleton.data());
+
+ // WHEN
+ armature.reset();
+ skeleton.reset();
+
+ // THEN Should not crash when the joint is destroyed (tests for failed removal of destruction helper)
+ }
+ }
+};
+
+QTEST_MAIN(tst_QArmature)
+
+#include "tst_qarmature.moc"
diff --git a/tests/auto/core/qjoint/qjoint.pro b/tests/auto/core/qjoint/qjoint.pro
new file mode 100644
index 000000000..e25d57102
--- /dev/null
+++ b/tests/auto/core/qjoint/qjoint.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qjoint
+
+QT += 3dcore 3dcore-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_qjoint.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/core/qjoint/tst_qjoint.cpp b/tests/auto/core/qjoint/tst_qjoint.cpp
new file mode 100644
index 000000000..ec1a45f90
--- /dev/null
+++ b/tests/auto/core/qjoint/tst_qjoint.cpp
@@ -0,0 +1,413 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/private/qjoint_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <testpostmanarbiter.h>
+
+using namespace Qt3DCore;
+
+class tst_QJoint : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ QJoint joint;
+
+ // THEN
+ QCOMPARE(joint.scale(), QVector3D(1.0f, 1.0f, 1.0f));
+ QCOMPARE(joint.rotation(), QQuaternion());
+ QCOMPARE(joint.translation(), QVector3D(0.0f, 0.0f, 0.0f));
+ QCOMPARE(joint.inverseBindMatrix(), QMatrix4x4());
+ QCOMPARE(joint.rotationX(), 0.0f);
+ QCOMPARE(joint.rotationY(), 0.0f);
+ QCOMPARE(joint.rotationZ(), 0.0f);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ QJoint joint;
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(scaleChanged(QVector3D)));
+ const QVector3D newValue(2.5f, 2.0f, 1.3f);
+ joint.setScale(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(joint.scale(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ joint.setScale(newValue);
+
+ // THEN
+ QCOMPARE(joint.scale(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(rotationChanged(QQuaternion)));
+ const auto newValue = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 45.0f);
+ joint.setRotation(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(joint.rotation(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ joint.setRotation(newValue);
+
+ // THEN
+ QCOMPARE(joint.rotation(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(translationChanged(QVector3D)));
+ const QVector3D newValue(1.0f, 2.0f, 3.0f);
+ joint.setTranslation(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(joint.translation(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ joint.setTranslation(newValue);
+
+ // THEN
+ QCOMPARE(joint.translation(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(inverseBindMatrixChanged(QMatrix4x4)));
+ QMatrix4x4 newValue;
+ newValue.scale(3.5f);
+ joint.setInverseBindMatrix(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(joint.inverseBindMatrix(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ joint.setInverseBindMatrix(newValue);
+
+ // THEN
+ QCOMPARE(joint.inverseBindMatrix(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(rotationChanged(QQuaternion)));
+ QSignalSpy spyEuler(&joint, SIGNAL(rotationXChanged(float)));
+ const auto newValue = 45.0f;
+ const auto newValueAsQuaternion = QQuaternion::fromEulerAngles(newValue, 0.0f, 0.0f);
+ joint.setRotationX(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QVERIFY(spyEuler.isValid());
+ QCOMPARE(joint.rotationX(), newValue);
+ QCOMPARE(joint.rotation(), newValueAsQuaternion);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spyEuler.count(), 1);
+
+ // WHEN
+ spy.clear();
+ spyEuler.clear();
+ joint.setRotationX(newValue);
+
+ // THEN
+ QCOMPARE(joint.rotationX(), newValue);
+ QCOMPARE(joint.rotation(), newValueAsQuaternion);
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(spyEuler.count(), 0);
+
+ joint.setRotationX(0.0f);
+ }
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(rotationChanged(QQuaternion)));
+ QSignalSpy spyEuler(&joint, SIGNAL(rotationYChanged(float)));
+ const auto newValue = 45.0f;
+ const auto newValueAsQuaternion = QQuaternion::fromEulerAngles(0.0f, newValue, 0.0f);
+ joint.setRotationY(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QVERIFY(spyEuler.isValid());
+ QCOMPARE(joint.rotationY(), newValue);
+ QCOMPARE(joint.rotation(), newValueAsQuaternion);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spyEuler.count(), 1);
+
+ // WHEN
+ spy.clear();
+ spyEuler.clear();
+ joint.setRotationY(newValue);
+
+ // THEN
+ QCOMPARE(joint.rotationY(), newValue);
+ QCOMPARE(joint.rotation(), newValueAsQuaternion);
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(spyEuler.count(), 0);
+
+ joint.setRotationY(0.0f);
+ }
+
+ {
+ // WHEN
+ joint.setToIdentity();
+ QSignalSpy spy(&joint, SIGNAL(rotationChanged(QQuaternion)));
+ QSignalSpy spyEuler(&joint, SIGNAL(rotationZChanged(float)));
+ const auto newValue = 45.0f;
+ const auto newValueAsQuaternion = QQuaternion::fromEulerAngles(0.0f, 0.0f, newValue);
+ joint.setRotationZ(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QVERIFY(spyEuler.isValid());
+ QCOMPARE(joint.rotationZ(), newValue);
+ QCOMPARE(joint.rotation(), newValueAsQuaternion);
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(spyEuler.count(), 1);
+
+ // WHEN
+ spy.clear();
+ spyEuler.clear();
+ joint.setRotationZ(newValue);
+
+ // THEN
+ QCOMPARE(joint.rotationZ(), newValue);
+ QCOMPARE(joint.rotation(), newValueAsQuaternion);
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(spyEuler.count(), 0);
+
+ joint.setRotationZ(0.0f);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ QJoint joint;
+
+ joint.setScale(QVector3D(3.5f, 2.0f, 1.3f));
+ joint.setRotation(QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 30.0f));
+ joint.setTranslation(QVector3D(3.0f, 2.0f, 1.0f));
+ QMatrix4x4 ibm;
+ ibm.scale(5.2f);
+ joint.setInverseBindMatrix(ibm);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&joint);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData
+ = qSharedPointerCast<QNodeCreatedChange<QJointData>>(creationChanges.first());
+ const QJointData data = creationChangeData->data;
+
+ QCOMPARE(joint.id(), creationChangeData->subjectId());
+ QCOMPARE(joint.isEnabled(), true);
+ QCOMPARE(joint.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(joint.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(joint.scale(), data.scale);
+ QCOMPARE(joint.rotation(), data.rotation);
+ QCOMPARE(joint.translation(), data.translation);
+ QCOMPARE(joint.inverseBindMatrix(), data.inverseBindMatrix);
+ }
+
+ // WHEN
+ joint.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&joint);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData
+ = qSharedPointerCast<QNodeCreatedChange<QJointData>>(creationChanges.first());
+ const QJointData data = creationChangeData->data;
+
+ QCOMPARE(joint.id(), creationChangeData->subjectId());
+ QCOMPARE(joint.isEnabled(), false);
+ QCOMPARE(joint.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(joint.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(joint.scale(), data.scale);
+ QCOMPARE(joint.rotation(), data.rotation);
+ QCOMPARE(joint.translation(), data.translation);
+ QCOMPARE(joint.inverseBindMatrix(), data.inverseBindMatrix);
+ }
+ }
+
+ void checkPropertyUpdateChanges()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ QJoint joint;
+ arbiter.setArbiterOnNode(&joint);
+
+ {
+ // WHEN
+ joint.setScale(QVector3D(2.0f, 1.0f, 3.0f));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "scale");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<QVector3D>(), joint.scale());
+
+ arbiter.events.clear();
+
+ // WHEN
+ joint.setScale(QVector3D(2.0f, 1.0f, 3.0f));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ {
+ // WHEN
+ const auto newValue = QQuaternion::fromAxisAndAngle(1.0f, 1.0f, 1.0f, 45.0f);
+ joint.setRotation(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "rotation");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<QQuaternion>(), newValue);
+
+ arbiter.events.clear();
+
+ // WHEN
+ joint.setRotation(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ {
+ // WHEN
+ const QVector3D newValue(1.0f, 2.0f, 3.0f);
+ joint.setTranslation(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "translation");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<QVector3D>(), newValue);
+
+ arbiter.events.clear();
+
+ // WHEN
+ joint.setTranslation(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ {
+ // WHEN
+ QMatrix4x4 newValue;
+ newValue.rotate(90.0f, 1.0f, 0.0f, 0.0f);
+ joint.setInverseBindMatrix(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "inverseBindMatrix");
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+ QCOMPARE(change->value().value<QMatrix4x4>(), newValue);
+
+ arbiter.events.clear();
+
+ // WHEN
+ joint.setInverseBindMatrix(newValue);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+};
+
+QTEST_MAIN(tst_QJoint)
+
+#include "tst_qjoint.moc"
diff --git a/tests/auto/core/qskeleton/qskeleton.pro b/tests/auto/core/qskeleton/qskeleton.pro
new file mode 100644
index 000000000..3bbb48a3c
--- /dev/null
+++ b/tests/auto/core/qskeleton/qskeleton.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qskeleton
+
+QT += core-private 3dcore 3dcore-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qskeleton.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/core/qskeleton/tst_qskeleton.cpp b/tests/auto/core/qskeleton/tst_qskeleton.cpp
new file mode 100644
index 000000000..f66e07cbe
--- /dev/null
+++ b/tests/auto/core/qskeleton/tst_qskeleton.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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: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/qskeleton.h>
+#include <Qt3DCore/private/qskeleton_p.h>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+
+#include <QSignalSpy>
+#include <testpostmanarbiter.h>
+
+using namespace Qt3DCore;
+
+class tst_QSkeleton: public QSkeleton
+{
+ Q_OBJECT
+public:
+ tst_QSkeleton()
+ {
+ qRegisterMetaType<Qt3DCore::QJoint*>();
+ }
+
+private Q_SLOTS:
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ QSkeleton skeleton;
+
+ // THEN
+ QCOMPARE(skeleton.jointCount(), 0);
+ }
+
+ void checkCreationChange_data()
+ {
+ QTest::addColumn<QSkeleton *>("skeleton");
+
+ QSkeleton *defaultConstructed = new QSkeleton();
+ QTest::newRow("defaultConstructed") << defaultConstructed;
+
+ QSkeleton *skeletonWithOneJoint = new QSkeleton();
+ skeletonWithOneJoint->setRootJoint(new QJoint());
+ QTest::newRow("skeletonWithOneJoint") << skeletonWithOneJoint;
+ }
+
+ void checkCreationChange()
+ {
+ // GIVEN
+ QFETCH(QSkeleton *, skeleton);
+
+ // WHEN
+ QNodeCreatedChangeGenerator creationChangeGenerator(skeleton);
+ QVector<QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges();
+
+ const int jointCount = skeleton->rootJoint() ? 1 : 0;
+
+ // THEN
+ QCOMPARE(creationChanges.size(), 1 + jointCount);
+
+ const auto creationChangeData = qSharedPointerCast<QNodeCreatedChange<QSkeletonData>>(creationChanges.first());
+ const QSkeletonData &data = creationChangeData->data;
+
+ // THEN
+ QCOMPARE(skeleton->id(), creationChangeData->subjectId());
+ QCOMPARE(skeleton->isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(skeleton->metaObject(), creationChangeData->metaObject());
+ if (skeleton->rootJoint()) {
+ QCOMPARE(skeleton->rootJoint()->id(), data.rootJointId);
+ }
+ }
+
+ void checkPropertyUpdates()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ QScopedPointer<QSkeleton> skeleton(new QSkeleton());
+ arbiter.setArbiterOnNode(skeleton.data());
+
+ // WHEN
+ QJoint *joint = new QJoint(skeleton.data());
+ QCoreApplication::processEvents();
+ arbiter.events.clear();
+
+ skeleton->setRootJoint(joint);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "rootJoint");
+ QCOMPARE(change->value().value<QNodeId>(), joint->id());
+ QCOMPARE(change->type(), PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ skeleton->setRootJoint(nullptr);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "rootJoint");
+ QCOMPARE(change->value().value<QNodeId>(), QNodeId());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ void checkRootJointBookkeeping()
+ {
+ // GIVEN
+ QScopedPointer<QSkeleton> skeleton(new QSkeleton);
+ {
+ // WHEN
+ QJoint joint;
+ skeleton->setRootJoint(&joint);
+
+ // THEN
+ QCOMPARE(joint.parent(), skeleton.data());
+ QCOMPARE(skeleton->rootJoint(), &joint);
+ }
+ // THEN (Should not crash and parameter be unset)
+ QVERIFY(skeleton->rootJoint() == nullptr);
+
+ {
+ // WHEN
+ QSkeleton someOtherSkeleton;
+ QScopedPointer<QJoint> joint(new QJoint(&someOtherSkeleton));
+ skeleton->setRootJoint(joint.data());
+
+ // THEN
+ QCOMPARE(joint->parent(), &someOtherSkeleton);
+ QCOMPARE(skeleton->rootJoint(), joint.data());
+
+ // WHEN
+ skeleton.reset();
+ joint.reset();
+
+ // THEN Should not crash when the joint is destroyed (tests for failed removal of destruction helper)
+ }
+ }
+
+ void checkJointCountPropertyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ arbiter.setArbiterOnNode(this);
+ QSignalSpy spy(this, SIGNAL(jointCountChanged(int)));
+ const int newJointCount = 99;
+
+ // THEN
+ QVERIFY(spy.isValid());
+
+ // WHEN
+ auto valueChange = QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ valueChange->setPropertyName("jointCount");
+ valueChange->setValue(QVariant(newJointCount));
+ sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(jointCount(), newJointCount);
+
+ // WHEN
+ spy.clear();
+ sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(jointCount(), newJointCount);
+ }
+};
+
+QTEST_MAIN(tst_QSkeleton)
+
+#include "tst_qskeleton.moc"
diff --git a/tests/auto/core/qskeletonloader/qskeletonloader.pro b/tests/auto/core/qskeletonloader/qskeletonloader.pro
new file mode 100644
index 000000000..6172906c2
--- /dev/null
+++ b/tests/auto/core/qskeletonloader/qskeletonloader.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qskeletonloader
+
+QT += 3dcore 3dcore-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_qskeletonloader.cpp
+
+include(../common/common.pri)
diff --git a/tests/auto/core/qskeletonloader/tst_qskeletonloader.cpp b/tests/auto/core/qskeletonloader/tst_qskeletonloader.cpp
new file mode 100644
index 000000000..1386429d4
--- /dev/null
+++ b/tests/auto/core/qskeletonloader/tst_qskeletonloader.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DCore/qskeletonloader.h>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/private/qskeletonloader_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/qnodecreatedchange.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <QObject>
+#include <QSignalSpy>
+#include <testpostmanarbiter.h>
+
+using namespace Qt3DCore;
+
+class tst_QSkeletonLoader : public QSkeletonLoader
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ QSkeletonLoader skeleton;
+
+ // THEN
+ QCOMPARE(skeleton.source(), QUrl());
+ QCOMPARE(skeleton.status(), QSkeletonLoader::NotReady);
+ QCOMPARE(skeleton.isCreateJointsEnabled(), false);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ QSkeletonLoader skeleton;
+
+ {
+ // WHEN
+ QSignalSpy spy(&skeleton, SIGNAL(sourceChanged(QUrl)));
+ const QUrl newValue(QStringLiteral("qrc:/zergling.skel"));
+ skeleton.setSource(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(skeleton.source(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ skeleton.setSource(newValue);
+
+ // THEN
+ QCOMPARE(skeleton.source(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+
+ {
+ // WHEN
+ QSignalSpy spy(&skeleton, SIGNAL(createJointsEnabledChanged(bool)));
+ const bool newValue(true);
+ skeleton.setCreateJointsEnabled(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(skeleton.isCreateJointsEnabled(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ skeleton.setCreateJointsEnabled(newValue);
+
+ // THEN
+ QCOMPARE(skeleton.isCreateJointsEnabled(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ QSkeletonLoader skeleton;
+
+ skeleton.setSource(QUrl(QStringLiteral("http://someRemoteURL.com/dem-bones.skel")));
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ QNodeCreatedChangeGenerator creationChangeGenerator(&skeleton);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<QNodeCreatedChange<QSkeletonLoaderData>>(creationChanges.first());
+ const QSkeletonLoaderData data = creationChangeData->data;
+
+ QCOMPARE(skeleton.id(), creationChangeData->subjectId());
+ QCOMPARE(skeleton.isEnabled(), true);
+ QCOMPARE(skeleton.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(skeleton.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(skeleton.source(), data.source);
+ QCOMPARE(skeleton.isCreateJointsEnabled(), data.createJoints);
+ }
+
+ // WHEN
+ skeleton.setEnabled(false);
+
+ {
+ QNodeCreatedChangeGenerator creationChangeGenerator(&skeleton);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 1);
+
+ const auto creationChangeData = qSharedPointerCast<QNodeCreatedChange<QSkeletonLoaderData>>(creationChanges.first());
+ const QSkeletonLoaderData data = creationChangeData->data;
+
+ QCOMPARE(skeleton.id(), creationChangeData->subjectId());
+ QCOMPARE(skeleton.isEnabled(), false);
+ QCOMPARE(skeleton.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(skeleton.metaObject(), creationChangeData->metaObject());
+ QCOMPARE(skeleton.source(), data.source);
+ QCOMPARE(skeleton.isCreateJointsEnabled(), data.createJoints);
+ }
+ }
+
+ void checkPropertyUpdates()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ QSkeletonLoader skeleton;
+ arbiter.setArbiterOnNode(&skeleton);
+
+ {
+ // WHEN
+ skeleton.setSource(QUrl(QStringLiteral("qrc:/hydralisk.skel")));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "source");
+ QCOMPARE(change->type(), PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ skeleton.setSource(QStringLiteral("qrc:/hydralisk.skel"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+
+ {
+ // WHEN
+ skeleton.setCreateJointsEnabled(true);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "createJointsEnabled");
+ QCOMPARE(change->type(), PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ skeleton.setCreateJointsEnabled(true);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+
+ void checkStatusPropertyUpdate()
+ {
+ // GIVEN
+ qRegisterMetaType<Qt3DCore::QSkeletonLoader::Status>("Status");
+ TestArbiter arbiter;
+ arbiter.setArbiterOnNode(this);
+ QSignalSpy spy(this, SIGNAL(statusChanged(Status)));
+ const QSkeletonLoader::Status newStatus = QSkeletonLoader::Error;
+
+ // THEN
+ QVERIFY(spy.isValid());
+
+ // WHEN
+ QPropertyUpdatedChangePtr valueChange(new QPropertyUpdatedChange(QNodeId()));
+ valueChange->setPropertyName("status");
+ valueChange->setValue(QVariant::fromValue(newStatus));
+ sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(status(), newStatus);
+
+ // WHEN
+ spy.clear();
+ sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 0);
+ QCOMPARE(arbiter.events.size(), 0);
+ QCOMPARE(status(), newStatus);
+ }
+
+ void checkRootJointPropertyUpdate()
+ {
+ // GIVEN
+ qRegisterMetaType<Qt3DCore::QJoint*>();
+ TestArbiter arbiter;
+ arbiter.setArbiterOnNode(this);
+ QSignalSpy spy(this, SIGNAL(rootJointChanged(Qt3DCore::QJoint*)));
+ std::unique_ptr<QJoint> root(new QJoint());
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QVERIFY(rootJoint() == nullptr);
+
+ // WHEN
+ auto valueChange = QJointChangePtr::create(id());
+ valueChange->setDeliveryFlags(Qt3DCore::QSceneChange::Nodes);
+ valueChange->setPropertyName("rootJoint");
+ valueChange->data = std::move(root);
+ sceneChangeEvent(valueChange);
+
+ // THEN
+ QCOMPARE(spy.count(), 1);
+ QCOMPARE(arbiter.events.size(), 1);
+ QVERIFY(rootJoint() != nullptr);
+ }
+};
+
+QTEST_MAIN(tst_QSkeletonLoader)
+
+#include "tst_qskeletonloader.moc"
diff --git a/tests/auto/core/vector3d_base/tst_vector3d_base.cpp b/tests/auto/core/vector3d_base/tst_vector3d_base.cpp
new file mode 100644
index 000000000..c3e5390a9
--- /dev/null
+++ b/tests/auto/core/vector3d_base/tst_vector3d_base.cpp
@@ -0,0 +1,705 @@
+/****************************************************************************
+**
+** 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/QtTest>
+#include <Qt3DCore/private/vector3d_p.h>
+
+class tst_Vector3D_Base: public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void defaultConstruction()
+ {
+ // GIVEN
+ QVector3D vec3;
+
+ // THEN
+ QCOMPARE(vec3.x(), 0.0f);
+ QCOMPARE(vec3.y(), 0.0f);
+ QCOMPARE(vec3.z(), 0.0f);
+ }
+
+ void checkExplicitConstruction()
+ {
+ // GIVEN
+ QVector3D vec3(427.0f, 454.0f, 383.0f);
+
+ // THEN
+ QCOMPARE(vec3.x(), 427.0f);
+ QCOMPARE(vec3.y(), 454.0f);
+ QCOMPARE(vec3.z(), 383.0f);
+ }
+
+ void checkSelfAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << 1.0f << 5.0f << 8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkSelfAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D vo(xO, yO, zO);
+
+ // WHEN
+ vo += QVector3D(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << -1.0f << -5.0f << -8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -10.0f << 16.0f << -8.0f;
+ }
+
+ void checkSelfSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D vo(xO, yO, zO);
+
+ // WHEN
+ vo -= QVector3D(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 16.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -25.0f << -64.0f << 16.0f;
+ }
+
+ void checkSelfMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D vo(xO, yO, zO);
+
+ // WHEN
+ vo *= QVector3D(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 0.25f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -1.0f << -1.0f << 1.0f;
+ }
+
+ void checkSelfDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D vo(xO, yO, zO);
+
+ // WHEN
+ vo /= QVector3D(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f;
+ }
+
+ void checkSelfDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D vo(xO, yO, zO);
+
+ // WHEN
+ vo /= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f;
+ }
+
+ void checkSelfMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D vo(xO, yO, zO);
+
+ // WHEN
+ vo *= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << 1.0f << 5.0f << 8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D v0(xO, yO, zO);
+ QVector3D v1(xA, yA, zA);
+
+ // WHEN
+ QVector3D v2 = v0 + v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << -1.0f << -5.0f << -8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -10.0f << 16.0f << -8.0f;
+ }
+
+ void checkSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D v0(xO, yO, zO);
+ QVector3D v1(xA, yA, zA);
+
+ // WHEN
+ QVector3D v2 = v0 - v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 16.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -25.0f << -64.0f << 16.0f;
+ }
+
+ void checkMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D v0(xO, yO, zO);
+ QVector3D v1(xA, yA, zA);
+
+ // WHEN
+ QVector3D v2 = v0 * v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 0.25f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -1.0f << -1.0f << 1.0f;
+ }
+
+ void checkDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D v0(xO, yO, zO);
+ QVector3D v1(xA, yA, zA);
+
+ // WHEN
+ QVector3D v2 = v0 / v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f;
+ }
+
+ void checkDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D v0(xO, yO, zO);
+
+ // WHEN
+ QVector3D v2 = v0 / factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f;
+ }
+
+ void checkMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ QVector3D v0(xO, yO, zO);
+
+ // WHEN
+ QVector3D v2 = v0 * factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkEquality()
+ {
+ {
+ // GIVEN
+ QVector3D v0;
+ QVector3D v1;
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ {
+ // GIVEN
+ QVector3D v0(1.0f, 2.0f, -5.0f);
+ QVector3D v1(1.0f, 2.0f, -5.0f);
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ }
+
+ void checkInequality()
+ {
+ {
+ // GIVEN
+ QVector3D v0;
+ QVector3D v1;
+
+ // THEN
+ QVERIFY(!(v0 != v1));
+ }
+ {
+ // GIVEN
+ QVector3D v0(1.0f, 2.0f, -5.0f);
+ QVector3D v1(1.0f, 5.0f, -5.0f);
+
+ // THEN
+ QVERIFY(v0 != v1);
+ }
+ }
+
+ void checkToQQVector3D()
+ {
+ {
+ // GIVEN
+ QVector3D v0;
+
+ // WHEN
+ QVector3D v1 = v0;
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ }
+ {
+ // GIVEN
+ QVector3D v0(1.0f, 2.0f, -5.0f);
+
+ // WHEN
+ QVector3D v1 = v0;
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ }
+ }
+};
+
+QTEST_MAIN(tst_Vector3D_Base)
+
+#include "tst_vector3d_base.moc"
diff --git a/tests/auto/core/vector3d_base/vector3d_base.pro b/tests/auto/core/vector3d_base/vector3d_base.pro
new file mode 100644
index 000000000..fa1ee87df
--- /dev/null
+++ b/tests/auto/core/vector3d_base/vector3d_base.pro
@@ -0,0 +1,7 @@
+TARGET = tst_vector3d_base
+CONFIG += testcase
+QT += testlib 3dcore 3dcore-private
+
+SOURCES += \
+ tst_vector3d_base.cpp
+
diff --git a/tests/auto/core/vector3d_sse/tst_vector3d_sse.cpp b/tests/auto/core/vector3d_sse/tst_vector3d_sse.cpp
new file mode 100644
index 000000000..be9fbc347
--- /dev/null
+++ b/tests/auto/core/vector3d_sse/tst_vector3d_sse.cpp
@@ -0,0 +1,816 @@
+/****************************************************************************
+**
+** 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/QtTest>
+#include <Qt3DCore/private/vector3d_sse_p.h>
+
+using namespace Qt3DCore;
+
+class tst_Vector3D_SSE: public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void defaultConstruction()
+ {
+ // GIVEN
+ Vector3D_SSE vec3;
+
+ // THEN
+ QCOMPARE(vec3.x(), 0.0f);
+ QCOMPARE(vec3.y(), 0.0f);
+ QCOMPARE(vec3.z(), 0.0f);
+ }
+
+ void checkExplicitConstruction()
+ {
+ // GIVEN
+ Vector3D_SSE vec3(427.0f, 454.0f, 383.0f);
+
+ // THEN
+ QCOMPARE(vec3.x(), 427.0f);
+ QCOMPARE(vec3.y(), 454.0f);
+ QCOMPARE(vec3.z(), 383.0f);
+ }
+
+ void checkSetters()
+ {
+ // GIVEN
+ Vector3D_SSE vec3;
+
+ // WHEN
+ vec3.setX(427.0f);
+ vec3.setY(454.0f);
+ vec3.setZ(383.0f);
+
+ // THEN
+ QCOMPARE(vec3.x(), 427.0f);
+ QCOMPARE(vec3.y(), 454.0f);
+ QCOMPARE(vec3.z(), 383.0f);
+ }
+
+
+ void checkSelfAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << 1.0f << 5.0f << 8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkSelfAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE vo(xO, yO, zO);
+
+ // WHEN
+ vo += Vector3D_SSE(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << -1.0f << -5.0f << -8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -10.0f << 16.0f << -8.0f;
+ }
+
+ void checkSelfSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE vo(xO, yO, zO);
+
+ // WHEN
+ vo -= Vector3D_SSE(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 16.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -25.0f << -64.0f << 16.0f;
+ }
+
+ void checkSelfMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE vo(xO, yO, zO);
+
+ // WHEN
+ vo *= Vector3D_SSE(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 0.25f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -1.0f << -1.0f << 1.0f;
+ }
+
+ void checkSelfDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE vo(xO, yO, zO);
+
+ // WHEN
+ vo /= Vector3D_SSE(xA, yA, zA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f;
+ }
+
+ void checkSelfDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE vo(xO, yO, zO);
+
+ // WHEN
+ vo /= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkSelfMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f;
+ }
+
+ void checkSelfMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE vo(xO, yO, zO);
+
+ // WHEN
+ vo *= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ }
+
+ void checkAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << 1.0f << 5.0f << 8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE v0(xO, yO, zO);
+ Vector3D_SSE v1(xA, yA, zA);
+
+ // WHEN
+ Vector3D_SSE v2 = v0 + v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f
+ << -1.0f << -5.0f << -8.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -10.0f << 16.0f << -8.0f;
+ }
+
+ void checkSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE v0(xO, yO, zO);
+ Vector3D_SSE v1(xA, yA, zA);
+
+ // WHEN
+ Vector3D_SSE v2 = v0 - v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 16.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -25.0f << -64.0f << 16.0f;
+ }
+
+ void checkMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE v0(xO, yO, zO);
+ Vector3D_SSE v1(xA, yA, zA);
+
+ // WHEN
+ Vector3D_SSE v2 = v0 * v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f << 5.0f << 8.0f
+ << 0.0f << 0.0f << 0.25f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f
+ << 5.0f << -8.0f << 4.0f
+ << -1.0f << -1.0f << 1.0f;
+ }
+
+ void checkDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE v0(xO, yO, zO);
+ Vector3D_SSE v1(xA, yA, zA);
+
+ // WHEN
+ Vector3D_SSE v2 = v0 / v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f;
+ }
+
+ void checkDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE v0(xO, yO, zO);
+
+ // WHEN
+ Vector3D_SSE v2 = v0 / factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f;
+ }
+
+ void checkMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+
+ // GIVEN
+ Vector3D_SSE v0(xO, yO, zO);
+
+ // WHEN
+ Vector3D_SSE v2 = v0 * factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ }
+
+ void checkEquality()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0;
+ Vector3D_SSE v1;
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(1.0f, 2.0f, -5.0f);
+ Vector3D_SSE v1(1.0f, 2.0f, -5.0f);
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ }
+
+ void checkInequality()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0;
+ Vector3D_SSE v1;
+
+ // THEN
+ QVERIFY(!(v0 != v1));
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(1.0f, 2.0f, -5.0f);
+ Vector3D_SSE v1(1.0f, 5.0f, -5.0f);
+
+ // THEN
+ QVERIFY(v0 != v1);
+ }
+ }
+
+ void checkToQVector3D_SSE()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0;
+
+ // WHEN
+ QVector3D v1 = v0.toQVector3D();
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(1.0f, 2.0f, -5.0f);
+
+ // WHEN
+ QVector3D v1 = v0.toQVector3D();
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ }
+ }
+
+ void checkLengthSquared()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0(10.0f, 10.0f, 10.0f);
+
+ // THEN
+ QCOMPARE(v0.lengthSquared(), 300.0f);
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(3.0f, 1.0f, 2.0f);
+
+ // THEN
+ QCOMPARE(v0.lengthSquared(), 14.0f);
+ }
+ }
+
+ void checkLength()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0(3.0f, 0.0f, 0.0f);
+
+ // THEN
+ QCOMPARE(v0.length(), 3.0f);
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(0.0f, 10.0f, 0.0f);
+
+ // THEN
+ QCOMPARE(v0.length(), 10.0f);
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(0.0f, 0.0f, 9.0f);
+
+ // THEN
+ QCOMPARE(v0.length(), 9.0f);
+ }
+ }
+
+ void checkNormalize()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0(10.0f, 0.0f, 0.0f);
+
+ // WHEN
+ v0.normalize();
+
+ // THEN
+ QCOMPARE(v0, Vector3D_SSE(1.0f, 0.0f, 0.0f));
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(3.0f, 0.0f, 3.0f);
+
+ // WHEN
+ v0.normalize();
+
+ // THEN
+ // (0.707107 == sqrt(2) / 2)
+ Vector3D_SSE v2(0.707107f, 0.0f, 0.707107f);
+ QCOMPARE(qFuzzyCompare(v0, v2), true);
+ }
+ }
+
+ void checkNormalized()
+ {
+
+ }
+
+ void checkIsNull()
+ {
+ {
+ // GIVEN
+ Vector3D_SSE v0;
+
+ // THEN
+ QVERIFY(v0.isNull());
+ }
+ {
+ // GIVEN
+ Vector3D_SSE v0(1.0f, 1.0f, 1.0f);
+
+ // THEN
+ QVERIFY(!v0.isNull());
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Vector3D_SSE)
+
+#include "tst_vector3d_sse.moc"
diff --git a/tests/auto/core/vector3d_sse/vector3d_sse.pro b/tests/auto/core/vector3d_sse/vector3d_sse.pro
new file mode 100644
index 000000000..6afc4a863
--- /dev/null
+++ b/tests/auto/core/vector3d_sse/vector3d_sse.pro
@@ -0,0 +1,8 @@
+TARGET = tst_vector3d_sse
+CONFIG += testcase simd
+QT += testlib 3dcore 3dcore-private
+
+SOURCES += \
+ tst_vector3d_sse.cpp
+
+QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE2
diff --git a/tests/auto/core/vector4d_base/tst_vector4d_base.cpp b/tests/auto/core/vector4d_base/tst_vector4d_base.cpp
new file mode 100644
index 000000000..e152625fe
--- /dev/null
+++ b/tests/auto/core/vector4d_base/tst_vector4d_base.cpp
@@ -0,0 +1,785 @@
+/****************************************************************************
+**
+** 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/QtTest>
+#include <Qt3DCore/private/vector4d_p.h>
+
+class tst_Vector4D_Base: public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void defaultConstruction()
+ {
+ // GIVEN
+ QVector4D vec4;
+
+ // THEN
+ QCOMPARE(vec4.x(), 0.0f);
+ QCOMPARE(vec4.y(), 0.0f);
+ QCOMPARE(vec4.z(), 0.0f);
+ QCOMPARE(vec4.w(), 0.0f);
+ }
+
+ void checkExplicitConstruction()
+ {
+ // GIVEN
+ QVector4D vec4(427.0f, 454.0f, 383.0f, 350.0f);
+
+ // THEN
+ QCOMPARE(vec4.x(), 427.0f);
+ QCOMPARE(vec4.y(), 454.0f);
+ QCOMPARE(vec4.z(), 383.0f);
+ QCOMPARE(vec4.w(), 350.0f);
+ }
+
+ void checkSelfAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << 0.0f << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkSelfAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo += QVector4D(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << -1.0f << -5.0f << -8.0f << 5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << -10.0f << 16.0f << -8.0f << 12.0f;
+ }
+
+ void checkSelfSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo -= QVector4D(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 16.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -25.0f << -64.0f << 16.0f << 36.0f;
+ }
+
+ void checkSelfMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo *= QVector4D(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 0.25f << -0.20f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -1.0f << -1.0f << 1.0f << 1.0f;
+ }
+
+ void checkSelfDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo /= QVector4D(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f << 2.0f;
+ }
+
+ void checkSelfDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo /= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f << 50.0f;
+ }
+
+ void checkSelfMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo *= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << 0.0f << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D v0(xO, yO, zO, wO);
+ QVector4D v1(xA, yA, zA, wA);
+
+ // WHEN
+ QVector4D v2 = v0 + v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << -1.0f << -5.0f << -8.0f << 5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << -10.0f << 16.0f << -8.0f << 12.0f;
+ }
+
+ void checkSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D v0(xO, yO, zO, wO);
+ QVector4D v1(xA, yA, zA, wA);
+
+ // WHEN
+ QVector4D v2 = v0 - v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 16.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -25.0f << -64.0f << 16.0f << 36.0f;
+ }
+
+ void checkMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D v0(xO, yO, zO, wO);
+ QVector4D v1(xA, yA, zA, wA);
+
+ // WHEN
+ QVector4D v2 = v0 * v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 0.25f << -0.20f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -1.0f << -1.0f << 1.0f << 1.0f;
+ }
+
+ void checkDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D v0(xO, yO, zO, wO);
+ QVector4D v1(xA, yA, zA, wA);
+
+ // WHEN
+ QVector4D v2 = v0 / v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f << 2.0f;
+ }
+
+ void checkDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D v0(xO, yO, zO, wO);
+
+ // WHEN
+ QVector4D v2 = v0 / factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f << 50.0f;
+ }
+
+ void checkMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ QVector4D v0(xO, yO, zO, wO);
+
+ // WHEN
+ QVector4D v2 = v0 * factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkEquality()
+ {
+ {
+ // GIVEN
+ QVector4D v0;
+ QVector4D v1;
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ {
+ // GIVEN
+ QVector4D v0(1.0f, 2.0f, -5.0f, 10.0f);
+ QVector4D v1(1.0f, 2.0f, -5.0f, 10.0f);
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ }
+
+ void checkInequality()
+ {
+ {
+ // GIVEN
+ QVector4D v0;
+ QVector4D v1;
+
+ // THEN
+ QVERIFY(!(v0 != v1));
+ }
+ {
+ // GIVEN
+ QVector4D v0(1.0f, 2.0f, -5.0f, 10.0f);
+ QVector4D v1(1.0f, 5.0f, -5.0f, 10.0f);
+
+ // THEN
+ QVERIFY(v0 != v1);
+ }
+ }
+
+ void checkToQQVector4D()
+ {
+ {
+ // GIVEN
+ QVector4D v0;
+
+ // WHEN
+ QVector4D v1 = v0;
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ QCOMPARE(v0.w(), v1.w());
+ }
+ {
+ // GIVEN
+ QVector4D v0(1.0f, 2.0f, -5.0f, 10.0f);
+
+ // WHEN
+ QVector4D v1 = v0;
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ QCOMPARE(v0.w(), v1.w());
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Vector4D_Base)
+
+#include "tst_vector4d_base.moc"
diff --git a/tests/auto/core/vector4d_base/vector4d_base.pro b/tests/auto/core/vector4d_base/vector4d_base.pro
new file mode 100644
index 000000000..9afaff092
--- /dev/null
+++ b/tests/auto/core/vector4d_base/vector4d_base.pro
@@ -0,0 +1,7 @@
+TARGET = tst_vector4d_base
+CONFIG += testcase
+
+SOURCES += \
+ tst_vector4d_base.cpp
+
+QT += testlib 3dcore 3dcore-private
diff --git a/tests/auto/core/vector4d_sse/tst_vector4d_sse.cpp b/tests/auto/core/vector4d_sse/tst_vector4d_sse.cpp
new file mode 100644
index 000000000..e7b58c8cf
--- /dev/null
+++ b/tests/auto/core/vector4d_sse/tst_vector4d_sse.cpp
@@ -0,0 +1,830 @@
+/****************************************************************************
+**
+** 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/QtTest>
+#include <Qt3DCore/private/vector4d_sse_p.h>
+#include <Qt3DCore/qt3dcore-config.h>
+
+using namespace Qt3DCore;
+
+class tst_Vector4D_SSE: public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void defaultConstruction()
+ {
+ // GIVEN
+ Vector4D_SSE vec4;
+
+ // THEN
+ QCOMPARE(vec4.x(), 0.0f);
+ QCOMPARE(vec4.y(), 0.0f);
+ QCOMPARE(vec4.z(), 0.0f);
+ QCOMPARE(vec4.w(), 0.0f);
+ }
+
+ void checkExplicitConstruction()
+ {
+ // GIVEN
+ Vector4D_SSE vec4(427.0f, 454.0f, 383.0f, 350.0f);
+
+ // THEN
+ QCOMPARE(vec4.x(), 427.0f);
+ QCOMPARE(vec4.y(), 454.0f);
+ QCOMPARE(vec4.z(), 383.0f);
+ QCOMPARE(vec4.w(), 350.0f);
+ }
+
+ void checkSetters()
+ {
+ // GIVEN
+ Vector4D_SSE vec4;
+
+ // WHEN
+ vec4.setX(427.0f);
+
+ // THEN
+ QCOMPARE(vec4.x(), 427.0f);
+ QCOMPARE(vec4.y(), 0.0f);
+ QCOMPARE(vec4.z(), 0.0f);
+ QCOMPARE(vec4.w(), 0.0f);
+
+ // WHEN
+ vec4.setY(454.0f);
+
+ // THEN
+ QCOMPARE(vec4.x(), 427.0f);
+ QCOMPARE(vec4.y(), 454.0f);
+ QCOMPARE(vec4.z(), 0.0f);
+ QCOMPARE(vec4.w(), 0.0f);
+
+ // WHEN
+ vec4.setZ(383.0f);
+
+ // THEN
+ QCOMPARE(vec4.x(), 427.0f);
+ QCOMPARE(vec4.y(), 454.0f);
+ QCOMPARE(vec4.z(), 383.0f);
+ QCOMPARE(vec4.w(), 0.0f);
+
+ // WHEN
+ vec4.setW(350.0f);
+
+ // THEN
+ QCOMPARE(vec4.x(), 427.0f);
+ QCOMPARE(vec4.y(), 454.0f);
+ QCOMPARE(vec4.z(), 383.0f);
+ QCOMPARE(vec4.w(), 350.0f);
+ }
+
+ void checkSelfAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << 0.0f << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkSelfAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo += Vector4D_SSE(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << -1.0f << -5.0f << -8.0f << 5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << -10.0f << 16.0f << -8.0f << 12.0f;
+ }
+
+ void checkSelfSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo -= Vector4D_SSE(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 16.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -25.0f << -64.0f << 16.0f << 36.0f;
+ }
+
+ void checkSelfMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo *= Vector4D_SSE(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 0.25f << -0.20f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -1.0f << -1.0f << 1.0f << 1.0f;
+ }
+
+ void checkSelfDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo /= Vector4D_SSE(xA, yA, zA, wA);
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f << 2.0f;
+ }
+
+ void checkSelfDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo /= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkSelfMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f << 50.0f;
+ }
+
+ void checkSelfMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE vo(xO, yO, zO, wO);
+
+ // WHEN
+ vo *= factor;
+
+ // THEN
+ QCOMPARE(vo.x(), xR);
+ QCOMPARE(vo.y(), yR);
+ QCOMPARE(vo.z(), zR);
+ QCOMPARE(vo.w(), wR);
+ }
+
+ void checkAddition_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << 0.0f << 0.0f << 0.0f << 0.0f;
+ }
+
+ void checkAddition()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE v0(xO, yO, zO, wO);
+ Vector4D_SSE v1(xA, yA, zA, wA);
+
+ // WHEN
+ Vector4D_SSE v2 = v0 + v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkSubstraction_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 0.0f << 0.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << -1.0f << -5.0f << -8.0f << 5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << -4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << -6.0f
+ << -10.0f << 16.0f << -8.0f << 12.0f;
+ }
+
+ void checkSubstraction()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE v0(xO, yO, zO, wO);
+ Vector4D_SSE v1(xA, yA, zA, wA);
+
+ // WHEN
+ Vector4D_SSE v2 = v0 - v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkMultiplication_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 16.0f << -5.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -25.0f << -64.0f << 16.0f << 36.0f;
+ }
+
+ void checkMultiplication()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE v0(xO, yO, zO, wO);
+ Vector4D_SSE v1(xA, yA, zA, wA);
+
+ // WHEN
+ Vector4D_SSE v2 = v0 * v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkDivision_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("xA");
+ QTest::addColumn<float>("yA");
+ QTest::addColumn<float>("zA");
+ QTest::addColumn<float>("wA");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f << 5.0f << 8.0f << -5.0f
+ << 0.0f << 0.0f << 0.25f << -0.20f;
+
+ QTest::newRow("sample_2") << -5.0f << 8.0f << 4.0f << 6.0f
+ << 5.0f << -8.0f << 4.0f << 6.0f
+ << -1.0f << -1.0f << 1.0f << 1.0f;
+ }
+
+ void checkDivision()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, xA);
+ QFETCH(float, yA);
+ QFETCH(float, zA);
+ QFETCH(float, wA);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE v0(xO, yO, zO, wO);
+ Vector4D_SSE v1(xA, yA, zA, wA);
+
+ // WHEN
+ Vector4D_SSE v2 = v0 / v1;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkDivisionFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << 0.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << 0.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -1.0f << 4.0f << -5.0f << 2.0f;
+ }
+
+ void checkDivisionFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE v0(xO, yO, zO, wO);
+
+ // WHEN
+ Vector4D_SSE v2 = v0 / factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkMultiplicationFactor_data()
+ {
+ QTest::addColumn<float>("xO");
+ QTest::addColumn<float>("yO");
+ QTest::addColumn<float>("zO");
+ QTest::addColumn<float>("wO");
+
+ QTest::addColumn<float>("factor");
+
+ QTest::addColumn<float>("xR");
+ QTest::addColumn<float>("yR");
+ QTest::addColumn<float>("zR");
+ QTest::addColumn<float>("wR");
+
+ QTest::newRow("sample_1") << 0.0f << -3.0f << 2.0f << 1.0f
+ << 1.0f
+ << 0.0f << -3.0f << 2.0f << 1.0f;
+
+ QTest::newRow("sample_2") << -5.0f << 20.0f << -25.0f << 10.0f
+ << 5.0f
+ << -25.0f << 100.0f << -125.0f << 50.0f;
+ }
+
+ void checkMultiplicationFactor()
+ {
+ QFETCH(float, xO);
+ QFETCH(float, yO);
+ QFETCH(float, zO);
+ QFETCH(float, wO);
+
+ QFETCH(float, factor);
+
+ QFETCH(float, xR);
+ QFETCH(float, yR);
+ QFETCH(float, zR);
+ QFETCH(float, wR);
+
+ // GIVEN
+ Vector4D_SSE v0(xO, yO, zO, wO);
+
+ // WHEN
+ Vector4D_SSE v2 = v0 * factor;
+
+ // THEN
+ QCOMPARE(v2.x(), xR);
+ QCOMPARE(v2.y(), yR);
+ QCOMPARE(v2.z(), zR);
+ QCOMPARE(v2.w(), wR);
+ }
+
+ void checkEquality()
+ {
+ {
+ // GIVEN
+ Vector4D_SSE v0;
+ Vector4D_SSE v1;
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ {
+ // GIVEN
+ Vector4D_SSE v0(1.0f, 2.0f, -5.0f, 10.0f);
+ Vector4D_SSE v1(1.0f, 2.0f, -5.0f, 10.0f);
+
+ // THEN
+ QVERIFY(v0 == v1);
+ }
+ }
+
+ void checkInequality()
+ {
+ {
+ // GIVEN
+ Vector4D_SSE v0;
+ Vector4D_SSE v1;
+
+ // THEN
+ QVERIFY(!(v0 != v1));
+ }
+ {
+ // GIVEN
+ Vector4D_SSE v0(1.0f, 2.0f, -5.0f, 10.0f);
+ Vector4D_SSE v1(1.0f, 5.0f, -5.0f, 10.0f);
+
+ // THEN
+ QVERIFY(v0 != v1);
+ }
+ }
+
+ void checkToQVector4D_SSE()
+ {
+ {
+ // GIVEN
+ Vector4D_SSE v0;
+
+ // WHEN
+ QVector4D v1 = v0.toQVector4D();
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ QCOMPARE(v0.w(), v1.w());
+ }
+ {
+ // GIVEN
+ Vector4D_SSE v0(1.0f, 2.0f, -5.0f, 10.0f);
+
+ // WHEN
+ QVector4D v1 = v0.toQVector4D();
+
+ // THEN
+ QCOMPARE(v0.x(), v1.x());
+ QCOMPARE(v0.y(), v1.y());
+ QCOMPARE(v0.z(), v1.z());
+ QCOMPARE(v0.w(), v1.w());
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Vector4D_SSE)
+
+#include "tst_vector4d_sse.moc"
diff --git a/tests/auto/core/vector4d_sse/vector4d_sse.pro b/tests/auto/core/vector4d_sse/vector4d_sse.pro
new file mode 100644
index 000000000..76c425548
--- /dev/null
+++ b/tests/auto/core/vector4d_sse/vector4d_sse.pro
@@ -0,0 +1,9 @@
+TARGET = tst_vector4d_sse
+CONFIG += testcase simd
+
+SOURCES += \
+ tst_vector4d_sse.cpp
+
+QT += testlib 3dcore 3dcore-private
+
+QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_SSE2
diff --git a/tests/auto/quick3d/3dcore/3dcore.qml b/tests/auto/quick3d/3dcore/3dcore.qml
index df9dd429b..72514591c 100644
--- a/tests/auto/quick3d/3dcore/3dcore.qml
+++ b/tests/auto/quick3d/3dcore/3dcore.qml
@@ -29,6 +29,7 @@
import Qt3D.Core 2.0 as QQ3Core20
import Qt3D.Core 2.9 as QQ3Core29
+import Qt3D.Core 2.10 as QQ3Core210
import QtQuick 2.0
Item {
@@ -42,4 +43,8 @@ Item {
QQ3Core20.QuaternionAnimation {} //Qt3DCore::Quick::QQuaternionAnimation
QQ3Core29.Entity {} //Qt3DCore::QEntity, Qt3DCore::Quick::Quick3DEntity
+
+ QQ3Core210.Armature {}
+ QQ3Core210.SkeletonLoader {}
+ QQ3Core210.Joint {}
}
diff --git a/tests/auto/quick3d/3drender/3drender.qml b/tests/auto/quick3d/3drender/3drender.qml
index 92461fe8d..112031282 100644
--- a/tests/auto/quick3d/3drender/3drender.qml
+++ b/tests/auto/quick3d/3drender/3drender.qml
@@ -29,6 +29,7 @@
import Qt3D.Render 2.0 as QQ3Render20
import Qt3D.Render 2.1 as QQ3Render21
+import Qt3D.Render 2.10 as QQ3Render210
import QtQuick 2.0
Item {
@@ -120,6 +121,7 @@ Item {
QQ3Render20.DispatchCompute {} //Qt3DRender::QDispatchCompute
QQ3Render21.RenderCapture {} //Qt3DRender::QRenderCapture
//QQ3Render21.RenderCaptureReply // (uncreatable) Qt3DRender::QRenderCaptureReply
+ QQ3Render210.ProximityFilter {} //Q3DRender::QProximityFilter
// RenderTarget
QQ3Render20.RenderTargetOutput {} //Qt3DRender::QRenderTargetOutput
diff --git a/tests/auto/render/armature/armature.pro b/tests/auto/render/armature/armature.pro
new file mode 100644
index 000000000..fc8d69eaa
--- /dev/null
+++ b/tests/auto/render/armature/armature.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_armature
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_armature.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/armature/tst_armature.cpp b/tests/auto/render/armature/tst_armature.cpp
new file mode 100644
index 000000000..2c481db7a
--- /dev/null
+++ b/tests/auto/render/armature/tst_armature.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/private/armature_p.h>
+#include <Qt3DCore/qarmature.h>
+#include <Qt3DCore/qskeleton.h>
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include <qbackendnodetester.h>
+#include <testpostmanarbiter.h>
+
+using namespace Qt3DCore;
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+class tst_Armature: public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ Armature backendArmature;
+ QArmature armature;
+ auto skeleton = new QSkeleton;
+
+ armature.setSkeleton(skeleton);
+
+ // WHEN
+ simulateInitialization(&armature, &backendArmature);
+
+ // THEN
+ QCOMPARE(backendArmature.peerId(), armature.id());
+ QCOMPARE(backendArmature.isEnabled(), armature.isEnabled());
+ QCOMPARE(backendArmature.skeletonId(), skeleton->id());
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ Armature backendArmature;
+
+ // THEN
+ QVERIFY(backendArmature.peerId().isNull());
+ QCOMPARE(backendArmature.isEnabled(), false);
+ QCOMPARE(backendArmature.skeletonId(), Qt3DCore::QNodeId());
+
+ // GIVEN
+ QArmature armature;
+ auto skeleton = new QSkeleton();
+ armature.setSkeleton(skeleton);
+
+ // WHEN
+ simulateInitialization(&armature, &backendArmature);
+ backendArmature.cleanup();
+
+ // THEN
+ QCOMPARE(backendArmature.skeletonId(), Qt3DCore::QNodeId());
+ QCOMPARE(backendArmature.isEnabled(), false);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Armature backendArmature;
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange;
+
+ // WHEN
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("enabled");
+ updateChange->setValue(true);
+ backendArmature.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendArmature.isEnabled(), true);
+
+ // WHEN
+ auto newSkeleton = new QSkeleton();
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("skeleton");
+ updateChange->setValue(QVariant::fromValue(newSkeleton->id()));
+ backendArmature.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendArmature.skeletonId(), newSkeleton->id());
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Armature)
+
+#include "tst_armature.moc"
diff --git a/tests/auto/render/blitframebuffer/blitframebuffer.pro b/tests/auto/render/blitframebuffer/blitframebuffer.pro
new file mode 100644
index 000000000..39531ae9a
--- /dev/null
+++ b/tests/auto/render/blitframebuffer/blitframebuffer.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_blitframebuffer
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_blitframebuffer.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/blitframebuffer/tst_blitframebuffer.cpp b/tests/auto/render/blitframebuffer/tst_blitframebuffer.cpp
new file mode 100644
index 000000000..6c70b0e95
--- /dev/null
+++ b/tests/auto/render/blitframebuffer/tst_blitframebuffer.cpp
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qblitframebuffer.h>
+#include <Qt3DRender/private/qblitframebuffer_p.h>
+#include <Qt3DRender/private/blitframebuffer_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_BlitFramebuffer : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::BlitFramebuffer backendBlitFramebuffer;
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.nodeType(), Qt3DRender::Render::FrameGraphNode::BlitFramebuffer);
+ QCOMPARE(backendBlitFramebuffer.isEnabled(), false);
+ QVERIFY(backendBlitFramebuffer.peerId().isNull());
+ QVERIFY(backendBlitFramebuffer.sourceRenderTargetId().isNull());
+ QVERIFY(backendBlitFramebuffer.destinationRenderTargetId().isNull());
+ QCOMPARE(backendBlitFramebuffer.sourceRect(), QRect());
+ QCOMPARE(backendBlitFramebuffer.destinationRect(), QRect());
+ QCOMPARE(backendBlitFramebuffer.sourceAttachmentPoint(), Qt3DRender::QRenderTargetOutput::Color0);
+ QCOMPARE(backendBlitFramebuffer.destinationAttachmentPoint(), Qt3DRender::QRenderTargetOutput::Color0);
+ QCOMPARE(backendBlitFramebuffer.interpolationMethod(), Qt3DRender::QBlitFramebuffer::Linear);
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QRenderTarget sourceTarget;
+ Qt3DRender::QRenderTarget destinationTarget;
+ Qt3DRender::QBlitFramebuffer blitFramebuffer;
+ blitFramebuffer.setSource(&sourceTarget);
+ blitFramebuffer.setDestination(&destinationTarget);
+ blitFramebuffer.setSourceRect(QRect(0,0,1,1));
+ blitFramebuffer.setDestinationRect(QRect(0,0,1,1));
+ blitFramebuffer.setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color1);
+ blitFramebuffer.setDestinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color1);
+ blitFramebuffer.setInterpolationMethod(Qt3DRender::QBlitFramebuffer::Nearest);
+
+ {
+ // WHEN
+ Qt3DRender::Render::BlitFramebuffer backendBlitFramebuffer;
+ simulateInitialization(&blitFramebuffer, &backendBlitFramebuffer);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.isEnabled(), true);
+ QCOMPARE(backendBlitFramebuffer.peerId(), blitFramebuffer.id());
+ QCOMPARE(backendBlitFramebuffer.sourceRenderTargetId(), sourceTarget.id());
+ QCOMPARE(backendBlitFramebuffer.destinationRenderTargetId(), destinationTarget.id());
+ QCOMPARE(backendBlitFramebuffer.sourceRect(), QRect(0,0,1,1));
+ QCOMPARE(backendBlitFramebuffer.destinationRect(), QRect(0,0,1,1));
+ QCOMPARE(backendBlitFramebuffer.sourceAttachmentPoint(), Qt3DRender::QRenderTargetOutput::Color1);
+ QCOMPARE(backendBlitFramebuffer.destinationAttachmentPoint(), Qt3DRender::QRenderTargetOutput::Color1);
+ QCOMPARE(backendBlitFramebuffer.interpolationMethod(), Qt3DRender::QBlitFramebuffer::Nearest);
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::BlitFramebuffer backendBlitFramebuffer;
+ blitFramebuffer.setEnabled(false);
+ simulateInitialization(&blitFramebuffer, &backendBlitFramebuffer);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.peerId(), blitFramebuffer.id());
+ QCOMPARE(backendBlitFramebuffer.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::BlitFramebuffer backendBlitFramebuffer;
+ TestRenderer renderer;
+ backendBlitFramebuffer.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const Qt3DRender::QRenderTarget sourceRenderTarget;
+ const Qt3DCore::QNodeId newValue = sourceRenderTarget.id();
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("sourceRenderTarget");
+ change->setValue(QVariant::fromValue(newValue));
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.sourceRenderTargetId(), newValue);
+ }
+ {
+ // WHEN
+ const Qt3DRender::QRenderTarget destinationRenderTarget;
+ const Qt3DCore::QNodeId newValue = destinationRenderTarget.id();
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("destinationRenderTarget");
+ change->setValue(QVariant::fromValue(newValue));
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.destinationRenderTargetId(), newValue);
+ }
+ {
+ // WHEN
+ const auto newValue = QRect(0,0,1,1);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("sourceRect");
+ change->setValue(QVariant::fromValue(newValue));
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.sourceRect(), newValue);
+ }
+ {
+ // WHEN
+ const auto newValue = QRect(0,0,1,1);
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("destinationRect");
+ change->setValue(QVariant::fromValue(newValue));
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.destinationRect(), newValue);
+ }
+ {
+ // WHEN
+ const auto newValue = Qt3DRender::QRenderTargetOutput::Color1;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("sourceAttachmentPoint");
+ change->setValue(QVariant::fromValue(newValue));
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.sourceAttachmentPoint(), newValue);
+ }
+ {
+ // WHEN
+ const auto newValue = Qt3DRender::QRenderTargetOutput::Color1;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("destinationAttachmentPoint");
+ change->setValue(QVariant::fromValue(newValue));
+ backendBlitFramebuffer.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendBlitFramebuffer.destinationAttachmentPoint(), newValue);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_BlitFramebuffer)
+
+#include "tst_blitframebuffer.moc"
diff --git a/tests/auto/render/buffer/tst_buffer.cpp b/tests/auto/render/buffer/tst_buffer.cpp
index 6fa7960fe..f9a54c8bf 100644
--- a/tests/auto/render/buffer/tst_buffer.cpp
+++ b/tests/auto/render/buffer/tst_buffer.cpp
@@ -73,18 +73,20 @@ private Q_SLOTS:
Qt3DRender::Render::Buffer renderBuffer;
Qt3DRender::QBuffer buffer(Qt3DRender::QBuffer::IndexBuffer);
Qt3DRender::Render::BufferManager bufferManager;
+ TestRenderer renderer;
+
buffer.setUsage(Qt3DRender::QBuffer::DynamicCopy);
buffer.setData(QByteArrayLiteral("Corvette"));
buffer.setDataGenerator(Qt3DRender::QBufferDataGeneratorPtr(new TestFunctor(883)));
// WHEN
+ renderBuffer.setRenderer(&renderer);
renderBuffer.setManager(&bufferManager);
simulateInitialization(&buffer, &renderBuffer);
// THEN
QCOMPARE(renderBuffer.peerId(), buffer.id());
QCOMPARE(renderBuffer.isDirty(), true);
- QCOMPARE(renderBuffer.type(), buffer.type());
QCOMPARE(renderBuffer.usage(), buffer.usage());
QCOMPARE(renderBuffer.data(), buffer.data());
QCOMPARE(renderBuffer.dataGenerator(), buffer.dataGenerator());
@@ -102,7 +104,6 @@ private Q_SLOTS:
// THEN
QCOMPARE(renderBuffer.isDirty(), false);
- QCOMPARE(renderBuffer.type(), Qt3DRender::QBuffer::VertexBuffer);
QCOMPARE(renderBuffer.usage(), Qt3DRender::QBuffer::StaticDraw);
QVERIFY(renderBuffer.data().isEmpty());
QVERIFY(renderBuffer.peerId().isNull());
@@ -110,7 +111,7 @@ private Q_SLOTS:
QVERIFY(renderBuffer.pendingBufferUpdates().empty());
// GIVEN
- Qt3DRender::QBuffer buffer(Qt3DRender::QBuffer::IndexBuffer);
+ Qt3DRender::QBuffer buffer;
buffer.setUsage(Qt3DRender::QBuffer::DynamicCopy);
buffer.setData(QByteArrayLiteral("C7"));
buffer.setDataGenerator(Qt3DRender::QBufferDataGeneratorPtr(new TestFunctor(73)));
@@ -129,7 +130,6 @@ private Q_SLOTS:
renderBuffer.sceneChangeEvent(updateChange);
// THEN
- QCOMPARE(renderBuffer.type(), Qt3DRender::QBuffer::IndexBuffer);
QCOMPARE(renderBuffer.usage(), Qt3DRender::QBuffer::DynamicCopy);
QCOMPARE(renderBuffer.isDirty(), true);
QCOMPARE(renderBuffer.data(), QByteArrayLiteral("C7"));
@@ -141,7 +141,6 @@ private Q_SLOTS:
// THEN
QCOMPARE(renderBuffer.isDirty(), false);
- QCOMPARE(renderBuffer.type(), Qt3DRender::QBuffer::VertexBuffer);
QCOMPARE(renderBuffer.usage(), Qt3DRender::QBuffer::StaticDraw);
QVERIFY(renderBuffer.data().isEmpty());
QVERIFY(renderBuffer.dataGenerator().isNull());
@@ -156,27 +155,14 @@ private Q_SLOTS:
renderBuffer.setRenderer(&renderer);
// THEN
- QVERIFY(renderBuffer.type() != Qt3DRender::QBuffer::IndexBuffer);
QVERIFY(renderBuffer.data().isEmpty());
QVERIFY(renderBuffer.usage() != Qt3DRender::QBuffer::DynamicRead);
QVERIFY(!renderBuffer.isDirty());
+ QVERIFY(!(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty));
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
// WHEN
Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
- updateChange->setValue(static_cast<int>(Qt3DRender::QBuffer::IndexBuffer));
- updateChange->setPropertyName("type");
- renderBuffer.sceneChangeEvent(updateChange);
-
- // THEN
- QCOMPARE(renderBuffer.type(), Qt3DRender::QBuffer::IndexBuffer);
- QVERIFY(renderer.dirtyBits() != 0);
- QVERIFY(renderBuffer.isDirty());
-
- renderBuffer.unsetDirty();
- QVERIFY(!renderBuffer.isDirty());
-
- // WHEN
- updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
updateChange->setValue(static_cast<int>(Qt3DRender::QBuffer::DynamicRead));
updateChange->setPropertyName("usage");
renderBuffer.sceneChangeEvent(updateChange);
@@ -185,6 +171,9 @@ private Q_SLOTS:
QCOMPARE(renderBuffer.usage(), Qt3DRender::QBuffer::DynamicRead);
QVERIFY(renderBuffer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderBuffer.unsetDirty();
QVERIFY(!renderBuffer.isDirty());
@@ -201,6 +190,10 @@ private Q_SLOTS:
QCOMPARE(renderBuffer.pendingBufferUpdates().first().offset, -1);
renderBuffer.pendingBufferUpdates().clear();
+
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderBuffer.unsetDirty();
QVERIFY(!renderBuffer.isDirty());
@@ -215,6 +208,9 @@ private Q_SLOTS:
QCOMPARE(renderBuffer.dataGenerator(), functor);
QVERIFY(renderBuffer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderBuffer.unsetDirty();
QVERIFY(!renderBuffer.isDirty());
@@ -228,6 +224,9 @@ private Q_SLOTS:
QCOMPARE(renderBuffer.isSyncData(), true);
QVERIFY(!renderBuffer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
// WHEN
TestArbiter arbiter;
Qt3DCore::QBackendNodePrivate::get(&renderBuffer)->setArbiter(&arbiter);
@@ -258,6 +257,9 @@ private Q_SLOTS:
QCOMPARE(renderBuffer.pendingBufferUpdates().first().offset, 2);
QVERIFY(renderBuffer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderBuffer.unsetDirty();
QVERIFY(!renderBuffer.isDirty());
}
@@ -268,8 +270,10 @@ private Q_SLOTS:
Qt3DRender::Render::Buffer renderBuffer;
Qt3DRender::QBuffer buffer(Qt3DRender::QBuffer::IndexBuffer);
Qt3DRender::Render::BufferManager bufferManager;
+ TestRenderer renderer;
// WHEN
+ renderBuffer.setRenderer(&renderer);
renderBuffer.setManager(&bufferManager);
simulateInitialization(&buffer, &renderBuffer);
@@ -285,6 +289,27 @@ private Q_SLOTS:
QVERIFY(buffers.first() == renderBuffer.peerId());
QVERIFY(bufferManager.takeBuffersToRelease().empty());
}
+
+ void checkSetRendererDirtyOnInitialization()
+ {
+ // GIVEN
+ Qt3DRender::Render::Buffer renderBuffer;
+ Qt3DRender::QBuffer buffer(Qt3DRender::QBuffer::IndexBuffer);
+ Qt3DRender::Render::BufferManager bufferManager;
+ TestRenderer renderer;
+
+ renderBuffer.setRenderer(&renderer);
+ renderBuffer.setManager(&bufferManager);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), 0);
+
+ // WHEN
+ simulateInitialization(&buffer, &renderBuffer);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::BuffersDirty);
+ }
};
diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h
index 74f529fa0..031ca214b 100644
--- a/tests/auto/render/commons/testrenderer.h
+++ b/tests/auto/render/commons/testrenderer.h
@@ -60,6 +60,7 @@ public:
QVector<Qt3DCore::QAspectJobPtr> renderBinJobs() Q_DECL_OVERRIDE { return QVector<Qt3DCore::QAspectJobPtr>(); }
Qt3DCore::QAspectJobPtr pickBoundingVolumeJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); }
Qt3DCore::QAspectJobPtr syncTextureLoadingJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); }
+ Qt3DCore::QAspectJobPtr expandBoundingVolumeJob() Q_DECL_OVERRIDE { return Qt3DCore::QAspectJobPtr(); }
void setSceneRoot(Qt3DCore::QBackendNodeFactory *factory, Qt3DRender::Render::Entity *root) Q_DECL_OVERRIDE { Q_UNUSED(factory); Q_UNUSED(root); }
Qt3DRender::Render::Entity *sceneRoot() const Q_DECL_OVERRIDE { return nullptr; }
Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const Q_DECL_OVERRIDE { return nullptr; }
diff --git a/tests/auto/render/ddstextures/data/16x16-etc1.pkm b/tests/auto/render/ddstextures/data/16x16-etc1.pkm
new file mode 100644
index 000000000..62ae2a11f
--- /dev/null
+++ b/tests/auto/render/ddstextures/data/16x16-etc1.pkm
Binary files differ
diff --git a/tests/auto/render/ddstextures/data/16x16-etc2.pkm b/tests/auto/render/ddstextures/data/16x16-etc2.pkm
new file mode 100644
index 000000000..be391113e
--- /dev/null
+++ b/tests/auto/render/ddstextures/data/16x16-etc2.pkm
Binary files differ
diff --git a/tests/auto/render/ddstextures/ddstextures.pro b/tests/auto/render/ddstextures/ddstextures.pro
index e81fd80d8..62456561f 100644
--- a/tests/auto/render/ddstextures/ddstextures.pro
+++ b/tests/auto/render/ddstextures/ddstextures.pro
@@ -30,7 +30,9 @@ OTHER_FILES = \
data/16x16x1-6-lumi.dds \
data/16x16x1-6-lumi-nomips.dds \
data/16x16x1-6-rgb.dds \
- data/16x16x1-6-rgb-nomips.dds
+ data/16x16x1-6-rgb-nomips.dds \
+ data/16x16-etc1.pkm \
+ data/16x16-etc2.pkm
TESTDATA = data/*
diff --git a/tests/auto/render/ddstextures/tst_ddstextures.cpp b/tests/auto/render/ddstextures/tst_ddstextures.cpp
index 4d9a1fb32..1f33f20e2 100644
--- a/tests/auto/render/ddstextures/tst_ddstextures.cpp
+++ b/tests/auto/render/ddstextures/tst_ddstextures.cpp
@@ -73,6 +73,8 @@ void tst_DdsTextures::ddsImageData()
{ "data/16x16x1-6-bc1-dx10.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA_DXT1 },
{ "data/16x16x1-6-bc3-nomips-dx10.dds", 16, 16, 1, 6, 1, QOpenGLTexture::RGBA_DXT5 },
{ "data/16x16x1-6-bc3-dx10.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA_DXT5 },
+ { "data/16x16-etc1.pkm", 16, 16, 1, 1, 1, QOpenGLTexture::RGB8_ETC1 },
+ { "data/16x16-etc2.pkm", 16, 16, 1, 1, 1, QOpenGLTexture::RGB8_ETC2 },
};
for (unsigned i = 0; i < sizeof(textures)/sizeof(*textures); i++) {
diff --git a/tests/auto/render/entity/tst_entity.cpp b/tests/auto/render/entity/tst_entity.cpp
index d1a222c92..6ad958451 100644
--- a/tests/auto/render/entity/tst_entity.cpp
+++ b/tests/auto/render/entity/tst_entity.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/QGeometryRenderer>
#include <Qt3DRender/QObjectPicker>
#include <Qt3DRender/QComputeCommand>
+#include <Qt3DCore/QArmature>
#include "testrenderer.h"
@@ -62,6 +63,7 @@ QNodeId materialUuid(Entity *entity) { return entity->componentUuid<Material>();
QNodeId geometryRendererUuid(Entity *entity) { return entity->componentUuid<GeometryRenderer>(); }
QNodeId objectPickerUuid(Entity *entity) { return entity->componentUuid<ObjectPicker>(); }
QNodeId computeJobUuid(Entity *entity) { return entity->componentUuid<ComputeCommand>(); }
+QNodeId armatureUuid(Entity *entity) { return entity->componentUuid<Armature>(); }
QVector<QNodeId> layersUuid(Entity *entity) { return entity->componentsUuid<Layer>(); }
QVector<QNodeId> shadersUuid(Entity *entity) { return entity->componentsUuid<ShaderData>(); }
@@ -89,7 +91,8 @@ private slots:
<< new QLayer
<< new QShaderData
<< new QComputeCommand
- << new QEnvironmentLight;
+ << new QEnvironmentLight
+ << new QArmature;
QTest::newRow("all components") << components;
}
@@ -116,8 +119,10 @@ private slots:
QVERIFY(entity.componentsUuid<Layer>().isEmpty());
QVERIFY(entity.componentsUuid<ShaderData>().isEmpty());
QVERIFY(entity.componentsUuid<EnvironmentLight>().isEmpty());
+ QVERIFY(entity.componentUuid<Armature>().isNull());
QVERIFY(!entity.isBoundingVolumeDirty());
QVERIFY(entity.childrenHandles().isEmpty());
+ QVERIFY(entity.layerIds().isEmpty());
// WHEN
Q_FOREACH (QComponent *component, components) {
@@ -144,10 +149,13 @@ private slots:
QVERIFY(!entity.componentsUuid<Layer>().isEmpty());
QVERIFY(!entity.componentsUuid<ShaderData>().isEmpty());
QVERIFY(!entity.componentsUuid<EnvironmentLight>().isEmpty());
+ QVERIFY(!entity.componentUuid<Armature>().isNull());
QVERIFY(entity.isBoundingVolumeDirty());
QVERIFY(!entity.childrenHandles().isEmpty());
+ QVERIFY(!entity.layerIds().isEmpty());
QVERIFY(renderer.dirtyBits() != 0);
- bool containsAll = entity.containsComponentsOfType<Transform, CameraLens, Material, GeometryRenderer, ObjectPicker, ComputeCommand>();
+ bool containsAll = entity.containsComponentsOfType<Transform,
+ CameraLens, Material, GeometryRenderer, ObjectPicker, ComputeCommand, Armature>();
QVERIFY(containsAll);
// WHEN
@@ -163,9 +171,12 @@ private slots:
QVERIFY(entity.componentsUuid<Layer>().isEmpty());
QVERIFY(entity.componentsUuid<ShaderData>().isEmpty());
QVERIFY(entity.componentsUuid<EnvironmentLight>().isEmpty());
+ QVERIFY(entity.componentUuid<Armature>().isNull());
QVERIFY(!entity.isBoundingVolumeDirty());
QVERIFY(entity.childrenHandles().isEmpty());
- containsAll = entity.containsComponentsOfType<Transform, CameraLens, Material, GeometryRenderer, ObjectPicker, ComputeCommand>();
+ QVERIFY(entity.layerIds().isEmpty());
+ containsAll = entity.containsComponentsOfType<Transform,
+ CameraLens, Material, GeometryRenderer, ObjectPicker, ComputeCommand, Armature>();
QVERIFY(!containsAll);
}
@@ -191,6 +202,9 @@ private slots:
component = new QComputeCommand;
QTest::newRow("computeJob") << component << reinterpret_cast<void*>(computeJobUuid);
+
+ component = new QArmature;
+ QTest::newRow("armature") << component << reinterpret_cast<void*>(armatureUuid);
}
void shouldHandleSingleComponentEvents()
diff --git a/tests/auto/render/filtercompatibletechniquejob/BLACKLIST b/tests/auto/render/filtercompatibletechniquejob/BLACKLIST
index c9313fd62..22cb59fab 100644
--- a/tests/auto/render/filtercompatibletechniquejob/BLACKLIST
+++ b/tests/auto/render/filtercompatibletechniquejob/BLACKLIST
@@ -1,4 +1,5 @@
-[checkRunRendererNotRunning]
-windows
-[checkRunRendererRunning]
+#[checkRunRendererNotRunning]
+#windows
+#[checkRunRendererRunning]
+#QTBUG-64271
windows
diff --git a/tests/auto/render/geometry/tst_geometry.cpp b/tests/auto/render/geometry/tst_geometry.cpp
index 6a8746f47..958edfd09 100644
--- a/tests/auto/render/geometry/tst_geometry.cpp
+++ b/tests/auto/render/geometry/tst_geometry.cpp
@@ -54,6 +54,7 @@ private Q_SLOTS:
{
// GIVEN
Qt3DRender::Render::Geometry renderGeometry;
+ TestRenderer renderer;
Qt3DRender::QGeometry geometry;
Qt3DRender::QAttribute attr1;
@@ -66,6 +67,7 @@ private Q_SLOTS:
geometry.addAttribute(&attr3);
geometry.addAttribute(&attr4);
geometry.setBoundingVolumePositionAttribute(&attr1);
+ renderGeometry.setRenderer(&renderer);
// WHEN
simulateInitialization(&geometry, &renderGeometry);
@@ -80,10 +82,31 @@ private Q_SLOTS:
QCOMPARE(geometry.attributes().at(i)->id(), renderGeometry.attributes().at(i));
}
+ void checkSetRendererDirtyOnInitialization()
+ {
+ // GIVEN
+ Qt3DRender::Render::Geometry renderGeometry;
+ Qt3DRender::QGeometry geometry;
+ TestRenderer renderer;
+
+ renderGeometry.setRenderer(&renderer);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), 0);
+
+ // WHEN
+ simulateInitialization(&geometry, &renderGeometry);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ }
+
void checkInitialAndCleanedUpState()
{
// GIVEN
+ TestRenderer renderer;
Qt3DRender::Render::Geometry renderGeometry;
+ renderGeometry.setRenderer(&renderer);
// THEN
QCOMPARE(renderGeometry.isDirty(), false);
@@ -131,6 +154,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(renderGeometry.attributes().count(), 1);
QVERIFY(renderGeometry.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
renderGeometry.unsetDirty();
QVERIFY(!renderGeometry.isDirty());
@@ -143,6 +168,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(renderGeometry.attributes().count(), 0);
QVERIFY(renderGeometry.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
renderGeometry.unsetDirty();
QVERIFY(!renderGeometry.isDirty());
@@ -157,6 +184,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(renderGeometry.boundingPositionAttribute(), boundingAttrId);
QVERIFY(!renderGeometry.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
}
};
diff --git a/tests/auto/render/geometryrenderer/tst_geometryrenderer.cpp b/tests/auto/render/geometryrenderer/tst_geometryrenderer.cpp
index d9ed000ab..af074def0 100644
--- a/tests/auto/render/geometryrenderer/tst_geometryrenderer.cpp
+++ b/tests/auto/render/geometryrenderer/tst_geometryrenderer.cpp
@@ -85,11 +85,13 @@ private Q_SLOTS:
Qt3DRender::QGeometry geometry;
Qt3DRender::QGeometryFactoryPtr factory(new TestFactory(1200));
Qt3DRender::Render::GeometryRendererManager geometryRendererManager;
+ TestRenderer renderer;
geometryRenderer.setInstanceCount(1584);
geometryRenderer.setVertexCount(1609);
geometryRenderer.setIndexOffset(750);
geometryRenderer.setFirstInstance(883);
+ geometryRenderer.setIndexBufferByteOffset(96);
geometryRenderer.setRestartIndexValue(65536);
geometryRenderer.setPrimitiveRestartEnabled(true);
geometryRenderer.setPrimitiveType(Qt3DRender::QGeometryRenderer::Patches);
@@ -98,6 +100,7 @@ private Q_SLOTS:
geometryRenderer.setEnabled(false);
// WHEN
+ renderGeometryRenderer.setRenderer(&renderer);
renderGeometryRenderer.setManager(&geometryRendererManager);
simulateInitialization(&geometryRenderer, &renderGeometryRenderer);
@@ -108,6 +111,7 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.vertexCount(), geometryRenderer.vertexCount());
QCOMPARE(renderGeometryRenderer.indexOffset(), geometryRenderer.indexOffset());
QCOMPARE(renderGeometryRenderer.firstInstance(), geometryRenderer.firstInstance());
+ QCOMPARE(renderGeometryRenderer.indexBufferByteOffset(), geometryRenderer.indexBufferByteOffset());
QCOMPARE(renderGeometryRenderer.restartIndexValue(), geometryRenderer.restartIndexValue());
QCOMPARE(renderGeometryRenderer.primitiveRestartEnabled(), geometryRenderer.primitiveRestartEnabled());
QCOMPARE(renderGeometryRenderer.primitiveType(), geometryRenderer.primitiveType());
@@ -131,6 +135,7 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.vertexCount(), 0);
QCOMPARE(renderGeometryRenderer.indexOffset(), 0);
QCOMPARE(renderGeometryRenderer.firstInstance(), 0);
+ QCOMPARE(renderGeometryRenderer.indexBufferByteOffset(), 0);
QCOMPARE(renderGeometryRenderer.restartIndexValue(), -1);
QCOMPARE(renderGeometryRenderer.primitiveRestartEnabled(), false);
QCOMPARE(renderGeometryRenderer.primitiveType(), Qt3DRender::QGeometryRenderer::Triangles);
@@ -141,12 +146,13 @@ private Q_SLOTS:
Qt3DRender::QGeometryRenderer geometryRenderer;
Qt3DRender::QGeometry geometry;
Qt3DRender::QGeometryFactoryPtr factory(new TestFactory(1200));
-
+ TestRenderer renderer;
geometryRenderer.setInstanceCount(454);
geometryRenderer.setVertexCount(350);
geometryRenderer.setIndexOffset(427);
geometryRenderer.setFirstInstance(383);
+ geometryRenderer.setIndexBufferByteOffset(96);
geometryRenderer.setRestartIndexValue(555);
geometryRenderer.setPrimitiveRestartEnabled(true);
geometryRenderer.setPrimitiveType(Qt3DRender::QGeometryRenderer::Patches);
@@ -155,6 +161,7 @@ private Q_SLOTS:
geometryRenderer.setEnabled(true);
// WHEN
+ renderGeometryRenderer.setRenderer(&renderer);
renderGeometryRenderer.setManager(&geometryRendererManager);
simulateInitialization(&geometryRenderer, &renderGeometryRenderer);
renderGeometryRenderer.cleanup();
@@ -166,6 +173,7 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.vertexCount(), 0);
QCOMPARE(renderGeometryRenderer.indexOffset(), 0);
QCOMPARE(renderGeometryRenderer.firstInstance(), 0);
+ QCOMPARE(renderGeometryRenderer.indexBufferByteOffset(), 0);
QCOMPARE(renderGeometryRenderer.restartIndexValue(), -1);
QCOMPARE(renderGeometryRenderer.primitiveRestartEnabled(), false);
QCOMPARE(renderGeometryRenderer.primitiveType(), Qt3DRender::QGeometryRenderer::Triangles);
@@ -191,7 +199,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(renderGeometryRenderer.instanceCount(), 2);
QVERIFY(renderGeometryRenderer.isDirty());
- QVERIFY(renderer.dirtyBits() != 0);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -206,6 +215,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.vertexCount(), 56);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -219,6 +231,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.indexOffset(), 65);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -232,6 +247,25 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.firstInstance(), 82);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ renderGeometryRenderer.unsetDirty();
+ QVERIFY(!renderGeometryRenderer.isDirty());
+
+ // WHEN
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("indexBufferByteOffset");
+ updateChange->setValue(96);
+ renderGeometryRenderer.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(renderGeometryRenderer.indexBufferByteOffset(), 96);
+ QVERIFY(renderGeometryRenderer.isDirty());
+
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -245,6 +279,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.restartIndexValue(), 46);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -258,6 +295,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.primitiveRestartEnabled(), true);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -271,6 +311,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.primitiveType(), Qt3DRender::QGeometryRenderer::LineLoop);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -285,9 +328,23 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.geometryFactory(), factory);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
+ // WHEN we set an identical factory again
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("geometryFactory");
+ Qt3DRender::QGeometryFactoryPtr factory2(new TestFactory(1450));
+ updateChange->setValue(QVariant::fromValue(factory2));
+ renderGeometryRenderer.sceneChangeEvent(updateChange);
+
+ // THEN not dirty and still uses original factory
+ QCOMPARE(renderGeometryRenderer.geometryFactory(), factory);
+ QVERIFY(!renderGeometryRenderer.isDirty());
+
// WHEN
DummyGeometry geometry;
const Qt3DCore::QNodeId geometryId = geometry.id();
@@ -300,6 +357,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.geometryId(), geometryId);
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -313,6 +373,9 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.geometryId(), Qt3DCore::QNodeId());
QVERIFY(renderGeometryRenderer.isDirty());
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
renderGeometryRenderer.unsetDirty();
QVERIFY(!renderGeometryRenderer.isDirty());
@@ -326,6 +389,27 @@ private Q_SLOTS:
QCOMPARE(renderGeometryRenderer.isEnabled(), true);
QVERIFY(!renderGeometryRenderer.isDirty());
}
+
+ void checkSetRendererDirtyOnInitialization()
+ {
+ // GIVEN
+ Qt3DRender::Render::GeometryRendererManager geometryRendererManager;
+ Qt3DRender::Render::GeometryRenderer renderGeometryRenderer;
+ Qt3DRender::QGeometryRenderer geometryRenderer;
+ TestRenderer renderer;
+
+ renderGeometryRenderer.setRenderer(&renderer);
+ renderGeometryRenderer.setManager(&geometryRendererManager);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), 0);
+
+ // WHEN
+ simulateInitialization(&geometryRenderer, &renderGeometryRenderer);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::GeometryDirty);
+ }
};
QTEST_APPLESS_MAIN(tst_RenderGeometryRenderer)
diff --git a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
index afd56e9bd..584b675ee 100644
--- a/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
+++ b/tests/auto/render/graphicshelpergl2/tst_graphicshelpergl2.cpp
@@ -33,8 +33,10 @@
#include <Qt3DRender/private/attachmentpack_p.h>
#include <QtOpenGLExtensions/QOpenGLExtensions>
#include <QOpenGLContext>
+#include <QOpenGLBuffer>
#include <QOpenGLFunctions_2_0>
#include <QOpenGLShaderProgram>
+#include <QOpenGLVertexArrayObject>
#include <QSurfaceFormat>
#ifndef QT_OPENGL_ES_2
@@ -612,6 +614,33 @@ private Q_SLOTS:
// Not supported by GL2
}
+ void enableVertexAttribute()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeSamplers);
+ QVERIFY(shaderProgram.link());
+ shaderProgram.bind();
+
+ // WHEN
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void frontFace()
{
if (!m_initializationSuccessful)
@@ -1019,6 +1048,51 @@ private Q_SLOTS:
// Not available in 3.2
}
+ void vertexAttributePointer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCode);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeSamplers);
+ QVERIFY(shaderProgram.link());
+
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+
+ const int vertexCount = 99;
+ QOpenGLBuffer positionBuffer(QOpenGLBuffer::VertexBuffer);
+ positionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ positionBuffer.create();
+ positionBuffer.bind();
+ positionBuffer.allocate(vertexCount * sizeof(QVector3D));
+
+ QOpenGLBuffer texCoordBuffer(QOpenGLBuffer::VertexBuffer);
+ texCoordBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ texCoordBuffer.create();
+ texCoordBuffer.allocate(vertexCount * sizeof(QVector2D));
+
+ // WHEN
+ shaderProgram.bind();
+ positionBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC3, positionLocation, 3, GL_FLOAT, GL_TRUE, 0, 0);
+
+ texCoordBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC2, texCoordLocation, 2, GL_FLOAT, GL_TRUE, 0, 0);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void glUniform1fv()
{
if (!m_initializationSuccessful)
@@ -1438,6 +1512,18 @@ private Q_SLOTS:
QCOMPARE(computed, expected);
}
+ void drawBuffer()
+ {
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
+ void readBuffer()
+ {
+ QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
+ // Not supported by GL2
+ }
+
private:
QScopedPointer<QWindow> m_window;
QOpenGLContext m_glContext;
diff --git a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
index 1414d13b0..648eaaddb 100644
--- a/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
+++ b/tests/auto/render/graphicshelpergl3_2/tst_graphicshelpergl3_2.cpp
@@ -31,8 +31,10 @@
#include <Qt3DRender/private/uniform_p.h>
#include <Qt3DRender/private/graphicshelpergl3_2_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QOpenGLBuffer>
#include <QOpenGLFunctions_3_2_Core>
#include <QOpenGLShaderProgram>
+#include <QOpenGLVertexArrayObject>
#include <QSurfaceFormat>
#if !defined(QT_OPENGL_ES_2) && defined(QT_OPENGL_3_2)
@@ -139,6 +141,7 @@ const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
"#version 150 core\n" \
"out vec4 color;\n" \
+ "in vec2 texCoord;\n" \
"flat in int colorIndex;\n" \
"uniform ColorArray\n" \
"{\n" \
@@ -146,7 +149,7 @@ const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
"};\n" \
"void main()\n" \
"{\n" \
- " color = colors[colorIndex];\n" \
+ " color = colors[colorIndex] + vec4(texCoord.s, texCoord.t, 0.0, 1.0);\n" \
"}\n");
const QByteArray fragCodeSamplers = QByteArrayLiteral(
@@ -823,6 +826,35 @@ private Q_SLOTS:
m_func->glDisable(GL_PRIMITIVE_RESTART);
}
+ void enableVertexAttribute()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+ shaderProgram.bind();
+
+ // WHEN
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ GLint colorIndexLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexColorIndex");
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void frontFace()
{
if (!m_initializationSuccessful)
@@ -1318,6 +1350,61 @@ private Q_SLOTS:
// Not available in 3.2
}
+ void vertexAttributePointer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ GLint colorIndexLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexColorIndex");
+
+ const int vertexCount = 99;
+ QOpenGLBuffer positionBuffer(QOpenGLBuffer::VertexBuffer);
+ positionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ positionBuffer.create();
+ positionBuffer.bind();
+ positionBuffer.allocate(vertexCount * sizeof(QVector3D));
+
+ QOpenGLBuffer texCoordBuffer(QOpenGLBuffer::VertexBuffer);
+ texCoordBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ texCoordBuffer.create();
+ texCoordBuffer.allocate(vertexCount * sizeof(QVector2D));
+
+ QOpenGLBuffer colorIndexBuffer(QOpenGLBuffer::VertexBuffer);
+ colorIndexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ colorIndexBuffer.create();
+ colorIndexBuffer.allocate(vertexCount * sizeof(int));
+
+ // WHEN
+ shaderProgram.bind();
+ positionBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC3, positionLocation, 3, GL_FLOAT, GL_TRUE, 0, 0);
+
+ texCoordBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC2, texCoordLocation, 2, GL_FLOAT, GL_TRUE, 0, 0);
+
+ colorIndexBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+ m_glHelper.vertexAttributePointer(GL_INT, colorIndexLocation, 1, GL_INT, GL_TRUE, 0, 0);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void glUniform1fv()
{
if (!m_initializationSuccessful)
@@ -2028,6 +2115,42 @@ private Q_SLOTS:
QCOMPARE(computed, expected);
}
+ void drawBuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ m_func->glGetError();
+
+ // WHEN
+ m_glHelper.drawBuffer(GL_FRONT);
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // THEN
+ GLint p;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER, &p);
+ QCOMPARE(p, GL_FRONT);
+ }
+
+ void readBuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.2 Core functions not supported");
+
+ m_func->glGetError();
+
+ // WHEN
+ m_glHelper.readBuffer(GL_FRONT);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint p;
+ m_func->glGetIntegerv(GL_READ_BUFFER, &p);
+ QCOMPARE(p, GL_FRONT);
+ }
+
private:
QScopedPointer<QWindow> m_window;
QOpenGLContext m_glContext;
diff --git a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
index eea0e9f14..06a3c41cd 100644
--- a/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
+++ b/tests/auto/render/graphicshelpergl3_3/tst_graphicshelpergl3_3.cpp
@@ -31,8 +31,10 @@
#include <Qt3DRender/private/uniform_p.h>
#include <Qt3DRender/private/graphicshelpergl3_3_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QOpenGLBuffer>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
+#include <QOpenGLVertexArrayObject>
#if !defined(QT_OPENGL_ES_2) && defined(QT_OPENGL_3_2)
@@ -138,6 +140,7 @@ const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
"#version 330 core\n" \
"out vec4 color;\n" \
+ "in vec2 texCoord;\n" \
"flat in int colorIndex;\n" \
"uniform ColorArray\n" \
"{\n" \
@@ -145,7 +148,7 @@ const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
"};\n" \
"void main()\n" \
"{\n" \
- " color = colors[colorIndex];\n" \
+ " color = colors[colorIndex] + vec4(texCoord.s, texCoord.t, 0.0, 1.0);\n" \
"}\n");
const QByteArray fragCodeSamplers = QByteArrayLiteral(
@@ -922,6 +925,35 @@ private Q_SLOTS:
m_func->glDisable(GL_PRIMITIVE_RESTART);
}
+ void enableVertexAttribute()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+ shaderProgram.bind();
+
+ // WHEN
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ GLint colorIndexLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexColorIndex");
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void frontFace()
{
if (!m_initializationSuccessful)
@@ -1417,6 +1449,61 @@ private Q_SLOTS:
QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
}
+ void vertexAttributePointer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ GLint colorIndexLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexColorIndex");
+
+ const int vertexCount = 99;
+ QOpenGLBuffer positionBuffer(QOpenGLBuffer::VertexBuffer);
+ positionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ positionBuffer.create();
+ positionBuffer.bind();
+ positionBuffer.allocate(vertexCount * sizeof(QVector3D));
+
+ QOpenGLBuffer texCoordBuffer(QOpenGLBuffer::VertexBuffer);
+ texCoordBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ texCoordBuffer.create();
+ texCoordBuffer.allocate(vertexCount * sizeof(QVector2D));
+
+ QOpenGLBuffer colorIndexBuffer(QOpenGLBuffer::VertexBuffer);
+ colorIndexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ colorIndexBuffer.create();
+ colorIndexBuffer.allocate(vertexCount * sizeof(int));
+
+ // WHEN
+ shaderProgram.bind();
+ positionBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC3, positionLocation, 3, GL_FLOAT, GL_TRUE, 0, 0);
+
+ texCoordBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC2, texCoordLocation, 2, GL_FLOAT, GL_TRUE, 0, 0);
+
+ colorIndexBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+ m_glHelper.vertexAttributePointer(GL_INT, colorIndexLocation, 1, GL_INT, GL_TRUE, 0, 0);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void glUniform1fv()
{
if (!m_initializationSuccessful)
@@ -2128,6 +2215,42 @@ private Q_SLOTS:
QCOMPARE(computed, expected);
}
+ void drawBuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ m_func->glGetError();
+
+ // WHEN
+ m_glHelper.drawBuffer(GL_FRONT);
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // THEN
+ GLint p;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER, &p);
+ QCOMPARE(p, GL_FRONT);
+ }
+
+ void readBuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 3.3 Core functions not supported");
+
+ m_func->glGetError();
+
+ // WHEN
+ m_glHelper.readBuffer(GL_FRONT);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint p;
+ m_func->glGetIntegerv(GL_READ_BUFFER, &p);
+ QCOMPARE(p, GL_FRONT);
+ }
+
private:
QScopedPointer<QWindow> m_window;
QOpenGLContext m_glContext;
diff --git a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
index 84d261659..5a96cf116 100644
--- a/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
+++ b/tests/auto/render/graphicshelpergl4/tst_graphicshelpergl4.cpp
@@ -31,8 +31,10 @@
#include <Qt3DRender/private/uniform_p.h>
#include <Qt3DRender/private/graphicshelpergl4_p.h>
#include <Qt3DRender/private/attachmentpack_p.h>
+#include <QOpenGLBuffer>
#include <QOpenGLFunctions_4_3_Core>
#include <QOpenGLShaderProgram>
+#include <QOpenGLVertexArrayObject>
#include <QSurfaceFormat>
#if !defined(QT_OPENGL_ES_2) && defined(QT_OPENGL_4_3)
@@ -60,11 +62,12 @@ const QByteArray vertCodeUniformBuffer = QByteArrayLiteral(
"layout(location = 1) in vec3 vertexPosition;\n" \
"layout(location = 2) in vec2 vertexTexCoord;\n" \
"layout(location = 3) in int vertexColorIndex;\n" \
+ "layout(location = 4) in double vertexTexCoordScale;\n" \
"out vec2 texCoord;\n" \
"flat out int colorIndex;\n" \
"void main()\n" \
"{\n" \
- " texCoord = vertexTexCoord;\n" \
+ " texCoord = vec2(vertexTexCoordScale * vertexTexCoord);\n" \
" colorIndex = vertexColorIndex;\n" \
" gl_Position = vec4(vertexPosition, 1.0);\n" \
"}\n");
@@ -139,6 +142,7 @@ const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
"#version 430 core\n" \
"out vec4 color;\n" \
+ "in vec2 texCoord;\n" \
"flat in int colorIndex;\n" \
"layout(binding = 2, std140) uniform ColorArray\n" \
"{\n" \
@@ -146,7 +150,7 @@ const QByteArray fragCodeUniformBuffer = QByteArrayLiteral(
"};\n" \
"void main()\n" \
"{\n" \
- " color = colors[colorIndex];\n" \
+ " color = colors[colorIndex] + vec4(texCoord.s, texCoord.t, 0.0, 1.0);\n" \
"}\n");
const QByteArray fragCodeSamplers = QByteArrayLiteral(
@@ -1020,6 +1024,35 @@ private Q_SLOTS:
m_func->glDisable(GL_PRIMITIVE_RESTART);
}
+ void enableVertexAttribute()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+ shaderProgram.bind();
+
+ // WHEN
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ GLint colorIndexLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexColorIndex");
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void frontFace()
{
if (!m_initializationSuccessful)
@@ -1507,6 +1540,71 @@ private Q_SLOTS:
QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
}
+ void vertexAttributePointer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ // GIVEN
+ QOpenGLVertexArrayObject vao;
+ vao.create();
+ QOpenGLVertexArrayObject::Binder binder(&vao);
+
+ QOpenGLShaderProgram shaderProgram;
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertCodeUniformBuffer);
+ shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragCodeUniformBuffer);
+ QVERIFY(shaderProgram.link());
+
+ GLint positionLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexPosition");
+ GLint texCoordLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoord");
+ GLint colorIndexLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexColorIndex");
+ GLint texCoordScaleLocation = m_func->glGetAttribLocation(shaderProgram.programId(), "vertexTexCoordScale");
+
+ const int vertexCount = 99;
+ QOpenGLBuffer positionBuffer(QOpenGLBuffer::VertexBuffer);
+ positionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ positionBuffer.create();
+ positionBuffer.bind();
+ positionBuffer.allocate(vertexCount * sizeof(QVector3D));
+
+ QOpenGLBuffer texCoordBuffer(QOpenGLBuffer::VertexBuffer);
+ texCoordBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ texCoordBuffer.create();
+ texCoordBuffer.allocate(vertexCount * sizeof(QVector2D));
+
+ QOpenGLBuffer colorIndexBuffer(QOpenGLBuffer::VertexBuffer);
+ colorIndexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ colorIndexBuffer.create();
+ colorIndexBuffer.allocate(vertexCount * sizeof(int));
+
+ QOpenGLBuffer scaleBuffer(QOpenGLBuffer::VertexBuffer);
+ scaleBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ scaleBuffer.create();
+ scaleBuffer.allocate(vertexCount * sizeof(double));
+
+ // WHEN
+ shaderProgram.bind();
+ positionBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(positionLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC3, positionLocation, 3, GL_FLOAT, GL_TRUE, 0, 0);
+
+ texCoordBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(texCoordLocation);
+ m_glHelper.vertexAttributePointer(GL_FLOAT_VEC2, texCoordLocation, 2, GL_FLOAT, GL_TRUE, 0, 0);
+
+ colorIndexBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+ m_glHelper.vertexAttributePointer(GL_INT, colorIndexLocation, 1, GL_INT, GL_TRUE, 0, 0);
+
+ scaleBuffer.bind();
+ m_glHelper.enableVertexAttributeArray(colorIndexLocation);
+ m_glHelper.vertexAttributePointer(GL_DOUBLE, texCoordScaleLocation, 1, GL_DOUBLE, GL_TRUE, 0, 0);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ }
+
void glUniform1fv()
{
if (!m_initializationSuccessful)
@@ -2196,6 +2294,42 @@ private Q_SLOTS:
QCOMPARE(computed, expected);
}
+ void drawBuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ m_func->glGetError();
+
+ // WHEN
+ m_glHelper.drawBuffer(GL_FRONT);
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+
+ // THEN
+ GLint p;
+ m_func->glGetIntegerv(GL_DRAW_BUFFER, &p);
+ QCOMPARE(p, GL_FRONT);
+ }
+
+ void readBuffer()
+ {
+ if (!m_initializationSuccessful)
+ QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
+
+ m_func->glGetError();
+
+ // WHEN
+ m_glHelper.readBuffer(GL_FRONT);
+
+ // THEN
+ const GLint error = m_func->glGetError();
+ QVERIFY(error == 0);
+ GLint p;
+ m_func->glGetIntegerv(GL_READ_BUFFER, &p);
+ QCOMPARE(p, GL_FRONT);
+ }
+
private:
QScopedPointer<QWindow> m_window;
QOpenGLContext m_glContext;
diff --git a/tests/auto/render/joint/joint.pro b/tests/auto/render/joint/joint.pro
new file mode 100644
index 000000000..9428ab5fd
--- /dev/null
+++ b/tests/auto/render/joint/joint.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_joint
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_joint.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/joint/tst_joint.cpp b/tests/auto/render/joint/tst_joint.cpp
new file mode 100644
index 000000000..13aa915d2
--- /dev/null
+++ b/tests/auto/render/joint/tst_joint.cpp
@@ -0,0 +1,242 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/private/joint_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
+#include <Qt3DCore/qpropertynodeaddedchange.h>
+#include <Qt3DCore/qpropertynoderemovedchange.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qvector3d.h>
+#include <qbackendnodetester.h>
+#include <testpostmanarbiter.h>
+#include <testrenderer.h>
+
+using namespace Qt3DCore;
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+class tst_Joint : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ Joint backendJoint;
+ backendJoint.setRenderer(&renderer);
+ backendJoint.setJointManager(nodeManagers.jointManager());
+ QJoint joint;
+
+ joint.setTranslation(QVector3D(1.0f, 2.0f, 3.0f));
+ joint.setScale(QVector3D(1.5f, 2.5f, 3.5));
+ joint.setRotation(QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, 45.0f));
+ QMatrix4x4 inverseBind;
+ inverseBind.rotate(-45.0f, 1.0f, 0.0, 0.0f);
+ joint.setInverseBindMatrix(inverseBind);
+
+ QVector<QJoint *> childJoints;
+ for (int i = 0; i < 10; ++i) {
+ const auto childJoint = new QJoint();
+ joint.addChildJoint(childJoint);
+ childJoints.push_back(childJoint);
+ }
+
+ // WHEN
+ simulateInitialization(&joint, &backendJoint);
+
+ // THEN
+ QCOMPARE(backendJoint.peerId(), joint.id());
+ QCOMPARE(backendJoint.isEnabled(), joint.isEnabled());
+ QCOMPARE(backendJoint.translation(), joint.translation());
+ QCOMPARE(backendJoint.rotation(), joint.rotation());
+ QCOMPARE(backendJoint.scale(), joint.scale());
+ QCOMPARE(backendJoint.inverseBindMatrix(), joint.inverseBindMatrix());
+ for (int i = 0; i < childJoints.size(); ++i) {
+ QCOMPARE(backendJoint.childJointIds()[i], childJoints[i]->id());
+ }
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ Joint backendJoint;
+ backendJoint.setRenderer(&renderer);
+ backendJoint.setJointManager(nodeManagers.jointManager());
+
+ // THEN
+ QVERIFY(backendJoint.peerId().isNull());
+ QCOMPARE(backendJoint.isEnabled(), false);
+ QCOMPARE(backendJoint.translation(), QVector3D());
+ QCOMPARE(backendJoint.rotation(), QQuaternion());
+ QCOMPARE(backendJoint.scale(), QVector3D(1.0f, 1.0f, 1.0f));
+ QCOMPARE(backendJoint.inverseBindMatrix(), QMatrix4x4());
+ QCOMPARE(backendJoint.childJointIds(), QNodeIdVector());
+ QCOMPARE(backendJoint.owningSkeleton(), HSkeleton());
+
+ // GIVEN
+ QJoint joint;
+ joint.setTranslation(QVector3D(1.0f, 2.0f, 3.0f));
+ joint.setScale(QVector3D(1.5f, 2.5f, 3.5));
+ joint.setRotation(QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, 45.0f));
+ QMatrix4x4 inverseBind;
+ inverseBind.rotate(-45.0f, 1.0f, 0.0, 0.0f);
+ joint.setInverseBindMatrix(inverseBind);
+
+ QVector<QJoint *> childJoints;
+ for (int i = 0; i < 10; ++i) {
+ const auto childJoint = new QJoint();
+ joint.addChildJoint(childJoint);
+ childJoints.push_back(childJoint);
+ }
+
+ // WHEN
+ simulateInitialization(&joint, &backendJoint);
+ backendJoint.cleanup();
+
+ // THEN
+ QCOMPARE(backendJoint.isEnabled(), false);
+ QCOMPARE(backendJoint.translation(), QVector3D());
+ QCOMPARE(backendJoint.rotation(), QQuaternion());
+ QCOMPARE(backendJoint.scale(), QVector3D(1.0f, 1.0f, 1.0f));
+ QCOMPARE(backendJoint.inverseBindMatrix(), QMatrix4x4());
+ QCOMPARE(backendJoint.childJointIds(), QNodeIdVector());
+ QCOMPARE(backendJoint.owningSkeleton(), HSkeleton());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ Joint backendJoint;
+ backendJoint.setRenderer(&renderer);
+ backendJoint.setJointManager(nodeManagers.jointManager());
+ backendJoint.setSkeletonManager(nodeManagers.skeletonManager());
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange;
+
+ // WHEN
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("enabled");
+ updateChange->setValue(true);
+ backendJoint.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendJoint.isEnabled(), true);
+
+ // WHEN
+ const QVector3D newTranslation = QVector3D(1.0f, 2.0f, 3.0f);
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("translation");
+ updateChange->setValue(newTranslation);
+ backendJoint.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendJoint.translation(), newTranslation);
+
+ // WHEN
+ const QQuaternion newRotation = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, 45.0f);
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("rotation");
+ updateChange->setValue(newRotation);
+ backendJoint.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendJoint.rotation(), newRotation);
+
+ // WHEN
+ const QVector3D newScale = QVector3D(1.5f, 2.5f, 3.5f);
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("scale");
+ updateChange->setValue(newScale);
+ backendJoint.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendJoint.scale(), newScale);
+
+ // WHEN
+ QMatrix4x4 newInverseBind;
+ newInverseBind.scale(5.4f);
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("inverseBindMatrix");
+ updateChange->setValue(newInverseBind);
+ backendJoint.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendJoint.inverseBindMatrix(), newInverseBind);
+
+ // WHEN
+ QVector<QJoint *> childJoints;
+ QPropertyNodeAddedChangePtr nodeAddedChange;
+ for (int i = 0; i < 10; ++i) {
+ const auto childJoint = new QJoint();
+ childJoints.push_back(childJoint);
+
+ nodeAddedChange.reset(new QPropertyNodeAddedChange(QNodeId(), childJoint));
+ nodeAddedChange->setPropertyName("childJoint");
+ backendJoint.sceneChangeEvent(nodeAddedChange);
+ }
+
+ // THEN
+ for (int i = 0; i < childJoints.size(); ++i) {
+ QCOMPARE(backendJoint.childJointIds()[i], childJoints[i]->id());
+ }
+
+ QPropertyNodeRemovedChangePtr nodeRemovedChange;
+ for (int i = 0; i < 10; ++i) {
+ // WHEN
+ const auto childJoint = childJoints.takeLast();
+
+ nodeRemovedChange.reset(new QPropertyNodeRemovedChange(QNodeId(), childJoint));
+ nodeRemovedChange->setPropertyName("childJoint");
+ backendJoint.sceneChangeEvent(nodeAddedChange);
+
+ // THEN
+ for (int i = 0; i < childJoints.size(); ++i) {
+ QCOMPARE(backendJoint.childJointIds()[i], childJoints[i]->id());
+ }
+ }
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Joint)
+
+#include "tst_joint.moc"
diff --git a/tests/auto/render/layerfiltering/tst_layerfiltering.cpp b/tests/auto/render/layerfiltering/tst_layerfiltering.cpp
index c66b85c8c..c2651c477 100644
--- a/tests/auto/render/layerfiltering/tst_layerfiltering.cpp
+++ b/tests/auto/render/layerfiltering/tst_layerfiltering.cpp
@@ -34,6 +34,7 @@
#include <Qt3DRender/private/filterlayerentityjob_p.h>
#include <Qt3DRender/private/updatetreeenabledjob_p.h>
#include <Qt3DRender/qlayer.h>
+#include <Qt3DRender/qlayerfilter.h>
#include "testaspect.h"
class tst_LayerFiltering : public QObject
@@ -45,18 +46,19 @@ private Q_SLOTS:
{
// GIVEN
Qt3DRender::Render::FilterLayerEntityJob filterJob;
+ Qt3DRender::QLayer frontendLayer;
// THEN
QCOMPARE(filterJob.hasLayerFilter(), false);
QCOMPARE(filterJob.filteredEntities().size(), 0);
- QCOMPARE(filterJob.layers().size(), 0);
+ QCOMPARE(filterJob.layerFilters().size(), 0);
+ QCOMPARE(frontendLayer.recursive(), false);
}
void filterEntities_data()
{
QTest::addColumn<Qt3DCore::QEntity *>("entitySubtree");
- QTest::addColumn<Qt3DCore::QNodeIdVector>("layerIds");
- QTest::addColumn<bool>("hasLayerFilter");
+ QTest::addColumn<Qt3DCore::QNodeIdVector>("layerFilterIds");
QTest::addColumn<Qt3DCore::QNodeIdVector>("expectedSelectedEntities");
@@ -70,15 +72,14 @@ private Q_SLOTS:
Q_UNUSED(childEntity2);
Q_UNUSED(childEntity3);
- QTest::newRow("EntitiesNoLayerNoLayerFilter-ShouldSelectAll") << rootEntity
- << Qt3DCore::QNodeIdVector()
- << false
- << (Qt3DCore::QNodeIdVector()
- << rootEntity->id()
- << childEntity1->id()
- << childEntity2->id()
- << childEntity3->id()
- );
+ QTest::newRow("EntitiesNoLayerNoLayerFilterNoDiscardNoRecursive-ShouldSelectAll") << rootEntity
+ << Qt3DCore::QNodeIdVector()
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id()
+ << childEntity2->id()
+ << childEntity3->id()
+ );
}
{
@@ -87,14 +88,14 @@ private Q_SLOTS:
Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
Q_UNUSED(childEntity1);
Q_UNUSED(childEntity2);
Q_UNUSED(childEntity3);
QTest::newRow("EntityNoLayerWithLayerFilterWithNoFilter-ShouldSelectNone") << rootEntity
- << Qt3DCore::QNodeIdVector()
- << true
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
<< Qt3DCore::QNodeIdVector();
}
@@ -109,12 +110,13 @@ private Q_SLOTS:
Q_UNUSED(childEntity3);
Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->addLayer(layer);
- QTest::newRow("NoLayerWithLayerFilterWithFilter-ShouldSelectNone") << rootEntity
- << (Qt3DCore::QNodeIdVector() << layer->id())
- << true
- << Qt3DCore::QNodeIdVector();
+ QTest::newRow("AcceptAny-NoLayerWithLayerFilterWithFilter-ShouldSelectNone") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << Qt3DCore::QNodeIdVector();
}
{
@@ -129,10 +131,12 @@ private Q_SLOTS:
childEntity2->addComponent(layer);
childEntity3->addComponent(layer);
- QTest::newRow("LayerWithLayerFilterWithFilter-ShouldSelectAllButRoot") << rootEntity
- << (Qt3DCore::QNodeIdVector() << layer->id())
- << true
- << (Qt3DCore::QNodeIdVector() << childEntity1->id() << childEntity2->id() << childEntity3->id());
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->addLayer(layer);
+
+ QTest::newRow("AcceptAny-LayerWithLayerFilterWithFilter-ShouldSelectAllButRoot") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector() << childEntity1->id() << childEntity2->id() << childEntity3->id());
}
{
@@ -148,10 +152,13 @@ private Q_SLOTS:
childEntity2->addComponent(layer2);
childEntity3->addComponent(layer);
- QTest::newRow("LayerWithLayerFilterWithFilter-ShouldSelectChild2And3") << rootEntity
- << (Qt3DCore::QNodeIdVector() << layer->id() << layer2->id())
- << true
- << (Qt3DCore::QNodeIdVector() << childEntity2->id() << childEntity3->id());
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->addLayer(layer);
+ layerFilter->addLayer(layer2);
+
+ QTest::newRow("AcceptAny-LayerWithLayerFilterWithFilter-ShouldSelectChild2And3") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector() << childEntity2->id() << childEntity3->id());
}
{
@@ -167,10 +174,12 @@ private Q_SLOTS:
childEntity2->addComponent(layer);
childEntity3->addComponent(layer);
- QTest::newRow("LayerWithLayerFilterWithFilter-ShouldSelectNone") << rootEntity
- << (Qt3DCore::QNodeIdVector() << layer2->id())
- << true
- << Qt3DCore::QNodeIdVector();
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->addLayer(layer2);
+
+ QTest::newRow("AcceptAny-LayerWithLayerFilterWithFilter-ShouldSelectNone") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << Qt3DCore::QNodeIdVector();
}
{
@@ -186,22 +195,436 @@ private Q_SLOTS:
childEntity2->addComponent(layer);
childEntity3->addComponent(layer);
- QTest::newRow("LayerWithEntityDisabled-ShouldSelectOnlyEntityEnabled") << rootEntity
- << (Qt3DCore::QNodeIdVector() << layer->id())
- << true
- << (Qt3DCore::QNodeIdVector() << childEntity2->id() << childEntity3->id());
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->addLayer(layer);
+
+ QTest::newRow("AcceptAny-LayerWithEntityDisabled-ShouldSelectOnlyEntityEnabled") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector() << childEntity2->id() << childEntity3->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+ rootEntity->addComponent(layer);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->addLayer(layer);
+
+ QTest::newRow("AcceptAny-RecursiveLayerOnRoot-ShouldSelectAll") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id()
+ << childEntity2->id()
+ << childEntity3->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Q_UNUSED(childEntity1);
+ Q_UNUSED(childEntity2);
+ Q_UNUSED(childEntity3);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+ rootEntity->addComponent(layer);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAnyMatchingLayers);
+ layerFilter->addLayer(layer);
+
+ QTest::newRow("DiscardAny-RecursiveLayerLayerFilterDiscardOnRoot-ShouldSelectNone") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ rootEntity->addComponent(layer);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAnyMatchingLayers);
+ layerFilter->addLayer(layer);
+
+ QTest::newRow("DiscardAny-LayerLayerFilterDiscardOnRoot-ShouldSelectAllButRoot") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity1->id()
+ << childEntity2->id()
+ << childEntity3->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer2);
+
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer2);
+ childEntity3->addComponent(layer3);
+ childEntity3->addComponent(layer);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAnyMatchingLayers);
+ layerFilter->addLayer(layer2);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("DiscardAny-LayerLayerFilterDiscardOnRoot-ShouldSelectRoot") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer3);
+ childEntity1->addComponent(layer2);
+
+ childEntity2->addComponent(layer);
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer);
+ childEntity3->addComponent(layer2);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::AcceptAllMatchingLayers);
+ layerFilter->addLayer(layer2);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("AcceptAll-LayerFilterWith2LayersNonRecursive-ShouldSelectChild1") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity1->id());
}
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer3);
+ childEntity1->addComponent(layer2);
+
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer2);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::AcceptAllMatchingLayers);
+ layerFilter->addLayer(layer);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("AcceptAll-LayerFilterWith2LayersRecursive-ShouldSelectChild12") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity1->id()
+ << childEntity2->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer3);
+ childEntity1->addComponent(layer2);
+
+ childEntity2->addComponent(layer);
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer2);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::AcceptAllMatchingLayers);
+ layerFilter->addLayer(layer);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("AcceptAll-LayerFilterWith2LayersRecursiveAndDirectReferenceToRecursiveLayer-ShouldSelectChild12") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity1->id()
+ << childEntity2->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer);
+ childEntity1->addComponent(layer2);
+
+ childEntity2->addComponent(layer);
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer2);
+ childEntity3->addComponent(layer3);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAllMatchingLayers);
+ layerFilter->addLayer(layer2);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("DiscardAll-LayerFilterWith2Layers-ShouldSelectRootAndChild12") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id()
+ << childEntity2->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer2);
+
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer3);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAllMatchingLayers);
+ layerFilter->addLayer(layer);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("DiscardAll-LayerFilterWith2LayersRecursive-ShouldSelectRootAndChild1") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer2);
+ childEntity1->addComponent(layer);
+
+ childEntity2->addComponent(layer3);
+
+ childEntity3->addComponent(layer3);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAllMatchingLayers);
+ layerFilter->addLayer(layer);
+ layerFilter->addLayer(layer3);
+
+ QTest::newRow("DiscardAll-LayerFilterWith2LayersRecursiveAndDirectReference-ShouldSelectRootAndChild1") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer4 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer5 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer2);
+ childEntity1->addComponent(layer3);
+
+ childEntity2->addComponent(layer2);
+ childEntity2->addComponent(layer3);
+ childEntity2->addComponent(layer4);
+ childEntity2->addComponent(layer5);
+
+ childEntity3->addComponent(layer2);
+ childEntity3->addComponent(layer3);
+ childEntity3->addComponent(layer5);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::AcceptAllMatchingLayers);
+ layerFilter->addLayer(layer);
+ layerFilter->addLayer(layer2);
+ layerFilter->addLayer(layer3);
+
+ Qt3DRender::QLayerFilter *layerFilter2 = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter2->setFilterMode(Qt3DRender::QLayerFilter::DiscardAnyMatchingLayers);
+ layerFilter2->addLayer(layer4);
+ layerFilter2->addLayer(layer5);
+
+ QTest::newRow("NestedFiltering-SelectAllOfLayer123AndNoneOf45-ShouldChild1") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id() << layerFilter2->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity1->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity4 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity5 = new Qt3DCore::QEntity(rootEntity);
+
+ Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(rootEntity);
+ layer->setRecursive(true);
+
+ Qt3DRender::QLayer *layer2 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer3 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer4 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer5 = new Qt3DRender::QLayer(rootEntity);
+ Qt3DRender::QLayer *layer6 = new Qt3DRender::QLayer(rootEntity);
+
+ rootEntity->addComponent(layer);
+
+ childEntity1->addComponent(layer2);
+ childEntity1->addComponent(layer3);
+
+ childEntity2->addComponent(layer2);
+ childEntity2->addComponent(layer3);
+ childEntity2->addComponent(layer4);
+ childEntity2->addComponent(layer5);
+
+ childEntity3->addComponent(layer2);
+ childEntity3->addComponent(layer5);
+
+ childEntity4->addComponent(layer2);
+ childEntity4->addComponent(layer);
+ childEntity4->addComponent(layer3);
+ childEntity4->addComponent(layer6);
+
+ childEntity5->addComponent(layer3);
+ childEntity5->addComponent(layer4);
+ childEntity5->addComponent(layer6);
+
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter->setFilterMode(Qt3DRender::QLayerFilter::DiscardAnyMatchingLayers);
+ layerFilter->addLayer(layer5);
+ layerFilter->addLayer(layer4);
+
+ Qt3DRender::QLayerFilter *layerFilter2 = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter2->setFilterMode(Qt3DRender::QLayerFilter::AcceptAnyMatchingLayers);
+ layerFilter2->addLayer(layer2);
+ layerFilter2->addLayer(layer3);
+
+ Qt3DRender::QLayerFilter *layerFilter3 = new Qt3DRender::QLayerFilter(rootEntity);
+ layerFilter3->setFilterMode(Qt3DRender::QLayerFilter::AcceptAllMatchingLayers);
+ layerFilter3->addLayer(layer);
+ layerFilter3->addLayer(layer6);
+
+ QTest::newRow("NestedFiltering-SelectAllNoneOfAnyLayer45AndAnyOf23AndAllOf16-ShouldSelectChild4-Step1") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id()
+ << childEntity4->id()
+ );
+
+ QTest::newRow("NestedFiltering-SelectAllNoneOfAnyLayer45AndAnyOf23AndAllOf16-ShouldSelectChild4-Step2") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id() << layerFilter2->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity1->id()
+ << childEntity4->id());
+
+ QTest::newRow("NestedFiltering-SelectAllNoneOfAnyLayer45AndAnyOf23AndAllOf16-ShouldSelectChild4-Step3") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << layerFilter->id() << layerFilter2->id() << layerFilter3->id())
+ << (Qt3DCore::QNodeIdVector()
+ << childEntity4->id());
+ }
}
void filterEntities()
{
//QSKIP("Skipping until TestAspect can be registered");
QFETCH(Qt3DCore::QEntity *, entitySubtree);
- QFETCH(Qt3DCore::QNodeIdVector, layerIds);
- QFETCH(bool, hasLayerFilter);
+ QFETCH(Qt3DCore::QNodeIdVector, layerFilterIds);
QFETCH(Qt3DCore::QNodeIdVector, expectedSelectedEntities);
+
// GIVEN
QScopedPointer<Qt3DRender::TestAspect> aspect(new Qt3DRender::TestAspect(entitySubtree));
@@ -213,16 +636,15 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::FilterLayerEntityJob filterJob;
- filterJob.setHasLayerFilter(hasLayerFilter);
- filterJob.setLayers(layerIds);
+ filterJob.setLayerFilters(layerFilterIds);
filterJob.setManager(aspect->nodeManagers());
filterJob.run();
// THEN
const QVector<Qt3DRender::Render::Entity *> filterEntities = filterJob.filteredEntities();
- QCOMPARE(expectedSelectedEntities.size(), filterEntities.size());
+ QCOMPARE(filterEntities.size(), expectedSelectedEntities.size());
for (auto i = 0, m = expectedSelectedEntities.size(); i < m; ++i)
- QCOMPARE(expectedSelectedEntities.at(i), filterEntities.at(i)->peerId());
+ QCOMPARE(filterEntities.at(i)->peerId(), expectedSelectedEntities.at(i));
}
};
diff --git a/tests/auto/render/loadscenejob/tst_loadscenejob.cpp b/tests/auto/render/loadscenejob/tst_loadscenejob.cpp
index 08d1caace..bd9848928 100644
--- a/tests/auto/render/loadscenejob/tst_loadscenejob.cpp
+++ b/tests/auto/render/loadscenejob/tst_loadscenejob.cpp
@@ -50,8 +50,15 @@ public:
m_source = source;
}
- bool isFileTypeSupported(const QUrl &) const Q_DECL_OVERRIDE
+ void setData(const QByteArray& data, const QString &basePath) Q_DECL_OVERRIDE
{
+ Q_UNUSED(data);
+ Q_UNUSED(basePath);
+ }
+
+ bool areFileTypesSupported(const QStringList &extensions) const Q_DECL_OVERRIDE
+ {
+ Q_UNUSED(extensions);
return m_supportsFormat;
}
@@ -99,7 +106,7 @@ private Q_SLOTS:
void checkInitialize()
{
// GIVEN
- const QUrl url(QStringLiteral("URL"));
+ const QUrl url(QStringLiteral("file:///URL"));
const Qt3DCore::QNodeId sceneId = Qt3DCore::QNodeId::createId();
Qt3DRender::Render::NodeManagers nodeManagers;
TestSceneImporter fakeImporter(true, true);
@@ -120,8 +127,10 @@ private Q_SLOTS:
void checkRunValidSourceSupportedFormat()
{
+ QSKIP("Can't test successful loading");
+
// GIVEN
- const QUrl url(QStringLiteral("URL"));
+ const QUrl url(QStringLiteral("file:///URL"));
TestArbiter arbiter;
Qt3DRender::Render::NodeManagers nodeManagers;
TestSceneImporter fakeImporter(true, false);
@@ -202,8 +211,11 @@ private Q_SLOTS:
void checkRunValidSourceUnsupportedFormat()
{
+ // no data is loaded so...
+ QSKIP("Can't differentiate between no data and unsupported data");
+
// GIVEN
- const QUrl url(QStringLiteral("URL"));
+ const QUrl url(QStringLiteral("file:///URL"));
TestArbiter arbiter;
Qt3DRender::Render::NodeManagers nodeManagers;
TestSceneImporter fakeImporter(false, false);
@@ -241,7 +253,7 @@ private Q_SLOTS:
void checkRunErrorAtLoading()
{
// GIVEN
- const QUrl url(QStringLiteral("URL"));
+ const QUrl url(QStringLiteral("file:///URL"));
TestArbiter arbiter;
Qt3DRender::Render::NodeManagers nodeManagers;
TestSceneImporter fakeImporter(true, true);
@@ -259,7 +271,7 @@ private Q_SLOTS:
loadSceneJob.run();
// THEN
- QCOMPARE(arbiter.events.count(), 4);
+ QCOMPARE(arbiter.events.count(), 3);
auto change = arbiter.events.at(0).staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->subjectId(), scene->peerId());
QCOMPARE(change->propertyName(), "status");
@@ -267,16 +279,11 @@ private Q_SLOTS:
change = arbiter.events.at(1).staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->subjectId(), scene->peerId());
- QCOMPARE(change->propertyName(), "status");
- QCOMPARE(change->value().value<Qt3DRender::QSceneLoader::Status>(), Qt3DRender::QSceneLoader::Loading);
-
- change = arbiter.events.at(2).staticCast<Qt3DCore::QPropertyUpdatedChange>();
- QCOMPARE(change->subjectId(), scene->peerId());
QCOMPARE(change->propertyName(), "scene");
QVERIFY(change->value().value<Qt3DCore::QEntity *>() == nullptr);
delete change->value().value<Qt3DCore::QEntity *>();
- change = arbiter.events.at(3).staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ change = arbiter.events.at(2).staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->subjectId(), scene->peerId());
QCOMPARE(change->propertyName(), "status");
QCOMPARE(change->value().value<Qt3DRender::QSceneLoader::Status>(), Qt3DRender::QSceneLoader::Error);
diff --git a/tests/auto/render/meshfunctors/tst_meshfunctors.cpp b/tests/auto/render/meshfunctors/tst_meshfunctors.cpp
index e2877b24b..fd430c5d8 100644
--- a/tests/auto/render/meshfunctors/tst_meshfunctors.cpp
+++ b/tests/auto/render/meshfunctors/tst_meshfunctors.cpp
@@ -32,6 +32,7 @@
#include <Qt3DRender/qgeometry.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/private/qmesh_p.h>
+#include <Qt3DCore/qaspectengine.h>
class MeshFunctorA : public Qt3DRender::QGeometryFactory
{
@@ -124,14 +125,27 @@ private Q_SLOTS:
void checkMeshFunctorEquality()
{
// GIVEN
- const Qt3DRender::MeshFunctor functorA(QUrl::fromLocalFile(QLatin1String("/foo")),
- QLatin1String("bar"));
- const Qt3DRender::MeshFunctor functorB(QUrl::fromLocalFile(QLatin1String("/foo")),
- QLatin1String("baz"));
- const Qt3DRender::MeshFunctor functorC(QUrl::fromLocalFile(QLatin1String("/baz")),
- QLatin1String("bar"));
- const Qt3DRender::MeshFunctor functorD(QUrl::fromLocalFile(QLatin1String("/foo")),
- QLatin1String("bar"));
+ Qt3DCore::QAspectEngine engine;
+ auto meshA = new Qt3DRender::QMesh();
+ meshA->setSource(QUrl::fromLocalFile(QLatin1String("/foo")));
+ meshA->setMeshName(QLatin1String("bar"));
+
+ auto meshB = new Qt3DRender::QMesh();
+ meshB->setSource(QUrl::fromLocalFile(QLatin1String("/foo")));
+ meshB->setMeshName(QLatin1String("baz"));
+
+ auto meshC = new Qt3DRender::QMesh();
+ meshC->setSource(QUrl::fromLocalFile(QLatin1String("/baz")));
+ meshC->setMeshName(QLatin1String("bar"));
+
+ auto meshD = new Qt3DRender::QMesh();
+ meshD->setSource(QUrl::fromLocalFile(QLatin1String("/foo")));
+ meshD->setMeshName(QLatin1String("bar"));
+
+ const Qt3DRender::MeshLoaderFunctor functorA(meshA, &engine);
+ const Qt3DRender::MeshLoaderFunctor functorB(meshB, &engine);
+ const Qt3DRender::MeshLoaderFunctor functorC(meshC, &engine);
+ const Qt3DRender::MeshLoaderFunctor functorD(meshD, &engine);
// WHEN
const bool selfEquality = (functorA == functorA);
@@ -147,6 +161,6 @@ private Q_SLOTS:
}
};
-QTEST_APPLESS_MAIN(tst_MeshFunctors)
+QTEST_MAIN(tst_MeshFunctors)
#include "tst_meshfunctors.moc"
diff --git a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
index c60ddda27..d9d90a03d 100644
--- a/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
+++ b/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <Qt3DRender/private/pickboundingvolumejob_p.h>
+#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
#include <Qt3DRender/private/updateworldboundingvolumejob_p.h>
#include <Qt3DRender/private/updateworldtransformjob_p.h>
diff --git a/tests/auto/render/proximityfilter/proximityfilter.pro b/tests/auto/render/proximityfilter/proximityfilter.pro
new file mode 100644
index 000000000..74599e4f0
--- /dev/null
+++ b/tests/auto/render/proximityfilter/proximityfilter.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_proximityfilter
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_proximityfilter.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/proximityfilter/tst_proximityfilter.cpp b/tests/auto/render/proximityfilter/tst_proximityfilter.cpp
new file mode 100644
index 000000000..774e2dd1f
--- /dev/null
+++ b/tests/auto/render/proximityfilter/tst_proximityfilter.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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/qproximityfilter.h>
+#include <Qt3DRender/private/qproximityfilter_p.h>
+#include <Qt3DRender/private/proximityfilter_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include "qbackendnodetester.h"
+#include "testrenderer.h"
+
+class tst_ProximityFilter : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::ProximityFilter backendProximityFilter;
+
+ // THEN
+ QCOMPARE(backendProximityFilter.isEnabled(), false);
+ QVERIFY(backendProximityFilter.peerId().isNull());
+ QCOMPARE(backendProximityFilter.distanceThreshold(), 0.0f);
+ QCOMPARE(backendProximityFilter.entityId(), Qt3DCore::QNodeId());
+ }
+
+ void checkInitializeFromPeer()
+ {
+ // GIVEN
+ Qt3DRender::QProximityFilter proximityFilter;
+ Qt3DCore::QEntity entity;
+ proximityFilter.setDistanceThreshold(1340.0f);
+ proximityFilter.setEntity(&entity);
+
+ {
+ // WHEN
+ Qt3DRender::Render::ProximityFilter backendProximityFilter;
+ simulateInitialization(&proximityFilter, &backendProximityFilter);
+
+ // THEN
+ QCOMPARE(backendProximityFilter.isEnabled(), true);
+ QCOMPARE(backendProximityFilter.peerId(), proximityFilter.id());
+ QCOMPARE(backendProximityFilter.distanceThreshold(), 1340.f);
+ QCOMPARE(backendProximityFilter.entityId(), entity.id());
+ }
+ {
+ // WHEN
+ Qt3DRender::Render::ProximityFilter backendProximityFilter;
+ proximityFilter.setEnabled(false);
+ simulateInitialization(&proximityFilter, &backendProximityFilter);
+
+ // THEN
+ QCOMPARE(backendProximityFilter.peerId(), proximityFilter.id());
+ QCOMPARE(backendProximityFilter.isEnabled(), false);
+ }
+ }
+
+ void checkSceneChangeEvents()
+ {
+ // GIVEN
+ Qt3DRender::Render::ProximityFilter backendProximityFilter;
+ TestRenderer renderer;
+ backendProximityFilter.setRenderer(&renderer);
+
+ {
+ // WHEN
+ const bool newValue = false;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("enabled");
+ change->setValue(newValue);
+ backendProximityFilter.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendProximityFilter.isEnabled(), newValue);
+ }
+ {
+ // WHEN
+ const float newValue = 383.0f;
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("distanceThreshold");
+ change->setValue(QVariant::fromValue(newValue));
+ backendProximityFilter.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendProximityFilter.distanceThreshold(), newValue);
+ }
+ {
+ // WHEN
+ const Qt3DCore::QNodeId newValue = Qt3DCore::QNodeId::createId();
+ const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ change->setPropertyName("entity");
+ change->setValue(QVariant::fromValue(newValue));
+ backendProximityFilter.sceneChangeEvent(change);
+
+ // THEN
+ QCOMPARE(backendProximityFilter.entityId(), newValue);
+ }
+ }
+
+};
+
+QTEST_MAIN(tst_ProximityFilter)
+
+#include "tst_proximityfilter.moc"
diff --git a/tests/auto/render/proximityfiltering/proximityfiltering.pro b/tests/auto/render/proximityfiltering/proximityfiltering.pro
new file mode 100644
index 000000000..68b709ec5
--- /dev/null
+++ b/tests/auto/render/proximityfiltering/proximityfiltering.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_proximityfiltering
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_proximityfiltering.cpp
+
+CONFIG += useCommonTestAspect
+
+include(../commons/commons.pri)
diff --git a/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp b/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp
new file mode 100644
index 000000000..7a5648271
--- /dev/null
+++ b/tests/auto/render/proximityfiltering/tst_proximityfiltering.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** 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/qtransform.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/filterproximitydistancejob_p.h>
+#include <Qt3DRender/private/updatetreeenabledjob_p.h>
+#include <Qt3DRender/qproximityfilter.h>
+
+#include "testaspect.h"
+
+namespace {
+
+Qt3DCore::QEntity *buildEntityAtDistance(float distance, Qt3DCore::QEntity *parent)
+{
+ Qt3DCore::QEntity *entity = new Qt3DCore::QEntity(parent);
+ Qt3DCore::QTransform *transform = new Qt3DCore::QTransform(parent);
+ const QVector3D t = QVector3D(1.0f, 0.0f, 0.0f) * distance;
+
+ transform->setTranslation(t);
+ entity->addComponent(transform);
+
+ return entity;
+}
+
+} // anonymous
+
+class tst_ProximityFiltering : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::FilterProximityDistanceJob filterJob;
+
+ // THEN
+ QCOMPARE(filterJob.hasProximityFilter(), false);
+ QCOMPARE(filterJob.filteredEntities().size(), 0);
+ QCOMPARE(filterJob.proximityFilterIds().size(), 0);
+ QVERIFY(filterJob.manager() == nullptr);
+ }
+
+ void filterEntities_data()
+ {
+ QTest::addColumn<Qt3DCore::QEntity *>("entitySubtree");
+ QTest::addColumn<Qt3DCore::QNodeIdVector>("proximityFilterIds");
+ QTest::addColumn<Qt3DCore::QNodeIdVector>("expectedSelectedEntities");
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+
+ QTest::newRow("ShouldSelectAll") << rootEntity
+ << Qt3DCore::QNodeIdVector()
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << childEntity1->id()
+ << childEntity2->id()
+ << childEntity3->id()
+ );
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *childEntity1 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity2 = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity3 = new Qt3DCore::QEntity(rootEntity);
+ Q_UNUSED(childEntity1);
+ Q_UNUSED(childEntity2);
+ Q_UNUSED(childEntity3);
+
+ Qt3DRender::QProximityFilter *proximityFilter = new Qt3DRender::QProximityFilter(rootEntity);
+
+ QTest::newRow("ShouldSelectNone") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << proximityFilter->id())
+ << (Qt3DCore::QNodeIdVector());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *targetEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity1 = buildEntityAtDistance(50.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity2 = buildEntityAtDistance(25.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity3 = buildEntityAtDistance(75.0f, rootEntity);
+ Qt3DRender::QProximityFilter *proximityFilter = new Qt3DRender::QProximityFilter(rootEntity);
+ proximityFilter->setDistanceThreshold(30.0f);
+
+ // Note: rootEntity BoundingSphere will be centered in vec3(75.0f / 2.0, 0.0f 0.0f);
+
+ // Note: we cannot set rootEntity here as that would mean
+ // that the parent of the root would then be the proximity filter
+ // (since rootEntity has no parent) but this isn't valid in the way
+ // we have build the test
+ // Also rootEntity is centered based on the size of the child it contains
+ proximityFilter->setEntity(targetEntity);
+
+ Q_UNUSED(childEntity1);
+ Q_UNUSED(childEntity3);
+
+ QTest::newRow("ShouldSelectChild2") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << proximityFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << targetEntity->id()
+ << childEntity2->id()
+ );
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *targetEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity1 = buildEntityAtDistance(50.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity2 = buildEntityAtDistance(25.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity3 = buildEntityAtDistance(49.9f, rootEntity);
+ Qt3DRender::QProximityFilter *proximityFilter = new Qt3DRender::QProximityFilter(rootEntity);
+ proximityFilter->setDistanceThreshold(50.0f);
+
+ // Note: rootEntity BoundingSphere will be centered in vec3(50.0f / 2.0, 0.0f 0.0f);
+
+ // Note: we cannot set rootEntity here as that would mean
+ // that the parent of the root would then be the proximity filter
+ // (since rootEntity has no parent) but this isn't valid in the way
+ // we have build the test
+ // Also rootEntity is centered based on the size of the child it contains
+ proximityFilter->setEntity(targetEntity);
+
+ QTest::newRow("ShouldSelectRootChild123") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << proximityFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << rootEntity->id()
+ << targetEntity->id()
+ << childEntity1->id()
+ << childEntity2->id()
+ << childEntity3->id()
+ );
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *targetEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity1 = buildEntityAtDistance(51.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity2 = buildEntityAtDistance(75.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity3 = buildEntityAtDistance(883.0f, rootEntity);
+ Qt3DRender::QProximityFilter *proximityFilter = new Qt3DRender::QProximityFilter(rootEntity);
+ proximityFilter->setDistanceThreshold(50.0f);
+
+ // Note: rootEntity BoundingSphere will be centered in vec3(883.0f / 2.0, 0.0f 0.0f);
+
+ // Note: we cannot set rootEntity here as that would mean
+ // that the parent of the root would then be the proximity filter
+ // (since rootEntity has no parent) but this isn't valid in the way
+ // we have build the test
+ // Also rootEntity is centered based on the size of the child it contains
+ proximityFilter->setEntity(targetEntity);
+
+ Q_UNUSED(childEntity1);
+ Q_UNUSED(childEntity2);
+ Q_UNUSED(childEntity3);
+
+ QTest::newRow("ShouldSelectNoneButTarget") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << proximityFilter->id())
+ << (Qt3DCore::QNodeIdVector() << targetEntity->id());
+ }
+
+ {
+ Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
+ Qt3DCore::QEntity *targetEntity = new Qt3DCore::QEntity(rootEntity);
+ Qt3DCore::QEntity *childEntity1 = buildEntityAtDistance(50.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity2 = buildEntityAtDistance(150.0f, rootEntity);
+ Qt3DCore::QEntity *childEntity3 = buildEntityAtDistance(25.0f, rootEntity);
+
+ Qt3DRender::QProximityFilter *proximityFilter = new Qt3DRender::QProximityFilter(rootEntity);
+ proximityFilter->setDistanceThreshold(50.0f);
+
+ Qt3DRender::QProximityFilter *proximityFilter2 = new Qt3DRender::QProximityFilter(rootEntity);
+ proximityFilter2->setDistanceThreshold(30.0f);
+
+ // Note: rootEntity BoundingSphere will be centered in vec3(150.0f / 2.0, 0.0f 0.0f);
+
+ // Note: we cannot set rootEntity here as that would mean
+ // that the parent of the root would then be the proximity filter
+ // (since rootEntity has no parent) but this isn't valid in the way
+ // we have build the test
+ // Also rootEntity is centered based on the size of the child it contains
+ proximityFilter->setEntity(targetEntity);
+ proximityFilter2->setEntity(targetEntity);
+
+ Q_UNUSED(childEntity2);
+
+ QTest::newRow("Nested-Step1") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << proximityFilter->id())
+ << (Qt3DCore::QNodeIdVector()
+ << targetEntity->id()
+ << childEntity1->id()
+ << childEntity3->id()
+ );
+ QTest::newRow("Nested-Step2") << rootEntity
+ << (Qt3DCore::QNodeIdVector() << proximityFilter->id() << proximityFilter2->id())
+ << (Qt3DCore::QNodeIdVector()
+ << targetEntity->id()
+ << childEntity3->id()
+ );
+ }
+ }
+
+ void filterEntities()
+ {
+ QFETCH(Qt3DCore::QEntity *, entitySubtree);
+ QFETCH(Qt3DCore::QNodeIdVector, proximityFilterIds);
+ QFETCH(Qt3DCore::QNodeIdVector, expectedSelectedEntities);
+
+ // GIVEN
+ QScopedPointer<Qt3DRender::TestAspect> aspect(new Qt3DRender::TestAspect(entitySubtree));
+
+ // WHEN
+ Qt3DRender::Render::Entity *backendRoot = aspect->nodeManagers()->renderNodesManager()->getOrCreateResource(entitySubtree->id());
+ Qt3DRender::Render::UpdateTreeEnabledJob updateTreeEnabledJob;
+ updateTreeEnabledJob.setRoot(backendRoot);
+ updateTreeEnabledJob.run();
+
+ Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform;
+ updateWorldTransform.setRoot(backendRoot);
+ updateWorldTransform.run();
+
+ Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
+ calcBVolume.setManagers(aspect->nodeManagers());
+ calcBVolume.setRoot(backendRoot);
+ calcBVolume.run();
+
+ Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
+ updateWorldBVolume.setManager(aspect->nodeManagers()->renderNodesManager());
+ updateWorldBVolume.run();
+
+ Qt3DRender::Render::ExpandBoundingVolumeJob expandBVolume;
+ expandBVolume.setRoot(backendRoot);
+ expandBVolume.run();
+
+ // WHEN
+ Qt3DRender::Render::FilterProximityDistanceJob filterJob;
+ filterJob.setProximityFilterIds(proximityFilterIds);
+ filterJob.setManager(aspect->nodeManagers());
+ filterJob.run();
+
+ // THEN
+ const QVector<Qt3DRender::Render::Entity *> filterEntities = filterJob.filteredEntities();
+ QCOMPARE(filterEntities.size(), expectedSelectedEntities.size());
+
+ for (auto i = 0, m = expectedSelectedEntities.size(); i < m; ++i)
+ QCOMPARE(filterEntities.at(i)->peerId(), expectedSelectedEntities.at(i));
+ }
+};
+
+QTEST_MAIN(tst_ProximityFiltering)
+
+#include "tst_proximityfiltering.moc"
diff --git a/tests/auto/render/qattribute/tst_qattribute.cpp b/tests/auto/render/qattribute/tst_qattribute.cpp
index 66854acdd..23532c435 100644
--- a/tests/auto/render/qattribute/tst_qattribute.cpp
+++ b/tests/auto/render/qattribute/tst_qattribute.cpp
@@ -58,6 +58,8 @@ private Q_SLOTS:
QCOMPARE(Qt3DRender::QAttribute::defaultColorAttributeName(), QStringLiteral("vertexColor"));
QCOMPARE(Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName(), QStringLiteral("vertexTexCoord"));
QCOMPARE(Qt3DRender::QAttribute::defaultTangentAttributeName(), QStringLiteral("vertexTangent"));
+ QCOMPARE(Qt3DRender::QAttribute::defaultJointIndicesAttributeName(), QStringLiteral("vertexJointIndices"));
+ QCOMPARE(Qt3DRender::QAttribute::defaultJointWeightsAttributeName(), QStringLiteral("vertexJointWeights"));
QCOMPARE(attribute.property("defaultPositionAttributeName").toString(),
Qt3DRender::QAttribute::defaultPositionAttributeName());
@@ -69,6 +71,10 @@ private Q_SLOTS:
Qt3DRender::QAttribute::defaultTextureCoordinateAttributeName());
QCOMPARE(attribute.property("defaultTangentAttributeName").toString(),
Qt3DRender::QAttribute::defaultTangentAttributeName());
+ QCOMPARE(attribute.property("defaultJointIndicesAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultJointIndicesAttributeName());
+ QCOMPARE(attribute.property("defaultJointWeightsAttributeName").toString(),
+ Qt3DRender::QAttribute::defaultJointWeightsAttributeName());
}
void checkCloning_data()
diff --git a/tests/auto/render/qblitframebuffer/qblitframebuffer.pro b/tests/auto/render/qblitframebuffer/qblitframebuffer.pro
new file mode 100644
index 000000000..219bad3d2
--- /dev/null
+++ b/tests/auto/render/qblitframebuffer/qblitframebuffer.pro
@@ -0,0 +1,11 @@
+TEMPLATE = app
+
+TARGET = tst_qblitframebuffer
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qblitframebuffer.cpp
+
+include(../../core/common/common.pri)
diff --git a/tests/auto/render/qblitframebuffer/tst_qblitframebuffer.cpp b/tests/auto/render/qblitframebuffer/tst_qblitframebuffer.cpp
new file mode 100644
index 000000000..26ef936f6
--- /dev/null
+++ b/tests/auto/render/qblitframebuffer/tst_qblitframebuffer.cpp
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** 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: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/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+
+#include <Qt3DRender/QBlitFramebuffer>
+#include <Qt3DRender/private/qblitframebuffer_p.h>
+
+#include "testpostmanarbiter.h"
+
+class tst_QBlitFrameBuffer: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QBlitFrameBuffer() : QObject()
+ {
+ qRegisterMetaType<Qt3DRender::QRenderTarget*>();
+ }
+
+private Q_SLOTS:
+
+ void checkCreationData_data()
+ {
+ QTest::addColumn<Qt3DRender::QBlitFramebuffer *>("blitFramebuffer");
+
+ Qt3DRender::QBlitFramebuffer *defaultConstructed = new Qt3DRender::QBlitFramebuffer();
+ Qt3DRender::QRenderTarget *sourceRenderTarget = new Qt3DRender::QRenderTarget();
+ Qt3DRender::QRenderTarget *destinationRenderTarget = new Qt3DRender::QRenderTarget();
+ defaultConstructed->setSource(sourceRenderTarget);
+ defaultConstructed->setDestination(destinationRenderTarget);
+ QTest::newRow("defaultConstructed") << defaultConstructed;
+ }
+
+ void checkInitialState()
+ {
+ // GIVEN
+ Qt3DRender::QBlitFramebuffer blitFramebuffer;
+
+ // THEN
+ QCOMPARE(blitFramebuffer.source(), nullptr);
+ QCOMPARE(blitFramebuffer.destination(), nullptr);
+ QCOMPARE(blitFramebuffer.sourceRect(), QRect());
+ QCOMPARE(blitFramebuffer.destinationRect(), QRect());
+ QCOMPARE(blitFramebuffer.sourceAttachmentPoint(), Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color0);
+ QCOMPARE(blitFramebuffer.destinationAttachmentPoint(), Qt3DRender::QRenderTargetOutput::AttachmentPoint::Color0);
+ QCOMPARE(blitFramebuffer.interpolationMethod(), Qt3DRender::QBlitFramebuffer::Linear);
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ QFETCH(Qt3DRender::QBlitFramebuffer *, blitFramebuffer);
+
+ // WHEN
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(blitFramebuffer);
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges = creationChangeGenerator.creationChanges();
+
+ // THEN
+ QCOMPARE(creationChanges.size(), 1);
+
+ const Qt3DCore::QNodeCreatedChangePtr<Qt3DRender::QBlitFramebufferData> creationChangeData =
+ qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QBlitFramebufferData>>(creationChanges.first());
+ const Qt3DRender::QBlitFramebufferData &cloneData = creationChangeData->data;
+
+ // THEN
+ QCOMPARE(blitFramebuffer->id(), creationChangeData->subjectId());
+ QCOMPARE(blitFramebuffer->isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(blitFramebuffer->metaObject(), creationChangeData->metaObject());
+ QCOMPARE(blitFramebuffer->source()->id(), cloneData.m_sourceRenderTargetId);
+ QCOMPARE(blitFramebuffer->destination()->id(), cloneData.m_destinationRenderTargetId);
+ QCOMPARE(blitFramebuffer->sourceRect(), cloneData.m_sourceRect);
+ QCOMPARE(blitFramebuffer->destinationRect(), cloneData.m_destinationRect);
+ QCOMPARE(blitFramebuffer->sourceAttachmentPoint(), cloneData.m_sourceAttachmentPoint);
+ QCOMPARE(blitFramebuffer->destinationAttachmentPoint(), cloneData.m_destinationAttachmentPoint);
+
+
+ delete blitFramebuffer;
+ }
+
+ void checkPropertyUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ QScopedPointer<Qt3DRender::QBlitFramebuffer> blitFramebuffer(new Qt3DRender::QBlitFramebuffer());
+ arbiter.setArbiterOnNode(blitFramebuffer.data());
+
+ Qt3DRender::QRenderTarget *sourceRenderTarget = new Qt3DRender::QRenderTarget;
+ Qt3DRender::QRenderTarget *destinationRenderTarget = new Qt3DRender::QRenderTarget;
+
+ // sourceRenderTarget
+ // WHEN
+ blitFramebuffer->setSource(sourceRenderTarget);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "source");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), sourceRenderTarget->id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ blitFramebuffer->setSource(sourceRenderTarget);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ blitFramebuffer->setSource(nullptr);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "source");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), Qt3DCore::QNodeId());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // destinationRenderTarget
+ // WHEN
+ blitFramebuffer->setDestination(destinationRenderTarget);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "destination");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), destinationRenderTarget->id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ blitFramebuffer->setDestination(destinationRenderTarget);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ blitFramebuffer->setDestination(nullptr);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "destination");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), Qt3DCore::QNodeId());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // sourceRect
+ // WHEN
+ blitFramebuffer->setSourceRect(QRect(0,0,1,1));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "sourceRect");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<QRect>(), QRect(0,0,1,1)) ;
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ blitFramebuffer->setSourceRect(QRect(0,0,1,1));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ blitFramebuffer->setSourceRect(QRect());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "sourceRect");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<QRect>(), QRect());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // destinationRect
+ blitFramebuffer->setDestinationRect(QRect(0,0,1,1));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "destinationRect");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<QRect>(), QRect(0,0,1,1)) ;
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ blitFramebuffer->setDestinationRect(QRect(0,0,1,1));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ blitFramebuffer->setDestinationRect(QRect());
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "destinationRect");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<QRect>(), QRect());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // sourceAttachmentPoint
+ // WHEN
+ blitFramebuffer->setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color1);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "sourceAttachmentPoint");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>(), Qt3DRender::QRenderTargetOutput::Color1);
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ blitFramebuffer->setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color1);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ blitFramebuffer->setSourceAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "sourceAttachmentPoint");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>(), Qt3DRender::QRenderTargetOutput::Color0);
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // destinationAttachmentPoint
+ // WHEN
+ blitFramebuffer->setDestinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color1);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "destinationAttachmentPoint");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>(), Qt3DRender::QRenderTargetOutput::Color1);
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
+ blitFramebuffer->setDestinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color1);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+
+ // WHEN
+ blitFramebuffer->setDestinationAttachmentPoint(Qt3DRender::QRenderTargetOutput::Color0);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "destinationAttachmentPoint");
+ QCOMPARE(change->subjectId(), blitFramebuffer->id());
+ QCOMPARE(change->value().value<Qt3DRender::QRenderTargetOutput::AttachmentPoint>(), Qt3DRender::QRenderTargetOutput::Color0);
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+};
+
+QTEST_MAIN(tst_QBlitFrameBuffer)
+
+#include "tst_qblitframebuffer.moc"
diff --git a/tests/auto/render/qbuffer/tst_qbuffer.cpp b/tests/auto/render/qbuffer/tst_qbuffer.cpp
index fdc25cbca..719c6229f 100644
--- a/tests/auto/render/qbuffer/tst_qbuffer.cpp
+++ b/tests/auto/render/qbuffer/tst_qbuffer.cpp
@@ -112,7 +112,6 @@ private Q_SLOTS:
QCOMPARE(buffer->metaObject(), creationChangeData->metaObject());
QCOMPARE(buffer->data(), cloneData.data);
QCOMPARE(buffer->usage(), cloneData.usage);
- QCOMPARE(buffer->type(), cloneData.type);
QCOMPARE(buffer->dataGenerator(), cloneData.functor);
QCOMPARE(buffer->isSyncData(), cloneData.syncData);
if (buffer->dataGenerator()) {
diff --git a/tests/auto/render/qgeometryrenderer/tst_qgeometryrenderer.cpp b/tests/auto/render/qgeometryrenderer/tst_qgeometryrenderer.cpp
index 94f720097..edd767ad9 100644
--- a/tests/auto/render/qgeometryrenderer/tst_qgeometryrenderer.cpp
+++ b/tests/auto/render/qgeometryrenderer/tst_qgeometryrenderer.cpp
@@ -88,6 +88,7 @@ private Q_SLOTS:
geometry1->setInstanceCount(1);
geometry1->setIndexOffset(0);
geometry1->setFirstInstance(55);
+ geometry1->setIndexBufferByteOffset(48);
geometry1->setRestartIndexValue(-1);
geometry1->setPrimitiveRestartEnabled(false);
geometry1->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles);
@@ -101,6 +102,7 @@ private Q_SLOTS:
geometry2->setInstanceCount(200);
geometry2->setIndexOffset(58);
geometry2->setFirstInstance(10);
+ geometry2->setIndexBufferByteOffset(96);
geometry2->setRestartIndexValue(65535);
geometry2->setVertexCount(2056);
geometry2->setPrimitiveRestartEnabled(true);
@@ -134,6 +136,7 @@ private Q_SLOTS:
QCOMPARE(cloneData.vertexCount, geometryRenderer->vertexCount());
QCOMPARE(cloneData.indexOffset, geometryRenderer->indexOffset());
QCOMPARE(cloneData.firstInstance, geometryRenderer->firstInstance());
+ QCOMPARE(cloneData.indexBufferByteOffset, geometryRenderer->indexBufferByteOffset());
QCOMPARE(cloneData.restartIndexValue, geometryRenderer->restartIndexValue());
QCOMPARE(cloneData.primitiveRestart, geometryRenderer->primitiveRestartEnabled());
QCOMPARE(cloneData.primitiveType, geometryRenderer->primitiveType());
@@ -207,6 +210,19 @@ private Q_SLOTS:
arbiter.events.clear();
// WHEN
+ geometryRenderer->setIndexBufferByteOffset(91);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "indexBufferByteOffset");
+ QCOMPARE(change->value().value<int>(), 91);
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+
+ // WHEN
geometryRenderer->setRestartIndexValue(65535);
QCoreApplication::processEvents();
diff --git a/tests/auto/render/qgraphicsapifilter/tst_qgraphicsapifilter.cpp b/tests/auto/render/qgraphicsapifilter/tst_qgraphicsapifilter.cpp
index ac6f79b3f..9e0cb8e57 100644
--- a/tests/auto/render/qgraphicsapifilter/tst_qgraphicsapifilter.cpp
+++ b/tests/auto/render/qgraphicsapifilter/tst_qgraphicsapifilter.cpp
@@ -36,6 +36,13 @@
class tst_QGraphicsApiFilter : public QObject
{
Q_OBJECT
+public:
+ tst_QGraphicsApiFilter() : QObject()
+ {
+ qRegisterMetaType<Qt3DRender::QGraphicsApiFilter::Api>();
+ qRegisterMetaType<Qt3DRender::QGraphicsApiFilter::OpenGLProfile>();
+ }
+
private Q_SLOTS:
void defaultConstruction()
{
diff --git a/tests/auto/render/qmesh/tst_qmesh.cpp b/tests/auto/render/qmesh/tst_qmesh.cpp
index 2122d7eb5..127371750 100644
--- a/tests/auto/render/qmesh/tst_qmesh.cpp
+++ b/tests/auto/render/qmesh/tst_qmesh.cpp
@@ -34,6 +34,7 @@
#include <QSignalSpy>
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
+#include <Qt3DCore/private/qscene_p.h>
#include <Qt3DCore/qnodecreatedchange.h>
#include "testpostmanarbiter.h"
@@ -121,9 +122,8 @@ private Q_SLOTS:
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);
+ // Geometry factory is null until the engine becomes available
+ QVERIFY(cloneData.geometryFactory == nullptr);
QCOMPARE(mesh.id(), creationChangeData->subjectId());
QCOMPARE(mesh.isEnabled(), true);
QCOMPARE(mesh.isEnabled(), creationChangeData->isNodeEnabled());
@@ -158,6 +158,13 @@ private Q_SLOTS:
Qt3DRender::QMesh mesh;
arbiter.setArbiterOnNode(&mesh);
+ Qt3DCore::QAspectEngine *engine = reinterpret_cast<Qt3DCore::QAspectEngine*>(0xdeadbeef);
+ Qt3DCore::QScene *scene = new Qt3DCore::QScene(engine);
+ Qt3DCore::QNodePrivate *meshd = Qt3DCore::QNodePrivate::get(&mesh);
+ meshd->setScene(scene);
+ QCoreApplication::processEvents();
+ arbiter.events.clear();
+
{
// WHEN
mesh.setSource(QUrl(QStringLiteral("qrc:/toyplane.obj")));
@@ -165,13 +172,15 @@ private Q_SLOTS:
// THEN
QCOMPARE(arbiter.events.size(), 1);
- auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ auto change = arbiter.events.last().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);
+ QSharedPointer<Qt3DRender::MeshLoaderFunctor> meshFunctor = qSharedPointerCast<Qt3DRender::MeshLoaderFunctor>(factory);
+ QVERIFY(meshFunctor != nullptr);
+ QCOMPARE(meshFunctor->m_mesh, mesh.id());
+ QCOMPARE(meshFunctor->m_sourcePath, mesh.source());
arbiter.events.clear();
}
@@ -194,6 +203,13 @@ private Q_SLOTS:
Qt3DRender::QMesh mesh;
arbiter.setArbiterOnNode(&mesh);
+ Qt3DCore::QAspectEngine *engine = reinterpret_cast<Qt3DCore::QAspectEngine*>(0xdeadbeef);
+ Qt3DCore::QScene *scene = new Qt3DCore::QScene(engine);
+ Qt3DCore::QNodePrivate *meshd = Qt3DCore::QNodePrivate::get(&mesh);
+ meshd->setScene(scene);
+ QCoreApplication::processEvents();
+ arbiter.events.clear();
+
{
// WHEN
mesh.setMeshName(QStringLiteral("Phil"));
@@ -205,9 +221,11 @@ private Q_SLOTS:
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);
+ QSharedPointer<Qt3DRender::MeshLoaderFunctor> meshFunctor = qSharedPointerCast<Qt3DRender::MeshLoaderFunctor>(factory);
+ QVERIFY(meshFunctor != nullptr);
+ QCOMPARE(meshFunctor->m_mesh, mesh.id());
+ QCOMPARE(meshFunctor->m_meshName, mesh.meshName());
arbiter.events.clear();
}
diff --git a/tests/auto/render/qproximityfilter/qproximityfilter.pro b/tests/auto/render/qproximityfilter/qproximityfilter.pro
new file mode 100644
index 000000000..4a12e244f
--- /dev/null
+++ b/tests/auto/render/qproximityfilter/qproximityfilter.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qproximityfilter
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qproximityfilter.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qproximityfilter/tst_qproximityfilter.cpp b/tests/auto/render/qproximityfilter/tst_qproximityfilter.cpp
new file mode 100644
index 000000000..890d6ee3e
--- /dev/null
+++ b/tests/auto/render/qproximityfilter/tst_qproximityfilter.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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/qproximityfilter.h>
+#include <Qt3DRender/private/qproximityfilter_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_QProximityFilter : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QProximityFilter() : QObject()
+ {
+ qRegisterMetaType<Qt3DCore::QEntity*>();
+ }
+
+private Q_SLOTS:
+
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QProximityFilter proximityFilter;
+
+ // THEN
+ QVERIFY(proximityFilter.entity() == nullptr);
+ QCOMPARE(proximityFilter.distanceThreshold(), 0.0f);
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QProximityFilter proximityFilter;
+
+ {
+ // WHEN
+ Qt3DCore::QEntity entity;
+
+ QSignalSpy spy(&proximityFilter, SIGNAL(entityChanged(Qt3DCore::QEntity *)));
+ Qt3DCore::QEntity *newValue = &entity;
+ proximityFilter.setEntity(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(proximityFilter.entity(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ proximityFilter.setEntity(newValue);
+
+ // THEN
+ QCOMPARE(proximityFilter.entity(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&proximityFilter, SIGNAL(distanceThresholdChanged(float)));
+ const float newValue = 883.0f;
+ proximityFilter.setDistanceThreshold(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(proximityFilter.distanceThreshold(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ proximityFilter.setDistanceThreshold(newValue);
+
+ // THEN
+ QCOMPARE(proximityFilter.distanceThreshold(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QProximityFilter proximityFilter;
+ Qt3DCore::QEntity entity;
+
+ proximityFilter.setEntity(&entity);
+ proximityFilter.setDistanceThreshold(1584.0f);
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&proximityFilter);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // Entity creation change is the second change
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QProximityFilterData>>(creationChanges.first());
+ const Qt3DRender::QProximityFilterData cloneData = creationChangeData->data;
+
+ QCOMPARE(proximityFilter.entity()->id(), cloneData.entityId);
+ QCOMPARE(proximityFilter.distanceThreshold(), cloneData.distanceThreshold);
+ QCOMPARE(proximityFilter.id(), creationChangeData->subjectId());
+ QCOMPARE(proximityFilter.isEnabled(), true);
+ QCOMPARE(proximityFilter.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(proximityFilter.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ proximityFilter.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&proximityFilter);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // Entity creation change is the second change
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QProximityFilterData>>(creationChanges.first());
+ const Qt3DRender::QProximityFilterData cloneData = creationChangeData->data;
+
+ QCOMPARE(proximityFilter.entity()->id(), cloneData.entityId);
+ QCOMPARE(proximityFilter.distanceThreshold(), cloneData.distanceThreshold);
+ QCOMPARE(proximityFilter.id(), creationChangeData->subjectId());
+ QCOMPARE(proximityFilter.isEnabled(), false);
+ QCOMPARE(proximityFilter.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(proximityFilter.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkEntityUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QProximityFilter proximityFilter;
+ arbiter.setArbiterOnNode(&proximityFilter);
+ Qt3DCore::QEntity entity;
+
+ {
+ // WHEN
+ proximityFilter.setEntity(&entity);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "entity");
+ QCOMPARE(change->value().value<Qt3DCore::QNodeId>(), proximityFilter.entity()->id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ proximityFilter.setEntity(&entity);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkDistanceThresholdUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QProximityFilter proximityFilter;
+ arbiter.setArbiterOnNode(&proximityFilter);
+
+ {
+ // WHEN
+ proximityFilter.setDistanceThreshold(454.0f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "distanceThreshold");
+ QCOMPARE(change->value().value<float>(), proximityFilter.distanceThreshold());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ proximityFilter.setDistanceThreshold(454.0f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkEntityBookkeeping()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DRender::QProximityFilter> proximityFilter(new Qt3DRender::QProximityFilter);
+ {
+ // WHEN
+ Qt3DCore::QEntity entity;
+ proximityFilter->setEntity(&entity);
+
+ // THEN
+ QCOMPARE(entity.parent(), proximityFilter.data());
+ QCOMPARE(proximityFilter->entity(), &entity);
+ }
+
+ // THEN (Should not crash and parameter be unset)
+ QVERIFY(proximityFilter->entity() == nullptr);
+
+ {
+ // WHEN
+ Qt3DRender::QProximityFilter someOtherProximityFilter;
+ QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity(&someOtherProximityFilter));
+ proximityFilter->setEntity(entity.data());
+
+ // THEN
+ QCOMPARE(entity->parent(), &someOtherProximityFilter);
+ QCOMPARE(proximityFilter->entity(), entity.data());
+
+ // WHEN
+ proximityFilter.reset();
+ entity.reset();
+
+ // THEN Should not crash when the camera is destroyed (tests for failed removal of destruction helper)
+ }
+ }
+};
+
+QTEST_MAIN(tst_QProximityFilter)
+
+#include "tst_qproximityfilter.moc"
diff --git a/tests/auto/render/qrendercapture/tst_qrendercapture.cpp b/tests/auto/render/qrendercapture/tst_qrendercapture.cpp
index d4e603ea4..830615a95 100644
--- a/tests/auto/render/qrendercapture/tst_qrendercapture.cpp
+++ b/tests/auto/render/qrendercapture/tst_qrendercapture.cpp
@@ -67,7 +67,7 @@ private Q_SLOTS:
arbiter.setArbiterOnNode(renderCapture.data());
// WHEN
- QScopedPointer<Qt3DRender::QRenderCaptureReply> reply(renderCapture->requestCapture());
+ QScopedPointer<Qt3DRender::QRenderCaptureReply> reply(renderCapture->requestCapture(QRect(10, 15, 20, 50)));
// THEN
QCOMPARE(arbiter.events.size(), 1);
@@ -75,7 +75,10 @@ private Q_SLOTS:
QCOMPARE(change->propertyName(), "renderCaptureRequest");
QCOMPARE(change->subjectId(),renderCapture->id());
QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
- QCOMPARE(change->value().toInt(), 1);
+ QVERIFY(change->value().canConvert<Qt3DRender::QRenderCaptureRequest>());
+ const Qt3DRender::QRenderCaptureRequest request = change->value().value<Qt3DRender::QRenderCaptureRequest>();
+ QCOMPARE(request.captureId, 1);
+ QCOMPARE(request.rect, QRect(10, 15, 20, 50));
arbiter.events.clear();
}
diff --git a/tests/auto/render/qrendersettings/tst_qrendersettings.cpp b/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
index 1f0a9f066..6f182cbeb 100644
--- a/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
+++ b/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
@@ -184,6 +184,7 @@ private Q_SLOTS:
pickingSettings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
pickingSettings->setPickResultMode(Qt3DRender::QPickingSettings::AllPicks);
pickingSettings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace);
+ pickingSettings->setWorldSpaceTolerance(5.f);
// WHEN
QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
@@ -203,6 +204,7 @@ private Q_SLOTS:
QCOMPARE(renderSettings.pickingSettings()->pickMethod(), cloneData.pickMethod);
QCOMPARE(renderSettings.pickingSettings()->pickResultMode(), cloneData.pickResultMode);
QCOMPARE(renderSettings.pickingSettings()->faceOrientationPickingMode(), cloneData.faceOrientationPickingMode);
+ QCOMPARE(renderSettings.pickingSettings()->worldSpaceTolerance(), cloneData.pickWorldSpaceTolerance);
QCOMPARE(renderSettings.renderPolicy(), cloneData.renderPolicy);
QCOMPARE(renderSettings.activeFrameGraph()->id(), cloneData.activeFrameGraphId);
QCOMPARE(renderSettings.id(), creationChangeData->subjectId());
@@ -410,6 +412,41 @@ private Q_SLOTS:
}
+ void checkWorldSpaceToleranceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+
+ arbiter.setArbiterOnNode(&renderSettings);
+
+ {
+ // WHEN
+ pickingSettings->setWorldSpaceTolerance(5.f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pickWorldSpaceTolerance");
+ QCOMPARE(change->value().toFloat(), pickingSettings->worldSpaceTolerance());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ pickingSettings->setWorldSpaceTolerance(5.f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
};
QTEST_MAIN(tst_QRenderSettings)
diff --git a/tests/auto/render/qshaderprogrambuilder/qshaderprogrambuilder.pro b/tests/auto/render/qshaderprogrambuilder/qshaderprogrambuilder.pro
new file mode 100644
index 000000000..32fe88e9f
--- /dev/null
+++ b/tests/auto/render/qshaderprogrambuilder/qshaderprogrambuilder.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = tst_qshaderprogrambuilder
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_qshaderprogrambuilder.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/qshaderprogrambuilder/tst_qshaderprogrambuilder.cpp b/tests/auto/render/qshaderprogrambuilder/tst_qshaderprogrambuilder.cpp
new file mode 100644
index 000000000..93bee22cc
--- /dev/null
+++ b/tests/auto/render/qshaderprogrambuilder/tst_qshaderprogrambuilder.cpp
@@ -0,0 +1,601 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QTest>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
+#include <Qt3DRender/private/qshaderprogrambuilder_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_QShaderProgramBuilder : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QShaderProgramBuilder()
+ : QObject()
+ {
+ qRegisterMetaType<Qt3DRender::QShaderProgram*>("Qt3DRender::QShaderProgram*");
+ }
+
+private Q_SLOTS:
+ void checkDefaultConstruction()
+ {
+ // GIVEN
+ Qt3DRender::QShaderProgramBuilder builder;
+
+ // THEN
+ QVERIFY(!builder.shaderProgram());
+ QVERIFY(builder.enabledLayers().isEmpty());
+ QCOMPARE(builder.vertexShaderGraph(), QUrl());
+ QCOMPARE(builder.tessellationControlShaderGraph(), QUrl());
+ QCOMPARE(builder.tessellationEvaluationShaderGraph(), QUrl());
+ QCOMPARE(builder.geometryShaderGraph(), QUrl());
+ QCOMPARE(builder.fragmentShaderGraph(), QUrl());
+ QCOMPARE(builder.computeShaderGraph(), QUrl());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ Qt3DRender::QShaderProgramBuilder builder;
+
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(shaderProgramChanged(Qt3DRender::QShaderProgram*)));
+ auto newValue = new Qt3DRender::QShaderProgram(&builder);
+ builder.setShaderProgram(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.shaderProgram(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setShaderProgram(newValue);
+
+ // THEN
+ QCOMPARE(builder.shaderProgram(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(enabledLayersChanged(QStringList)));
+ const auto newValue = QStringList() << "foo" << "bar";
+ builder.setEnabledLayers(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.enabledLayers(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setEnabledLayers(newValue);
+
+ // THEN
+ QCOMPARE(builder.enabledLayers(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(vertexShaderGraphChanged(QUrl)));
+ const auto newValue = QUrl::fromEncoded("qrc:/vertex.json");
+ builder.setVertexShaderGraph(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.vertexShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setVertexShaderGraph(newValue);
+
+ // THEN
+ QCOMPARE(builder.vertexShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(tessellationControlShaderGraphChanged(QUrl)));
+ const auto newValue = QUrl::fromEncoded("qrc:/tesscontrol.json");
+ builder.setTessellationControlShaderGraph(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.tessellationControlShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setTessellationControlShaderGraph(newValue);
+
+ // THEN
+ QCOMPARE(builder.tessellationControlShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(tessellationEvaluationShaderGraphChanged(QUrl)));
+ const auto newValue = QUrl::fromEncoded("qrc:/tesseval.json");
+ builder.setTessellationEvaluationShaderGraph(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.tessellationEvaluationShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setTessellationEvaluationShaderGraph(newValue);
+
+ // THEN
+ QCOMPARE(builder.tessellationEvaluationShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(geometryShaderGraphChanged(QUrl)));
+ const auto newValue = QUrl::fromEncoded("qrc:/geometry.json");
+ builder.setGeometryShaderGraph(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.geometryShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setGeometryShaderGraph(newValue);
+
+ // THEN
+ QCOMPARE(builder.geometryShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(fragmentShaderGraphChanged(QUrl)));
+ const auto newValue = QUrl::fromEncoded("qrc:/fragment.json");
+ builder.setFragmentShaderGraph(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.fragmentShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setFragmentShaderGraph(newValue);
+
+ // THEN
+ QCOMPARE(builder.fragmentShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ {
+ // WHEN
+ QSignalSpy spy(&builder, SIGNAL(computeShaderGraphChanged(QUrl)));
+ const auto newValue = QUrl::fromEncoded("qrc:/compute.json");
+ builder.setComputeShaderGraph(newValue);
+
+ // THEN
+ QVERIFY(spy.isValid());
+ QCOMPARE(builder.computeShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 1);
+
+ // WHEN
+ spy.clear();
+ builder.setComputeShaderGraph(newValue);
+
+ // THEN
+ QCOMPARE(builder.computeShaderGraph(), newValue);
+ QCOMPARE(spy.count(), 0);
+ }
+ }
+
+ void checkShaderProgramBookkeeping()
+ {
+ // GIVEN
+ QScopedPointer<Qt3DRender::QShaderProgramBuilder> builder(new Qt3DRender::QShaderProgramBuilder);
+ {
+ // WHEN
+ Qt3DRender::QShaderProgram program;
+ builder->setShaderProgram(&program);
+
+ // THEN
+ QCOMPARE(program.parent(), builder.data());
+ QCOMPARE(builder->shaderProgram(), &program);
+ }
+ // THEN (Should not crash and effect be unset)
+ QVERIFY(!builder->shaderProgram());
+
+ {
+ // WHEN
+ Qt3DRender::QShaderProgramBuilder someOtherBuilder;
+ QScopedPointer<Qt3DRender::QShaderProgram> program(new Qt3DRender::QShaderProgram(&someOtherBuilder));
+ builder->setShaderProgram(program.data());
+
+ // THEN
+ QCOMPARE(program->parent(), &someOtherBuilder);
+ QCOMPARE(builder->shaderProgram(), program.data());
+
+ // WHEN
+ builder.reset();
+ program.reset();
+
+ // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper)
+ }
+ }
+
+ void checkCreationData()
+ {
+ // GIVEN
+ Qt3DRender::QShaderProgramBuilder builder;
+
+ builder.setShaderProgram(new Qt3DRender::QShaderProgram(&builder));
+ builder.setEnabledLayers({"foo", "bar"});
+ builder.setVertexShaderGraph(QUrl::fromEncoded("qrc:/vertex.json"));
+ builder.setTessellationControlShaderGraph(QUrl::fromEncoded("qrc:/tesscontrol.json"));
+ builder.setTessellationEvaluationShaderGraph(QUrl::fromEncoded("qrc:/tesseval.json"));
+ builder.setGeometryShaderGraph(QUrl::fromEncoded("qrc:/geometry.json"));
+ builder.setFragmentShaderGraph(QUrl::fromEncoded("qrc:/fragment.json"));
+ builder.setComputeShaderGraph(QUrl::fromEncoded("qrc:/compute.json"));
+
+ // WHEN
+ QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&builder);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // second one is for the shader program child
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QShaderProgramBuilderData>>(creationChanges.first());
+ const Qt3DRender::QShaderProgramBuilderData cloneData = creationChangeData->data;
+
+ QCOMPARE(builder.shaderProgram()->id(), cloneData.shaderProgramId);
+ QCOMPARE(builder.enabledLayers(), cloneData.enabledLayers);
+ QCOMPARE(builder.vertexShaderGraph(), cloneData.vertexShaderGraph);
+ QCOMPARE(builder.tessellationControlShaderGraph(), cloneData.tessellationControlShaderGraph);
+ QCOMPARE(builder.tessellationEvaluationShaderGraph(), cloneData.tessellationEvaluationShaderGraph);
+ QCOMPARE(builder.geometryShaderGraph(), cloneData.geometryShaderGraph);
+ QCOMPARE(builder.fragmentShaderGraph(), cloneData.fragmentShaderGraph);
+ QCOMPARE(builder.computeShaderGraph(), cloneData.computeShaderGraph);
+ QCOMPARE(builder.id(), creationChangeData->subjectId());
+ QCOMPARE(builder.isEnabled(), true);
+ QCOMPARE(builder.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(builder.metaObject(), creationChangeData->metaObject());
+ }
+
+ // WHEN
+ builder.setEnabled(false);
+
+ {
+ Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&builder);
+ creationChanges = creationChangeGenerator.creationChanges();
+ }
+
+ // THEN
+ {
+ QCOMPARE(creationChanges.size(), 2); // second one is for the shader program child
+
+ const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QShaderProgramBuilderData>>(creationChanges.first());
+ const Qt3DRender::QShaderProgramBuilderData cloneData = creationChangeData->data;
+
+ QCOMPARE(builder.shaderProgram()->id(), cloneData.shaderProgramId);
+ QCOMPARE(builder.enabledLayers(), cloneData.enabledLayers);
+ QCOMPARE(builder.vertexShaderGraph(), cloneData.vertexShaderGraph);
+ QCOMPARE(builder.tessellationControlShaderGraph(), cloneData.tessellationControlShaderGraph);
+ QCOMPARE(builder.tessellationEvaluationShaderGraph(), cloneData.tessellationEvaluationShaderGraph);
+ QCOMPARE(builder.geometryShaderGraph(), cloneData.geometryShaderGraph);
+ QCOMPARE(builder.fragmentShaderGraph(), cloneData.fragmentShaderGraph);
+ QCOMPARE(builder.computeShaderGraph(), cloneData.computeShaderGraph);
+ QCOMPARE(builder.id(), creationChangeData->subjectId());
+ QCOMPARE(builder.isEnabled(), false);
+ QCOMPARE(builder.isEnabled(), creationChangeData->isNodeEnabled());
+ QCOMPARE(builder.metaObject(), creationChangeData->metaObject());
+ }
+ }
+
+ void checkShaderProgramUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+ auto program = new Qt3DRender::QShaderProgram(&builder);
+
+ {
+ // WHEN
+ builder.setShaderProgram(program);
+ 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>(), builder.shaderProgram()->id());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setShaderProgram(program);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+
+ void checkEnabledLayersUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+ const auto layers = QStringList() << "foo" << "bar";
+
+ {
+ // WHEN
+ builder.setEnabledLayers(layers);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "enabledLayers");
+ QCOMPARE(change->value().toStringList(), layers);
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setEnabledLayers(layers);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+ }
+
+ void checkVertexShaderGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+
+ {
+ // WHEN
+ builder.setVertexShaderGraph(QUrl::fromEncoded("qrc:/vertex.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "vertexShaderGraph");
+ QCOMPARE(change->value().value<QUrl>(), builder.vertexShaderGraph());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setVertexShaderGraph(QUrl::fromEncoded("qrc:/vertex.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkTessellationControlShaderGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+
+ {
+ // WHEN
+ builder.setTessellationControlShaderGraph(QUrl::fromEncoded("qrc:/tesscontrol.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "tessellationControlShaderGraph");
+ QCOMPARE(change->value().value<QUrl>(), builder.tessellationControlShaderGraph());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setTessellationControlShaderGraph(QUrl::fromEncoded("qrc:/tesscontrol.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkTessellationEvaluationShaderGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+
+ {
+ // WHEN
+ builder.setTessellationEvaluationShaderGraph(QUrl::fromEncoded("qrc:/tesseval.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "tessellationEvaluationShaderGraph");
+ QCOMPARE(change->value().value<QUrl>(), builder.tessellationEvaluationShaderGraph());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setTessellationEvaluationShaderGraph(QUrl::fromEncoded("qrc:/tesseval.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkGeometryShaderGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+
+ {
+ // WHEN
+ builder.setGeometryShaderGraph(QUrl::fromEncoded("qrc:/geometry.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "geometryShaderGraph");
+ QCOMPARE(change->value().value<QUrl>(), builder.geometryShaderGraph());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setGeometryShaderGraph(QUrl::fromEncoded("qrc:/geometry.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkFragmentShaderGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+
+ {
+ // WHEN
+ builder.setFragmentShaderGraph(QUrl::fromEncoded("qrc:/fragment.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "fragmentShaderGraph");
+ QCOMPARE(change->value().value<QUrl>(), builder.fragmentShaderGraph());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setFragmentShaderGraph(QUrl::fromEncoded("qrc:/fragment.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
+ void checkComputeShaderGraphUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QShaderProgramBuilder builder;
+ arbiter.setArbiterOnNode(&builder);
+
+ {
+ // WHEN
+ builder.setComputeShaderGraph(QUrl::fromEncoded("qrc:/compute.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "computeShaderGraph");
+ QCOMPARE(change->value().value<QUrl>(), builder.computeShaderGraph());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ builder.setComputeShaderGraph(QUrl::fromEncoded("qrc:/compute.json"));
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+};
+
+QTEST_MAIN(tst_QShaderProgramBuilder)
+
+#include "tst_qshaderprogrambuilder.moc"
diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro
index 5a82ee835..32a7b35fc 100644
--- a/tests/auto/render/render.pro
+++ b/tests/auto/render/render.pro
@@ -7,13 +7,13 @@ qtConfig(private_tests) {
renderpass \
qgraphicsutils \
shader \
+ shaderbuilder \
texture \
renderviewutils \
renderviews \
material \
vsyncframeadvanceservice \
meshfunctors \
- qmaterial \
qattribute \
qbuffer \
qgeometry \
@@ -23,7 +23,6 @@ qtConfig(private_tests) {
buffer \
attribute \
geometry \
- geometryloaders \
geometryrenderer \
raycasting \
qcameraselector \
@@ -44,11 +43,8 @@ qtConfig(private_tests) {
framegraphnode \
qobjectpicker \
objectpicker \
- picking \
# qboundingvolumedebug \
# boundingvolumedebug \
- boundingsphere \
- qdefaultmeshes \
trianglesextractor \
triangleboundingvolume \
ddstextures \
@@ -70,8 +66,6 @@ qtConfig(private_tests) {
graphicshelpergl3_3 \
graphicshelpergl3_2 \
graphicshelpergl2 \
- gltfplugins \
- pickboundingvolumejob \
sendrendercapturejob \
textures \
qparameter \
@@ -81,8 +75,6 @@ qtConfig(private_tests) {
qabstracttexture \
qabstracttextureimage \
qrendersettings \
- updatemeshtrianglelistjob \
- updateshaderdatatransformjob \
texturedatamanager \
rendertarget \
transform \
@@ -101,14 +93,43 @@ qtConfig(private_tests) {
renderviewbuilder \
filtercompatibletechniquejob \
rendercapture \
+ segmentvisitor \
trianglevisitor \
qmemorybarrier \
memorybarrier \
qshaderprogram \
- qscene2d \
- scene2d \
+ qshaderprogrambuilder \
coordinatereader \
- framegraphvisitor
+ framegraphvisitor \
+ renderer \
+ armature \
+ skeleton \
+ joint \
+ qproximityfilter \
+ proximityfilter \
+ proximityfiltering \
+ qblitframebuffer \
+ blitframebuffer
+
+ QT_FOR_CONFIG = 3dcore-private
+ qtConfig(qt3d-extras) {
+ SUBDIRS += \
+ qmaterial \
+ geometryloaders \
+ picking \
+ boundingsphere \
+ qdefaultmeshes \
+ pickboundingvolumejob \
+ gltfplugins \
+ updatemeshtrianglelistjob \
+ updateshaderdatatransformjob
+ }
+
+ qtConfig(qt3d-input) {
+ SUBDIRS += \
+ qscene2d \
+ scene2d
+ }
!macos: SUBDIRS += graphicshelpergl4
}
diff --git a/tests/auto/render/rendercapture/tst_rendercapture.cpp b/tests/auto/render/rendercapture/tst_rendercapture.cpp
index 4029ba136..799a7ccff 100644
--- a/tests/auto/render/rendercapture/tst_rendercapture.cpp
+++ b/tests/auto/render/rendercapture/tst_rendercapture.cpp
@@ -90,7 +90,7 @@ private Q_SLOTS:
QCOMPARE(renderCapture.wasCaptureRequested(), true);
}
- void checkAcknowledgeCaptureRequest()
+ void checkTakeCaptureRequest()
{
// GIVEN
Qt3DRender::Render::RenderCapture renderCapture;
@@ -99,22 +99,26 @@ private Q_SLOTS:
renderCapture.setEnabled(true);
// WHEN
- renderCapture.requestCapture(2);
- renderCapture.requestCapture(4);
+ renderCapture.requestCapture({ 2, QRect(10, 10, 20, 20) });
+ renderCapture.requestCapture({ 4, QRect(15, 15, 30, 30) });
// THEN
QCOMPARE(renderCapture.wasCaptureRequested(), true);
// WHEN
- renderCapture.acknowledgeCaptureRequest();
+ Qt3DRender::QRenderCaptureRequest r1 = renderCapture.takeCaptureRequest();
// THEN
+ QCOMPARE(r1.captureId, 2);
+ QCOMPARE(r1.rect, QRect(10, 10, 20, 20));
QCOMPARE(renderCapture.wasCaptureRequested(), true);
// WHEN
- renderCapture.acknowledgeCaptureRequest();
+ Qt3DRender::QRenderCaptureRequest r2 = renderCapture.takeCaptureRequest();
// THEN
+ QCOMPARE(r2.captureId, 4);
+ QCOMPARE(r2.rect, QRect(15, 15, 30, 30));
QCOMPARE(renderCapture.wasCaptureRequested(), false);
}
};
diff --git a/tests/auto/render/renderer/renderer.pro b/tests/auto/render/renderer/renderer.pro
new file mode 100644
index 000000000..cbafc156b
--- /dev/null
+++ b/tests/auto/render/renderer/renderer.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+
+TARGET = tst_renderer
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_renderer.cpp
diff --git a/tests/auto/render/renderer/tst_renderer.cpp b/tests/auto/render/renderer/tst_renderer.cpp
new file mode 100644
index 000000000..85d978926
--- /dev/null
+++ b/tests/auto/render/renderer/tst_renderer.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QThread>
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/viewportnode_p.h>
+#include <Qt3DRender/private/renderview_p.h>
+#include <Qt3DRender/private/renderviewbuilder_p.h>
+
+class tst_Renderer : public QObject
+{
+ Q_OBJECT
+public :
+ tst_Renderer() {}
+ ~tst_Renderer() {}
+
+private Q_SLOTS:
+ void checkRenderBinJobs()
+ {
+ // GIVEN
+ Qt3DRender::Render::NodeManagers nodeManagers;
+ Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
+ Qt3DRender::Render::RenderSettings settings;
+ // owned by FG manager
+ Qt3DRender::Render::ViewportNode *fgRoot = new Qt3DRender::Render::ViewportNode();
+ const Qt3DCore::QNodeId fgRootId = Qt3DCore::QNodeId::createId();
+
+ nodeManagers.frameGraphManager()->appendNode(fgRootId, fgRoot);
+ settings.setActiveFrameGraphId(fgRootId);
+
+ renderer.setNodeManagers(&nodeManagers);
+ renderer.setSettings(&settings);
+ renderer.initialize();
+
+ const int singleRenderViewJobCount = 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount();
+ // RenderViewBuilder renderViewJob,
+ // renderableEntityFilterJob,
+ // lightGatherJob,
+ // computableEntityFilterJob,
+ // syncRenderViewInitializationJob,
+ // syncFrustumCullingJob,
+ // filterEntityByLayerJob,
+ // filterProximityJob,
+ // setClearDrawBufferIndexJob,
+ // frustumCullingJob,
+ // syncRenderCommandBuldingJob,
+ // syncRenderViewCommandBuilderJob)
+ // n * (RenderViewCommandBuildJobs + MaterialGathererJobs
+
+ // WHEN (nothing dirty, no buffers)
+ QVector<Qt3DCore::QAspectJobPtr> jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // updateSkinningPaletteJob
+ singleRenderViewJobCount); // Only valid for the first call to renderBinJobs(), since subsequent calls won't have the renderqueue reset
+
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::EntityEnabledDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // updateSkinningPaletteJob
+ 1); // EntityEnabledDirty
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::TransformDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // WorldTransformJob
+ 1 + // UpdateWorldBoundingVolume
+ 1 + // UpdateShaderDataTransform
+ 1 + // updateSkinningPaletteJob
+ 1); // ExpandBoundingVolumeJob
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::GeometryDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // CalculateBoundingVolumeJob
+ 1 + // UpdateMeshTriangleListJob
+ 1 + // updateSkinningPaletteJob
+ 1); // ExpandBoundingVolumeJob
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::BuffersDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // updateSkinningPaletteJob
+ 1); // BufferGathererJob
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::ShadersDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // updateSkinningPaletteJob
+ 1); // ShaderGathererJob
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::TexturesDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // TexturesGathererJob
+ 1 + // updateSkinningPaletteJob
+ 1); // SyncTexturesGathererJob
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+ // WHEN
+ renderer.markDirty(Qt3DRender::Render::AbstractRenderer::AllDirty, nullptr);
+ jobs = renderer.renderBinJobs();
+
+ // THEN (level
+ QCOMPARE(jobs.size(),
+ 1 + // updateLevelOfDetailJob
+ 1 + // cleanupJob
+ 1 + // sendRenderCaptureJob
+ 1 + // sendBufferCaptureJob
+ 1 + // filterCompatibleTechniquesJob
+ 1 + // VAOGatherer
+ 1 + // EntityEnabledDirty
+ 1 + // WorldTransformJob
+ 1 + // UpdateWorldBoundingVolume
+ 1 + // UpdateShaderDataTransform
+ 1 + // ExpandBoundingVolumeJob
+ 1 + // CalculateBoundingVolumeJob
+ 1 + // UpdateMeshTriangleListJob
+ 1 + // BufferGathererJob
+ 1 + // ShaderGathererJob
+ 1 + // TexturesGathererJob
+ 1 + // updateSkinningPaletteJob
+ 1); // SyncTexturesGathererJob
+
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
+
+
+ }
+};
+
+QTEST_MAIN(tst_Renderer)
+
+#include "tst_renderer.moc"
diff --git a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
index 1ab687b34..23861f3a9 100644
--- a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
+++ b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
@@ -179,27 +179,60 @@ private Q_SLOTS:
Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id());
QVERIFY(leafNode != nullptr);
- // WHEN
- Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ {
+ // WHEN
+ Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+
+ // THEN
+ QCOMPARE(renderViewBuilder.renderViewIndex(), 0);
+ QCOMPARE(renderViewBuilder.renderer(), testAspect.renderer());
+ QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), false);
+ QVERIFY(!renderViewBuilder.renderViewJob().isNull());
+ QVERIFY(!renderViewBuilder.lightGathererJob().isNull());
+ QVERIFY(!renderViewBuilder.renderableEntityFilterJob().isNull());
+ QVERIFY(!renderViewBuilder.computableEntityFilterJob().isNull());
+ QVERIFY(!renderViewBuilder.frustumCullingJob().isNull());
+ QVERIFY(!renderViewBuilder.syncFrustumCullingJob().isNull());
+ QVERIFY(!renderViewBuilder.setClearDrawBufferIndexJob().isNull());
+
+ QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull());
+ QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull());
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob().isNull());
+ QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob().isNull());
+ QVERIFY(renderViewBuilder.syncRenderViewInitializationJob().isNull());
+
+ QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), 0);
+ QCOMPARE(renderViewBuilder.materialGathererJobs().size(), 0);
+
+ // WHEN
+ renderViewBuilder.prepareJobs();
+
+ // THEN
+ QVERIFY(!renderViewBuilder.syncRenderCommandBuildingJob().isNull());
+ QVERIFY(!renderViewBuilder.syncRenderViewCommandBuildersJob().isNull());
+ QVERIFY(!renderViewBuilder.syncRenderViewInitializationJob().isNull());
+ QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull());
+ QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull());
+
+ QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+ QCOMPARE(renderViewBuilder.materialGathererJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+ QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+ }
- // THEN
- QCOMPARE(renderViewBuilder.renderViewIndex(), 0);
- QCOMPARE(renderViewBuilder.renderer(), testAspect.renderer());
- QVERIFY(!renderViewBuilder.renderViewJob().isNull());
- QVERIFY(!renderViewBuilder.filterEntityByLayerJob().isNull());
- QVERIFY(!renderViewBuilder.lightGathererJob().isNull());
- QVERIFY(!renderViewBuilder.renderableEntityFilterJob().isNull());
- QVERIFY(!renderViewBuilder.computableEntityFilterJob().isNull());
- QVERIFY(!renderViewBuilder.frustumCullingJob().isNull());
- QVERIFY(!renderViewBuilder.syncRenderViewInitializationJob().isNull());
- QVERIFY(!renderViewBuilder.syncFrustumCullingJob().isNull());
- QVERIFY(!renderViewBuilder.syncRenderCommandBuildingJob().isNull());
- QVERIFY(!renderViewBuilder.syncRenderViewCommandBuildersJob().isNull());
- QVERIFY(!renderViewBuilder.setClearDrawBufferIndexJob().isNull());
- QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
- QCOMPARE(renderViewBuilder.materialGathererJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
-
- QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+ {
+ // WHEN
+ Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true);
+ renderViewBuilder.prepareJobs();
+
+ // THEN
+ QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), true);
+ QVERIFY(!renderViewBuilder.filterEntityByLayerJob().isNull());
+ QVERIFY(!renderViewBuilder.syncFilterEntityByLayerJob().isNull());
+
+ // mark jobs dirty and recheck
+ QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 13 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
+ }
}
void checkCheckJobDependencies()
@@ -213,66 +246,145 @@ private Q_SLOTS:
Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(clearBuffer->id());
QVERIFY(leafNode != nullptr);
- // WHEN
- Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
- renderViewBuilder.buildJobHierachy();
-
- // THEN
- // Step 1
- QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 0);
- QCOMPARE(renderViewBuilder.lightGathererJob()->dependencies().size(), 0);
- QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->dependencies().size(),0);
- QCOMPARE(renderViewBuilder.computableEntityFilterJob()->dependencies().size(), 0);
-
- // Step 2
- QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().size(), 1);
- QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().first().data(), renderViewBuilder.renderViewJob().data());
-
- // Step 3
- QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->dependencies().size(), 2);
- QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
- QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(testAspect.renderer()->updateTreeEnabledJob()));
-
- QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1);
- QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().first().data(), renderViewBuilder.syncRenderViewInitializationJob().data());
-
- QCOMPARE(renderViewBuilder.syncFrustumCullingJob()->dependencies().size(), 3);
- QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
- QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateWorldTransformJob()));
- QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob()));
-
- for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
- QCOMPARE(materialGatherer->dependencies().size(), 2);
- QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
- QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob()));
- }
-
- // Step 4
- QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2);
- QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncFrustumCullingJob()));
- QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob()));
-
- QCOMPARE(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 6);
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.renderableEntityFilterJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.computableEntityFilterJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterEntityByLayerJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob()));
- for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(materialGatherer));
+ {
+ // WHEN
+ Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.prepareJobs();
+ renderViewBuilder.buildJobHierachy();
+
+ // THEN
+ // Step 1
+ QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update
+ QCOMPARE(renderViewBuilder.lightGathererJob()->dependencies().size(), 0);
+ QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->dependencies().size(),0);
+ QCOMPARE(renderViewBuilder.computableEntityFilterJob()->dependencies().size(), 0);
+
+ // Step 2
+ QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().size(), 1);
+ QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().first().data(), renderViewBuilder.renderViewJob().data());
+
+ // Step 3
+ QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull());
+ QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull());
+
+ QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2);
+ QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob()));
+
+ QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1);
+ QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().first().data(), renderViewBuilder.syncRenderViewInitializationJob().data());
+
+ QCOMPARE(renderViewBuilder.syncFrustumCullingJob()->dependencies().size(), 3);
+ QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateWorldTransformJob()));
+ QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob()));
+
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QCOMPARE(materialGatherer->dependencies().size(), 2);
+ QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob()));
+ }
+
+ // Step 4
+ QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2);
+ QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncFrustumCullingJob()));
+ QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob()));
+
+ QCOMPARE(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 6);
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.renderableEntityFilterJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.computableEntityFilterJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterProximityJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob()));
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(materialGatherer));
+ }
+
+ // Step 5
+ for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) {
+ QCOMPARE(renderViewBuilderJob->dependencies().size(), 1);
+ QCOMPARE(renderViewBuilderJob->dependencies().first().data(), renderViewBuilder.syncRenderCommandBuildingJob().data());
+ }
+
+ // Step 6
+ QCOMPARE(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().size(), renderViewBuilder.renderViewBuilderJobs().size());
+ for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) {
+ QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().contains(renderViewBuilderJob));
+ }
}
-
- // Step 5
- for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) {
- QCOMPARE(renderViewBuilderJob->dependencies().size(), 1);
- QCOMPARE(renderViewBuilderJob->dependencies().first().data(), renderViewBuilder.syncRenderCommandBuildingJob().data());
- }
-
- // Step 6
- QCOMPARE(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().size(), renderViewBuilder.renderViewBuilderJobs().size());
- for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) {
- QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().contains(renderViewBuilderJob));
+ {
+ // WHEN
+ Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true);
+ renderViewBuilder.prepareJobs();
+ renderViewBuilder.buildJobHierachy();
+
+ // THEN
+ // Step 1
+ QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update
+ QCOMPARE(renderViewBuilder.lightGathererJob()->dependencies().size(), 0);
+ QCOMPARE(renderViewBuilder.renderableEntityFilterJob()->dependencies().size(),0);
+ QCOMPARE(renderViewBuilder.computableEntityFilterJob()->dependencies().size(), 0);
+
+ // Step 2
+ QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().size(), 1);
+ QCOMPARE(renderViewBuilder.syncRenderViewInitializationJob()->dependencies().first().data(), renderViewBuilder.renderViewJob().data());
+
+ // Step 3
+ QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->dependencies().size(), 2);
+ QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(testAspect.renderer()->updateTreeEnabledJob()));
+
+ QCOMPARE(renderViewBuilder.syncFilterEntityByLayerJob()->dependencies().size(), 1);
+ QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob()->dependencies().contains(renderViewBuilder.filterEntityByLayerJob()));
+
+ QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2);
+ QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob()));
+
+ QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1);
+ QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().first().data(), renderViewBuilder.syncRenderViewInitializationJob().data());
+
+ QCOMPARE(renderViewBuilder.syncFrustumCullingJob()->dependencies().size(), 3);
+ QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateWorldTransformJob()));
+ QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob()));
+
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QCOMPARE(materialGatherer->dependencies().size(), 2);
+ QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob()));
+ }
+
+ // Step 4
+ QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2);
+ QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncFrustumCullingJob()));
+ QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(testAspect.renderer()->expandBoundingVolumeJob()));
+
+ QCOMPARE(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 7);
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.renderableEntityFilterJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.computableEntityFilterJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.syncFilterEntityByLayerJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterProximityJob()));
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(materialGatherer));
+ }
+
+ // Step 5
+ for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) {
+ QCOMPARE(renderViewBuilderJob->dependencies().size(), 1);
+ QCOMPARE(renderViewBuilderJob->dependencies().first().data(), renderViewBuilder.syncRenderCommandBuildingJob().data());
+ }
+
+ // Step 6
+ QCOMPARE(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().size(), renderViewBuilder.renderViewBuilderJobs().size());
+ for (const auto renderViewBuilderJob : renderViewBuilder.renderViewBuilderJobs()) {
+ QVERIFY(renderViewBuilder.syncRenderViewCommandBuildersJob()->dependencies().contains(renderViewBuilderJob));
+ }
}
}
@@ -289,6 +401,7 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.prepareJobs();
renderViewBuilder.buildJobHierachy();
renderViewBuilder.renderViewJob()->run();
@@ -309,6 +422,7 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.prepareJobs();
renderViewBuilder.buildJobHierachy();
renderViewBuilder.renderableEntityFilterJob()->run();
@@ -329,6 +443,7 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.prepareJobs();
renderViewBuilder.buildJobHierachy();
renderViewBuilder.computableEntityFilterJob()->run();
@@ -354,30 +469,58 @@ private Q_SLOTS:
Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(renderPassFilter->id());
QVERIFY(leafNode != nullptr);
- // WHEN
- Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
- renderViewBuilder.buildJobHierachy();
-
- // THEN
- QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false);
- QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), false);
- QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layers().size(), 0);
- for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
- QVERIFY(materialGatherer->techniqueFilter() == nullptr);
- QVERIFY(materialGatherer->renderPassFilter() == nullptr);
+ {
+ // WHEN
+ Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.prepareJobs();
+ renderViewBuilder.buildJobHierachy();
+
+ // THEN
+ QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false);
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QVERIFY(materialGatherer->techniqueFilter() == nullptr);
+ QVERIFY(materialGatherer->renderPassFilter() == nullptr);
+ }
+
+ // WHEN
+ renderViewBuilder.renderViewJob()->run();
+ renderViewBuilder.syncRenderViewInitializationJob()->run();
+
+ // THEN
+ QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true);
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QVERIFY(materialGatherer->techniqueFilter() != nullptr);
+ QVERIFY(materialGatherer->renderPassFilter() != nullptr);
+ }
}
-
- // WHEN
- renderViewBuilder.renderViewJob()->run();
- renderViewBuilder.syncRenderViewInitializationJob()->run();
-
- // THEN
- QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true);
- QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), true);
- QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layers().size(), 1);
- for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
- QVERIFY(materialGatherer->techniqueFilter() != nullptr);
- QVERIFY(materialGatherer->renderPassFilter() != nullptr);
+ {
+ // WHEN
+ Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true);
+ renderViewBuilder.prepareJobs();
+ renderViewBuilder.buildJobHierachy();
+
+ // THEN
+ QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false);
+ QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), false);
+ QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 0);
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QVERIFY(materialGatherer->techniqueFilter() == nullptr);
+ QVERIFY(materialGatherer->renderPassFilter() == nullptr);
+ }
+
+ // WHEN
+ renderViewBuilder.renderViewJob()->run();
+ renderViewBuilder.syncRenderViewInitializationJob()->run();
+
+ // THEN
+ QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true);
+ QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), true);
+ QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 1);
+ for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
+ QVERIFY(materialGatherer->techniqueFilter() != nullptr);
+ QVERIFY(materialGatherer->renderPassFilter() != nullptr);
+ }
}
}
@@ -399,6 +542,7 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.prepareJobs();
renderViewBuilder.buildJobHierachy();
// THEN
@@ -428,6 +572,8 @@ private Q_SLOTS:
// WHEN
Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
+ renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true);
+ renderViewBuilder.prepareJobs();
renderViewBuilder.buildJobHierachy();
renderViewBuilder.renderViewJob()->run();
diff --git a/tests/auto/render/sceneloader/tst_sceneloader.cpp b/tests/auto/render/sceneloader/tst_sceneloader.cpp
index 18cfe0aeb..9aac50c73 100644
--- a/tests/auto/render/sceneloader/tst_sceneloader.cpp
+++ b/tests/auto/render/sceneloader/tst_sceneloader.cpp
@@ -79,7 +79,7 @@ private Q_SLOTS:
{
// GIVEN
Qt3DRender::QSceneLoader frontendSceneLoader;
- frontendSceneLoader.setSource(QUrl(QStringLiteral("CorvetteMuseum")));
+ frontendSceneLoader.setSource(QUrl(QStringLiteral("file:///CorvetteMuseum")));
Qt3DRender::Render::Scene sceneLoader;
Qt3DRender::Render::SceneManager sceneManager;
@@ -109,7 +109,7 @@ private Q_SLOTS:
// WHEN
Qt3DCore::QPropertyUpdatedChangePtr updateChange(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
- const QUrl newUrl(QStringLiteral("Bownling_Green_KY"));
+ const QUrl newUrl(QStringLiteral("file:///Bownling_Green_KY"));
updateChange->setValue(newUrl);
updateChange->setPropertyName("source");
sceneLoader.sceneChangeEvent(updateChange);
diff --git a/tests/auto/render/segmentvisitor/segmentvisitor.pro b/tests/auto/render/segmentvisitor/segmentvisitor.pro
new file mode 100644
index 000000000..2f650aa0b
--- /dev/null
+++ b/tests/auto/render/segmentvisitor/segmentvisitor.pro
@@ -0,0 +1,12 @@
+TEMPLATE = app
+
+TARGET = segmentvisitor
+
+QT += 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_segmentvisitor.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/segmentvisitor/tst_segmentvisitor.cpp b/tests/auto/render/segmentvisitor/tst_segmentvisitor.cpp
new file mode 100644
index 000000000..d56daf159
--- /dev/null
+++ b/tests/auto/render/segmentvisitor/tst_segmentvisitor.cpp
@@ -0,0 +1,814 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <qbackendnodetester.h>
+#include <Qt3DRender/qgeometryrenderer.h>
+#include <Qt3DRender/qbuffer.h>
+#include <private/segmentsvisitor_p.h>
+#include <private/nodemanagers_p.h>
+#include <private/managers_p.h>
+#include <private/geometryrenderer_p.h>
+#include <private/geometryrenderermanager_p.h>
+#include <private/buffermanager_p.h>
+#include "testrenderer.h"
+
+using namespace Qt3DRender::Render;
+
+class TestVisitor : public SegmentsVisitor
+{
+public:
+ TestVisitor(NodeManagers *manager)
+ : SegmentsVisitor(manager)
+ {
+
+ }
+
+ virtual void visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b)
+ {
+ m_segments.push_back(TestSegment(andx, a, bndx, b));
+ }
+
+ NodeManagers *nodeManagers() const
+ {
+ return m_manager;
+ }
+
+ Qt3DCore::QNodeId nodeId() const
+ {
+ return m_nodeId;
+ }
+
+ uint segmentCount() const
+ {
+ return m_segments.size();
+ }
+
+ bool verifySegment(uint segment, uint andx, uint bndx, QVector3D a, QVector3D b) const
+ {
+ if (segment >= uint(m_segments.size()))
+ return false;
+ if (andx != m_segments[segment].abcndx[0]
+ || bndx != m_segments[segment].abcndx[1])
+ return false;
+
+ if (!qFuzzyCompare(a, m_segments[segment].abc[0])
+ || !qFuzzyCompare(b, m_segments[segment].abc[1]))
+ return false;
+
+ return true;
+ }
+private:
+ struct TestSegment
+ {
+ uint abcndx[2];
+ QVector3D abc[2];
+ TestSegment()
+ {
+ abcndx[0] = abcndx[1] = uint(-1);
+ }
+
+ TestSegment(uint andx, const QVector3D &a, uint bndx, const QVector3D &b)
+ {
+ abcndx[0] = andx;
+ abcndx[1] = bndx;
+ abc[0] = a;
+ abc[1] = b;
+ }
+ };
+ QVector<TestSegment> m_segments;
+};
+
+class tst_SegmentVisitor : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+
+ void checkInitialize()
+ {
+ // WHEN
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ TestVisitor visitor(nodeManagers.data());
+
+ // THEN
+ QCOMPARE(visitor.nodeManagers(), nodeManagers.data());
+ }
+
+ void checkApplyEntity()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ QScopedPointer<Qt3DCore::QEntity> entity(new Qt3DCore::QEntity());
+ TestVisitor visitor(nodeManagers.data());
+
+ // WHEN
+ visitor.apply(entity.data());
+
+ // THEN
+ QCOMPARE(visitor.nodeId(), entity->id());
+ QCOMPARE(visitor.segmentCount(), uint(0));
+ }
+
+ void checkApplyGeometryRenderer()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ QScopedPointer<GeometryRenderer> geometryRenderer(new GeometryRenderer());
+ TestVisitor visitor(nodeManagers.data());
+
+ // WHEN
+ visitor.apply(geometryRenderer.data(), Qt3DCore::QNodeId());
+
+ // THEN
+ // tadaa, nothing should happen
+ }
+
+ void testVisitSegments()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 2 * 3);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 1.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+
+ dataPtr[6] = 0;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 0;
+ dataPtr[10] = 0;
+ dataPtr[11] = 1.0f;
+
+ dataPtr[12] = 1.0f;
+ dataPtr[13] = 0;
+ dataPtr[14] = 0;
+ dataPtr[15] = 0;
+ dataPtr[16] = 1.0f;
+ dataPtr[17] = 0;
+
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(6);
+ positionAttribute->setByteStride(3*4);
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+ geometry->addAttribute(positionAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(3));
+ QVERIFY(visitor.verifySegment(0, 0,1, QVector3D(0,0,1), QVector3D(1,0,0)));
+ QVERIFY(visitor.verifySegment(1, 2,3, QVector3D(0,1,0), QVector3D(0,0,1)));
+ QVERIFY(visitor.verifySegment(2, 4,5, QVector3D(1,0,0), QVector3D(0,1,0)));
+ }
+
+ void testVisitSegmentsIndexed()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QAttribute> indexAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ QScopedPointer<Qt3DRender::QBuffer> indexDataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 4);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 0.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+ dataPtr[6] = 1.0;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 0;
+ dataPtr[10] = 1.0f;
+ dataPtr[11] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ QByteArray indexData;
+ indexData.resize(sizeof(uint) * 2 * 5);
+ uint *iDataPtr = reinterpret_cast<uint *>(indexData.data());
+ iDataPtr[0] = 0;
+ iDataPtr[1] = 1;
+ iDataPtr[2] = 1;
+ iDataPtr[3] = 2;
+ iDataPtr[4] = 2;
+ iDataPtr[5] = 3;
+ iDataPtr[6] = 0;
+ iDataPtr[7] = 2;
+ iDataPtr[8] = 1;
+ iDataPtr[9] = 3;
+ indexDataBuffer->setData(indexData);
+
+ Buffer *backendIndexBuffer = nodeManagers->bufferManager()->getOrCreateResource(indexDataBuffer->id());
+ backendIndexBuffer->setRenderer(&renderer);
+ backendIndexBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(indexDataBuffer.data(), backendIndexBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*sizeof(float));
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+
+ indexAttribute->setBuffer(indexDataBuffer.data());
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setCount(2*5);
+ indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
+
+ geometry->addAttribute(positionAttribute.data());
+ geometry->addAttribute(indexAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Attribute *backendIndexAttribute = nodeManagers->attributeManager()->getOrCreateResource(indexAttribute->id());
+ backendIndexAttribute->setRenderer(&renderer);
+ simulateInitialization(indexAttribute.data(), backendIndexAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(5));
+ QVERIFY(visitor.verifySegment(0, 0,1, QVector3D(0,0,0), QVector3D(1,0,0)));
+ QVERIFY(visitor.verifySegment(1, 1,2, QVector3D(1,0,0), QVector3D(1,1,0)));
+ QVERIFY(visitor.verifySegment(2, 2,3, QVector3D(1,1,0), QVector3D(0,1,0)));
+ QVERIFY(visitor.verifySegment(3, 0,2, QVector3D(0,0,0), QVector3D(1,1,0)));
+ QVERIFY(visitor.verifySegment(4, 1,3, QVector3D(1,0,0), QVector3D(0,1,0)));
+ }
+
+ void testVisitLineStrip()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 4);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 0.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+ dataPtr[6] = 1.0f;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 0;
+ dataPtr[10] = 1.0f;
+ dataPtr[11] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*4);
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+ geometry->addAttribute(positionAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineStrip);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(3));
+ QVERIFY(visitor.verifySegment(0, 0,1, QVector3D(0,0,0), QVector3D(1,0,0)));
+ QVERIFY(visitor.verifySegment(1, 1,2, QVector3D(1,0,0), QVector3D(1,1,0)));
+ QVERIFY(visitor.verifySegment(2, 2,3, QVector3D(1,1,0), QVector3D(0,1,0)));
+ }
+
+ void testVisitListStripIndexed()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QAttribute> indexAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ QScopedPointer<Qt3DRender::QBuffer> indexDataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 4);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 0.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+ dataPtr[6] = 1.0;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 0;
+ dataPtr[10] = 1.0f;
+ dataPtr[11] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ QByteArray indexData;
+ indexData.resize(sizeof(uint) * 2 * 4);
+ uint *iDataPtr = reinterpret_cast<uint *>(indexData.data());
+ iDataPtr[0] = 0;
+ iDataPtr[1] = 1;
+ iDataPtr[2] = 2;
+ iDataPtr[3] = 3;
+ indexDataBuffer->setData(indexData);
+
+ Buffer *backendIndexBuffer = nodeManagers->bufferManager()->getOrCreateResource(indexDataBuffer->id());
+ backendIndexBuffer->setRenderer(&renderer);
+ backendIndexBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(indexDataBuffer.data(), backendIndexBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*sizeof(float));
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+
+ indexAttribute->setBuffer(indexDataBuffer.data());
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setCount(4);
+ indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
+
+ geometry->addAttribute(positionAttribute.data());
+ geometry->addAttribute(indexAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineStrip);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Attribute *backendIndexAttribute = nodeManagers->attributeManager()->getOrCreateResource(indexAttribute->id());
+ backendIndexAttribute->setRenderer(&renderer);
+ simulateInitialization(indexAttribute.data(), backendIndexAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(3));
+ QVERIFY(visitor.verifySegment(0, 0,1, QVector3D(0,0,0), QVector3D(1,0,0)));
+ QVERIFY(visitor.verifySegment(1, 1,2, QVector3D(1,0,0), QVector3D(1,1,0)));
+ QVERIFY(visitor.verifySegment(2, 2,3, QVector3D(1,1,0), QVector3D(0,1,0)));
+ }
+
+ void testVisitLineLoop()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 4);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 0.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+ dataPtr[6] = 1.0f;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 0;
+ dataPtr[10] = 1.0f;
+ dataPtr[11] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*4);
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+ geometry->addAttribute(positionAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineLoop);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(4));
+ QVERIFY(visitor.verifySegment(0, 0,1, QVector3D(0,0,0), QVector3D(1,0,0)));
+ QVERIFY(visitor.verifySegment(1, 1,2, QVector3D(1,0,0), QVector3D(1,1,0)));
+ QVERIFY(visitor.verifySegment(2, 2,3, QVector3D(1,1,0), QVector3D(0,1,0)));
+ QVERIFY(visitor.verifySegment(3, 3,0, QVector3D(0,1,0), QVector3D(0,0,0)));
+ }
+
+ void testVisitLineLoopIndexed()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QAttribute> indexAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ QScopedPointer<Qt3DRender::QBuffer> indexDataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 4);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 0.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+ dataPtr[6] = 1.0;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 0;
+ dataPtr[10] = 1.0f;
+ dataPtr[11] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ QByteArray indexData;
+ indexData.resize(sizeof(uint) * 2 * 4);
+ uint *iDataPtr = reinterpret_cast<uint *>(indexData.data());
+ iDataPtr[0] = 0;
+ iDataPtr[1] = 1;
+ iDataPtr[2] = 2;
+ iDataPtr[3] = 3;
+ indexDataBuffer->setData(indexData);
+
+ Buffer *backendIndexBuffer = nodeManagers->bufferManager()->getOrCreateResource(indexDataBuffer->id());
+ backendIndexBuffer->setRenderer(&renderer);
+ backendIndexBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(indexDataBuffer.data(), backendIndexBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*sizeof(float));
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+
+ indexAttribute->setBuffer(indexDataBuffer.data());
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setCount(4);
+ indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
+
+ geometry->addAttribute(positionAttribute.data());
+ geometry->addAttribute(indexAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::LineLoop);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Attribute *backendIndexAttribute = nodeManagers->attributeManager()->getOrCreateResource(indexAttribute->id());
+ backendIndexAttribute->setRenderer(&renderer);
+ simulateInitialization(indexAttribute.data(), backendIndexAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(4));
+ QVERIFY(visitor.verifySegment(0, 0,1, QVector3D(0,0,0), QVector3D(1,0,0)));
+ QVERIFY(visitor.verifySegment(1, 1,2, QVector3D(1,0,0), QVector3D(1,1,0)));
+ QVERIFY(visitor.verifySegment(2, 2,3, QVector3D(1,1,0), QVector3D(0,1,0)));
+ QVERIFY(visitor.verifySegment(3, 3,0, QVector3D(0,1,0), QVector3D(0,0,0)));
+ }
+
+ void testVisitLineAdjacency()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 2 * 2);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 1.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+
+ dataPtr[6] = 0;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 1.0f;
+ dataPtr[10] = 0;
+ dataPtr[12] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*4);
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+ geometry->addAttribute(positionAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::LinesAdjacency);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(1));
+ QVERIFY(visitor.verifySegment(0, 1, 2, QVector3D(1,0,0), QVector3D(0,1,0)));
+ }
+
+ void testVisitLinesAdjacencyIndexed()
+ {
+ QScopedPointer<NodeManagers> nodeManagers(new NodeManagers());
+ Qt3DRender::QGeometry *geometry = new Qt3DRender::QGeometry();
+ QScopedPointer<Qt3DRender::QGeometryRenderer> geometryRenderer(new Qt3DRender::QGeometryRenderer());
+ QScopedPointer<Qt3DRender::QAttribute> positionAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QAttribute> indexAttribute(new Qt3DRender::QAttribute());
+ QScopedPointer<Qt3DRender::QBuffer> dataBuffer(new Qt3DRender::QBuffer());
+ QScopedPointer<Qt3DRender::QBuffer> indexDataBuffer(new Qt3DRender::QBuffer());
+ TestVisitor visitor(nodeManagers.data());
+ TestRenderer renderer;
+
+ QByteArray data;
+ data.resize(sizeof(float) * 3 * 2 * 2);
+ float *dataPtr = reinterpret_cast<float *>(data.data());
+ dataPtr[0] = 0;
+ dataPtr[1] = 0;
+ dataPtr[2] = 1.0f;
+ dataPtr[3] = 1.0f;
+ dataPtr[4] = 0;
+ dataPtr[5] = 0;
+
+ dataPtr[6] = 0;
+ dataPtr[7] = 1.0f;
+ dataPtr[8] = 0;
+ dataPtr[9] = 1.0f;
+ dataPtr[10] = 0;
+ dataPtr[12] = 0;
+ dataBuffer->setData(data);
+ Buffer *backendBuffer = nodeManagers->bufferManager()->getOrCreateResource(dataBuffer->id());
+ backendBuffer->setRenderer(&renderer);
+ backendBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(dataBuffer.data(), backendBuffer);
+
+ QByteArray indexData;
+ indexData.resize(sizeof(uint) * 2);
+ uint *iDataPtr = reinterpret_cast<uint *>(indexData.data());
+ iDataPtr[0] = 0;
+ iDataPtr[1] = 1;
+ iDataPtr[2] = 2;
+ iDataPtr[3] = 3;
+ indexDataBuffer->setData(indexData);
+
+ Buffer *backendIndexBuffer = nodeManagers->bufferManager()->getOrCreateResource(indexDataBuffer->id());
+ backendIndexBuffer->setRenderer(&renderer);
+ backendIndexBuffer->setManager(nodeManagers->bufferManager());
+ simulateInitialization(indexDataBuffer.data(), backendIndexBuffer);
+
+ positionAttribute->setBuffer(dataBuffer.data());
+ positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
+ positionAttribute->setCount(4);
+ positionAttribute->setByteStride(3*sizeof(float));
+ positionAttribute->setByteOffset(0);
+ positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
+
+ indexAttribute->setBuffer(indexDataBuffer.data());
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setCount(4);
+ indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
+
+ geometry->addAttribute(positionAttribute.data());
+ geometry->addAttribute(indexAttribute.data());
+
+ geometryRenderer->setGeometry(geometry);
+ geometryRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::LinesAdjacency);
+
+ Attribute *backendAttribute = nodeManagers->attributeManager()->getOrCreateResource(positionAttribute->id());
+ backendAttribute->setRenderer(&renderer);
+ simulateInitialization(positionAttribute.data(), backendAttribute);
+
+ Attribute *backendIndexAttribute = nodeManagers->attributeManager()->getOrCreateResource(indexAttribute->id());
+ backendIndexAttribute->setRenderer(&renderer);
+ simulateInitialization(indexAttribute.data(), backendIndexAttribute);
+
+ Geometry *backendGeometry = nodeManagers->geometryManager()->getOrCreateResource(geometry->id());
+ backendGeometry->setRenderer(&renderer);
+ simulateInitialization(geometry, backendGeometry);
+
+ GeometryRenderer *backendRenderer = nodeManagers->geometryRendererManager()->getOrCreateResource(geometryRenderer->id());
+ backendRenderer->setRenderer(&renderer);
+ backendRenderer->setManager(nodeManagers->geometryRendererManager());
+ simulateInitialization(geometryRenderer.data(), backendRenderer);
+
+ // WHEN
+ visitor.apply(backendRenderer, Qt3DCore::QNodeId());
+
+ // THEN
+ QCOMPARE(visitor.segmentCount(), uint(1));
+ QVERIFY(visitor.verifySegment(0, 1, 2, QVector3D(1,0,0), QVector3D(0,1,0)));
+ }
+};
+
+QTEST_MAIN(tst_SegmentVisitor)
+
+#include "tst_segmentvisitor.moc"
diff --git a/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp b/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp
index 3310941ed..c6bd65324 100644
--- a/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp
+++ b/tests/auto/render/sendrendercapturejob/tst_sendrendercapturejob.cpp
@@ -55,9 +55,9 @@ private Q_SLOTS:
renderer.setNodeManagers(&nodeManagers);
job.setManagers(&nodeManagers);
- renderCapture->requestCapture(42);
- renderCapture->acknowledgeCaptureRequest();
- renderCapture->addRenderCapture(image);
+ renderCapture->requestCapture({ 42, QRect() });
+ auto request = renderCapture->takeCaptureRequest();
+ renderCapture->addRenderCapture(request.captureId, image);
renderer.addRenderCaptureSendRequest(renderCapture->peerId());
//WHEN
diff --git a/tests/auto/render/shader/shader.pro b/tests/auto/render/shader/shader.pro
index 7c908e0f6..6e8a8ec2e 100644
--- a/tests/auto/render/shader/shader.pro
+++ b/tests/auto/render/shader/shader.pro
@@ -9,3 +9,4 @@ CONFIG += testcase
SOURCES += tst_shader.cpp
include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/shader/tst_shader.cpp b/tests/auto/render/shader/tst_shader.cpp
index f6ed41a8b..067db55e7 100644
--- a/tests/auto/render/shader/tst_shader.cpp
+++ b/tests/auto/render/shader/tst_shader.cpp
@@ -30,6 +30,7 @@
#include <qbackendnodetester.h>
#include <Qt3DRender/private/shader_p.h>
#include <Qt3DRender/qshaderprogram.h>
+#include "testrenderer.h"
class tst_RenderShader : public Qt3DCore::QBackendNodeTester
{
@@ -39,6 +40,11 @@ private slots:
void hasCoherentInitialState();
void matchesFrontendPeer();
void cleanupLeavesACoherentState();
+ void dealWithPropertyChanges_data();
+ void dealWithPropertyChanges();
+ void checkSetRendererDirtyOnInitialization();
+ void allowToChangeShaderCode_data();
+ void allowToChangeShaderCode();
};
@@ -86,36 +92,180 @@ void tst_RenderShader::hasCoherentInitialState()
void tst_RenderShader::matchesFrontendPeer()
{
- Qt3DRender::QShaderProgram *frontend = createFrontendShader();
- Qt3DRender::Render::Shader *backend = new Qt3DRender::Render::Shader();
+ QScopedPointer<Qt3DRender::QShaderProgram> frontend(createFrontendShader());
+ TestRenderer renderer;
+ Qt3DRender::Render::Shader backend;
- simulateInitialization(frontend, backend);
- QCOMPARE(backend->isLoaded(), false);
- QVERIFY(backend->dna() != 0U);
+ backend.setRenderer(&renderer);
+ simulateInitialization(frontend.data(), &backend);
+ QCOMPARE(backend.isLoaded(), false);
+ QVERIFY(backend.dna() != 0U);
for (int i = Qt3DRender::QShaderProgram::Vertex; i <= Qt3DRender::QShaderProgram::Compute; ++i)
- QCOMPARE(backend->shaderCode()[i],
+ QCOMPARE(backend.shaderCode()[i],
frontend->shaderCode( static_cast<const Qt3DRender::QShaderProgram::ShaderType>(i)));
}
void tst_RenderShader::cleanupLeavesACoherentState()
{
- Qt3DRender::QShaderProgram *frontend = createFrontendShader();
- Qt3DRender::Render::Shader *shader = new Qt3DRender::Render::Shader();
+ QScopedPointer<Qt3DRender::QShaderProgram> frontend(createFrontendShader());
+ TestRenderer renderer;
+ Qt3DRender::Render::Shader shader;
- simulateInitialization(frontend, shader);
+ shader.setRenderer(&renderer);
+ simulateInitialization(frontend.data(), &shader);
- shader->cleanup();
+ shader.cleanup();
- QCOMPARE(shader->isLoaded(), false);
- QCOMPARE(shader->dna(), 0U);
- QVERIFY(shader->uniformsNames().isEmpty());
- QVERIFY(shader->attributesNames().isEmpty());
- QVERIFY(shader->uniformBlockNames().isEmpty());
- QVERIFY(shader->uniforms().isEmpty());
- QVERIFY(shader->attributes().isEmpty());
- QVERIFY(shader->uniformBlocks().isEmpty());
- QCOMPARE(shader->status(), Qt3DRender::QShaderProgram::NotReady);
+ QCOMPARE(shader.isLoaded(), false);
+ QCOMPARE(shader.dna(), 0U);
+ QVERIFY(shader.uniformsNames().isEmpty());
+ QVERIFY(shader.attributesNames().isEmpty());
+ QVERIFY(shader.uniformBlockNames().isEmpty());
+ QVERIFY(shader.uniforms().isEmpty());
+ QVERIFY(shader.attributes().isEmpty());
+ QVERIFY(shader.uniformBlocks().isEmpty());
+ QCOMPARE(shader.status(), Qt3DRender::QShaderProgram::NotReady);
+}
+
+void tst_RenderShader::dealWithPropertyChanges_data()
+{
+ QTest::addColumn<QByteArray>("property");
+ QTest::addColumn<Qt3DRender::QShaderProgram::ShaderType>("type");
+
+ QTest::newRow("vertex") << QByteArrayLiteral("vertexShaderCode")
+ << Qt3DRender::QShaderProgram::Vertex;
+
+ QTest::newRow("tessControl") << QByteArrayLiteral("tessellationControlShaderCode")
+ << Qt3DRender::QShaderProgram::TessellationControl;
+
+ QTest::newRow("tessEval") << QByteArrayLiteral("tessellationEvaluationShaderCode")
+ << Qt3DRender::QShaderProgram::TessellationEvaluation;
+
+ QTest::newRow("geometry") << QByteArrayLiteral("geometryShaderCode")
+ << Qt3DRender::QShaderProgram::Geometry;
+
+ QTest::newRow("fragment") << QByteArrayLiteral("fragmentShaderCode")
+ << Qt3DRender::QShaderProgram::Fragment;
+
+ QTest::newRow("compute") << QByteArrayLiteral("computeShaderCode")
+ << Qt3DRender::QShaderProgram::Compute;
+}
+
+void tst_RenderShader::dealWithPropertyChanges()
+{
+ // GIVEN
+ QFETCH(QByteArray, property);
+ QFETCH(Qt3DRender::QShaderProgram::ShaderType, type);
+
+ Qt3DRender::Render::Shader backend;
+ backend.setLoaded(true);
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+
+ // WHEN
+ auto updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QStringLiteral("foo"));
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderCode().at(type), QStringLiteral("foo"));
+ QVERIFY(!backend.isLoaded());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ backend.setLoaded(true);
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QStringLiteral("foo"));
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderCode().at(type), QStringLiteral("foo"));
+ QVERIFY(backend.isLoaded());
+ QCOMPARE(renderer.dirtyBits(), 0);
+ renderer.resetDirty();
+ backend.setLoaded(true);
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QStringLiteral("bar"));
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderCode().at(type), QStringLiteral("bar"));
+ QVERIFY(!backend.isLoaded());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ backend.setLoaded(true);
+}
+
+void tst_RenderShader::checkSetRendererDirtyOnInitialization()
+{
+ // GIVEN
+ QScopedPointer<Qt3DRender::QShaderProgram> frontend(createFrontendShader());
+ Qt3DRender::Render::Shader shader;
+ TestRenderer renderer;
+
+ shader.setRenderer(&renderer);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), 0);
+
+ // WHEN
+ simulateInitialization(frontend.data(), &shader);
+
+ // THEN
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+}
+
+void tst_RenderShader::allowToChangeShaderCode_data()
+{
+ dealWithPropertyChanges_data();
+}
+
+void tst_RenderShader::allowToChangeShaderCode()
+{
+ // GIVEN
+ QFETCH(Qt3DRender::QShaderProgram::ShaderType, type);
+
+ Qt3DRender::Render::Shader backend;
+ backend.setLoaded(true);
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+
+ // WHEN
+ backend.setShaderCode(type, QByteArrayLiteral("foo"));
+
+ // THEN
+ QCOMPARE(backend.shaderCode().at(type), QStringLiteral("foo"));
+ QVERIFY(!backend.isLoaded());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ backend.setLoaded(true);
+
+ // WHEN
+ backend.setShaderCode(type, QByteArrayLiteral("foo"));
+
+ // THEN
+ QCOMPARE(backend.shaderCode().at(type), QStringLiteral("foo"));
+ QVERIFY(backend.isLoaded());
+ QCOMPARE(renderer.dirtyBits(), 0);
+ renderer.resetDirty();
+ backend.setLoaded(true);
+
+ // WHEN
+ backend.setShaderCode(type, QByteArrayLiteral("bar"));
+
+ // THEN
+ QCOMPARE(backend.shaderCode().at(type), QStringLiteral("bar"));
+ QVERIFY(!backend.isLoaded());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ backend.setLoaded(true);
}
QTEST_APPLESS_MAIN(tst_RenderShader)
diff --git a/tests/auto/render/shaderbuilder/input.json b/tests/auto/render/shaderbuilder/input.json
new file mode 100644
index 000000000..5437bd5b5
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/input.json
@@ -0,0 +1,90 @@
+{
+ "nodes": [
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000001}",
+ "type": "worldPosition"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000002}",
+ "type": "texture"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000003}",
+ "type": "texCoord"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000004}",
+ "type": "lightIntensity"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000005}",
+ "type": "exposure"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000006}",
+ "type": "fragColor"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000007}",
+ "type": "sampleTexture"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000008}",
+ "type": "lightModel"
+ },
+ {
+ "uuid": "{00000000-0000-0000-0000-000000000009}",
+ "type": "exposureFunction"
+ }
+ ],
+ "edges": [
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000002}",
+ "sourcePort": "texture",
+ "targetUuid": "{00000000-0000-0000-0000-000000000007}",
+ "targetPort": "sampler"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000003}",
+ "sourcePort": "texCoord",
+ "targetUuid": "{00000000-0000-0000-0000-000000000007}",
+ "targetPort": "coord"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000001}",
+ "sourcePort": "worldPosition",
+ "targetUuid": "{00000000-0000-0000-0000-000000000008}",
+ "targetPort": "position"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000007}",
+ "sourcePort": "color",
+ "targetUuid": "{00000000-0000-0000-0000-000000000008}",
+ "targetPort": "baseColor"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000004}",
+ "sourcePort": "lightIntensity",
+ "targetUuid": "{00000000-0000-0000-0000-000000000008}",
+ "targetPort": "lightIntensity"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000008}",
+ "sourcePort": "outputColor",
+ "targetUuid": "{00000000-0000-0000-0000-000000000009}",
+ "targetPort": "inputColor"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000005}",
+ "sourcePort": "exposure",
+ "targetUuid": "{00000000-0000-0000-0000-000000000009}",
+ "targetPort": "exposure"
+ },
+ {
+ "sourceUuid": "{00000000-0000-0000-0000-000000000009}",
+ "sourcePort": "outputColor",
+ "targetUuid": "{00000000-0000-0000-0000-000000000006}",
+ "targetPort": "fragColor"
+ }
+ ]
+}
diff --git a/tests/auto/render/shaderbuilder/lightmodel.es2.inc b/tests/auto/render/shaderbuilder/lightmodel.es2.inc
new file mode 100644
index 000000000..8e603d9a8
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/lightmodel.es2.inc
@@ -0,0 +1,6 @@
+highp vec4 lightModel(const in highp vec3 baseColor,
+ const in highp vec3 pos,
+ const in highp float intensity)
+{
+ ...
+}
diff --git a/tests/auto/render/shaderbuilder/lightmodel.gl3.inc b/tests/auto/render/shaderbuilder/lightmodel.gl3.inc
new file mode 100644
index 000000000..31615dfcd
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/lightmodel.gl3.inc
@@ -0,0 +1,6 @@
+vec4 lightModel(const in vec3 baseColor,
+ const in vec3 pos,
+ const in float intensity)
+{
+ ...
+}
diff --git a/tests/auto/render/shaderbuilder/output.es2 b/tests/auto/render/shaderbuilder/output.es2
new file mode 100644
index 000000000..b543bc5ee
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/output.es2
@@ -0,0 +1,36 @@
+#version 100
+
+varying highp vec3 worldPosition;
+uniform sampler2D texture;
+varying highp vec2 texCoord;
+uniform highp float lightIntensity;
+uniform highp float exposure;
+highp vec4 lightModel(const in highp vec3 baseColor,
+ const in highp vec3 pos,
+ const in highp float intensity)
+{
+ ...
+}
+
+#line 9
+highp vec4 lightModel(const in highp vec3 baseColor,
+ const in highp vec3 pos,
+ const in highp float intensity)
+{
+ ...
+}
+
+#line 11
+
+void main()
+{
+ highp vec2 v2 = texCoord;
+ sampler2D v1 = texture;
+ highp float v3 = lightIntensity;
+ highp vec4 v5 = texture2D(v1, v2);
+ highp vec3 v0 = worldPosition;
+ highp float v4 = exposure;
+ highp vec4 v6 = lightModel(v5, v0, v3);
+ highp vec4 v7 = v6 * pow(2.0, v4);
+ gl_fragColor = v7;
+}
diff --git a/tests/auto/render/shaderbuilder/output.gl3 b/tests/auto/render/shaderbuilder/output.gl3
new file mode 100644
index 000000000..95a9c53fd
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/output.gl3
@@ -0,0 +1,37 @@
+#version 150 core
+
+in vec3 worldPosition;
+uniform sampler2D texture;
+in vec2 texCoord;
+uniform float lightIntensity;
+uniform float exposure;
+out vec4 fragColor;
+vec4 lightModel(const in vec3 baseColor,
+ const in vec3 pos,
+ const in float intensity)
+{
+ ...
+}
+
+#line 10
+vec4 lightModel(const in vec3 baseColor,
+ const in vec3 pos,
+ const in float intensity)
+{
+ ...
+}
+
+#line 12
+
+void main()
+{
+ vec2 v2 = texCoord;
+ sampler2D v1 = texture;
+ float v3 = lightIntensity;
+ vec4 v5 = texture2D(v1, v2);
+ vec3 v0 = worldPosition;
+ float v4 = exposure;
+ vec4 v6 = lightModel(v5, v0, v3);
+ vec4 v7 = v6 * pow(2.0, v4);
+ fragColor = v7;
+}
diff --git a/tests/auto/render/shaderbuilder/prototypes.json b/tests/auto/render/shaderbuilder/prototypes.json
new file mode 100644
index 000000000..e9bf2e802
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/prototypes.json
@@ -0,0 +1,237 @@
+{
+ "worldPosition": {
+ "outputs": [
+ "worldPosition"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec3 $worldPosition = worldPosition;",
+ "headerSnippets": [ "varying highp vec3 worldPosition;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "vec3 $worldPosition = worldPosition;",
+ "headerSnippets": [ "in vec3 worldPosition;" ]
+ }
+ ]
+ },
+ "texture": {
+ "outputs": [
+ "texture"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "sampler2D $texture = texture;",
+ "headerSnippets": [ "uniform sampler2D texture;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "sampler2D $texture = texture;",
+ "headerSnippets": [ "uniform sampler2D texture;" ]
+ }
+ ]
+ },
+ "texCoord": {
+ "outputs": [
+ "texCoord"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec2 $texCoord = texCoord;",
+ "headerSnippets": [ "varying highp vec2 texCoord;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "vec2 $texCoord = texCoord;",
+ "headerSnippets": [ "in vec2 texCoord;" ]
+ }
+ ]
+ },
+ "lightIntensity": {
+ "outputs": [
+ "lightIntensity"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp float $lightIntensity = lightIntensity;",
+ "headerSnippets": [ "uniform highp float lightIntensity;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "float $lightIntensity = lightIntensity;",
+ "headerSnippets": [ "uniform float lightIntensity;" ]
+ }
+ ]
+ },
+ "exposure": {
+ "outputs": [
+ "exposure"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp float $exposure = exposure;",
+ "headerSnippets": [ "uniform highp float exposure;" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "float $exposure = exposure;",
+ "headerSnippets": [ "uniform float exposure;" ]
+ }
+ ]
+ },
+ "fragColor": {
+ "inputs": [
+ "fragColor"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "gl_fragColor = $fragColor;"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "fragColor = $fragColor;",
+ "headerSnippets": [ "out vec4 fragColor;" ]
+ }
+ ]
+ },
+ "sampleTexture": {
+ "inputs": [
+ "sampler",
+ "coord"
+ ],
+ "outputs": [
+ "color"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec4 $color = texture2D($sampler, $coord);"
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "vec4 $color = texture2D($sampler, $coord);"
+ }
+ ]
+ },
+ "lightModel": {
+ "inputs": [
+ "baseColor",
+ "position",
+ "lightIntensity"
+ ],
+ "outputs": [
+ "outputColor"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
+ "headerSnippets": [ "#pragma include lightmodel.es2.inc" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
+ "headerSnippets": [ "#pragma include lightmodel.gl3.inc" ]
+ }
+ ]
+ },
+ "exposureFunction": {
+ "inputs": [
+ "inputColor",
+ "exposure"
+ ],
+ "outputs": [
+ "outputColor"
+ ],
+ "rules": [
+ {
+ "format": {
+ "api": "OpenGLES",
+ "major": 2,
+ "minor": 0
+ },
+ "substitution": "highp vec4 $outputColor = $inputColor * pow(2.0, $exposure);",
+ "headerSnippets": [ "#pragma include :/lightmodel.es2.inc" ]
+ },
+ {
+ "format": {
+ "api": "OpenGLCoreProfile",
+ "major": 3,
+ "minor": 2
+ },
+ "substitution": "vec4 $outputColor = $inputColor * pow(2.0, $exposure);",
+ "headerSnippets": [ "#pragma include :/lightmodel.gl3.inc" ]
+ }
+ ]
+ }
+}
diff --git a/tests/auto/render/shaderbuilder/shaderbuilder.pro b/tests/auto/render/shaderbuilder/shaderbuilder.pro
new file mode 100644
index 000000000..bd5f7dfe2
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/shaderbuilder.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_shaderbuilder
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += tst_shaderbuilder.cpp
+RESOURCES += shaderbuilder.qrc
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/shaderbuilder/shaderbuilder.qrc b/tests/auto/render/shaderbuilder/shaderbuilder.qrc
new file mode 100644
index 000000000..92ab0405c
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/shaderbuilder.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>prototypes.json</file>
+ <file>input.json</file>
+ <file>output.gl3</file>
+ <file>output.es2</file>
+ <file>lightmodel.gl3.inc</file>
+ <file>lightmodel.es2.inc</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/render/shaderbuilder/tst_shaderbuilder.cpp b/tests/auto/render/shaderbuilder/tst_shaderbuilder.cpp
new file mode 100644
index 000000000..6557acb6c
--- /dev/null
+++ b/tests/auto/render/shaderbuilder/tst_shaderbuilder.cpp
@@ -0,0 +1,548 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <qbackendnodetester.h>
+#include <Qt3DRender/private/shaderbuilder_p.h>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DRender/qshaderprogrambuilder.h>
+#include "testrenderer.h"
+
+Q_DECLARE_METATYPE(Qt3DRender::Render::ShaderBuilder::ShaderType)
+
+class tst_ShaderBuilder : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+private slots:
+ void shouldHaveGlobalDefaultPrototypes()
+ {
+ // GIVEN
+
+ // THEN
+ QCOMPARE(Qt3DRender::Render::ShaderBuilder::getPrototypesFile(), QStringLiteral(":/prototypes/default.json"));
+ QVERIFY(!Qt3DRender::Render::ShaderBuilder::getPrototypeNames().isEmpty());
+
+ // WHEN
+ Qt3DRender::Render::ShaderBuilder::setPrototypesFile(":/prototypes.json");
+
+ // THEN
+ QCOMPARE(Qt3DRender::Render::ShaderBuilder::getPrototypesFile(), QStringLiteral(":/prototypes.json"));
+ auto prototypeNames = Qt3DRender::Render::ShaderBuilder::getPrototypeNames();
+ prototypeNames.sort();
+ const auto expectedPrototypeNames = QStringList() << "exposure"
+ << "exposureFunction"
+ << "fragColor"
+ << "lightIntensity"
+ << "lightModel"
+ << "sampleTexture"
+ << "texCoord"
+ << "texture"
+ << "worldPosition";
+ QCOMPARE(prototypeNames, expectedPrototypeNames);
+ }
+
+ void shouldHaveInitialState()
+ {
+ // GIVEN
+ Qt3DRender::Render::ShaderBuilder shaderBuilder;
+
+ // THEN
+ QVERIFY(!shaderBuilder.isEnabled());
+ QVERIFY(shaderBuilder.enabledLayers().isEmpty());
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ QCOMPARE(shaderBuilder.shaderGraph(type), QUrl());
+ QCOMPARE(shaderBuilder.shaderCode(type), QByteArray());
+ QVERIFY(!shaderBuilder.isShaderCodeDirty(type));
+ }
+ }
+
+ void shouldHavePropertiesMirroringFromItsPeer_data()
+ {
+ QTest::addColumn<Qt3DRender::QShaderProgramBuilder*>("frontend");
+
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ QTest::newRow("empty") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ auto program = new Qt3DRender::QShaderProgram(frontend);
+ frontend->setShaderProgram(program);
+ QTest::newRow("shaderProgram") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setEnabledLayers({"foo", "bar"});
+ QTest::newRow("enabledLayers") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setVertexShaderGraph(QUrl::fromEncoded("qrc:/vertex.json"));
+ QTest::newRow("vertex") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setTessellationControlShaderGraph(QUrl::fromEncoded("qrc:/tesscontrol.json"));
+ QTest::newRow("tessellationControl") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setTessellationEvaluationShaderGraph(QUrl::fromEncoded("qrc:/tesseval.json"));
+ QTest::newRow("tessellationEvaluation") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setGeometryShaderGraph(QUrl::fromEncoded("qrc:/geometry.json"));
+ QTest::newRow("geometry") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setFragmentShaderGraph(QUrl::fromEncoded("qrc:/fragment.json"));
+ QTest::newRow("fragment") << frontend;
+ }
+ {
+ auto frontend = new Qt3DRender::QShaderProgramBuilder;
+ frontend->setComputeShaderGraph(QUrl::fromEncoded("qrc:/compute.json"));
+ QTest::newRow("compute") << frontend;
+ }
+ }
+
+ void shouldHavePropertiesMirroringFromItsPeer()
+ {
+ // GIVEN
+ QFETCH(Qt3DRender::QShaderProgramBuilder*, frontend);
+ Qt3DRender::Render::ShaderBuilder backend;
+
+ // WHEN
+ simulateInitialization(frontend, &backend);
+
+ // THEN
+ QVERIFY(backend.isEnabled() == frontend->isEnabled());
+
+ if (frontend->shaderProgram())
+ QCOMPARE(backend.shaderProgramId(), frontend->shaderProgram()->id());
+ else
+ QVERIFY(backend.shaderProgramId().isNull());
+
+ QCOMPARE(backend.enabledLayers(), frontend->enabledLayers());
+
+ QCOMPARE(backend.shaderGraph(Qt3DRender::Render::ShaderBuilder::Vertex), frontend->vertexShaderGraph());
+ QCOMPARE(backend.shaderCode(Qt3DRender::Render::ShaderBuilder::Vertex), QByteArray());
+ QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::Render::ShaderBuilder::Vertex), !frontend->vertexShaderGraph().isEmpty());
+
+ QCOMPARE(backend.shaderGraph(Qt3DRender::Render::ShaderBuilder::TessellationControl), frontend->tessellationControlShaderGraph());
+ QCOMPARE(backend.shaderCode(Qt3DRender::Render::ShaderBuilder::TessellationControl), QByteArray());
+ QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::Render::ShaderBuilder::TessellationControl), !frontend->tessellationControlShaderGraph().isEmpty());
+
+ QCOMPARE(backend.shaderGraph(Qt3DRender::Render::ShaderBuilder::TessellationEvaluation), frontend->tessellationEvaluationShaderGraph());
+ QCOMPARE(backend.shaderCode(Qt3DRender::Render::ShaderBuilder::TessellationEvaluation), QByteArray());
+ QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::Render::ShaderBuilder::TessellationEvaluation), !frontend->tessellationEvaluationShaderGraph().isEmpty());
+
+ QCOMPARE(backend.shaderGraph(Qt3DRender::Render::ShaderBuilder::Geometry), frontend->geometryShaderGraph());
+ QCOMPARE(backend.shaderCode(Qt3DRender::Render::ShaderBuilder::Geometry), QByteArray());
+ QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::Render::ShaderBuilder::Geometry), !frontend->geometryShaderGraph().isEmpty());
+
+ QCOMPARE(backend.shaderGraph(Qt3DRender::Render::ShaderBuilder::Fragment), frontend->fragmentShaderGraph());
+ QCOMPARE(backend.shaderCode(Qt3DRender::Render::ShaderBuilder::Fragment), QByteArray());
+ QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::Render::ShaderBuilder::Fragment), !frontend->fragmentShaderGraph().isEmpty());
+
+ QCOMPARE(backend.shaderGraph(Qt3DRender::Render::ShaderBuilder::Compute), frontend->computeShaderGraph());
+ QCOMPARE(backend.shaderCode(Qt3DRender::Render::ShaderBuilder::Compute), QByteArray());
+ QCOMPARE(backend.isShaderCodeDirty(Qt3DRender::Render::ShaderBuilder::Compute), !frontend->computeShaderGraph().isEmpty());
+
+ // WHEN
+ backend.cleanup();
+
+ // THEN
+ QVERIFY(!backend.isEnabled());
+ QVERIFY(backend.enabledLayers().isEmpty());
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ QCOMPARE(backend.shaderGraph(type), QUrl());
+ QCOMPARE(backend.shaderCode(type), QByteArray());
+ QVERIFY(!backend.isShaderCodeDirty(type));
+ }
+
+ delete frontend;
+ }
+
+ void shouldHandleEnablePropertyChange()
+ {
+ // GIVEN
+ Qt3DRender::Render::ShaderBuilder backend;
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+
+ // WHEN
+ auto updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(true);
+ updateChange->setPropertyName("enabled");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QVERIFY(backend.isEnabled());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(false);
+ updateChange->setPropertyName("enabled");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QVERIFY(!backend.isEnabled());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(true);
+ updateChange->setPropertyName("enabled");
+ backend.sceneChangeEvent(updateChange);
+ // AND
+ backend.cleanup();
+
+ // THEN
+ QVERIFY(!backend.isEnabled());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ }
+
+ void shouldHandleShaderProgramPropertyChange()
+ {
+ // GIVEN
+ Qt3DRender::Render::ShaderBuilder backend;
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+ const auto programId = Qt3DCore::QNodeId::createId();
+
+ // WHEN
+ auto updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QVariant::fromValue(programId));
+ updateChange->setPropertyName("shaderProgram");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderProgramId(), programId);
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QVariant::fromValue(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("shaderProgram");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QVERIFY(backend.shaderProgramId().isNull());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QVariant::fromValue(programId));
+ updateChange->setPropertyName("shaderProgram");
+ backend.sceneChangeEvent(updateChange);
+ // AND
+ backend.cleanup();
+
+ // THEN
+ QVERIFY(backend.shaderProgramId().isNull());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ }
+
+ void shouldHandleEnabledLayersPropertyChange()
+ {
+ // GIVEN
+ Qt3DRender::Render::ShaderBuilder backend;
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+ const auto layers = QStringList() << "foo" << "bar";
+
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ const auto graphUrl = QUrl::fromEncoded("qrc:/input.json");
+ backend.setShaderGraph(type, graphUrl);
+ }
+
+ // WHEN
+ auto updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(layers);
+ updateChange->setPropertyName("enabledLayers");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.enabledLayers(), layers);
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ QVERIFY(backend.isShaderCodeDirty(type));
+ backend.generateCode(type); // Resets the dirty flag
+ }
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(layers);
+ updateChange->setPropertyName("enabledLayers");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.enabledLayers(), layers);
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ QVERIFY(!backend.isShaderCodeDirty(type));
+ backend.generateCode(type); // Resets the dirty flag
+ }
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QStringList());
+ updateChange->setPropertyName("enabledLayers");
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QVERIFY(backend.shaderProgramId().isNull());
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ QVERIFY(backend.isShaderCodeDirty(type));
+ backend.generateCode(type); // Resets the dirty flag
+ }
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(layers);
+ updateChange->setPropertyName("enabledLayers");
+ backend.sceneChangeEvent(updateChange);
+ // AND
+ backend.cleanup();
+
+ // THEN
+ QVERIFY(backend.enabledLayers().isEmpty());
+ for (int i = 0; i <= Qt3DRender::Render::ShaderBuilder::Compute; i++) {
+ const auto type = static_cast<Qt3DRender::Render::ShaderBuilder::ShaderType>(i);
+ QVERIFY(!backend.isShaderCodeDirty(type));
+ backend.generateCode(type); // Resets the dirty flag
+ }
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ }
+
+ void shouldHandleShaderGraphPropertiesChanges_data()
+ {
+ QTest::addColumn<QByteArray>("property");
+ QTest::addColumn<Qt3DRender::Render::ShaderBuilder::ShaderType>("type");
+ QTest::addColumn<QUrl>("graphUrl");
+
+ QTest::newRow("vertex") << QByteArrayLiteral("vertexShaderGraph")
+ << Qt3DRender::Render::ShaderBuilder::Vertex
+ << QUrl::fromEncoded("qrc:/vertex.json");
+
+ QTest::newRow("tessControl") << QByteArrayLiteral("tessellationControlShaderGraph")
+ << Qt3DRender::Render::ShaderBuilder::TessellationControl
+ << QUrl::fromEncoded("qrc:/tesscontrol.json");
+
+ QTest::newRow("tessEval") << QByteArrayLiteral("tessellationEvaluationShaderGraph")
+ << Qt3DRender::Render::ShaderBuilder::TessellationEvaluation
+ << QUrl::fromEncoded("qrc:/tesseval.json");
+
+ QTest::newRow("geometry") << QByteArrayLiteral("geometryShaderGraph")
+ << Qt3DRender::Render::ShaderBuilder::Geometry
+ << QUrl::fromEncoded("qrc:/geometry.json");
+
+ QTest::newRow("fragment") << QByteArrayLiteral("fragmentShaderGraph")
+ << Qt3DRender::Render::ShaderBuilder::Fragment
+ << QUrl::fromEncoded("qrc:/fragment.json");
+
+ QTest::newRow("compute") << QByteArrayLiteral("computeShaderGraph")
+ << Qt3DRender::Render::ShaderBuilder::Compute
+ << QUrl::fromEncoded("qrc:/compute.json");
+ }
+
+ void shouldHandleShaderGraphPropertiesChanges()
+ {
+ // GIVEN
+ QFETCH(QByteArray, property);
+ QFETCH(Qt3DRender::Render::ShaderBuilder::ShaderType, type);
+ QFETCH(QUrl, graphUrl);
+
+ Qt3DRender::Render::ShaderBuilder backend;
+ TestRenderer renderer;
+ backend.setRenderer(&renderer);
+
+ // WHEN
+ auto updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QUrl());
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), QUrl());
+ QVERIFY(!backend.isShaderCodeDirty(type));
+ QVERIFY(backend.shaderCode(type).isEmpty());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(graphUrl);
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), graphUrl);
+ QVERIFY(backend.isShaderCodeDirty(type));
+ QVERIFY(backend.shaderCode(type).isEmpty());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(QUrl());
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), QUrl());
+ QVERIFY(backend.isShaderCodeDirty(type));
+ QVERIFY(backend.shaderCode(type).isEmpty());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+
+ // WHEN
+ updateChange = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId());
+ updateChange->setValue(graphUrl);
+ updateChange->setPropertyName(property);
+ backend.sceneChangeEvent(updateChange);
+ // AND
+ backend.cleanup();
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), QUrl());
+ QVERIFY(!backend.isShaderCodeDirty(type));
+ QVERIFY(backend.shaderCode(type).isEmpty());
+ QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::ShadersDirty);
+ renderer.resetDirty();
+ }
+
+ void shouldHandleShaderCodeGeneration_data()
+ {
+ QTest::addColumn<Qt3DRender::Render::ShaderBuilder::ShaderType>("type");
+
+ QTest::newRow("vertex") << Qt3DRender::Render::ShaderBuilder::Vertex;
+ QTest::newRow("tessControl") << Qt3DRender::Render::ShaderBuilder::TessellationControl;
+ QTest::newRow("tessEval") << Qt3DRender::Render::ShaderBuilder::TessellationEvaluation;
+ QTest::newRow("geometry") << Qt3DRender::Render::ShaderBuilder::Geometry;
+ QTest::newRow("fragment") << Qt3DRender::Render::ShaderBuilder::Fragment;
+ QTest::newRow("compute") << Qt3DRender::Render::ShaderBuilder::Compute;
+ }
+
+ void shouldHandleShaderCodeGeneration()
+ {
+ // GIVEN
+ Qt3DRender::Render::ShaderBuilder::setPrototypesFile(":/prototypes.json");
+ QVERIFY(!Qt3DRender::Render::ShaderBuilder::getPrototypeNames().isEmpty());
+
+ QFETCH(Qt3DRender::Render::ShaderBuilder::ShaderType, type);
+
+ const auto gl3Api = []{
+ auto api = Qt3DRender::GraphicsApiFilterData();
+ api.m_api = Qt3DRender::QGraphicsApiFilter::OpenGL;
+ api.m_profile = Qt3DRender::QGraphicsApiFilter::CoreProfile;
+ api.m_major = 3;
+ api.m_minor = 2;
+ return api;
+ }();
+
+ const auto es2Api = []{
+ auto api = Qt3DRender::GraphicsApiFilterData();
+ api.m_api = Qt3DRender::QGraphicsApiFilter::OpenGLES;
+ api.m_major = 2;
+ api.m_minor = 0;
+ return api;
+ }();
+
+ const auto readCode = [](const QString &suffix) -> QString {
+ const auto filePath = QStringLiteral(":/output.") + suffix;
+ QFile file(filePath);
+ if (!file.open(QFile::ReadOnly | QFile::Text))
+ qFatal("File open failed: %s", qPrintable(filePath));
+ return file.readAll();
+ };
+
+ const auto gl3Code = readCode("gl3");
+ const auto es2Code = readCode("es2");
+
+ Qt3DRender::Render::ShaderBuilder backend;
+
+ // WHEN
+ const auto graphUrl = QUrl::fromEncoded("qrc:/input.json");
+ backend.setShaderGraph(type, graphUrl);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), graphUrl);
+ QVERIFY(backend.isShaderCodeDirty(type));
+ QVERIFY(backend.shaderCode(type).isEmpty());
+
+ // WHEN
+ backend.setGraphicsApi(gl3Api);
+ backend.generateCode(type);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), graphUrl);
+ QVERIFY(!backend.isShaderCodeDirty(type));
+ QCOMPARE(backend.shaderCode(type), gl3Code);
+
+ // WHEN
+ backend.setGraphicsApi(es2Api);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), graphUrl);
+ QVERIFY(backend.isShaderCodeDirty(type));
+ QCOMPARE(backend.shaderCode(type), gl3Code);
+
+ // WHEN
+ backend.generateCode(type);
+
+ // THEN
+ QCOMPARE(backend.shaderGraph(type), graphUrl);
+ QVERIFY(!backend.isShaderCodeDirty(type));
+// QCOMPARE(backend.shaderCode(type), es2Code);
+ }
+};
+
+QTEST_MAIN(tst_ShaderBuilder)
+
+#include "tst_shaderbuilder.moc"
diff --git a/tests/auto/render/skeleton/skeleton.pro b/tests/auto/render/skeleton/skeleton.pro
new file mode 100644
index 000000000..8dbd1b3df
--- /dev/null
+++ b/tests/auto/render/skeleton/skeleton.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+
+TARGET = tst_skeleton
+
+QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib
+
+CONFIG += testcase
+
+SOURCES += \
+ tst_skeleton.cpp
+
+include(../../core/common/common.pri)
+include(../commons/commons.pri)
diff --git a/tests/auto/render/skeleton/tst_skeleton.cpp b/tests/auto/render/skeleton/tst_skeleton.cpp
new file mode 100644
index 000000000..499bb7cc7
--- /dev/null
+++ b/tests/auto/render/skeleton/tst_skeleton.cpp
@@ -0,0 +1,405 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QTest>
+#include <Qt3DRender/private/skeleton_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DCore/qjoint.h>
+#include <Qt3DCore/qskeleton.h>
+#include <Qt3DCore/qskeletonloader.h>
+#include <Qt3DCore/private/qnode_p.h>
+#include <Qt3DCore/private/qscene_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+#include <Qt3DCore/private/qbackendnode_p.h>
+#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
+#include <qbackendnodetester.h>
+#include <testpostmanarbiter.h>
+#include <testrenderer.h>
+
+using namespace Qt3DCore;
+using namespace Qt3DRender;
+using namespace Qt3DRender::Render;
+
+Q_DECLARE_METATYPE(Qt3DRender::Render::JointInfo)
+Q_DECLARE_METATYPE(Qt3DRender::Render::SkeletonData)
+Q_DECLARE_METATYPE(Qt3DCore::Sqt)
+
+namespace {
+
+void linearizeTreeHelper(QJoint *joint, QVector<QJoint *> &joints)
+{
+ joints.push_back(joint);
+ for (const auto child : joint->childJoints())
+ linearizeTreeHelper(child, joints);
+}
+
+QVector<QJoint *> linearizeTree(QJoint *rootJoint)
+{
+ QVector<QJoint *> joints;
+ linearizeTreeHelper(rootJoint, joints);
+ return joints;
+}
+
+}
+
+class tst_Skeleton : public Qt3DCore::QBackendNodeTester
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void checkPeerPropertyMirroring()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ Skeleton backendSkeleton;
+ backendSkeleton.setRenderer(&renderer);
+ backendSkeleton.setSkeletonManager(nodeManagers.skeletonManager());
+ QSkeletonLoader skeleton;
+
+ skeleton.setSource(QUrl::fromLocalFile("funnybones.json"));
+
+ // WHEN
+ simulateInitialization(&skeleton, &backendSkeleton);
+
+ // THEN
+ QCOMPARE(backendSkeleton.peerId(), skeleton.id());
+ QCOMPARE(backendSkeleton.isEnabled(), skeleton.isEnabled());
+ QCOMPARE(backendSkeleton.source(), skeleton.source());
+ QCOMPARE(backendSkeleton.rootJointId(), QNodeId());
+
+ // GIVEN
+ Skeleton backendSkeleton2;
+ backendSkeleton2.setRenderer(&renderer);
+ backendSkeleton2.setSkeletonManager(nodeManagers.skeletonManager());
+ QSkeleton skeleton2;
+
+ QJoint *joint = new QJoint();
+ skeleton2.setRootJoint(joint);
+
+ // WHEN
+ simulateInitialization(&skeleton2, &backendSkeleton2);
+
+ // THEN
+ QCOMPARE(backendSkeleton2.peerId(), skeleton2.id());
+ QCOMPARE(backendSkeleton2.isEnabled(), skeleton2.isEnabled());
+ QCOMPARE(backendSkeleton2.source(), QUrl());
+ QCOMPARE(backendSkeleton2.rootJointId(), joint->id());
+ }
+
+ void checkInitialAndCleanedUpState()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ Skeleton backendSkeleton;
+ backendSkeleton.setRenderer(&renderer);
+ backendSkeleton.setSkeletonManager(nodeManagers.skeletonManager());
+
+ // THEN
+ QVERIFY(backendSkeleton.peerId().isNull());
+ QCOMPARE(backendSkeleton.isEnabled(), false);
+ QCOMPARE(backendSkeleton.source(), QUrl());
+ QCOMPARE(backendSkeleton.status(), QSkeletonLoader::NotReady);
+ QCOMPARE(backendSkeleton.rootJointId(), QNodeId());
+
+ // GIVEN
+ QSkeletonLoader skeleton;
+ skeleton.setSource(QUrl::fromLocalFile("skeleton1.json"));
+
+ // WHEN
+ simulateInitialization(&skeleton, &backendSkeleton);
+ backendSkeleton.cleanup();
+
+ // THEN
+ QCOMPARE(backendSkeleton.source(), QUrl());
+ QCOMPARE(backendSkeleton.isEnabled(), false);
+ QCOMPARE(backendSkeleton.status(), QSkeletonLoader::NotReady);
+ QCOMPARE(backendSkeleton.rootJointId(), QNodeId());
+ }
+
+ void checkPropertyChanges()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ Skeleton backendSkeleton;
+ backendSkeleton.setRenderer(&renderer);
+ backendSkeleton.setSkeletonManager(nodeManagers.skeletonManager());
+ backendSkeleton.setDataType(Skeleton::File);
+ Qt3DCore::QPropertyUpdatedChangePtr updateChange;
+
+ // Initialize to ensure skeleton manager is set
+ QSkeletonLoader skeleton;
+ skeleton.setSource(QUrl::fromLocalFile("skeleton1.json"));
+ simulateInitialization(&skeleton, &backendSkeleton);
+
+ // WHEN
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("enabled");
+ updateChange->setValue(true);
+ backendSkeleton.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendSkeleton.isEnabled(), true);
+
+ // WHEN
+ const QUrl newSource = QUrl::fromLocalFile("terminator.json");
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("source");
+ updateChange->setValue(newSource);
+ backendSkeleton.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendSkeleton.source(), newSource);
+
+ // WHEN
+ const QNodeId newRootJointId = QNodeId::createId();
+ updateChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId()));
+ updateChange->setPropertyName("rootJoint");
+ updateChange->setValue(QVariant::fromValue(newRootJointId));
+ backendSkeleton.sceneChangeEvent(updateChange);
+
+ // THEN
+ QCOMPARE(backendSkeleton.rootJointId(), newRootJointId);
+ }
+
+ void checkStatusPropertyBackendNotification()
+ {
+ // GIVEN
+ TestRenderer renderer;
+ NodeManagers nodeManagers;
+ renderer.setNodeManagers(&nodeManagers);
+ TestArbiter arbiter;
+ Skeleton backendSkeleton;
+ backendSkeleton.setRenderer(&renderer);
+ backendSkeleton.setSkeletonManager(nodeManagers.skeletonManager());
+ backendSkeleton.setEnabled(true);
+ Qt3DCore::QBackendNodePrivate::get(&backendSkeleton)->setArbiter(&arbiter);
+
+ // WHEN
+ backendSkeleton.setStatus(QSkeletonLoader::Error);
+
+ // THEN
+ QCOMPARE(backendSkeleton.status(), QSkeletonLoader::Error);
+ QCOMPARE(arbiter.events.count(), 1);
+ Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "status");
+ QCOMPARE(change->value().value<QSkeletonLoader::Status>(), backendSkeleton.status());
+ QCOMPARE(Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(change.data())->m_isIntermediate,
+ false);
+
+ arbiter.events.clear();
+
+ // WHEN
+ backendSkeleton.setStatus(QSkeletonLoader::Error);
+
+ // THEN
+ QCOMPARE(backendSkeleton.status(), QSkeletonLoader::Error);
+ QCOMPARE(arbiter.events.count(), 0);
+
+ arbiter.events.clear();
+ }
+
+ void checkCreateFrontendJoint_data()
+ {
+ QTest::addColumn<QMatrix4x4>("inverseBindMatrix");
+ QTest::addColumn<Qt3DCore::Sqt>("localPose");
+ QTest::addColumn<QString>("jointName");
+ QTest::addColumn<QJoint *>("expectedJoint");
+
+ QMatrix4x4 m;
+ Qt3DCore::Sqt localPose;
+ QTest::newRow("default") << m << localPose << QString() << new QJoint();
+
+ const QVector3D t(1.0f, 2.0f, 3.0f);
+ const QQuaternion r = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, 45.0f);
+ const QVector3D s(1.5f, 2.5f, 3.5f);
+ localPose.scale = s;
+ localPose.rotation = r;
+ localPose.translation = t;
+
+
+ QString name = QLatin1String("Foo");
+ QJoint *joint = new QJoint();
+ joint->setTranslation(t);
+ joint->setRotation(r);
+ joint->setScale(s);
+ joint->setName(name);
+ joint->setInverseBindMatrix(m);
+ QTest::newRow("localPose") << m << localPose << name << joint;
+
+ m.rotate(r);
+ m.scale(QVector3D(1.0f, 1.0f, 1.0f) / s);
+ m.translate(-t);
+ name = QLatin1String("Bar");
+
+ joint = new QJoint();
+ joint->setTranslation(t);
+ joint->setRotation(r);
+ joint->setScale(s);
+ joint->setInverseBindMatrix(m);
+ joint->setName(name);
+ QTest::newRow("inverseBind") << m << localPose << name << joint;
+ }
+
+ void checkCreateFrontendJoint()
+ {
+ // GIVEN
+ Skeleton backendSkeleton;
+ QFETCH(QMatrix4x4, inverseBindMatrix);
+ QFETCH(Qt3DCore::Sqt, localPose);
+ QFETCH(QString, jointName);
+ QFETCH(QJoint *, expectedJoint);
+
+ // WHEN
+ const QJoint *actualJoint = backendSkeleton.createFrontendJoint(jointName, localPose, inverseBindMatrix);
+
+ // THEN
+ QCOMPARE(actualJoint->scale(), expectedJoint->scale());
+ QCOMPARE(actualJoint->rotation(), expectedJoint->rotation());
+ QCOMPARE(actualJoint->translation(), expectedJoint->translation());
+ QCOMPARE(actualJoint->inverseBindMatrix(), expectedJoint->inverseBindMatrix());
+ QCOMPARE(actualJoint->name(), expectedJoint->name());
+
+ // Cleanup
+ delete actualJoint;
+ delete expectedJoint;
+ }
+
+ void checkCreateFrontendJoints_data()
+ {
+ QTest::addColumn<SkeletonData>("skeletonData");
+ QTest::addColumn<QJoint *>("expectedRootJoint");
+
+ QTest::newRow("empty") << SkeletonData() << (QJoint*)nullptr;
+
+ SkeletonData skeletonData;
+ JointInfo rootJointInfo;
+ skeletonData.joints.push_back(rootJointInfo);
+ skeletonData.jointNames.push_back(QLatin1String("rootJoint"));
+ skeletonData.localPoses.push_back(Qt3DCore::Sqt());
+ const int childCount = 10;
+ for (int i = 0; i < childCount; ++i) {
+ JointInfo childJointInfo;
+ childJointInfo.parentIndex = 0;
+ skeletonData.joints.push_back(childJointInfo);
+
+ const float x = static_cast<float>(i);
+ Qt3DCore::Sqt localPose;
+ localPose.translation = QVector3D(x, x, x);
+ skeletonData.localPoses.push_back(localPose);
+
+ skeletonData.jointNames.push_back(QString("Child-%1").arg(i));
+ }
+
+ QJoint *rootJoint = new QJoint();
+ for (int i = 0; i < childCount; ++i) {
+ QJoint *childJoint = new QJoint();
+ const float x = static_cast<float>(i);
+ childJoint->setTranslation(QVector3D(x, x, x));
+ rootJoint->addChildJoint(childJoint);
+ }
+
+ QTest::newRow("wide") << skeletonData << rootJoint;
+
+ skeletonData.joints.clear();
+ skeletonData.joints.push_back(rootJointInfo);
+ for (int i = 0; i < childCount; ++i) {
+ JointInfo childJointInfo;
+ childJointInfo.parentIndex = i;
+ skeletonData.joints.push_back(childJointInfo);
+
+ const float x = static_cast<float>(i);
+ Qt3DCore::Sqt localPose;
+ localPose.translation = QVector3D(x, x, x);
+ skeletonData.localPoses.push_back(localPose);
+
+ skeletonData.jointNames.push_back(QString("Child-%1").arg(i));
+ }
+
+ rootJoint = new QJoint();
+ QJoint *previousJoint = rootJoint;
+ for (int i = 0; i < childCount; ++i) {
+ QJoint *childJoint = new QJoint();
+ const float x = static_cast<float>(i);
+ childJoint->setTranslation(QVector3D(x, x, x));
+ previousJoint->addChildJoint(childJoint);
+ previousJoint = childJoint;
+ }
+
+ QTest::newRow("deep") << skeletonData << rootJoint;
+ }
+
+ void checkCreateFrontendJoints()
+ {
+ // GIVEN
+ Skeleton backendSkeleton;
+ QFETCH(SkeletonData, skeletonData);
+ QFETCH(QJoint *, expectedRootJoint);
+
+ // WHEN
+ QJoint *actualRootJoint = backendSkeleton.createFrontendJoints(skeletonData);
+
+ // THEN
+ if (skeletonData.joints.isEmpty()) {
+ QVERIFY(actualRootJoint == expectedRootJoint); // nullptr
+ return;
+ }
+
+ // Linearise the tree of joints and check them against the skeletonData
+ QVector<QJoint *> joints = linearizeTree(actualRootJoint);
+ QCOMPARE(joints.size(), skeletonData.joints.size());
+ for (int i = 0; i < joints.size(); ++i) {
+ // Check the translations match
+ QCOMPARE(joints[i]->translation(), skeletonData.localPoses[i].translation);
+ }
+
+ // Now we know the order of Joints match. Check the parents match too
+ for (int i = 0; i < joints.size(); ++i) {
+ // Get parent index from joint info
+ const int parentIndex = skeletonData.joints[i].parentIndex;
+ if (parentIndex == -1) {
+ QVERIFY(joints[i]->parent() == nullptr);
+ } else {
+ QCOMPARE(joints[i]->parent(), joints[parentIndex]);
+ }
+ }
+
+ // Cleanup
+ delete actualRootJoint;
+ delete expectedRootJoint;
+ }
+};
+
+QTEST_APPLESS_MAIN(tst_Skeleton)
+
+#include "tst_skeleton.moc"
diff --git a/tests/auto/render/texture/tst_texture.cpp b/tests/auto/render/texture/tst_texture.cpp
index 9a84714a6..784186690 100644
--- a/tests/auto/render/texture/tst_texture.cpp
+++ b/tests/auto/render/texture/tst_texture.cpp
@@ -223,6 +223,8 @@ void tst_RenderTexture::checkPropertyChanges()
// THEN
QCOMPARE(backend.properties().width, 256);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
// WHEN
updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
@@ -232,6 +234,8 @@ void tst_RenderTexture::checkPropertyChanges()
// THEN
QCOMPARE(backend.properties().height, 128);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
// WHEN
updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
@@ -241,6 +245,8 @@ void tst_RenderTexture::checkPropertyChanges()
// THEN
QCOMPARE(backend.properties().depth, 16);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
// WHEN
updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
@@ -250,6 +256,8 @@ void tst_RenderTexture::checkPropertyChanges()
// THEN
QCOMPARE(backend.properties().layers, 32);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
// WHEN
updateChange = QSharedPointer<Qt3DCore::QPropertyUpdatedChange>::create(Qt3DCore::QNodeId());
@@ -259,6 +267,8 @@ void tst_RenderTexture::checkPropertyChanges()
// THEN
QCOMPARE(backend.properties().samples, 64);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TexturesDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
}
QTEST_APPLESS_MAIN(tst_RenderTexture)
diff --git a/tests/auto/render/transform/tst_transform.cpp b/tests/auto/render/transform/tst_transform.cpp
index 26916b2ab..ebb27953d 100644
--- a/tests/auto/render/transform/tst_transform.cpp
+++ b/tests/auto/render/transform/tst_transform.cpp
@@ -127,6 +127,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendTransform.isEnabled(), newValue);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TransformDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
}
{
// WHEN
@@ -138,6 +140,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendTransform.rotation(), newValue);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TransformDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
}
{
// WHEN
@@ -149,6 +153,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendTransform.scale(), newValue);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TransformDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
}
{
// WHEN
@@ -160,6 +166,8 @@ private Q_SLOTS:
// THEN
QCOMPARE(backendTransform.translation(), newValue);
+ QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TransformDirty);
+ renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty);
}
}
diff --git a/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp b/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp
index 1e76751cc..9b6481423 100644
--- a/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp
+++ b/tests/auto/render/trianglevisitor/tst_trianglevisitor.cpp
@@ -191,8 +191,8 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*4);
positionAttribute->setByteOffset(0);
@@ -291,15 +291,15 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*sizeof(float));
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
indexAttribute->setBuffer(indexDataBuffer.data());
- indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setCount(3*5);
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
@@ -378,8 +378,8 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*4);
positionAttribute->setByteOffset(0);
@@ -477,15 +477,15 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*sizeof(float));
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
indexAttribute->setBuffer(indexDataBuffer.data());
- indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setCount(3*4);
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
@@ -567,8 +567,8 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*4);
positionAttribute->setByteOffset(0);
@@ -660,15 +660,15 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*sizeof(float));
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
indexAttribute->setBuffer(indexDataBuffer.data());
- indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setCount(3*2);
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
@@ -746,8 +746,8 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*4);
positionAttribute->setByteOffset(0);
@@ -843,15 +843,15 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*sizeof(float));
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
indexAttribute->setBuffer(indexDataBuffer.data());
- indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setCount(3*4);
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
@@ -940,8 +940,8 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(8);
positionAttribute->setByteStride(3*4);
positionAttribute->setByteOffset(0);
@@ -1034,15 +1034,15 @@ private Q_SLOTS:
positionAttribute->setBuffer(dataBuffer.data());
positionAttribute->setName(Qt3DRender::QAttribute::defaultPositionAttributeName());
- positionAttribute->setDataType(Qt3DRender::QAttribute::Float);
- positionAttribute->setDataSize(3);
+ positionAttribute->setVertexBaseType(Qt3DRender::QAttribute::Float);
+ positionAttribute->setVertexSize(3);
positionAttribute->setCount(6);
positionAttribute->setByteStride(3*sizeof(float));
positionAttribute->setByteOffset(0);
positionAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute);
indexAttribute->setBuffer(indexDataBuffer.data());
- indexAttribute->setDataType(Qt3DRender::QAttribute::UnsignedInt);
+ indexAttribute->setVertexBaseType(Qt3DRender::QAttribute::UnsignedInt);
indexAttribute->setCount(8);
indexAttribute->setAttributeType(Qt3DRender::QAttribute::IndexAttribute);
diff --git a/tests/auto/render/uniform/tst_uniform.cpp b/tests/auto/render/uniform/tst_uniform.cpp
index 47e64eafe..b8578b294 100644
--- a/tests/auto/render/uniform/tst_uniform.cpp
+++ b/tests/auto/render/uniform/tst_uniform.cpp
@@ -123,6 +123,26 @@ private Q_SLOTS:
QCOMPARE(v.constData<float>()[2], 1340.0f);
QCOMPARE(v.constData<float>()[3], 1603.0f);
}
+ {
+ // GIVEN
+ const QMatrix4x4 m1;
+ QMatrix4x4 m2;
+ m2.rotate(90.0f, 1.0f, 0.0f, 0.0f);
+ QMatrix4x4 m3;
+ m3.scale(2.5f);
+ QMatrix4x4 m4;
+ m4.translate(1.0f, 2.0f, 3.0f);
+
+ const QVector<QMatrix4x4> matrices = (QVector<QMatrix4x4>() << m1 << m2 << m3 << m4);
+ UniformValue v(matrices);
+
+ // THEN
+ for (int j = 0; j < matrices.size(); ++j) {
+ for (int i = 0; i < 16; ++i) {
+ QCOMPARE(v.constData<float>()[16 * j + i], matrices[j].constData()[i]);
+ }
+ }
+ }
}
void checkFromVariant()
@@ -345,6 +365,51 @@ private Q_SLOTS:
QVERIFY(!(v1 == v2));
QVERIFY(v1 != v2);
}
+
+ void checkSetData()
+ {
+ // GIVEN
+ const QMatrix4x4 m1;
+ QMatrix4x4 m2;
+ m2.rotate(90.0f, 1.0f, 0.0f, 0.0f);
+ QMatrix4x4 m3;
+ m3.scale(2.5f);
+ QMatrix4x4 m4;
+ m4.translate(1.0f, 2.0f, 3.0f);
+
+ const QVector<QMatrix4x4> matrices1 = (QVector<QMatrix4x4>() << m1 << m2 << m3 << m4);
+ UniformValue v(matrices1);
+
+ // WHEN
+ const QVector<QMatrix4x4> matrices2 = (QVector<QMatrix4x4>() << m4 << m3 << m2 << m1 << m4);
+ v.setData(matrices2);
+
+ // THEN
+ for (int j = 0; j < matrices2.size(); ++j) {
+ for (int i = 0; i < 16; ++i) {
+ QCOMPARE(v.constData<float>()[16 * j + i], matrices2[j].constData()[i]);
+ }
+ }
+
+ // GIVEN
+ const int positionCount = 10;
+ QVector<QVector3D> positions(positionCount);
+ for (int i = 0; i < positionCount; ++i) {
+ const QVector3D p(float(i), 10.0f * i, 100.0f * i);
+ positions[i] = p;
+ }
+
+ UniformValue positionsUniform;
+
+ // WHEN
+ positionsUniform.setData(positions);
+
+ // THEN
+ const QVector3D *data = positionsUniform.constData<QVector3D>();
+ for (int i = 0; i < positionCount; ++i) {
+ QCOMPARE(*(data + i), positions[i]);
+ }
+ }
};
diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro
index bcaf713c6..7dfc52eec 100644
--- a/tests/benchmarks/benchmarks.pro
+++ b/tests/benchmarks/benchmarks.pro
@@ -1,4 +1,7 @@
TEMPLATE = subdirs
SUBDIRS = \
- core \
- render
+ core
+
+QT_FOR_CONFIG += 3dcore
+
+qtConfig(qt3d-render): SUBDIRS += render
diff --git a/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp b/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp
index 78f264349..2f88043a4 100644
--- a/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp
+++ b/tests/benchmarks/render/layerfiltering/tst_bench_layerfiltering.cpp
@@ -26,7 +26,7 @@
**
****************************************************************************/
-#include <QtTest/QTest>
+#include <QtTest/QtTest>
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/private/qnodecreatedchangegenerator_p.h>
#include <Qt3DCore/private/qaspectjobmanager_p.h>
@@ -38,6 +38,7 @@
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <Qt3DRender/private/filterlayerentityjob_p.h>
#include <Qt3DRender/qlayer.h>
+#include <Qt3DRender/qlayerfilter.h>
QT_BEGIN_NAMESPACE
@@ -85,26 +86,28 @@ namespace {
Qt3DCore::QEntity *buildTestScene(int layersCount,
int entityCount,
- QVector<Qt3DCore::QNodeId> &layerIds,
+ QVector<Qt3DCore::QNodeId> &layerFilterIds,
bool alwaysEnabled = true)
{
Qt3DCore::QEntity *root = new Qt3DCore::QEntity();
+ Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(root);
+ layerFilterIds.push_back(layerFilter->id());
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());
+ layerFilter->addLayer(layer);
}
for (int i = 0; i < entityCount; ++i) {
Qt3DCore::QEntity *entity = new Qt3DCore::QEntity(root);
if (layersCount > 0)
- entity->addComponent(layers.at(qrand() % layersCount));
+ entity->addComponent(layers.at(QRandomGenerator::global()->bounded(layersCount)));
if (!alwaysEnabled && i % 128 == 0)
entity->setEnabled(false);
@@ -123,43 +126,38 @@ private Q_SLOTS:
void filterEntities_data()
{
QTest::addColumn<Qt3DCore::QEntity *>("entitySubtree");
- QTest::addColumn<Qt3DCore::QNodeIdVector>("layerIds");
- QTest::addColumn<bool>("hasLayerFilter");
+ QTest::addColumn<Qt3DCore::QNodeIdVector>("layerFilterIds");
{
- Qt3DCore::QNodeIdVector layerIds;
- Qt3DCore::QEntity *rootEntity = buildTestScene(0, 5000, layerIds);
+ Qt3DCore::QNodeIdVector layerFilterIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(0, 5000, layerFilterIds);
QTest::newRow("Filter-NoLayerFilterAllEnabled") << rootEntity
- << layerIds
- << (layerIds.size() != 0);
+ << layerFilterIds;
}
{
- Qt3DCore::QNodeIdVector layerIds;
- Qt3DCore::QEntity *rootEntity = buildTestScene(0, 5000, layerIds, false);
+ Qt3DCore::QNodeIdVector layerFilterIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(0, 5000, layerFilterIds, false);
QTest::newRow("Filter-NoLayerFilterSomeDisabled") << rootEntity
- << layerIds
- << (layerIds.size() != 0);
+ << layerFilterIds;
}
{
- Qt3DCore::QNodeIdVector layerIds;
- Qt3DCore::QEntity *rootEntity = buildTestScene(10, 5000, layerIds);
+ Qt3DCore::QNodeIdVector layerFilterIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(10, 5000, layerFilterIds);
QTest::newRow("FilterLayerFilterAllEnabled") << rootEntity
- << layerIds
- << (layerIds.size() != 0);
+ << layerFilterIds;
}
{
- Qt3DCore::QNodeIdVector layerIds;
- Qt3DCore::QEntity *rootEntity = buildTestScene(10, 5000, layerIds, false);
+ Qt3DCore::QNodeIdVector layerFilterIds;
+ Qt3DCore::QEntity *rootEntity = buildTestScene(10, 5000, layerFilterIds, false);
QTest::newRow("FilterLayerFilterSomeDisabled") << rootEntity
- << layerIds
- << (layerIds.size() != 0);
+ << layerFilterIds;
}
}
@@ -167,16 +165,14 @@ private Q_SLOTS:
void filterEntities()
{
QFETCH(Qt3DCore::QEntity *, entitySubtree);
- QFETCH(Qt3DCore::QNodeIdVector, layerIds);
- QFETCH(bool, hasLayerFilter);
+ QFETCH(Qt3DCore::QNodeIdVector, layerFilterIds);
// GIVEN
QScopedPointer<Qt3DRender::TestAspect> aspect(new Qt3DRender::TestAspect(entitySubtree));
// WHEN
Qt3DRender::Render::FilterLayerEntityJob filterJob;
- filterJob.setHasLayerFilter(hasLayerFilter);
- filterJob.setLayers(layerIds);
+ filterJob.setLayerFilters(layerFilterIds);
filterJob.setManager(aspect->nodeManagers());
QBENCHMARK {
diff --git a/tests/manual/animation-keyframe-blendtree/main.qml b/tests/manual/animation-keyframe-blendtree/main.qml
index 23aba4b79..3d7fa47e5 100644
--- a/tests/manual/animation-keyframe-blendtree/main.qml
+++ b/tests/manual/animation-keyframe-blendtree/main.qml
@@ -75,16 +75,36 @@ DefaultSceneEntity {
shininess: 50
},
ObjectPicker {
- onClicked: blendedAnimator.running = true
+ onClicked: {
+ if (blendedAnimator.running == false) {
+ blendedAnimator.running = true;
+ } else {
+ switch (pick.button) {
+ case PickEvent.RightButton:
+ animatorClock.playbackRate *= 2.0;
+ break;
+ case PickEvent.LeftButton:
+ animatorClock.playbackRate /= 2.0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
},
BlendedClipAnimator {
id: blendedAnimator
- loops: 2
+ loops: 3
+
+ clock: Clock {
+ id: animatorClock
+ playbackRate: 0.5
+ }
onRunningChanged: console.log("running = " + running)
blendTree: LerpClipBlend {
- blendFactor: 0.2
+ blendFactor: 0.8
startClip: ClipBlendValue {
clip: AnimationClipLoader { source: "sliding-cube.json" }
}
diff --git a/tests/manual/animation-keyframe-simple/main.qml b/tests/manual/animation-keyframe-simple/main.qml
index 79fb75fbd..9246f2467 100644
--- a/tests/manual/animation-keyframe-simple/main.qml
+++ b/tests/manual/animation-keyframe-simple/main.qml
@@ -75,13 +75,33 @@ DefaultSceneEntity {
shininess: 50
},
ObjectPicker {
- onClicked: animator.running = true
+ onClicked: {
+ if (animator.running == false) {
+ animator.running = true;
+ } else {
+ switch (pick.button) {
+ case PickEvent.RightButton:
+ animationClock.playbackRate *= 2.0;
+ break;
+ case PickEvent.LeftButton:
+ animationClock.playbackRate /= 2.0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
},
ClipAnimator {
id: animator
loops: 3
onRunningChanged: console.log("running = " + running)
+ clock: Clock {
+ id: animationClock
+ playbackRate: 1
+ }
+
clip: AnimationClipLoader {
source: "cubeanimation.json"
onDurationChanged: console.log("duration = " + duration)
diff --git a/tests/manual/bigscene-instanced-qml/instanced.vert b/tests/manual/bigscene-instanced-qml/instanced.vert
index f713957e3..141cf9927 100644
--- a/tests/manual/bigscene-instanced-qml/instanced.vert
+++ b/tests/manual/bigscene-instanced-qml/instanced.vert
@@ -1,6 +1,6 @@
#version 150 core
-#define M_PI 3.14159
+#define M_PI 3.14159265358979323846
in vec3 vertexPosition;
in vec3 vertexNormal;
diff --git a/tests/manual/blitframebuffer-qml/blitframebuffer-qml.pro b/tests/manual/blitframebuffer-qml/blitframebuffer-qml.pro
new file mode 100644
index 000000000..c115cbeaf
--- /dev/null
+++ b/tests/manual/blitframebuffer-qml/blitframebuffer-qml.pro
@@ -0,0 +1,14 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick 3dlogic qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ blitframebuffer-qml.qrc
diff --git a/tests/manual/blitframebuffer-qml/blitframebuffer-qml.qrc b/tests/manual/blitframebuffer-qml/blitframebuffer-qml.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/blitframebuffer-qml/blitframebuffer-qml.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/blitframebuffer-qml/main.cpp b/tests/manual/blitframebuffer-qml/main.cpp
new file mode 100644
index 000000000..3d85df6eb
--- /dev/null
+++ b/tests/manual/blitframebuffer-qml/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc, argv);
+ Qt3DExtras::Quick::Qt3DQuickWindow view;
+
+
+ QSurfaceFormat format;
+ format.setVersion(4, 3);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ format.setDepthBufferSize(24);
+ format.setSamples(1);
+ format.setStencilBufferSize(8);
+ view.setFormat(format);
+
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/blitframebuffer-qml/main.qml b/tests/manual/blitframebuffer-qml/main.qml
new file mode 100644
index 000000000..4b3c1915b
--- /dev/null
+++ b/tests/manual/blitframebuffer-qml/main.qml
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.10
+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 )
+ }
+
+ RenderTarget {
+ id: intermediateRenderTarget
+ attachments : [
+ RenderTargetOutput {
+ objectName : "color"
+ attachmentPoint : RenderTargetOutput.Color0
+ texture : Texture2D {
+ id : colorAttachment0
+ width : 1024
+ height : 768
+ format : Texture.R32F
+ generateMipMaps : false
+ magnificationFilter : Texture.Linear
+ minificationFilter : Texture.Linear
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ }
+ },
+ RenderTargetOutput {
+ objectName : "color"
+ attachmentPoint : RenderTargetOutput.Color1
+ texture : Texture2D {
+ id : colorAttachment1
+ width : 1024
+ height : 1024
+ format : Texture.R32F
+ generateMipMaps : false
+ magnificationFilter : Texture.Linear
+ minificationFilter : Texture.Linear
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ }
+ }
+ ]
+ }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: RenderSurfaceSelector {
+ Viewport {
+ RenderTargetSelector {
+ target: intermediateRenderTarget
+ NoDraw {}
+ }
+
+ RenderTargetSelector {
+ target: RenderTarget {
+ id: renderTarget
+ attachments : [
+ RenderTargetOutput {
+ objectName : "color"
+ attachmentPoint : RenderTargetOutput.Color0
+ texture : Texture2D {
+ id : colorAttachment
+ width : 1024
+ height : 768
+ format : Texture.RGBA32F
+ generateMipMaps : false
+ magnificationFilter : Texture.Linear
+ minificationFilter : Texture.Linear
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ }
+ },
+ RenderTargetOutput {
+ objectName : "depth"
+ attachmentPoint : RenderTargetOutput.Depth
+ texture : Texture2D {
+ id : depthAttachment
+ width : 1024
+ height : 1024
+ format : Texture.D32F
+ generateMipMaps : false
+ magnificationFilter : Texture.Linear
+ minificationFilter : Texture.Linear
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ }
+ }
+ ]
+ }
+ ClearBuffers {
+ clearColor: "white"
+ buffers: ClearBuffers.ColorDepthBuffer
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+
+ NoDraw{
+
+ BlitFramebuffer {
+ source: renderTarget
+ destination: intermediateRenderTarget
+ sourceRect: Qt.rect(0,0,1024,768)
+ destinationRect: Qt.rect(0,0,1024,1024)
+ sourceAttachmentPoint: RenderTargetOutput.Color0
+ destinationAttachmentPoint: RenderTargetOutput.Color0
+ interpolationMethod: BlitFramebuffer.Linear
+ }
+
+ BlitFramebuffer {
+ source: intermediateRenderTarget
+ sourceRect: Qt.rect(0,0,1024,1024)
+ destinationRect: Qt.rect(0,0,512,384)
+ sourceAttachmentPoint: RenderTargetOutput.Color0
+ interpolationMethod: BlitFramebuffer.Linear
+ }
+
+ BlitFramebuffer {
+ source: renderTarget
+ sourceRect: Qt.rect(0,0,1024,768)
+ destinationRect: Qt.rect(0,384,512,384)
+ sourceAttachmentPoint: RenderTargetOutput.Color0
+ interpolationMethod: BlitFramebuffer.Linear
+ }
+
+ BlitFramebuffer {
+ source: renderTarget
+ sourceRect: Qt.rect(128,200,256,256)
+ destinationRect: Qt.rect(512,384,512,384)
+ sourceAttachmentPoint: RenderTargetOutput.Color0
+ interpolationMethod: BlitFramebuffer.Linear
+ }
+
+ BlitFramebuffer {
+ source: renderTarget
+ sourceRect: Qt.rect(128,200,256,256)
+ destinationRect: Qt.rect(512,0,512,384)
+ sourceAttachmentPoint: RenderTargetOutput.Color0
+ interpolationMethod: BlitFramebuffer.Nearest
+ }
+ }
+ }
+ }
+ }
+ ]
+
+ 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/tests/manual/buffercapture-qml/bufferSetter.comp b/tests/manual/buffercapture-qml/bufferSetter.comp
index d7c383669..d7c383669 100755..100644
--- a/tests/manual/buffercapture-qml/bufferSetter.comp
+++ b/tests/manual/buffercapture-qml/bufferSetter.comp
diff --git a/tests/manual/custom-mesh-update-data-cpp/main.cpp b/tests/manual/custom-mesh-update-data-cpp/main.cpp
index c7f5742dc..80ee2088d 100644
--- a/tests/manual/custom-mesh-update-data-cpp/main.cpp
+++ b/tests/manual/custom-mesh-update-data-cpp/main.cpp
@@ -277,7 +277,7 @@ int main(int argc, char* argv[])
void TimerObject::timeout()
{
- angle += float(M_PI / 360.0);
+ angle += qDegreesToRadians(0.5f);
QByteArray updateData;
updateData.resize(3*sizeof(float));
diff --git a/tests/manual/downloading/downloading.pro b/tests/manual/downloading/downloading.pro
new file mode 100644
index 000000000..6f1b6e3d5
--- /dev/null
+++ b/tests/manual/downloading/downloading.pro
@@ -0,0 +1,14 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ downloading.qrc
diff --git a/tests/manual/downloading/downloading.qrc b/tests/manual/downloading/downloading.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/downloading/downloading.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/downloading/main.cpp b/tests/manual/downloading/main.cpp
new file mode 100644
index 000000000..dba6e0bff
--- /dev/null
+++ b/tests/manual/downloading/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+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();
+}
diff --git a/tests/manual/downloading/main.qml b/tests/manual/downloading/main.qml
new file mode 100644
index 000000000..47d1c09fb
--- /dev/null
+++ b/tests/manual/downloading/main.qml
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.Input 2.0
+import Qt3D.Extras 2.0
+
+Entity {
+ id: sceneRoot
+
+ Camera {
+ id: camera
+ position: Qt.vector3d( 0.0, 0.5, 15.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.5, 0.0 )
+ }
+
+ OrbitCameraController { camera: camera }
+
+ RenderSettings {
+ id : external_forward_renderer
+ activeFrameGraph : ForwardRenderer {
+ camera: camera
+ clearColor: "white"
+ }
+ }
+
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { id: inputSettings }
+
+ DirectionalLight { id: light; worldDirection: camera.viewVector }
+
+ components: [external_forward_renderer, inputSettings, light]
+
+ Mesh {
+ id: mesh
+ source: "https://codereview.qt-project.org/gitweb?p=qt/qt3d.git;a=blob_plain;hb=refs/heads/dev;f=examples/qt3d/exampleresources/assets/chest/Chest.obj"
+ }
+
+ Transform {
+ id: transform
+ scale: 0.03
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 30)
+ }
+
+ DiffuseMapMaterial {
+ id: material
+ diffuse: TextureLoader { source: "https://codereview.qt-project.org/gitweb?p=qt/qt3d.git;a=blob_plain;hb=refs/heads/dev;f=examples/qt3d/planets-qml/images/solarsystemscope/earthmap2k.jpg" }
+ specular: Qt.rgba( 0.2, 0.2, 0.2, 1.0 )
+ shininess: 2.0
+ }
+
+ Entity {
+ id: mainEntity
+ objectName: "mainEntity"
+ components: [ mesh, material, transform ]
+ }
+}
diff --git a/tests/manual/layerfilter-qml/layerfilter-qml.pro b/tests/manual/layerfilter-qml/layerfilter-qml.pro
new file mode 100644
index 000000000..edeb4c6e2
--- /dev/null
+++ b/tests/manual/layerfilter-qml/layerfilter-qml.pro
@@ -0,0 +1,14 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ layerfilter-qml.qrc
diff --git a/tests/manual/layerfilter-qml/layerfilter-qml.qrc b/tests/manual/layerfilter-qml/layerfilter-qml.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/layerfilter-qml/layerfilter-qml.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/layerfilter-qml/main.cpp b/tests/manual/layerfilter-qml/main.cpp
new file mode 100644
index 000000000..dba6e0bff
--- /dev/null
+++ b/tests/manual/layerfilter-qml/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+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();
+}
diff --git a/tests/manual/layerfilter-qml/main.qml b/tests/manual/layerfilter-qml/main.qml
new file mode 100644
index 000000000..00b1cffa0
--- /dev/null
+++ b/tests/manual/layerfilter-qml/main.qml
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.10
+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, 3.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ Camera {
+ id: backgroundCamera
+ projectionType: CameraLens.OrthographicProjection
+ left: -0.25
+ bottom: -0.25
+ top: 0.25
+ right: 0.25
+ nearPlane: 0.1
+ farPlane: 1.5
+ position: Qt.vector3d( 0.0, 0.0, 1.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ Layer {
+ id: backgroundLayer
+ recursive: true
+ }
+
+ Layer {
+ id: sceneLayer
+ recursive: true
+ }
+
+ Layer {
+ id: secondBackgroundLayer
+ }
+
+ RenderSettings {
+ id : external_forward_renderer
+ activeFrameGraph :
+
+ RenderSurfaceSelector {
+ Viewport {
+ normalizedRect: Qt.rect(0,0,1,1)
+
+ ClearBuffers {
+ buffers: ClearBuffers.ColorDepthStencilBuffer
+ clearColor: "white"
+
+ LayerFilter {
+ layers: [
+ backgroundLayer,
+ secondBackgroundLayer
+ ]
+
+ CameraSelector {
+ camera: backgroundCamera
+ }
+ }
+ }
+
+ ClearBuffers {
+ buffers: ClearBuffers.DepthStencilBuffer
+
+ LayerFilter {
+ layers: [
+ backgroundLayer,
+ ]
+ filterMode: LayerFilter.DiscardAnyMatchingLayers
+
+ CameraSelector {
+ camera: camera
+ }
+ }
+ }
+ }
+ }
+ }
+
+ OrbitCameraController {
+ camera: camera
+ }
+
+ InputSettings {
+ id: inputSettings
+ }
+
+ components: [external_forward_renderer, inputSettings]
+
+ PlaneMesh {
+ id: backgroundMesh
+ width: 0.5
+ height: 0.5
+ }
+
+ Transform {
+ id: backgroundTransform
+ rotation: fromAxisAndAngle(Qt.vector3d(1,0,0), 90)
+ }
+
+ Transform {
+ id: smallBackgroundTransform
+ translation: Qt.vector3d(0,0.5,0)
+ scale: 0.5
+ }
+
+ PhongMaterial {
+ id: backgroundMaterial
+ ambient: "black"
+ }
+
+ PhongMaterial {
+ id: smallBackgroundMaterial
+ ambient: "red"
+ }
+
+ PlaneMesh {
+ id: mesh
+ width: 1
+ height: 1
+ }
+
+ Transform {
+ id: transform
+ translation: Qt.vector3d(0,0,-1)
+ rotation: fromAxisAndAngle(Qt.vector3d(1,0,0), 90)
+ }
+
+ PhongMaterial {
+ id: material
+ ambient: "blue"
+ }
+
+ Entity {
+ id: backgroundFilterEntity
+ components: [backgroundLayer]
+
+ Entity {
+ id: backgroundEntity
+ objectName: "backgroundEntity"
+ components: [backgroundMesh, backgroundMaterial, backgroundTransform]
+
+ Entity {
+ id: smallBackground
+ objectName: "smallBackground"
+ components: [backgroundMesh, smallBackgroundMaterial, smallBackgroundTransform]
+ }
+ }
+ }
+
+ Entity {
+ components: [sceneLayer]
+
+ Entity {
+ id: mainEntity
+ objectName: "mainEntity"
+ components: [ mesh, material, transform ]
+ }
+ }
+}
diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro
index 7eedbe05e..724cc0fb3 100644
--- a/tests/manual/manual.pro
+++ b/tests/manual/manual.pro
@@ -16,6 +16,7 @@ SUBDIRS += \
cylinder-qml \
deferred-renderer-cpp \
deferred-renderer-qml \
+ downloading \
dragging \
dynamicscene-cpp \
enabled-qml \
@@ -28,11 +29,13 @@ SUBDIRS += \
multiplewindows-qml \
picking-qml \
plasma \
+ pointlinesize \
scene3d-loader \
simple-shaders-qml \
skybox \
tessellation-modes \
transforms-qml \
+ spritegrid \
transparency-qml \
transparency-qml-scene3d \
rendercapture-qml \
@@ -48,7 +51,11 @@ SUBDIRS += \
mesh-morphing \
anim-viewer \
animation-keyframe-programmatic \
- rendercapture-qml-fbo
+ layerfilter-qml \
+ skinned-mesh \
+ proximityfilter \
+ rendercapture-qml-fbo \
+ blitframebuffer-qml
qtHaveModule(widgets): {
SUBDIRS += \
diff --git a/tests/manual/pointlinesize/Scene.qml b/tests/manual/pointlinesize/Scene.qml
new file mode 100644
index 000000000..94f3bf351
--- /dev/null
+++ b/tests/manual/pointlinesize/Scene.qml
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.10
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.0
+import QtQuick 2.0 as QQ2;
+
+Entity {
+ id: sceneRoot
+
+ property real width : 1
+ property alias smooth : lineWidth.smooth
+
+ Camera {
+ id: camera
+ projectionType: CameraLens.PerspectiveProjection
+ fieldOfView: 45
+ aspectRatio: 16/9
+ nearPlane : 0.1
+ farPlane : 1000.0
+ position: Qt.vector3d( 0.0, 0.0, 2.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ FirstPersonCameraController {
+ camera: camera
+ linearSpeed: 1.0
+ }
+
+ components: [
+ RenderSettings {
+ activeFrameGraph : RenderStateSet {
+ renderStates: [
+ PointSize {
+ value: sceneRoot.width
+ sizeMode: PointSize.Fixed
+ },
+ LineWidth {
+ id: lineWidth
+ value: sceneRoot.width / 3.0
+ }
+
+ ]
+
+ ForwardRenderer {
+ camera: camera
+ clearColor: "black"
+ }
+ }
+ },
+ InputSettings {
+ }
+ ]
+
+ SphereGeometry {
+ id: sphere
+ rings: 4
+ slices: 4
+ radius: 1
+ }
+
+ Entity {
+ components: [
+ GeometryRenderer {
+ // abuse PlaneGeometry to give us some lines
+ geometry: sphere
+ primitiveType: GeometryRenderer.LineStrip
+ },
+ PhongMaterial {
+ ambient: "white"
+ }
+ ]
+ }
+
+ Entity {
+ components: [
+ GeometryRenderer {
+ // abuse PlaneGeometry to give us some points
+ geometry: sphere
+ primitiveType: GeometryRenderer.Points
+ },
+ PhongMaterial {
+ ambient: "red"
+ }
+ ]
+ }
+
+}
diff --git a/tests/manual/pointlinesize/main.cpp b/tests/manual/pointlinesize/main.cpp
new file mode 100644
index 000000000..5ede02f15
--- /dev/null
+++ b/tests/manual/pointlinesize/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQuickView>
+#include <QOpenGLContext>
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+ QSurfaceFormat format;
+ format.setVersion(2, 0);
+ format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ format.setDepthBufferSize(24);
+
+ QQuickView view;
+ view.setFormat(format);
+ view.resize(1200, 600);
+ view.setResizeMode(QQuickView::SizeRootObjectToView);
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/pointlinesize/main.qml b/tests/manual/pointlinesize/main.qml
new file mode 100644
index 000000000..a0180391f
--- /dev/null
+++ b/tests/manual/pointlinesize/main.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.0
+import QtQuick.Scene3D 2.0
+
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+
+Item {
+ id: root
+
+ Scene3D {
+ anchors.fill: parent
+ focus: true
+ aspects: ["input", "logic", "render"]
+ cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
+
+ Scene {
+ id: scene
+ width : root.lineWidth
+ }
+ }
+
+ property real wMin : 0.5
+ property real wMax : 64.0
+ property real lineWidth : wMin * Math.exp(Math.log(wMax / wMin) * slider.value)
+
+ Text {
+ id: sliderLabel
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.margins: 20
+ font.pixelSize: 20
+ color: "white"
+ text: "width = " + lineWidth.toFixed(2)
+ }
+
+ Slider {
+ id: slider
+ anchors.top: sliderLabel.bottom
+ anchors.right: parent.right
+ anchors.margins: 20
+ width: 200
+ value: 0.0
+ }
+
+ Text {
+ anchors.top: slider.bottom
+ anchors.right: parent.right
+ anchors.margins: 20
+ color: scene.smooth ? "white" : "lightgray"
+ text: scene.smooth ? "Line Smoothing enabled" : "Line Smoothing disabled"
+ font.pixelSize: 20
+ MouseArea {
+ anchors.fill: parent
+ onClicked: scene.smooth = !scene.smooth
+ }
+ }
+}
diff --git a/tests/manual/pointlinesize/pointlinesize.pro b/tests/manual/pointlinesize/pointlinesize.pro
new file mode 100644
index 000000000..7ebde2e11
--- /dev/null
+++ b/tests/manual/pointlinesize/pointlinesize.pro
@@ -0,0 +1,15 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ Scene.qml \
+ main.qml
+
+RESOURCES += \
+ pointlinesize.qrc
diff --git a/tests/manual/pointlinesize/pointlinesize.qrc b/tests/manual/pointlinesize/pointlinesize.qrc
new file mode 100644
index 000000000..72868031a
--- /dev/null
+++ b/tests/manual/pointlinesize/pointlinesize.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>Scene.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/proximityfilter/main.cpp b/tests/manual/proximityfilter/main.cpp
new file mode 100644
index 000000000..41d2f08a5
--- /dev/null
+++ b/tests/manual/proximityfilter/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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: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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+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();
+}
diff --git a/tests/manual/proximityfilter/main.qml b/tests/manual/proximityfilter/main.qml
new file mode 100644
index 000000000..05c2e4415
--- /dev/null
+++ b/tests/manual/proximityfilter/main.qml
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.9
+import Qt3D.Core 2.10
+import Qt3D.Render 2.10
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.9
+
+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, 150.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: RenderSurfaceSelector {
+ Viewport {
+ normalizedRect: Qt.rect(0, 0, 1, 1)
+
+ ClearBuffers {
+ buffers: ClearBuffers.ColorDepthBuffer
+ clearColor: Qt.rgba(0.6, 0.6, 0.6, 1.0)
+ NoDraw {}
+ }
+
+ FrustumCulling {
+ CameraSelector {
+ camera: camera
+ ProximityFilter {
+ entity: proximityTarget
+ distanceThreshold: 30
+ }
+ }
+ }
+ }
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+ SphereMesh {
+ id: sphereMesh
+ }
+
+ PhongMaterial {
+ id: phongMaterial
+ diffuse: "orange"
+ }
+
+ NodeInstantiator {
+ id: instantiator
+ model: 64
+ Entity {
+ readonly property real angle: Math.PI * 2.0 * model.index % 8
+ readonly property real radius: 20
+ readonly property real verticalStep: 10
+ readonly property color meshColor: Qt.hsla(model.index / instantiator.count, 0.5, 0.5, 1.0);
+
+ readonly property Transform transform: Transform {
+ translation: Qt.vector3d(radius * Math.cos(angle),
+ (-(instantiator.count / (8 * 2)) + model.index / 8) * verticalStep,
+ radius * Math.sin(angle))
+ }
+ readonly property Material material: Material {
+ effect: phongMaterial.effect
+ parameters: Parameter { name: "kd"; value: meshColor }
+ }
+ readonly property SphereMesh mesh: sphereMesh
+ components: [ transform, mesh, material ]
+ }
+ }
+
+ Entity {
+ id: proximityTarget
+ readonly property Transform transform: Transform
+ {
+ property real y: 0;
+ SequentialAnimation on y {
+ NumberAnimation { from: -50; to: 50; duration: 2000; easing.type: Easing.InOutQuart }
+ NumberAnimation { from: 50; to: -50; duration: 2000; easing.type: Easing.InOutQuart }
+ loops: Animation.Infinite
+ }
+ translation: Qt.vector3d(0.0, y, 0.0)
+ }
+ components: [ sphereMesh, phongMaterial, transform ]
+ }
+}
diff --git a/tests/manual/proximityfilter/proximityfilter.pro b/tests/manual/proximityfilter/proximityfilter.pro
new file mode 100644
index 000000000..2e3f19157
--- /dev/null
+++ b/tests/manual/proximityfilter/proximityfilter.pro
@@ -0,0 +1,11 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+RESOURCES += \
+ proximityfilter.qrc
diff --git a/tests/manual/proximityfilter/proximityfilter.qrc b/tests/manual/proximityfilter/proximityfilter.qrc
new file mode 100644
index 000000000..5f6483ac3
--- /dev/null
+++ b/tests/manual/proximityfilter/proximityfilter.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/rendercapture-qml/main.cpp b/tests/manual/rendercapture-qml/main.cpp
index 5c581c88e..9f8a8ed24 100644
--- a/tests/manual/rendercapture-qml/main.cpp
+++ b/tests/manual/rendercapture-qml/main.cpp
@@ -65,6 +65,12 @@ int main(int argc, char* argv[])
RenderCaptureProvider *provider = new RenderCaptureProvider;
qmlRegisterType<RenderCaptureProvider>("Extras", 1, 0, "RenderCaptureProvider");
+ QSurfaceFormat format;
+ format.setVersion(3, 2);
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ format.setDepthBufferSize(24);
+ view.setFormat(format);
+
view.engine()->rootContext()->setContextProperty("_renderCaptureProvider", provider);
view.engine()->addImageProvider("rendercapture", provider);
diff --git a/tests/manual/skinned-mesh/DefaultSceneEntity.qml b/tests/manual/skinned-mesh/DefaultSceneEntity.qml
new file mode 100644
index 000000000..e3465a8bb
--- /dev/null
+++ b/tests/manual/skinned-mesh/DefaultSceneEntity.qml
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.10
+import Qt3D.Render 2.10
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.10
+
+Entity {
+ id: root
+
+ components: [
+ RenderSettings {
+ activeFrameGraph: ForwardRenderer {
+ camera: mainCamera
+ }
+ },
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { }
+ ]
+
+ Camera {
+ id: mainCamera
+ position: Qt.vector3d(2.5, 0.8, 5)
+ viewCenter: Qt.vector3d(2.5, 0.8, 0)
+ fieldOfView: 60
+ }
+
+ OrbitCameraController {
+ camera: mainCamera
+ linearSpeed: 10
+ lookSpeed: 180
+ }
+
+ Entity {
+ components: [
+ PointLight {
+ enabled: parent.enabled
+ color: "black"
+ intensity: 0
+ },
+ EnvironmentLight {
+ enabled: parent.enabled
+
+ irradiance: TextureLoader {
+ source: "qrc:/assets/envmaps/cedar-bridge/cedar_bridge_irradiance.dds"
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ generateMipMaps: false
+ }
+ specular: TextureLoader {
+ source: "qrc:/assets/envmaps/cedar-bridge/cedar_bridge_specular.dds"
+ wrapMode {
+ x: WrapMode.ClampToEdge
+ y: WrapMode.ClampToEdge
+ }
+ generateMipMaps: false
+ }
+ }
+ ]
+
+ SkyboxEntity {
+ baseName: "qrc:/assets/envmaps/cedar-bridge/cedar_bridge_irradiance"
+ extension: ".dds"
+ }
+ }
+}
diff --git a/tests/manual/skinned-mesh/SkinnedEntity.qml b/tests/manual/skinned-mesh/SkinnedEntity.qml
new file mode 100644
index 000000000..f1c3ee0c2
--- /dev/null
+++ b/tests/manual/skinned-mesh/SkinnedEntity.qml
@@ -0,0 +1,41 @@
+import Qt3D.Core 2.10
+import Qt3D.Render 2.10
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.10
+
+Entity {
+ id: root
+
+ property Effect effect: skinnedPbrEffect
+ property url source: ""
+ property alias createJointsEnabled: skeleton.createJointsEnabled
+ property alias transform: transform
+ property color baseColor: "red"
+ property alias rootJoint: skeleton.rootJoint
+ property alias skeleton: skeleton
+
+ components: [
+ Transform {
+ id: transform
+ rotationX: -90
+ },
+ Mesh {
+ source: root.source
+ },
+ Armature {
+ skeleton: SkeletonLoader {
+ id: skeleton
+ source: root.source
+ onStatusChanged: console.log("skeleton loader status: " + status)
+ onJointCountChanged: console.log("skeleton has " + jointCount + " joints")
+ }
+ },
+ Material {
+ effect: root.effect
+
+ parameters: [
+ Parameter { name: "baseColor"; value: root.baseColor }
+ ]
+ }
+ ]
+}
diff --git a/tests/manual/skinned-mesh/SkinnedPbrEffect.qml b/tests/manual/skinned-mesh/SkinnedPbrEffect.qml
new file mode 100644
index 000000000..c1c383a74
--- /dev/null
+++ b/tests/manual/skinned-mesh/SkinnedPbrEffect.qml
@@ -0,0 +1,39 @@
+import Qt3D.Core 2.10
+import Qt3D.Render 2.10
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.10
+
+Effect {
+ id: skinnedPbrEffect
+ parameters: [
+ Parameter { name: "baseColor"; value: "red" },
+ Parameter { name: "metalness"; value: 0.1 },
+ Parameter { name: "roughness"; value: 0.2 }
+ ]
+
+ techniques: [
+ Technique {
+ filterKeys: FilterKey { name: "renderingStyle"; value: "forward" }
+
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ majorVersion: 3
+ minorVersion: 1
+ profile: GraphicsApiFilter.CoreProfile
+ }
+
+ renderPasses: RenderPass {
+ shaderProgram: ShaderProgram {
+ id: prog
+ vertexShaderCode: loadSource("qrc:/skinnedPbr.vert")
+ }
+
+ ShaderProgramBuilder {
+ shaderProgram: prog
+ fragmentShaderGraph: "qrc:/shaders/graphs/metalrough.frag.json"
+ enabledLayers: ["baseColor", "metalness", "roughness", "ambientOcclusion", "normal"]
+ }
+ }
+ }
+ ]
+}
diff --git a/tests/manual/skinned-mesh/jump.json b/tests/manual/skinned-mesh/jump.json
new file mode 100644
index 000000000..7d7447a40
--- /dev/null
+++ b/tests/manual/skinned-mesh/jump.json
@@ -0,0 +1,4571 @@
+{
+ "animations": [
+ {
+ "animationName": "Jump",
+ "channels": [
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Location X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ -0.5
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ -0.5
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ -0.5
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ -0.5
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ -0.5
+ ],
+ "rightHandle": [
+ 1.5305366516113281,
+ -0.5
+ ]
+ },
+ {
+ "coords": [
+ 1.7083333333333333,
+ 2.5
+ ],
+ "leftHandle": [
+ 1.5944633483886719,
+ 1.4873701333999634
+ ],
+ "rightHandle": [
+ 1.838470458984375,
+ 3.6572914123535156
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 5.0
+ ],
+ "leftHandle": [
+ 1.911529541015625,
+ 5.0
+ ],
+ "rightHandle": [
+ 2.5296810468037925,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 5.0
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 5.0
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 5.0
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 5.0
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 5.0
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 5.0
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 5.0
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 5.0
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 5.0
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 5.0
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 5.0
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 5.0
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 5.0
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 5.0
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 5.0
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 5.0
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 5.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ 5.0
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 5.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 5.5
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 5.5
+ ],
+ "rightHandle": [
+ 6.706335703531901,
+ 5.5
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 5.5
+ ],
+ "leftHandle": [
+ 6.751997629801433,
+ 5.5
+ ],
+ "rightHandle": [
+ 6.947203318277995,
+ 5.5
+ ]
+ },
+ {
+ "coords": [
+ 7.125,
+ 2.5
+ ],
+ "leftHandle": [
+ 7.011130015055339,
+ 3.512629985809326
+ ],
+ "rightHandle": [
+ 7.255137125651042,
+ 1.342708706855774
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 7.328196207682292,
+ 0.0
+ ],
+ "rightHandle": [
+ 7.946347554524739,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 0.0
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.664669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.710330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.873002370198568,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.9186642964681,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.0813357035319,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.126997629801432,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.289669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.335330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.498002370198568,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.5436642964681,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.7063357035319,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.5305366516113281,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.7083333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.5944633483886719,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.838470458984375,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.911529541015625,
+ 0.0
+ ],
+ "rightHandle": [
+ 2.5296810468037925,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 0.0
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 0.0
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.706335703531901,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 6.751997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.947203318277995,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 7.125,
+ 0.0
+ ],
+ "leftHandle": [
+ 7.011130015055339,
+ 0.0
+ ],
+ "rightHandle": [
+ 7.255137125651042,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 7.328196207682292,
+ 0.0
+ ],
+ "rightHandle": [
+ 7.946347554524739,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 0.0
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.664669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.710330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.873002370198568,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.9186642964681,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.0813357035319,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.126997629801432,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.289669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.335330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.498002370198568,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.5436642964681,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.7063357035319,
+ 0.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Location Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.5305366516113281,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.7083333333333333,
+ 2.0
+ ],
+ "leftHandle": [
+ 1.5944633483886719,
+ 2.0
+ ],
+ "rightHandle": [
+ 1.838470458984375,
+ 2.0
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.911529541015625,
+ 0.0
+ ],
+ "rightHandle": [
+ 2.5296810468037925,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 0.5
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 0.5
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 0.5
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 0.30000001192092896
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 0.30000001192092896
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 0.30000001192092896
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.706335703531901,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 6.751997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.947203318277995,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 7.125,
+ 2.0
+ ],
+ "leftHandle": [
+ 7.011130015055339,
+ 2.0
+ ],
+ "rightHandle": [
+ 7.255137125651042,
+ 2.0
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 7.328196207682292,
+ 0.0
+ ],
+ "rightHandle": [
+ 7.946347554524739,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 0.0
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.5
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ 0.5
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ 0.5
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.664669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.710330963134766,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.873002370198568,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 9.9186642964681,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.0813357035319,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.126997629801432,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.289669036865234,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.30000001192092896
+ ],
+ "leftHandle": [
+ 10.335330963134766,
+ 0.30000001192092896
+ ],
+ "rightHandle": [
+ 10.498002370198568,
+ 0.30000001192092896
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.5436642964681,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.7063357035319,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Location",
+ "jointIndex": 0
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Scale X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ -0.3090757926305135,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 1.6150120099385579,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 1.0099881490071614,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 1.5305366516113281,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 1.7083333333333333,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 1.5944633483886719,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 1.838470458984375,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 1.9603309631347656,
+ 1.0536658763885498
+ ],
+ "rightHandle": [
+ 2.057933807373047,
+ 1.229351282119751
+ ]
+ },
+ {
+ "coords": [
+ 2.0833333333333335,
+ 1.3000702857971191
+ ],
+ "leftHandle": [
+ 2.0386231740315757,
+ 1.3000702857971191
+ ],
+ "rightHandle": [
+ 2.1339289347330728,
+ 1.3000702857971191
+ ]
+ },
+ {
+ "coords": [
+ 2.2083333333333335,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 2.1606807708740234,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 2.255985895792643,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 2.3333333333333335,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 2.2827377319335938,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 2.3780434926350913,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 2.917522430419922,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 1.1508238315582275
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 1.0493168830871582
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 1.1000703573226929
+ ],
+ "rightHandle": [
+ 5.2734018961588545,
+ 1.1000703573226929
+ ]
+ },
+ {
+ "coords": [
+ 5.375,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 5.3099314371744795,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 5.7003428141276045,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 5.8829905192057295,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 7.031678517659505,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 6.426654815673828,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 6.947203318277995,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 7.125,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 7.011130015055339,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 7.255137125651042,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 7.376997629801433,
+ 1.0536658763885498
+ ],
+ "rightHandle": [
+ 7.474600474039714,
+ 1.229351282119751
+ ]
+ },
+ {
+ "coords": [
+ 7.5,
+ 1.3000702857971191
+ ],
+ "leftHandle": [
+ 7.455289204915364,
+ 1.3000702857971191
+ ],
+ "rightHandle": [
+ 7.550595601399739,
+ 1.3000702857971191
+ ]
+ },
+ {
+ "coords": [
+ 7.625,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 7.5773468017578125,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 7.6726531982421875,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 7.75,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 7.699404398600261,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 7.794710795084636,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 8.334189097086588,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 9.469462076822916,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 9.664667765299479,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 9.710332234700521,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 9.873001098632812,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 9.918665568033854,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 10.081334431966146,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 10.126998901367188,
+ 1.1000703573226929
+ ],
+ "rightHandle": [
+ 10.289667765299479,
+ 1.1000703573226929
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 10.335332234700521,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 10.498001098632812,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 10.543665568033854,
+ 1.1000703573226929
+ ],
+ "rightHandle": [
+ 10.690068562825521,
+ 1.1000703573226929
+ ]
+ },
+ {
+ "coords": [
+ 10.791666666666666,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 10.726598103841146,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 10.856735229492188,
+ 1.000070333480835
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ -0.3090757926305135,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 1.6150120099385579,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 1.0099881490071614,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 1.5305366516113281,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 1.7083333333333333,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 1.5944633483886719,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 1.838470458984375,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 1.9603309631347656,
+ 1.0536658763885498
+ ],
+ "rightHandle": [
+ 2.057933807373047,
+ 1.229351282119751
+ ]
+ },
+ {
+ "coords": [
+ 2.0833333333333335,
+ 1.3000702857971191
+ ],
+ "leftHandle": [
+ 2.0386231740315757,
+ 1.3000702857971191
+ ],
+ "rightHandle": [
+ 2.1339289347330728,
+ 1.3000702857971191
+ ]
+ },
+ {
+ "coords": [
+ 2.2083333333333335,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 2.1606807708740234,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 2.255985895792643,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 2.3333333333333335,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 2.2827377319335938,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 2.3780434926350913,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 2.917522430419922,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 1.1508238315582275
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 1.0493168830871582
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 1.1000703573226929
+ ],
+ "rightHandle": [
+ 5.2734018961588545,
+ 1.1000703573226929
+ ]
+ },
+ {
+ "coords": [
+ 5.375,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 5.3099314371744795,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 5.7003428141276045,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 5.8829905192057295,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 7.031678517659505,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 6.426654815673828,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 6.947203318277995,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 7.125,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 7.011130015055339,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 7.255137125651042,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 7.376997629801433,
+ 1.0536658763885498
+ ],
+ "rightHandle": [
+ 7.474600474039714,
+ 1.229351282119751
+ ]
+ },
+ {
+ "coords": [
+ 7.5,
+ 1.3000702857971191
+ ],
+ "leftHandle": [
+ 7.455289204915364,
+ 1.3000702857971191
+ ],
+ "rightHandle": [
+ 7.550595601399739,
+ 1.3000702857971191
+ ]
+ },
+ {
+ "coords": [
+ 7.625,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 7.5773468017578125,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 7.6726531982421875,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 7.75,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 7.699404398600261,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 7.794710795084636,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 8.334189097086588,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 1.000070333480835
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.8000703454017639
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ 0.8000703454017639
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ 0.8000703454017639
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 9.469462076822916,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 9.664667765299479,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 9.710332234700521,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 9.873001098632812,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 1.2000703811645508
+ ],
+ "leftHandle": [
+ 9.918665568033854,
+ 1.2000703811645508
+ ],
+ "rightHandle": [
+ 10.081334431966146,
+ 1.2000703811645508
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 10.126998901367188,
+ 1.1508238315582275
+ ],
+ "rightHandle": [
+ 10.289667765299479,
+ 1.0493168830871582
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.9400703310966492
+ ],
+ "leftHandle": [
+ 10.335332234700521,
+ 0.9400703310966492
+ ],
+ "rightHandle": [
+ 10.498001098632812,
+ 0.9400703310966492
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 1.1000703573226929
+ ],
+ "leftHandle": [
+ 10.543665568033854,
+ 1.1000703573226929
+ ],
+ "rightHandle": [
+ 10.690068562825521,
+ 1.1000703573226929
+ ]
+ },
+ {
+ "coords": [
+ 10.791666666666666,
+ 1.000070333480835
+ ],
+ "leftHandle": [
+ 10.726598103841146,
+ 1.000070333480835
+ ],
+ "rightHandle": [
+ 10.856735229492188,
+ 1.000070333480835
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Scale Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.0
+ ],
+ "leftHandle": [
+ -0.30907583236694336,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 1.0
+ ],
+ "leftHandle": [
+ 0.44092432657877606,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.9126714070638021,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 0.6000000238418579
+ ],
+ "leftHandle": [
+ 1.0039952596028645,
+ 0.6000000238418579
+ ],
+ "rightHandle": [
+ 1.5733451843261719,
+ 0.6000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 0.6000000238418579
+ ],
+ "leftHandle": [
+ 1.0099881490071614,
+ 0.6000000238418579
+ ],
+ "rightHandle": [
+ 1.5305366516113281,
+ 0.6000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 1.7083333333333333,
+ 1.2000000476837158
+ ],
+ "leftHandle": [
+ 1.5527966817220051,
+ 1.2000000476837158
+ ],
+ "rightHandle": [
+ 1.7968037923177083,
+ 1.2000000476837158
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 0.550000011920929
+ ],
+ "leftHandle": [
+ 1.996956507364909,
+ 0.550000011920929
+ ],
+ "rightHandle": [
+ 2.0922622680664062,
+ 0.550000011920929
+ ]
+ },
+ {
+ "coords": [
+ 2.2083333333333335,
+ 1.0499999523162842
+ ],
+ "leftHandle": [
+ 2.119014104207357,
+ 1.0499999523162842
+ ],
+ "rightHandle": [
+ 2.2143192291259766,
+ 1.0499999523162842
+ ]
+ },
+ {
+ "coords": [
+ 2.3333333333333335,
+ 1.0
+ ],
+ "leftHandle": [
+ 2.2827377319335938,
+ 1.0
+ ],
+ "rightHandle": [
+ 2.3780434926350913,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 1.0
+ ],
+ "leftHandle": [
+ 2.8758557637532554,
+ 1.0
+ ],
+ "rightHandle": [
+ 3.3638699849446616,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 0.6000000238418579
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 0.6000000238418579
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 0.6000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 1.100000023841858
+ ],
+ "leftHandle": [
+ 3.719463348388672,
+ 1.100000023841858
+ ],
+ "rightHandle": [
+ 3.9472033182779946,
+ 1.100000023841858
+ ]
+ },
+ {
+ "coords": [
+ 4.125,
+ 0.800000011920929
+ ],
+ "leftHandle": [
+ 4.011130015055339,
+ 0.800000011920929
+ ],
+ "rightHandle": [
+ 4.206335703531901,
+ 0.800000011920929
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 1.0
+ ],
+ "leftHandle": [
+ 4.251997629801433,
+ 1.0
+ ],
+ "rightHandle": [
+ 4.414669036865234,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 1.0
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 1.0
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 0.8999999761581421
+ ],
+ "leftHandle": [
+ 4.668664296468099,
+ 0.8999999761581421
+ ],
+ "rightHandle": [
+ 4.831335703531901,
+ 0.8999999761581421
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 1.0499999523162842
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 1.0499999523162842
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 1.0499999523162842
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 0.8999999761581421
+ ],
+ "leftHandle": [
+ 5.085330963134766,
+ 0.8999999761581421
+ ],
+ "rightHandle": [
+ 5.2317352294921875,
+ 0.8999999761581421
+ ]
+ },
+ {
+ "coords": [
+ 5.375,
+ 1.0
+ ],
+ "leftHandle": [
+ 5.2682647705078125,
+ 1.0
+ ],
+ "rightHandle": [
+ 5.6586761474609375,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 1.0
+ ],
+ "leftHandle": [
+ 5.8413238525390625,
+ 1.0
+ ],
+ "rightHandle": [
+ 6.329338073730469,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 0.6000000238418579
+ ],
+ "leftHandle": [
+ 6.420661926269531,
+ 0.6000000238418579
+ ],
+ "rightHandle": [
+ 6.990011850992839,
+ 0.6000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 6.791666666666667,
+ 0.6000000238418579
+ ],
+ "leftHandle": [
+ 6.384988149007161,
+ 0.6000000238418579
+ ],
+ "rightHandle": [
+ 6.905536651611328,
+ 0.6000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 7.125,
+ 1.2000000476837158
+ ],
+ "leftHandle": [
+ 6.969463348388672,
+ 1.2000000476837158
+ ],
+ "rightHandle": [
+ 7.213470458984375,
+ 1.2000000476837158
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.800000011920929
+ ],
+ "leftHandle": [
+ 7.3353322347005205,
+ 1.0928102731704712
+ ],
+ "rightHandle": [
+ 7.4631195068359375,
+ 0.7886062860488892
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.550000011920929
+ ],
+ "leftHandle": [
+ 7.413622538248698,
+ 0.550000011920929
+ ],
+ "rightHandle": [
+ 7.508928934733073,
+ 0.550000011920929
+ ]
+ },
+ {
+ "coords": [
+ 7.625,
+ 1.0499999523162842
+ ],
+ "leftHandle": [
+ 7.5356801350911455,
+ 1.0499999523162842
+ ],
+ "rightHandle": [
+ 7.6309865315755205,
+ 1.0499999523162842
+ ]
+ },
+ {
+ "coords": [
+ 7.75,
+ 1.0
+ ],
+ "leftHandle": [
+ 7.699404398600261,
+ 1.0
+ ],
+ "rightHandle": [
+ 7.794710795084636,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 1.0
+ ],
+ "leftHandle": [
+ 8.292522430419922,
+ 1.0
+ ],
+ "rightHandle": [
+ 8.780536651611328,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 8.958333333333334,
+ 0.6000000238418579
+ ],
+ "leftHandle": [
+ 8.844463348388672,
+ 0.6000000238418579
+ ],
+ "rightHandle": [
+ 9.07220458984375,
+ 0.6000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 1.100000023841858
+ ],
+ "leftHandle": [
+ 9.136128743489584,
+ 1.100000023841858
+ ],
+ "rightHandle": [
+ 9.363871256510416,
+ 1.100000023841858
+ ]
+ },
+ {
+ "coords": [
+ 9.541666666666666,
+ 0.800000011920929
+ ],
+ "leftHandle": [
+ 9.42779541015625,
+ 0.800000011920929
+ ],
+ "rightHandle": [
+ 9.623001098632812,
+ 0.800000011920929
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 1.0
+ ],
+ "leftHandle": [
+ 9.668665568033854,
+ 1.0
+ ],
+ "rightHandle": [
+ 9.831334431966146,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 1.0
+ ],
+ "leftHandle": [
+ 9.918665568033854,
+ 1.0
+ ],
+ "rightHandle": [
+ 10.081334431966146,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 0.8999999761581421
+ ],
+ "leftHandle": [
+ 10.085332234700521,
+ 0.8999999761581421
+ ],
+ "rightHandle": [
+ 10.248001098632812,
+ 0.8999999761581421
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 1.0499999523162842
+ ],
+ "leftHandle": [
+ 10.335332234700521,
+ 1.0499999523162842
+ ],
+ "rightHandle": [
+ 10.498001098632812,
+ 1.0499999523162842
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 0.8999999761581421
+ ],
+ "leftHandle": [
+ 10.501998901367188,
+ 0.8999999761581421
+ ],
+ "rightHandle": [
+ 10.648401896158854,
+ 0.8999999761581421
+ ]
+ },
+ {
+ "coords": [
+ 10.791666666666666,
+ 1.0
+ ],
+ "leftHandle": [
+ 10.684931437174479,
+ 1.0
+ ],
+ "rightHandle": [
+ 10.815068562825521,
+ 1.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Scale",
+ "jointIndex": 0
+ },
+ {
+ "channelComponents": [
+ {
+ "channelComponentName": "Rotation W",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 1.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 1.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 1.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 1.0
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 1.0
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 1.0
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ 1.0
+ ],
+ "rightHandle": [
+ 1.4817352294921875,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 1.5833333333333333,
+ 0.9848077893257141
+ ],
+ "leftHandle": [
+ 1.5182647705078125,
+ 0.9848077893257141
+ ],
+ "rightHandle": [
+ 1.6809361775716145,
+ 0.9848077893257141
+ ]
+ },
+ {
+ "coords": [
+ 1.8333333333333333,
+ 0.9961948394775391
+ ],
+ "leftHandle": [
+ 1.735730489095052,
+ 0.9930806159973145
+ ],
+ "rightHandle": [
+ 1.9146690368652344,
+ 0.9987900257110596
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 1.9603309631347656,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 2.448345343271891,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 0.8191520571708679
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 0.9475935697555542
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 0.6907105445861816
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 0.3420201539993286
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 0.3420201539993286
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 0.3420201539993286
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 0.3420201539993286
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 0.3420201539993286
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 0.3420201539993286
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 0.3420201539993286
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 0.3420201539993286
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 0.3420201539993286
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 0.3420201539993286
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 0.3420201539993286
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 0.3420201539993286
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 0.17364823818206787
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 0.24041254818439484
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 0.1068839281797409
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ -5.960464477539063e-08
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ -5.960464477539063e-08
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ -5.960464477539063e-08
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ -5.960464477539063e-08
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 2.4835268064293814e-08
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 2.384185791015625e-07
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 2.384185791015625e-07
+ ],
+ "rightHandle": [
+ 7.031678517659505,
+ 2.384185791015625e-07
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 2.384185791015625e-07
+ ],
+ "leftHandle": [
+ 6.5079905192057295,
+ 2.384185791015625e-07
+ ],
+ "rightHandle": [
+ 6.8984018961588545,
+ 2.384185791015625e-07
+ ]
+ },
+ {
+ "coords": [
+ 7.0,
+ 1.9185245037078857e-07
+ ],
+ "leftHandle": [
+ 6.9349314371744795,
+ 1.9185245037078857e-07
+ ],
+ "rightHandle": [
+ 7.097602844238281,
+ 1.9185245037078857e-07
+ ]
+ },
+ {
+ "coords": [
+ 7.25,
+ -4.353933036327362e-08
+ ],
+ "leftHandle": [
+ 7.152397155761719,
+ 0.003114179940894246
+ ],
+ "rightHandle": [
+ 7.331335703531901,
+ -0.0025952300056815147
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 7.376997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 7.865011850992839,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 0.0
+ ],
+ "rightHandle": [
+ 8.82220458984375,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.886128743489584,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.113871256510416,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.5735764503479004
+ ],
+ "leftHandle": [
+ 9.178207397460938,
+ 0.3380364775657654
+ ],
+ "rightHandle": [
+ 9.428712209065756,
+ 0.8580812215805054
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 9.469462076822916,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 9.664667765299479,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 9.710332234700521,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 9.873001098632812,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 9.918665568033854,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 10.081334431966146,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 10.126998901367188,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 10.289667765299479,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.9848077297210693
+ ],
+ "leftHandle": [
+ 10.335332234700521,
+ 0.9627091884613037
+ ],
+ "rightHandle": [
+ 10.498001098632812,
+ 1.006906270980835
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 1.0
+ ],
+ "leftHandle": [
+ 10.543665568033854,
+ 1.0
+ ],
+ "rightHandle": [
+ 10.706334431966146,
+ 1.0
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation X",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.4817352294921875,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.5833333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.5182647705078125,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.6809361775716145,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.8333333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.735730489095052,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.9146690368652344,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.9603309631347656,
+ 0.0
+ ],
+ "rightHandle": [
+ 2.448345343271891,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 4.2734766836360905e-09
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 2.906791696233313e-09
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 5.640161671038868e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 7.001254243022004e-09
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 7.001254243022004e-09
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 7.001254243022004e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 7.001254243022004e-09
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 7.001254243022004e-09
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 7.001254243022004e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 7.001254243022004e-09
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 7.001254243022004e-09
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 7.001254243022004e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 7.001254243022004e-09
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 7.001254243022004e-09
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 7.001254243022004e-09
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 7.337388030492775e-09
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 7.249677302922919e-09
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 7.4250987580626315e-09
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 7.450578376477779e-09
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 7.450578376477779e-09
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ 7.450578376477779e-09
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.706335703531901,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 6.751997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 6.8984018961588545,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 7.0,
+ -0.1736481785774231
+ ],
+ "leftHandle": [
+ 6.9349314371744795,
+ -0.1736481785774231
+ ],
+ "rightHandle": [
+ 7.097602844238281,
+ -0.1736481785774231
+ ]
+ },
+ {
+ "coords": [
+ 7.25,
+ 0.08715573698282242
+ ],
+ "leftHandle": [
+ 7.152397155761719,
+ 0.08715573698282242
+ ],
+ "rightHandle": [
+ 7.331335703531901,
+ 0.08715573698282242
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 7.376997629801433,
+ 0.0
+ ],
+ "rightHandle": [
+ 7.865011850992839,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 0.0
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 0.0
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 0.0
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ -2.410053712154081e-09
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ -1.8343819796484695e-09
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ -2.9857254446596926e-09
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ -2.9857254446596926e-09
+ ],
+ "leftHandle": [
+ 9.469463348388672,
+ -2.9857254446596926e-09
+ ],
+ "rightHandle": [
+ 9.664669036865234,
+ -2.9857254446596926e-09
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ -2.9857254446596926e-09
+ ],
+ "leftHandle": [
+ 9.710330963134766,
+ -2.9857254446596926e-09
+ ],
+ "rightHandle": [
+ 9.873002370198568,
+ -2.9857254446596926e-09
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ -2.9857254446596926e-09
+ ],
+ "leftHandle": [
+ 9.9186642964681,
+ -2.9857254446596926e-09
+ ],
+ "rightHandle": [
+ 10.0813357035319,
+ -2.9857254446596926e-09
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ -2.9857254446596926e-09
+ ],
+ "leftHandle": [
+ 10.126997629801432,
+ -2.9857254446596926e-09
+ ],
+ "rightHandle": [
+ 10.289669036865234,
+ -2.9857254446596926e-09
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ -1.5745631465335919e-09
+ ],
+ "leftHandle": [
+ 10.335330963134766,
+ -2.2619428552417276e-09
+ ],
+ "rightHandle": [
+ 10.498002370198568,
+ -8.871833823143049e-10
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 5.355835774878415e-10
+ ],
+ "leftHandle": [
+ 10.5436642964681,
+ 5.355835774878415e-10
+ ],
+ "rightHandle": [
+ 10.7063357035319,
+ 5.355835774878415e-10
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Z",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ -0.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ -0.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ -0.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ -0.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ -0.0
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ -0.0
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ -0.0
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ -0.0
+ ],
+ "rightHandle": [
+ 1.4817352294921875,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.5833333333333333,
+ -0.1736481785774231
+ ],
+ "leftHandle": [
+ 1.5182647705078125,
+ -0.1736481785774231
+ ],
+ "rightHandle": [
+ 1.6809361775716145,
+ -0.1736481785774231
+ ]
+ },
+ {
+ "coords": [
+ 1.8333333333333333,
+ 0.08715575933456421
+ ],
+ "leftHandle": [
+ 1.735730489095052,
+ 0.08715575933456421
+ ],
+ "rightHandle": [
+ 1.9146690368652344,
+ 0.08715575933456421
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 1.9603309631347656,
+ 7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 2.448345343271891,
+ 7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 6.1031566467306675e-09
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 7.060120044144469e-09
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 5.146193249316866e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 2.5482482790550876e-09
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 2.5482482790550876e-09
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 2.5482482790550876e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 2.5482482790550876e-09
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 2.5482482790550876e-09
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 2.5482482790550876e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 2.5482482790550876e-09
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 2.5482482790550876e-09
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 2.5482482790550876e-09
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 2.5482482790550876e-09
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 2.5482482790550876e-09
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 2.5482482790550876e-09
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 1.2937797500001125e-09
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 1.7912125116481548e-09
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 7.96346932840919e-10
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ -4.440892098500626e-16
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ -4.440892098500626e-16
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ -4.440892098500626e-16
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ -0.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ -0.0
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ -0.0
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ -0.0
+ ],
+ "rightHandle": [
+ 6.706335703531901,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ -0.0
+ ],
+ "leftHandle": [
+ 6.751997629801433,
+ -0.0
+ ],
+ "rightHandle": [
+ 6.8984018961588545,
+ -0.0
+ ]
+ },
+ {
+ "coords": [
+ 7.0,
+ 2.9802322387695312e-08
+ ],
+ "leftHandle": [
+ 6.9349314371744795,
+ 2.9802322387695312e-08
+ ],
+ "rightHandle": [
+ 7.097602844238281,
+ 2.9802322387695312e-08
+ ]
+ },
+ {
+ "coords": [
+ 7.25,
+ -7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 7.152397155761719,
+ -7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 7.331335703531901,
+ -7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 7.376997629801433,
+ 7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 7.865011850992839,
+ 7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 8.822203318277994,
+ 7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 7.450580596923828e-09
+ ],
+ "leftHandle": [
+ 8.886130015055338,
+ 7.450580596923828e-09
+ ],
+ "rightHandle": [
+ 9.113869984944662,
+ 7.450580596923828e-09
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 1.0482139600753726e-08
+ ],
+ "leftHandle": [
+ 9.177796681722006,
+ 8.819545094240766e-09
+ ],
+ "rightHandle": [
+ 9.405536651611328,
+ 1.2144734107266686e-08
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 1.5967721367360355e-08
+ ],
+ "leftHandle": [
+ 9.469463348388672,
+ 1.5967721367360355e-08
+ ],
+ "rightHandle": [
+ 9.664669036865234,
+ 1.5967721367360355e-08
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 1.5967721367360355e-08
+ ],
+ "leftHandle": [
+ 9.710330963134766,
+ 1.5967721367360355e-08
+ ],
+ "rightHandle": [
+ 9.873002370198568,
+ 1.5967721367360355e-08
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 1.5967721367360355e-08
+ ],
+ "leftHandle": [
+ 9.9186642964681,
+ 1.5967721367360355e-08
+ ],
+ "rightHandle": [
+ 10.0813357035319,
+ 1.5967721367360355e-08
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 1.5967721367360355e-08
+ ],
+ "leftHandle": [
+ 10.126997629801432,
+ 1.5967721367360355e-08
+ ],
+ "rightHandle": [
+ 10.289669036865234,
+ 1.5967721367360355e-08
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 1.7476175173669617e-08
+ ],
+ "leftHandle": [
+ 10.335330963134766,
+ 1.7084600401062744e-08
+ ],
+ "rightHandle": [
+ 10.498002370198568,
+ 1.786774994627649e-08
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 1.7973679433680445e-08
+ ],
+ "leftHandle": [
+ 10.5436642964681,
+ 1.7973679433680445e-08
+ ],
+ "rightHandle": [
+ 10.7063357035319,
+ 1.7973679433680445e-08
+ ]
+ }
+ ]
+ },
+ {
+ "channelComponentName": "Rotation Y",
+ "keyFrames": [
+ {
+ "coords": [
+ 0.0,
+ 0.0
+ ],
+ "leftHandle": [
+ -0.3090757727622986,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.3090757528940837,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 0.7916666666666666,
+ 0.0
+ ],
+ "leftHandle": [
+ 0.482590913772583,
+ 0.0
+ ],
+ "rightHandle": [
+ 0.9543381532033285,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.2083333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.0456618467966716,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.2896690368652344,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.4166666666666667,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.3353309631347656,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.4817352294921875,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.5833333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.5182647705078125,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.6809361775716145,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 1.8333333333333333,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.735730489095052,
+ 0.0
+ ],
+ "rightHandle": [
+ 1.9146690368652344,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 2.0416666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 1.9603309631347656,
+ 0.0
+ ],
+ "rightHandle": [
+ 2.448345343271891,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.2916666666666665,
+ 0.0
+ ],
+ "leftHandle": [
+ 2.8036524454752603,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.405536651611328,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.5833333333333335,
+ 0.0
+ ],
+ "leftHandle": [
+ 3.469463348388672,
+ 0.0
+ ],
+ "rightHandle": [
+ 3.6972033182779946,
+ 0.0
+ ]
+ },
+ {
+ "coords": [
+ 3.875,
+ 0.5735764503479004
+ ],
+ "leftHandle": [
+ 3.7611300150553384,
+ 0.3901430368423462
+ ],
+ "rightHandle": [
+ 3.9888699849446616,
+ 0.7570098638534546
+ ]
+ },
+ {
+ "coords": [
+ 4.166666666666667,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 4.052796681722005,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 4.248002370198567,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 4.375,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 4.293664296468099,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 4.456335703531901,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 4.583333333333333,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 4.501997629801433,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 4.664669036865234,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 4.791666666666667,
+ 0.9396926164627075
+ ],
+ "leftHandle": [
+ 4.710330963134766,
+ 0.9396926164627075
+ ],
+ "rightHandle": [
+ 4.873002370198567,
+ 0.9396926164627075
+ ]
+ },
+ {
+ "coords": [
+ 5.0,
+ 0.9848077297210693
+ ],
+ "leftHandle": [
+ 4.918664296468099,
+ 0.9730353951454163
+ ],
+ "rightHandle": [
+ 5.081335703531901,
+ 0.9965800642967224
+ ]
+ },
+ {
+ "coords": [
+ 5.208333333333333,
+ 1.0
+ ],
+ "leftHandle": [
+ 5.126997629801433,
+ 1.0
+ ],
+ "rightHandle": [
+ 5.598744710286458,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 6.208333333333333,
+ 1.0
+ ],
+ "leftHandle": [
+ 5.817921956380208,
+ 1.0
+ ],
+ "rightHandle": [
+ 6.371004740397136,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 6.625,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 6.462328592936198,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 7.031678517659505,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 6.833333333333333,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 6.5079905192057295,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 6.8984018961588545,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 7.0,
+ 1.0
+ ],
+ "leftHandle": [
+ 6.9349314371744795,
+ 1.0
+ ],
+ "rightHandle": [
+ 7.097605387369792,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 7.25,
+ 1.0
+ ],
+ "leftHandle": [
+ 7.152397155761719,
+ 1.0
+ ],
+ "rightHandle": [
+ 7.331335703531901,
+ 1.0
+ ]
+ },
+ {
+ "coords": [
+ 7.458333333333333,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 7.376997629801433,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 7.865011850992839,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 8.708333333333334,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 8.220319112141928,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 8.82220458984375,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 9.0,
+ 1.000000238418579
+ ],
+ "leftHandle": [
+ 8.886128743489584,
+ 1.000000238418579
+ ],
+ "rightHandle": [
+ 9.113871256510416,
+ 1.000000238418579
+ ]
+ },
+ {
+ "coords": [
+ 9.291666666666666,
+ 0.8191520571708679
+ ],
+ "leftHandle": [
+ 9.17779541015625,
+ 0.932508647441864
+ ],
+ "rightHandle": [
+ 9.405537923177084,
+ 0.7057954668998718
+ ]
+ },
+ {
+ "coords": [
+ 9.583333333333334,
+ 0.3420201241970062
+ ],
+ "leftHandle": [
+ 9.469462076822916,
+ 0.3420201241970062
+ ],
+ "rightHandle": [
+ 9.664667765299479,
+ 0.3420201241970062
+ ]
+ },
+ {
+ "coords": [
+ 9.791666666666666,
+ 0.3420201241970062
+ ],
+ "leftHandle": [
+ 9.710332234700521,
+ 0.3420201241970062
+ ],
+ "rightHandle": [
+ 9.873001098632812,
+ 0.3420201241970062
+ ]
+ },
+ {
+ "coords": [
+ 10.0,
+ 0.3420201241970062
+ ],
+ "leftHandle": [
+ 9.918665568033854,
+ 0.3420201241970062
+ ],
+ "rightHandle": [
+ 10.081334431966146,
+ 0.3420201241970062
+ ]
+ },
+ {
+ "coords": [
+ 10.208333333333334,
+ 0.3420201241970062
+ ],
+ "leftHandle": [
+ 10.126998901367188,
+ 0.3420201241970062
+ ],
+ "rightHandle": [
+ 10.289667765299479,
+ 0.3420201241970062
+ ]
+ },
+ {
+ "coords": [
+ 10.416666666666666,
+ 0.1736481785774231
+ ],
+ "leftHandle": [
+ 10.335413614908854,
+ 0.2643083930015564
+ ],
+ "rightHandle": [
+ 10.498001098632812,
+ 0.08289717137813568
+ ]
+ },
+ {
+ "coords": [
+ 10.625,
+ 0.0
+ ],
+ "leftHandle": [
+ 10.543665568033854,
+ 0.0
+ ],
+ "rightHandle": [
+ 10.706334431966146,
+ 0.0
+ ]
+ }
+ ]
+ }
+ ],
+ "channelName": "Rotation",
+ "jointIndex": 0
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/manual/skinned-mesh/main.cpp b/tests/manual/skinned-mesh/main.cpp
new file mode 100644
index 000000000..8e2ebcbfb
--- /dev/null
+++ b/tests/manual/skinned-mesh/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <Qt3DAnimation/QAnimationAspect>
+#include <QGuiApplication>
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc, argv);
+ Qt3DExtras::Quick::Qt3DQuickWindow view;
+ view.registerAspect(new Qt3DAnimation::QAnimationAspect());
+
+ view.setSource(QUrl("qrc:/main.qml"));
+ view.show();
+
+ return app.exec();
+}
diff --git a/tests/manual/skinned-mesh/main.qml b/tests/manual/skinned-mesh/main.qml
new file mode 100644
index 000000000..174d54f83
--- /dev/null
+++ b/tests/manual/skinned-mesh/main.qml
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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.10
+import Qt3D.Render 2.10
+import Qt3D.Input 2.0
+import Qt3D.Animation 2.10
+import Qt3D.Extras 2.10
+import QtQuick 2.9
+
+DefaultSceneEntity {
+ id: scene
+
+ SkinnedPbrEffect {
+ id: skinnedPbrEffect
+ }
+
+ Timer {
+ interval: 2000
+ running: true
+ repeat: false
+ onTriggered: {
+ animator1.running = true
+ animator2.running = true
+ animator3.running = true
+ animator4.running = true
+ animator5.running = true
+ }
+ }
+
+ SkinnedEntity {
+ id: riggedFigure1
+ effect: skinnedPbrEffect
+ source: "qrc:/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf"
+ baseColor: "red"
+
+ components: [
+// ClipAnimator {
+// loops: 3
+// clip: AnimationClipLoader { source: "qrc:/jump.json" }
+// channelMapper: ChannelMapper {
+// mappings: [
+// SkeletonChannelMapping { target: riggedFigure.skeleton }
+// ]
+// }
+// }
+ BlendedClipAnimator {
+ id: animator1
+ loops: 5
+ blendTree: ClipBlendValue {
+ clip: AnimationClipLoader { source: "qrc:/jump.json" }
+ }
+ channelMapper: ChannelMapper {
+ mappings: [
+ SkeletonMapping { skeleton: riggedFigure1.skeleton }
+ ]
+ }
+
+ onRunningChanged: console.log("running = " + running)
+ }
+ ]
+ }
+
+ SkinnedEntity {
+ id: riggedFigure2
+ effect: skinnedPbrEffect
+ source: "qrc:/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf"
+ baseColor: "purple"
+ transform.translation: Qt.vector3d(0.0, 0.0, -1.0);
+
+ components: [
+ BlendedClipAnimator {
+ id: animator2
+ loops: 5
+ blendTree: ClipBlendValue {
+ clip: AnimationClipLoader { source: "qrc:/jump.json" }
+ }
+ channelMapper: ChannelMapper {
+ mappings: [
+ SkeletonMapping { skeleton: riggedFigure2.skeleton }
+ ]
+ }
+
+ onRunningChanged: console.log("running = " + running)
+ }
+ ]
+ }
+
+ SkinnedEntity {
+ id: riggedFigure3
+ effect: skinnedPbrEffect
+ source: "qrc:/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf"
+ baseColor: "blue"
+ transform.translation: Qt.vector3d(0.0, 0.0, -2.0);
+
+ components: [
+ BlendedClipAnimator {
+ id: animator3
+ loops: 5
+ blendTree: ClipBlendValue {
+ clip: AnimationClipLoader { source: "qrc:/jump.json" }
+ }
+ channelMapper: ChannelMapper {
+ mappings: [
+ SkeletonMapping { skeleton: riggedFigure3.skeleton }
+ ]
+ }
+
+ onRunningChanged: console.log("running = " + running)
+ }
+ ]
+ }
+
+ SkinnedEntity {
+ id: riggedFigure4
+ effect: skinnedPbrEffect
+ source: "qrc:/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf"
+ baseColor: "green"
+ transform.translation: Qt.vector3d(0.0, 0.0, -3.0);
+
+ components: [
+ BlendedClipAnimator {
+ id: animator4
+ loops: 5
+ blendTree: ClipBlendValue {
+ clip: AnimationClipLoader { source: "qrc:/jump.json" }
+ }
+ channelMapper: ChannelMapper {
+ mappings: [
+ SkeletonMapping { skeleton: riggedFigure4.skeleton }
+ ]
+ }
+
+ onRunningChanged: console.log("running = " + running)
+ }
+ ]
+ }
+
+ SkinnedEntity {
+ id: riggedFigure5
+ effect: skinnedPbrEffect
+ source: "qrc:/assets/gltf/2.0/RiggedFigure/RiggedFigure.gltf"
+ baseColor: "orange"
+ transform.translation: Qt.vector3d(0.0, 0.0, -4.0);
+
+ components: [
+ BlendedClipAnimator {
+ id: animator5
+ loops: 5
+ blendTree: ClipBlendValue {
+ clip: AnimationClipLoader { source: "qrc:/jump.json" }
+ }
+ channelMapper: ChannelMapper {
+ mappings: [
+ SkeletonMapping { skeleton: riggedFigure5.skeleton }
+ ]
+ }
+
+ onRunningChanged: console.log("running = " + running)
+ }
+ ]
+ }
+
+ SkinnedEntity {
+ id: riggedSimple
+ effect: skinnedPbrEffect
+ source: "qrc:/assets/gltf/2.0/RiggedSimple/RiggedSimple.gltf"
+ baseColor: "blue"
+ transform.scale: 0.05
+ transform.translation: Qt.vector3d(0.5, 0.25, 0.0)
+ createJointsEnabled: true
+
+ onRootJointChanged: {
+ var animation = animationComp.createObject(rootJoint)
+ var targetJoint = rootJoint.childJoints[0]
+ animation.target = targetJoint
+ animation.running = true
+ }
+
+ Component {
+ id: animationComp
+ SequentialAnimation {
+ id: sequentialAnimation
+ property variant target: null
+ property real dz: 30.0
+ loops: Animation.Infinite
+
+ NumberAnimation {
+ target: sequentialAnimation.target
+ property: "rotationZ"
+ from: -dz
+ to: dz
+ duration: 600
+ easing.type: Easing.OutCubic
+ }
+ NumberAnimation {
+ target: sequentialAnimation.target
+ property: "rotationZ"
+ from: dz
+ to: -dz
+ duration: 600
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+}
diff --git a/tests/manual/skinned-mesh/skinned-mesh.pro b/tests/manual/skinned-mesh/skinned-mesh.pro
new file mode 100644
index 000000000..380b1bb35
--- /dev/null
+++ b/tests/manual/skinned-mesh/skinned-mesh.pro
@@ -0,0 +1,23 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras 3danimation
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml \
+ DefaultSceneEntity.qml \
+ SkinnedEntity.qml \
+ SkinnedPbrEffect.qml
+
+RESOURCES += \
+ skinned-mesh.qrc \
+ ../../../examples/qt3d/exampleresources/cubemaps.qrc \
+ ../../../examples/qt3d/exampleresources/envmaps.qrc \
+ ../../../examples/qt3d/exampleresources/gltf.qrc
+
+DISTFILES += \
+ skinnedPbr.vert
diff --git a/tests/manual/skinned-mesh/skinned-mesh.qrc b/tests/manual/skinned-mesh/skinned-mesh.qrc
new file mode 100644
index 000000000..f34f93f37
--- /dev/null
+++ b/tests/manual/skinned-mesh/skinned-mesh.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>DefaultSceneEntity.qml</file>
+ <file>skinnedPbr.vert</file>
+ <file>SkinnedEntity.qml</file>
+ <file>SkinnedPbrEffect.qml</file>
+ <file>jump.json</file>
+ </qresource>
+</RCC>
diff --git a/tests/manual/skinned-mesh/skinnedPbr.vert b/tests/manual/skinned-mesh/skinnedPbr.vert
new file mode 100644
index 000000000..94cb3417c
--- /dev/null
+++ b/tests/manual/skinned-mesh/skinnedPbr.vert
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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$
+**
+****************************************************************************/
+
+#version 150
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec4 vertexTangent;
+in vec2 vertexTexCoord;
+in ivec4 vertexJointIndices;
+in vec4 vertexJointWeights;
+
+out vec3 worldPosition;
+out vec3 worldNormal;
+out vec4 worldTangent;
+out vec2 texCoord;
+
+uniform mat4 modelMatrix;
+uniform mat3 modelNormalMatrix;
+uniform mat4 mvp;
+
+const int maxJoints = 100;
+uniform mat4 skinningPalette[maxJoints];
+
+void main()
+{
+ // Pass the texture coordinates through
+ texCoord = vertexTexCoord;
+
+ // Perform the skinning
+ mat4 skinningMatrix = skinningPalette[vertexJointIndices[0]] * vertexJointWeights[0];
+ skinningMatrix += skinningPalette[vertexJointIndices[1]] * vertexJointWeights[1];
+ skinningMatrix += skinningPalette[vertexJointIndices[2]] * vertexJointWeights[2];
+ skinningMatrix += skinningPalette[vertexJointIndices[3]] * vertexJointWeights[3];
+
+ vec4 skinnedPosition = skinningMatrix * vec4(vertexPosition, 1.0);
+ vec3 skinnedNormal = vec3(skinningMatrix * vec4(vertexNormal, 0.0));
+ vec3 skinnedTangent = vec3(skinningMatrix * vec4(vertexTangent.xyz, 0.0));
+
+ // Transform position, normal, and tangent to world space
+ worldPosition = vec3(modelMatrix * skinnedPosition);
+ worldNormal = normalize(modelNormalMatrix * skinnedNormal);
+ worldTangent.xyz = normalize(vec3(modelMatrix * vec4(skinnedTangent, 0.0)));
+ worldTangent.w = vertexTangent.w;
+
+ gl_Position = mvp * skinnedPosition;
+}
diff --git a/tests/manual/spritegrid/main.cpp b/tests/manual/spritegrid/main.cpp
new file mode 100644
index 000000000..70a8ec467
--- /dev/null
+++ b/tests/manual/spritegrid/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 <Qt3DQuickExtras/qt3dquickwindow.h>
+#include <QGuiApplication>
+
+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();
+}
diff --git a/tests/manual/spritegrid/main.qml b/tests/manual/spritegrid/main.qml
new file mode 100644
index 000000000..ca3d7fd92
--- /dev/null
+++ b/tests/manual/spritegrid/main.qml
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** 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 Qt3D.Core 2.0
+import Qt3D.Render 2.0
+import Qt3D.Input 2.0
+import Qt3D.Extras 2.10
+import QtQuick 2.5
+
+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, 20.0 )
+ upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
+ viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
+ }
+
+ OrbitCameraController { camera: camera }
+
+ RenderSettings {
+ id : external_forward_renderer
+ activeFrameGraph : ForwardRenderer {
+ camera: camera
+ clearColor: "lightgrey"
+ }
+ }
+
+ // Event Source will be set by the Qt3DQuickWindow
+ InputSettings { id: inputSettings }
+
+ components: [external_forward_renderer, inputSettings]
+
+ PlaneMesh {
+ id: mesh
+ }
+
+ SpriteGrid {
+ id: spriteGrid
+ rows: 2
+ columns: 6
+ texture: textureLoader
+ }
+
+ SpriteSheet {
+ id:spriteSheet
+ texture: textureLoader
+
+ SpriteItem { x: 0; y: 0; width: 250; height: 172 }
+ SpriteItem { x: 276; y: 0; width: 250; height: 172 }
+ SpriteItem { x: 550; y: 0; width: 250; height: 172 }
+ SpriteItem { x: 826; y: 0; width: 250; height: 172 }
+ SpriteItem { x: 1100; y: 0; width: 250; height: 172 }
+ SpriteItem { x: 1376; y: 0; width: 250; height: 172 }
+ SpriteItem { x: 0; y: 198; width: 250; height: 172 }
+ SpriteItem { x: 276; y: 198; width: 250; height: 172 }
+ SpriteItem { x: 550; y: 198; width: 250; height: 172 }
+ SpriteItem { x: 826; y: 198; width: 250; height: 172 }
+ SpriteItem { x: 1100; y: 198; width: 250; height: 172 }
+ SpriteItem { x: 1376; y: 198; width: 250; height: 172 }
+ }
+
+ Transform {
+ id: transform1
+ scale: 8
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ translation: Qt.vector3d(-6, 0, 0)
+ }
+
+ TextureMaterial {
+ id: material1
+ texture: TextureLoader {
+ id: textureLoader
+ source: "spritegrid.png"
+ mirrored: false
+ }
+ textureTransform: spriteGrid.textureTransform
+ }
+
+ Entity {
+ components: [ mesh, material1, transform1 ]
+ }
+
+
+ Transform {
+ id: transform2
+ scale: 8
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45)
+ translation: Qt.vector3d(6, 0, 0)
+ }
+
+ TextureMaterial {
+ id: material2
+ texture: material1.texture
+ textureTransform: spriteSheet.textureTransform
+ }
+
+ Entity {
+ components: [ mesh, material2, transform2 ]
+ }
+
+
+ Transform {
+ id: transform3
+ scale3D: Qt.vector3d(12, 4, 4)
+ rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 90)
+ translation: Qt.vector3d(0, -6, 0)
+ }
+
+ TextureMaterial {
+ id: material3
+ texture: material1.texture
+ }
+
+ Entity {
+ components: [ mesh, material3, transform3 ]
+ }
+
+
+ Timer {
+ interval: 1000
+ repeat: true
+ running: true
+ onTriggered: {
+ spriteGrid.currentIndex = (spriteGrid.currentIndex + 1) % (spriteGrid.rows * spriteGrid.columns)
+ spriteSheet.currentIndex = (spriteSheet.currentIndex + 1) % (spriteSheet.sprites.length)
+ }
+ }
+}
diff --git a/tests/manual/spritegrid/spritegrid.png b/tests/manual/spritegrid/spritegrid.png
new file mode 100644
index 000000000..47c7f5577
--- /dev/null
+++ b/tests/manual/spritegrid/spritegrid.png
Binary files differ
diff --git a/tests/manual/spritegrid/spritegrid.pro b/tests/manual/spritegrid/spritegrid.pro
new file mode 100644
index 000000000..8e4a1f2a7
--- /dev/null
+++ b/tests/manual/spritegrid/spritegrid.pro
@@ -0,0 +1,14 @@
+!include( ../manual.pri ) {
+ error( "Couldn't find the manual.pri file!" )
+}
+
+QT += 3dcore 3drender 3dinput 3dquick qml quick 3dquickextras
+
+SOURCES += \
+ main.cpp
+
+OTHER_FILES += \
+ main.qml
+
+RESOURCES += \
+ spritegrid.qrc
diff --git a/tests/manual/spritegrid/spritegrid.qrc b/tests/manual/spritegrid/spritegrid.qrc
new file mode 100644
index 000000000..5e648adf2
--- /dev/null
+++ b/tests/manual/spritegrid/spritegrid.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>main.qml</file>
+ <file>spritegrid.png</file>
+ </qresource>
+</RCC>
diff --git a/tests/tests.pro b/tests/tests.pro
index 2ab283fc2..157bdcea5 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -1,8 +1,11 @@
TEMPLATE = subdirs
-!package: SUBDIRS += \
- auto \
- manual
+QT_FOR_CONFIG += 3dcore
+
+!package {
+ SUBDIRS += auto
+ qtConfig(qt3d-extras): SUBDIRS += manual
+}
# Benchmarks make sense in release mode only.
# Disable them for code coverage.
diff --git a/tools/utils/exporters/blender/qt3d_animation_export.py b/tools/utils/exporters/blender/qt3d_animation_export.py
index 2d6575198..b1987ea95 100644
--- a/tools/utils/exporters/blender/qt3d_animation_export.py
+++ b/tools/utils/exporters/blender/qt3d_animation_export.py
@@ -165,8 +165,8 @@ class PropertyData:
def generateKeyframesData(self, outputComponentIndex):
outputKeyframes = []
+ print("generateKeyframesData: fcurveIndices: " + str(self.m_fcurveIndices) + " curve index: " + str(outputComponentIndex))
# Lookup fcurve index for this component
- fcurveIndex = self.m_fcurveIndices[outputComponentIndex]
# Invert the sign of the 2nd component of quaternions for rotations
# We already swap the Y and Z components in the componentSuffix function
@@ -175,6 +175,7 @@ class PropertyData:
axisOrientationfactor = -1.0
if self.m_dataType == self.m_outputDataType:
+ fcurveIndex = self.m_fcurveIndices[outputComponentIndex]
# We can take easy route if no data type conversion is needed
# Iterate over keyframes
fcurve = self.m_action.fcurves[fcurveIndex]
@@ -300,7 +301,7 @@ class Qt3DAnimationConverter:
lastTitle = ""
property = PropertyData()
- for fcurveIndex,fcurve in enumerate(action.fcurves):
+ for fcurveIndex, fcurve in enumerate(action.fcurves):
title = fcurve.data_path.title()
# For debugging
@@ -310,12 +311,6 @@ class Qt3DAnimationConverter:
dataPath = fcurve.data_path
type = resolveDataType(resolverObject, dataPath)
labelSuffix = componentSuffix("Vector", fcurve.array_index)
- print(" " + str(fcurveIndex) + ": Group: " + groupName \
- + ", Title = " + title \
- + ", Component:" + str(fcurve.array_index) \
- + ", Data Path: " + dataPath \
- + ", Data Type: " + type \
- + ", Label: " + labelSuffix)
# Create a new PropertyData if this fcurve is for a new property
if title != lastTitle:
@@ -332,11 +327,19 @@ class Qt3DAnimationConverter:
property.m_componentIndices.append(fcurve.array_index)
property.m_fcurveIndices.append(fcurveIndex)
+ print(" " + str(fcurveIndex) + ": Group: " + groupName \
+ + ", Title = " + title \
+ + ", Component:" + str(fcurve.array_index) \
+ + ", Data Path: " + dataPath \
+ + ", Data Type: " + type \
+ + ", Label: " + labelSuffix \
+ + ", fCurveIndices: " + str(property.m_fcurveIndices))
+
lastTitle = title
print("")
# For debugging
- print("Pass 1 - Collected data for " + str(len(propertyDataMap)) + " actions")
+ print("animationsToJson: Pass 1 - Collected data for " + str(len(propertyDataMap)) + " actions")
actionIndex = 0
for key in propertyDataMap:
print(str(actionIndex) + ": " + key + " has " + str(len(propertyDataMap[key])) + " properties")
@@ -345,6 +348,7 @@ class Qt3DAnimationConverter:
actionIndex = actionIndex + 1
# Pass 2
+ print("animationsToJson: Pass 2")
# The data structure that will be exported
output = {"animations": []}
@@ -370,6 +374,7 @@ class Qt3DAnimationConverter:
output["animations"].append(outputAction)
actionIndex = actionIndex + 1
+ print("animationsToJson: Generating JSON data")
jsonData = json.dumps(output, indent=2, sort_keys=True, separators=(',', ': '))
return jsonData
diff --git a/tools/utils/exporters/blender/qt3d_armature_export.py b/tools/utils/exporters/blender/qt3d_armature_export.py
new file mode 100644
index 000000000..de5583220
--- /dev/null
+++ b/tools/utils/exporters/blender/qt3d_armature_export.py
@@ -0,0 +1,158 @@
+#############################################################################
+##
+## Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt3D module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE: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$
+##
+#############################################################################
+
+# Required Blender information.
+bl_info = {
+ "name": "Qt3D Armature Exporter",
+ "author": "Sean Harmer <sean.harmer@kdab.com>, Robert Brock <robert.brock@kdab.com>",
+ "version": (0, 1),
+ "blender": (2, 78, 0),
+ "location": "File > Export > Qt3D Armature Exporter (.json)",
+ "description": "Export Armature to json to use with Qt3D",
+ "warning": "",
+ "wiki_url": "",
+ "tracker_url": "",
+ "category": "Import-Export"
+ }
+
+import bpy
+import os
+import struct
+import mathutils
+import math
+import json
+from array import array
+from bpy import context
+from bpy_extras.io_utils import ExportHelper
+from bpy.props import (
+ BoolProperty,
+ FloatProperty,
+ StringProperty,
+ EnumProperty,
+ )
+from collections import defaultdict
+
+def jsonBuilder():
+ bonesList = []
+ name = ""
+ boneParent = ""
+
+ ob = bpy.context.object.data
+
+ for bone in ob.bones:
+
+ #check parent exists
+ if bone.parent:
+ boneParent = bone.parent.name
+ else:
+ boneParent = ""
+
+ #add the bones
+ bonesList.append({"bone": bone.name,
+ "parent": boneParent,
+ "matrix": jsonMatrix(bone)
+ })
+
+ return bonesList
+
+def jsonMatrix(bone):
+ matrix = []
+
+ for i in range(0, 4):
+ matrix.append(str("%.4f, %.4f, %.4f, %.4f" % (bone.matrix_local[i][0],
+ bone.matrix_local[i][1],
+ bone.matrix_local[i][2],
+ bone.matrix_local[i][3])))
+
+ return matrix
+
+
+class Qt3DMeshDataConverter:
+
+ def boneInfoToJson(self):
+ # Pass 1 - collect data we need to produce the output in pass 2
+ print(">>> About to enter Objects")
+
+ jsonData = json.dumps({ "bones": jsonBuilder()}, indent=2, sort_keys=True, separators=(',', ': '))
+ return jsonData
+
+
+class Qt3DArmatureExporter(bpy.types.Operator, ExportHelper):
+ """Qt3D Exporter"""
+ bl_idname = "export_scene.qt3d_armature_exporter";
+ bl_label = "Qt3DArmatureExporter";
+ bl_options = {'PRESET'};
+
+ filename_ext = ""
+ use_filter_folder = True
+
+ def __init__(self):
+ pass
+
+ def execute(self, context):
+ print("In Execute" + bpy.context.scene.name)
+
+ self.userpath = self.properties.filepath
+
+ # unselect all
+ bpy.ops.object.select_all(action='DESELECT')
+
+ converter = Qt3DMeshDataConverter()
+ fileContent = converter.boneInfoToJson()
+ with open(self.userpath + ".json", '+w') as f:
+ f.write(fileContent)
+
+ return {'FINISHED'}
+
+def createBlenderMenu(self, context):
+ self.layout.operator(Qt3DArmatureExporter.bl_idname, text="Qt3D Armature Export(.json)")
+
+# Register against Blender
+def register():
+ bpy.utils.register_class(Qt3DArmatureExporter)
+ bpy.types.INFO_MT_file_export.append(createBlenderMenu)
+
+def unregister():
+ bpy.utils.unregister_class(Qt3DArmatureExporter)
+ bpy.types.INFO_MT_file_export.remove(createBlenderMenu)
+
+# Handle running the script from Blender's text editor.
+if (__name__ == "__main__"):
+ register();
+ bpy.ops.export_scene.qt3d_Armature_exporter();
diff --git a/tools/utils/exporters/blender/qt3d_path_export.py b/tools/utils/exporters/blender/qt3d_path_export.py
new file mode 100644
index 000000000..7c42fac9a
--- /dev/null
+++ b/tools/utils/exporters/blender/qt3d_path_export.py
@@ -0,0 +1,138 @@
+#############################################################################
+##
+## Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the Qt3D module of the Qt Toolkit.
+##
+## $QT_BEGIN_LICENSE: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$
+##
+#############################################################################
+
+# Required Blender information.
+bl_info = {
+ "name": "Qt3D Path Exporter",
+ "author": "Sean Harmer <sean.harmer@kdab.com>, Robert Brock <robert.brock@kdab.com>",
+ "version": (0, 1),
+ "blender": (2, 78, 0),
+ "location": "File > Export > Qt3D Path Exporter (.json)",
+ "description": "Export path to json to use with Qt3D",
+ "warning": "",
+ "wiki_url": "",
+ "tracker_url": "",
+ "category": "Import-Export"
+ }
+
+import bpy
+import os
+import struct
+import mathutils
+import math
+import json
+from array import array
+from bpy_extras.io_utils import ExportHelper
+from bpy.props import (
+ BoolProperty,
+ FloatProperty,
+ StringProperty,
+ EnumProperty,
+ )
+from collections import defaultdict
+
+def jsonBuilder():
+ pathList = []
+ name = ""
+
+ obj = bpy.context.object
+ curve = obj.data
+ spline = curve.splines.active
+
+ for point in spline.points:
+ # add the stuff
+ pathList.append({"position": str("%.0f, %.0f, %.0f" % (point.co[0] * -1,
+ point.co[2],
+ point.co[1]))})
+
+ return pathList
+
+class Qt3DPathDataConverter:
+
+ def pathInfoToJson(self):
+ # Pass 1 - collect data we need to produce the output in pass 2
+ print(">>> About to enter Objects")
+
+ jsonData = json.dumps({ "splines": jsonBuilder()}, indent=2, sort_keys=True, separators=(',', ': '))
+ return jsonData
+
+
+class Qt3DTDPathExporter(bpy.types.Operator, ExportHelper):
+ """Qt3D Exporter"""
+ bl_idname = "export_scene.qt3d_td_path_exporter";
+ bl_label = "Qt3DPathExporter";
+ bl_options = {'PRESET'};
+
+ filename_ext = ""
+ use_filter_folder = True
+
+ def __init__(self):
+ pass
+
+ def execute(self, context):
+ print("In Execute" + bpy.context.scene.name)
+
+ self.userpath = self.properties.filepath
+
+ # unselect all
+ bpy.ops.object.select_all(action='DESELECT')
+
+ converter = Qt3DPathDataConverter()
+ fileContent = converter.pathInfoToJson()
+ with open(self.userpath + ".json", '+w') as f:
+ f.write(fileContent)
+
+ return {'FINISHED'}
+
+def createBlenderMenu(self, context):
+ self.layout.operator(Qt3DPathExporter.bl_idname, text="Qt3D Path Export(.json)")
+
+# Register against Blender
+def register():
+ bpy.utils.register_class(Qt3DPathExporter)
+ bpy.types.INFO_MT_file_export.append(createBlenderMenu)
+
+def unregister():
+ bpy.utils.unregister_class(Qt3DPathExporter)
+ bpy.types.INFO_MT_file_export.remove(createBlenderMenu)
+
+# Handle running the script from Blender's text editor.
+if (__name__ == "__main__"):
+ register();
+ bpy.ops.export_scene.qt3d_path_exporter();