summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-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
191 files changed, 12048 insertions, 1265 deletions
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