summaryrefslogtreecommitdiffstats
path: root/src/render
diff options
context:
space:
mode:
Diffstat (limited to 'src/render')
-rw-r--r--src/render/backend/abstractrenderer_p.h4
-rw-r--r--src/render/backend/attachmentpack.cpp2
-rw-r--r--src/render/backend/backendnode.cpp16
-rw-r--r--src/render/backend/backendnode_p.h8
-rw-r--r--src/render/backend/bufferutils_p.h115
-rw-r--r--src/render/backend/buffervisitor_p.h212
-rw-r--r--src/render/backend/cameralens.cpp126
-rw-r--r--src/render/backend/cameralens_p.h28
-rw-r--r--src/render/backend/commandexecuter.cpp5
-rw-r--r--src/render/backend/commandexecuter_p.h4
-rw-r--r--src/render/backend/commandthread.cpp129
-rw-r--r--src/render/backend/commandthread_p.h105
-rw-r--r--src/render/backend/entity.cpp32
-rw-r--r--src/render/backend/entity_p.h18
-rw-r--r--src/render/backend/frameprofiler_p.h14
-rw-r--r--src/render/backend/handle_types_p.h2
-rw-r--r--src/render/backend/levelofdetail.cpp29
-rw-r--r--src/render/backend/levelofdetail_p.h8
-rw-r--r--src/render/backend/managers_p.h15
-rw-r--r--src/render/backend/nodemanagers.cpp15
-rw-r--r--src/render/backend/nodemanagers_p.h13
-rw-r--r--src/render/backend/openglvertexarrayobject.cpp63
-rw-r--r--src/render/backend/openglvertexarrayobject_p.h18
-rw-r--r--src/render/backend/platformsurfacefilter.cpp4
-rw-r--r--src/render/backend/platformsurfacefilter_p.h4
-rw-r--r--src/render/backend/render-backend.pri22
-rw-r--r--src/render/backend/renderer.cpp290
-rw-r--r--src/render/backend/renderer_p.h23
-rw-r--r--src/render/backend/renderqueue.cpp6
-rw-r--r--src/render/backend/renderqueue_p.h4
-rw-r--r--src/render/backend/rendertargetoutput.cpp9
-rw-r--r--src/render/backend/rendertargetoutput_p.h3
-rw-r--r--src/render/backend/renderthread_p.h8
-rw-r--r--src/render/backend/renderview.cpp52
-rw-r--r--src/render/backend/renderview_p.h20
-rw-r--r--src/render/backend/renderviewbuilder.cpp29
-rw-r--r--src/render/backend/resourceaccessor.cpp123
-rw-r--r--src/render/backend/resourceaccessor_p.h102
-rw-r--r--src/render/backend/shadervariables_p.h1
-rw-r--r--src/render/backend/triangleboundingvolume.cpp17
-rw-r--r--src/render/backend/triangleboundingvolume_p.h2
-rw-r--r--src/render/backend/trianglesvisitor.cpp129
-rw-r--r--src/render/backend/trianglesvisitor_p.h27
-rw-r--r--src/render/framegraph/buffercapture.cpp61
-rw-r--r--src/render/framegraph/buffercapture_p.h (renamed from src/render/frontend/qboundingsphere_p.h)27
-rw-r--r--src/render/framegraph/framegraph.pri5
-rw-r--r--src/render/framegraph/framegraphnode_p.h1
-rw-r--r--src/render/framegraph/framegraphvisitor.cpp26
-rw-r--r--src/render/framegraph/framegraphvisitor_p.h14
-rw-r--r--src/render/framegraph/memorybarrier.cpp12
-rw-r--r--src/render/framegraph/memorybarrier_p.h4
-rw-r--r--src/render/framegraph/qbuffercapture.cpp73
-rw-r--r--src/render/framegraph/qbuffercapture.h69
-rw-r--r--src/render/framegraph/qbuffercapture_p.h74
-rw-r--r--src/render/framegraph/qmemorybarrier.cpp49
-rw-r--r--src/render/framegraph/qmemorybarrier.h45
-rw-r--r--src/render/framegraph/qmemorybarrier_p.h4
-rw-r--r--src/render/framegraph/qrendercapture.cpp81
-rw-r--r--src/render/framegraph/qrendercapture.h17
-rw-r--r--src/render/framegraph/qsortpolicy.cpp4
-rw-r--r--src/render/framegraph/qviewport.cpp34
-rw-r--r--src/render/framegraph/qviewport.h4
-rw-r--r--src/render/framegraph/qviewport_p.h2
-rw-r--r--src/render/framegraph/rendercapture.cpp2
-rw-r--r--src/render/framegraph/viewportnode.cpp16
-rw-r--r--src/render/framegraph/viewportnode_p.h4
-rw-r--r--src/render/frontend/qabstractfunctor.h1
-rw-r--r--src/render/frontend/qcamera.cpp103
-rw-r--r--src/render/frontend/qcamera.h8
-rw-r--r--src/render/frontend/qcameralens.cpp79
-rw-r--r--src/render/frontend/qcameralens.h10
-rw-r--r--src/render/frontend/qcameralens_p.h9
-rw-r--r--src/render/frontend/qlevelofdetail.cpp107
-rw-r--r--src/render/frontend/qlevelofdetail.h24
-rw-r--r--src/render/frontend/qlevelofdetail_p.h6
-rw-r--r--src/render/frontend/qlevelofdetailboundingsphere.cpp (renamed from src/render/frontend/qboundingsphere.cpp)105
-rw-r--r--src/render/frontend/qlevelofdetailboundingsphere.h (renamed from src/render/frontend/qboundingsphere.h)35
-rw-r--r--src/render/frontend/qlevelofdetailswitch.cpp14
-rw-r--r--src/render/frontend/qpickingsettings.cpp60
-rw-r--r--src/render/frontend/qrenderaspect.cpp87
-rw-r--r--src/render/frontend/qrenderaspect.h2
-rw-r--r--src/render/frontend/qrenderaspect_p.h15
-rw-r--r--src/render/frontend/qrenderplugin_p.h89
-rw-r--r--src/render/frontend/qrenderpluginfactory.cpp99
-rw-r--r--src/render/frontend/qrenderpluginfactory_p.h75
-rw-r--r--src/render/frontend/qrenderpluginfactoryif.cpp65
-rw-r--r--src/render/frontend/qrenderpluginfactoryif_p.h82
-rw-r--r--src/render/frontend/qrendersettings.cpp7
-rw-r--r--src/render/frontend/render-frontend.pri14
-rw-r--r--src/render/frontend/sphere.cpp3
-rw-r--r--src/render/frontend/sphere_p.h2
-rw-r--r--src/render/geometry/attribute.cpp2
-rw-r--r--src/render/geometry/buffer.cpp44
-rw-r--r--src/render/geometry/buffer_p.h6
-rw-r--r--src/render/geometry/geometryrenderer.cpp2
-rw-r--r--src/render/geometry/qbuffer.cpp40
-rw-r--r--src/render/geometry/qbuffer.h12
-rw-r--r--src/render/geometry/qbuffer_p.h2
-rw-r--r--src/render/geometry/qgeometry.cpp16
-rw-r--r--src/render/geometry/qmesh.cpp190
-rw-r--r--src/render/geometry/qmesh_p.h26
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp163
-rw-r--r--src/render/graphicshelpers/graphicscontext_p.h10
-rw-r--r--src/render/graphicshelpers/graphicshelperes2.cpp41
-rw-r--r--src/render/graphicshelpers/graphicshelperes2_p.h8
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2.cpp26
-rw-r--r--src/render/graphicshelpers/graphicshelpergl2_p.h4
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2.cpp44
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_2_p.h4
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3.cpp12
-rw-r--r--src/render/graphicshelpers/graphicshelpergl3_3_p.h4
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4.cpp44
-rw-r--r--src/render/graphicshelpers/graphicshelpergl4_p.h4
-rw-r--r--src/render/graphicshelpers/graphicshelperinterface_p.h7
-rw-r--r--src/render/io/glbuffer.cpp12
-rw-r--r--src/render/io/glbuffer_p.h2
-rw-r--r--src/render/io/qgeometryloaderfactory_p.h1
-rw-r--r--src/render/io/qsceneimporter_p.h3
-rw-r--r--src/render/io/qsceneloader.cpp28
-rw-r--r--src/render/io/qsceneloader.h8
-rw-r--r--src/render/io/qsceneloader_p.h2
-rw-r--r--src/render/io/scene.cpp14
-rw-r--r--src/render/io/scenemanager.cpp65
-rw-r--r--src/render/io/scenemanager_p.h28
-rw-r--r--src/render/jobs/calcboundingvolumejob.cpp188
-rw-r--r--src/render/jobs/computefilteredboundingvolumejob.cpp130
-rw-r--r--src/render/jobs/computefilteredboundingvolumejob_p.h91
-rw-r--r--src/render/jobs/job_common_p.h2
-rw-r--r--src/render/jobs/jobs.pri9
-rw-r--r--src/render/jobs/lightgatherer.cpp9
-rw-r--r--src/render/jobs/lightgatherer_p.h8
-rw-r--r--src/render/jobs/loadscenejob.cpp68
-rw-r--r--src/render/jobs/loadscenejob_p.h2
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp75
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h10
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp57
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h17
-rw-r--r--src/render/jobs/renderviewjobutils.cpp33
-rw-r--r--src/render/jobs/renderviewjobutils_p.h2
-rw-r--r--src/render/jobs/sendbuffercapturejob.cpp89
-rw-r--r--src/render/jobs/sendbuffercapturejob_p.h99
-rw-r--r--src/render/jobs/updatelevelofdetailjob.cpp8
-rw-r--r--src/render/lights/environmentlight.cpp (renamed from src/render/framegraph/qsortcriterion.cpp)44
-rw-r--r--src/render/lights/environmentlight_p.h (renamed from src/render/framegraph/qsortcriterion.h)56
-rw-r--r--src/render/lights/lights.pri5
-rw-r--r--src/render/lights/qenvironmentlight.cpp189
-rw-r--r--src/render/lights/qenvironmentlight.h86
-rw-r--r--src/render/lights/qenvironmentlight_p.h85
-rw-r--r--src/render/materialsystem/qeffect.cpp60
-rw-r--r--src/render/materialsystem/qmaterial.cpp102
-rw-r--r--src/render/materialsystem/qparameter.cpp127
-rw-r--r--src/render/materialsystem/qrenderpass.cpp91
-rw-r--r--src/render/materialsystem/qshaderdata_p.h7
-rw-r--r--src/render/materialsystem/qshaderprogram.cpp79
-rw-r--r--src/render/materialsystem/qshaderprogram.h15
-rw-r--r--src/render/materialsystem/qshaderprogram_p.h8
-rw-r--r--src/render/materialsystem/qtechnique.cpp128
-rw-r--r--src/render/materialsystem/shader.cpp63
-rw-r--r--src/render/materialsystem/shader_p.h18
-rw-r--r--src/render/materialsystem/shadercache.cpp5
-rw-r--r--src/render/materialsystem/shadercache_p.h1
-rw-r--r--src/render/picking/objectpicker.cpp13
-rw-r--r--src/render/picking/pickeventfilter.cpp21
-rw-r--r--src/render/picking/pickeventfilter_p.h7
-rw-r--r--src/render/picking/qobjectpicker.cpp44
-rw-r--r--src/render/picking/qpickevent.cpp32
-rw-r--r--src/render/picking/qpickevent_p.h11
-rw-r--r--src/render/picking/qpicktriangleevent.cpp52
-rw-r--r--src/render/picking/qpicktriangleevent.h5
-rw-r--r--src/render/raycasting/qabstractcollisionqueryservice.cpp6
-rw-r--r--src/render/raycasting/qabstractcollisionqueryservice_p.h4
-rw-r--r--src/render/raycasting/qboundingvolume_p.h3
-rw-r--r--src/render/raycasting/qcollisionqueryresult.cpp5
-rw-r--r--src/render/raycasting/qcollisionqueryresult_p.h21
-rw-r--r--src/render/raycasting/qraycastingservice.cpp8
-rw-r--r--src/render/render.pro3
-rw-r--r--src/render/renderlogging.cpp22
-rw-r--r--src/render/texture/apitexturemanager_p.h17
-rw-r--r--src/render/texture/gltexture.cpp59
-rw-r--r--src/render/texture/gltexture_p.h15
-rw-r--r--src/render/texture/qabstracttexture.cpp5
-rw-r--r--src/render/texture/qabstracttexture_p.h4
-rw-r--r--src/render/texture/qpaintedtextureimage.cpp44
-rw-r--r--src/render/texture/qtexture.cpp202
-rw-r--r--src/render/texture/qtexture_p.h28
-rw-r--r--src/render/texture/texture.cpp28
-rw-r--r--src/render/texture/texture_p.h7
-rw-r--r--src/render/texture/textureimage.cpp2
188 files changed, 6042 insertions, 1151 deletions
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index 8b17cbf45..2f7545454 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -56,6 +56,8 @@
#include <Qt3DCore/qnodeid.h>
#include <QtGui/qsurfaceformat.h>
+#include <QtGui/qopenglcontext.h>
+
QT_BEGIN_NAMESPACE
class QSurface;
@@ -137,6 +139,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;
@@ -153,6 +156,7 @@ public:
virtual void setOffscreenSurfaceHelper(OffscreenSurfaceHelper *helper) = 0;
virtual QSurfaceFormat format() = 0;
+ virtual QOpenGLContext *shareContext() const = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractRenderer::BackendNodeDirtySet)
diff --git a/src/render/backend/attachmentpack.cpp b/src/render/backend/attachmentpack.cpp
index d2bb5ee9a..6dee7587b 100644
--- a/src/render/backend/attachmentpack.cpp
+++ b/src/render/backend/attachmentpack.cpp
@@ -60,7 +60,7 @@ AttachmentPack::AttachmentPack(const RenderTargetSelector *selector, const Rende
for (Qt3DCore::QNodeId outputId : outputIds) {
const RenderTargetOutput *output = attachmentManager->lookupResource(outputId);
if (output)
- m_attachments.append(output->attachment());
+ m_attachments.append(*output->attachment());
}
// Create actual DrawBuffers list that is used for glDrawBuffers
diff --git a/src/render/backend/backendnode.cpp b/src/render/backend/backendnode.cpp
index 7054db6a4..0dc8da237 100644
--- a/src/render/backend/backendnode.cpp
+++ b/src/render/backend/backendnode.cpp
@@ -37,7 +37,10 @@
**
****************************************************************************/
-#include "backendnode_p.h"
+#include <private/backendnode_p.h>
+#include <private/renderer_p.h>
+#include <private/resourceaccessor_p.h>
+#include <private/nodemanagers_p.h>
QT_BEGIN_NAMESPACE
@@ -61,12 +64,23 @@ void BackendNode::setRenderer(AbstractRenderer *renderer)
m_renderer = renderer;
}
+AbstractRenderer *BackendNode::renderer() const
+{
+ return m_renderer;
+}
+
void BackendNode::markDirty(AbstractRenderer::BackendNodeDirtySet changes)
{
Q_ASSERT(m_renderer);
m_renderer->markDirty(changes, this);
}
+QSharedPointer<RenderBackendResourceAccessor> BackendNode::resourceAccessor()
+{
+ Render::Renderer *r = static_cast<Render::Renderer *>(renderer());
+ return r->nodeManagers()->resourceAccessor();
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/backendnode_p.h b/src/render/backend/backendnode_p.h
index 5688c2412..8db68b11d 100644
--- a/src/render/backend/backendnode_p.h
+++ b/src/render/backend/backendnode_p.h
@@ -54,6 +54,7 @@
#include <Qt3DRender/qt3drender_global.h>
#include <Qt3DCore/qbackendnode.h>
#include <Qt3DRender/private/abstractrenderer_p.h>
+#include <private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -61,13 +62,18 @@ namespace Qt3DRender {
namespace Render {
-class Q_AUTOTEST_EXPORT BackendNode : public Qt3DCore::QBackendNode
+class RenderBackendResourceAccessor;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT BackendNode : public Qt3DCore::QBackendNode
{
public:
BackendNode(Qt3DCore::QBackendNode::Mode mode = ReadOnly);
~BackendNode();
void setRenderer(AbstractRenderer *renderer);
+ AbstractRenderer *renderer() const;
+
+ QSharedPointer<RenderBackendResourceAccessor> resourceAccessor();
protected:
void markDirty(AbstractRenderer::BackendNodeDirtySet changes);
diff --git a/src/render/backend/bufferutils_p.h b/src/render/backend/bufferutils_p.h
new file mode 100644
index 000000000..2bb35fac6
--- /dev/null
+++ b/src/render/backend/bufferutils_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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_RENDER_BUFFERUTILS_P_H
+#define QT3DRENDER_RENDER_BUFFERUTILS_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/QAttribute>
+#include <QByteArray>
+
+QT_BEGIN_NAMESPACE
+
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GeometryRenderer;
+class NodeManagers;
+class Attribute;
+class Buffer;
+
+struct BufferInfo
+{
+ BufferInfo()
+ : type(QAttribute::VertexBaseType::Float)
+ , dataSize(0)
+ , count(0)
+ , byteStride(0)
+ , byteOffset(0)
+ {}
+
+ QByteArray data;
+ QAttribute::VertexBaseType type;
+ uint dataSize;
+ uint count;
+ uint byteStride;
+ uint byteOffset;
+};
+
+
+namespace BufferTypeInfo {
+
+ 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)
+ {
+ return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+ }
+
+} // namespace BufferTypeInfo
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_BUFFERUTILS_P_H
diff --git a/src/render/backend/buffervisitor_p.h b/src/render/backend/buffervisitor_p.h
new file mode 100644
index 000000000..7149e21ae
--- /dev/null
+++ b/src/render/backend/buffervisitor_p.h
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** 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_BUFFERVISITOR_P_H
+#define QT3DRENDER_RENDER_BUFFERVISITOR_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 <Qt3DRender/QAttribute>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/bufferutils_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
+#include <Qt3DRender/private/geometry_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DCore {
+class QEntity;
+}
+
+namespace Qt3DRender {
+namespace Render {
+
+
+template <typename ValueType, QAttribute::VertexBaseType VertexBaseType, uint dataSize>
+class Q_AUTOTEST_EXPORT BufferVisitor
+{
+public:
+ explicit BufferVisitor(NodeManagers *manager)
+ : m_manager(manager)
+ {
+ }
+ virtual ~BufferVisitor() { }
+
+ virtual void visit(uint ndx, ValueType x) {
+ Q_UNUSED(ndx); Q_UNUSED(x);
+ }
+ virtual void visit(uint ndx, ValueType x, ValueType y) {
+ Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y);
+ }
+ virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z) {
+ Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z);
+ }
+ virtual void visit(uint ndx, ValueType x, ValueType y, ValueType z, ValueType w) {
+ Q_UNUSED(ndx); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(z); Q_UNUSED(w);
+ }
+
+ bool apply(const GeometryRenderer *renderer, const QString &attributeName)
+ {
+ if (renderer == nullptr || renderer->instanceCount() != 1) {
+ return false;
+ }
+
+ Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+
+ if (!geom)
+ return false;
+
+ 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() == attributeName
+ || (attributeName == QStringLiteral("default")
+ && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) {
+ break;
+ }
+ }
+ attribute = nullptr;
+ }
+
+ if (!attribute)
+ return false;
+
+ return apply(attribute);
+ }
+
+ bool apply(Qt3DRender::Render::Attribute *attribute)
+ {
+ if (attribute->vertexBaseType() != VertexBaseType)
+ return false;
+ if (attribute->vertexSize() < dataSize)
+ return false;
+
+ auto data = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId())->data();
+ auto buffer = BufferTypeInfo::castToType<VertexBaseType>(data, attribute->byteOffset());
+ switch (dataSize) {
+ case 1: traverseCoordinates1(buffer, attribute->byteStride(), attribute->count()); break;
+ case 2: traverseCoordinates2(buffer, attribute->byteStride(), attribute->count()); break;
+ case 3: traverseCoordinates3(buffer, attribute->byteStride(), attribute->count()); break;
+ case 4: traverseCoordinates4(buffer, attribute->byteStride(), attribute->count()); break;
+ default: Q_UNREACHABLE();
+ }
+
+ return true;
+ }
+
+protected:
+
+ template <typename Coordinate>
+ void traverseCoordinates1(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0]);
+ coordinates += stride;
+ }
+ }
+
+ template <typename Coordinate>
+ void traverseCoordinates2(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0], coordinates[1]);
+ coordinates += stride;
+ }
+ }
+
+ template <typename Coordinate>
+ void traverseCoordinates3(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0], coordinates[1], coordinates[2]);
+ coordinates += stride;
+ }
+ }
+
+ template <typename Coordinate>
+ void traverseCoordinates4(Coordinate *coordinates,
+ const uint byteStride,
+ const uint count)
+ {
+ const uint stride = byteStride / sizeof(Coordinate);
+ for (uint ndx = 0; ndx < count; ++ndx) {
+ visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
+ coordinates += stride;
+ }
+ }
+
+ NodeManagers *m_manager;
+};
+
+typedef BufferVisitor<float, QAttribute::Float, 3> Buffer3fVisitor;
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_RENDER_BUFFERVISITOR_P_H
diff --git a/src/render/backend/cameralens.cpp b/src/render/backend/cameralens.cpp
index e60a32422..ef71507eb 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,35 @@ 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)
{
}
@@ -67,11 +100,52 @@ 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);
const auto &data = typedChange->data;
m_projection = data.projectionMatrix;
+ 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)
@@ -79,6 +153,11 @@ void CameraLens::setProjection(const QMatrix4x4 &projection)
m_projection = projection;
}
+void CameraLens::setExposure(float exposure)
+{
+ m_exposure = exposure;
+}
+
void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
switch (e->type()) {
@@ -88,18 +167,63 @@ void CameraLens::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
if (propertyChange->propertyName() == QByteArrayLiteral("projectionMatrix")) {
QMatrix4x4 projectionMatrix = propertyChange->value().value<QMatrix4x4>();
m_projection = projectionMatrix;
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("exposure")) {
+ setExposure(propertyChange->value().toFloat());
}
markDirty(AbstractRenderer::AllDirty);
}
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);
}
+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 e5268da53..4bf147f48 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>
@@ -62,6 +63,21 @@ namespace Qt3DRender {
namespace Render {
class CameraManager;
+class Sphere;
+
+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 CameraLens : public BackendNode
{
@@ -70,15 +86,27 @@ public:
~CameraLens();
void cleanup();
+ void setRenderAspect(QRenderAspect* renderAspect);
+
void setProjection(const QMatrix4x4 &projection);
inline QMatrix4x4 projection() const { return m_projection; }
+ void setExposure(float exposure);
+ 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);
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;
};
} // namespace Render
diff --git a/src/render/backend/commandexecuter.cpp b/src/render/backend/commandexecuter.cpp
index 2f13b27ea..84bf7455a 100644
--- a/src/render/backend/commandexecuter.cpp
+++ b/src/render/backend/commandexecuter.cpp
@@ -34,9 +34,8 @@
**
****************************************************************************/
-#ifdef QT3D_JOBS_RUN_STATS
-
#include "commandexecuter_p.h"
+
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DCore/private/qabstractaspect_p.h>
#include <Qt3DCore/qbackendnode.h>
@@ -388,5 +387,3 @@ QVariant CommandExecuter::executeCommand(const QStringList &args)
} // Qt3DRenderer
QT_END_NAMESPACE
-
-#endif
diff --git a/src/render/backend/commandexecuter_p.h b/src/render/backend/commandexecuter_p.h
index 8135d97d9..896164543 100644
--- a/src/render/backend/commandexecuter_p.h
+++ b/src/render/backend/commandexecuter_p.h
@@ -48,8 +48,6 @@
// We mean it.
//
-#ifdef QT3D_JOBS_RUN_STATS
-
#include <QVector>
#include <QVariant>
@@ -92,6 +90,4 @@ private:
QT_END_NAMESPACE
-#endif // QT3D_JOBS_RUN_STATS
-
#endif // QT3DRENDER_DEBUG_COMMANDEXECUTER_H
diff --git a/src/render/backend/commandthread.cpp b/src/render/backend/commandthread.cpp
new file mode 100644
index 000000000..f91cff017
--- /dev/null
+++ b/src/render/backend/commandthread.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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 "commandthread_p.h"
+#include <QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+CommandThread::CommandThread(Renderer *renderer)
+ : QThread()
+ , m_renderer(renderer)
+ , m_waitForStartSemaphore(0)
+ , m_initializedSemaphore(0)
+{
+}
+
+CommandThread::~CommandThread()
+{
+}
+
+// Called by RenderThread or MainThread (Scene3d)
+void CommandThread::initialize(QOpenGLContext *mainContext)
+{
+ // Start the thread
+ start();
+
+ // Wait for thread to be started
+ m_waitForStartSemaphore.acquire();
+
+ m_mainContext = mainContext;
+ Q_ASSERT(m_mainContext);
+
+ // Allow thread to proceed
+ m_initializedSemaphore.release();
+}
+
+// Called by RenderThread of MainThread (Scene3D)
+void CommandThread::shutdown()
+{
+ // Tell thread to exit event loop
+ QThread::quit();
+
+ // Wait for thread to exit
+ wait();
+
+ // Reset semaphores (in case we ever want to restart)
+ m_waitForStartSemaphore.release(m_waitForStartSemaphore.available());
+ m_initializedSemaphore.release(m_initializedSemaphore.available());
+ m_localContext.reset();
+}
+
+// Any thread can call this, this is a blocking command
+void CommandThread::executeCommand(Command *command)
+{
+ if (!isRunning())
+ return;
+ QMetaObject::invokeMethod(this,
+ "executeCommandInternal",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(Command *, command));
+}
+
+void CommandThread::run()
+{
+ // Allow initialize to proceed
+ m_waitForStartSemaphore.release();
+
+ // Wait for initialize to be completed
+ m_initializedSemaphore.acquire();
+
+ // Initialize shared context and resources for the thread
+ m_localContext.reset(new QOpenGLContext());
+ m_localContext->setShareContext(m_mainContext);
+
+ // Launch exec loop
+ QThread::exec();
+}
+
+// Executed in the Command Thread
+void CommandThread::executeCommandInternal(Command *command)
+{
+ command->execute(m_renderer, m_localContext.data());
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/commandthread_p.h b/src/render/backend/commandthread_p.h
new file mode 100644
index 000000000..1955d13ac
--- /dev/null
+++ b/src/render/backend/commandthread_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_COMMANDTHREAD_P_H
+#define QT3DRENDER_RENDER_COMMANDTHREAD_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 <QtCore/QThread>
+#include <QtCore/QSemaphore>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Renderer;
+
+class Command
+{
+public:
+ virtual void execute(Renderer *renderer, QOpenGLContext *localContext) = 0;
+};
+
+class CommandThread : public QThread
+{
+ Q_OBJECT
+public:
+ explicit CommandThread(Renderer *renderer);
+ ~CommandThread();
+
+ Render::Renderer* renderer() const { return m_renderer; }
+
+ void initialize(QOpenGLContext *mainContext);
+ void shutdown();
+
+ void executeCommand(Command *command);
+
+private:
+ void run() Q_DECL_OVERRIDE;
+ Q_INVOKABLE void executeCommandInternal(Command *command);
+
+private:
+ Renderer* m_renderer;
+ QSemaphore m_waitForStartSemaphore;
+ QSemaphore m_initializedSemaphore;
+ QOpenGLContext *m_mainContext;
+ QScopedPointer<QOpenGLContext> m_localContext;
+};
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_COMMANDTHREAD_P_H
diff --git a/src/render/backend/entity.cpp b/src/render/backend/entity.cpp
index 42233c85a..898c1e36e 100644
--- a/src/render/backend/entity.cpp
+++ b/src/render/backend/entity.cpp
@@ -41,6 +41,7 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/qabstractlight.h>
+#include <Qt3DRender/qenvironmentlight.h>
#include <Qt3DRender/qlayer.h>
#include <Qt3DRender/qlevelofdetail.h>
#include <Qt3DRender/qmaterial.h>
@@ -118,6 +119,7 @@ void Entity::cleanup()
m_levelOfDetailComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
+ m_environmentLightComponents.clear();
m_localBoundingVolume.reset();
m_worldBoundingVolume.reset();
m_worldBoundingVolumeWithChildren.reset();
@@ -174,6 +176,7 @@ void Entity::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
m_levelOfDetailComponents.clear();
m_shaderDataComponents.clear();
m_lightComponents.clear();
+ m_environmentLightComponents.clear();
m_localBoundingVolume.reset(new Sphere(peerId()));
m_worldBoundingVolume.reset(new Sphere(peerId()));
m_worldBoundingVolumeWithChildren.reset(new Sphere(peerId()));
@@ -293,6 +296,8 @@ void Entity::addComponent(Qt3DCore::QComponent *component)
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) {
@@ -326,6 +331,8 @@ void Entity::addComponent(Qt3DCore::QNodeIdTypePair idAndType)
m_materialComponent = id;
} else if (type->inherits(&QAbstractLight::staticMetaObject)) { // QAbstractLight subclasses QShaderData
m_lightComponents.append(id);
+ } else if (type->inherits(&QEnvironmentLight::staticMetaObject)) {
+ m_environmentLightComponents.append(id);
} else if (type->inherits(&QShaderData::staticMetaObject)) {
m_shaderDataComponents.append(id);
} else if (type->inherits(&QGeometryRenderer::staticMetaObject)) {
@@ -363,6 +370,8 @@ void Entity::removeComponent(Qt3DCore::QNodeId nodeId)
// m_boundingVolumeDebugComponent = QNodeId();
} else if (m_lightComponents.contains(nodeId)) {
m_lightComponents.removeAll(nodeId);
+ } else if (m_environmentLightComponents.contains(nodeId)) {
+ m_environmentLightComponents.removeAll(nodeId);
} else if (m_computeComponent == nodeId) {
m_computeComponent = QNodeId();
}
@@ -457,6 +466,16 @@ QVector<HLight> Entity::componentsHandle<Light>() const
}
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);
@@ -534,6 +553,16 @@ QVector<Light *> Entity::renderComponents<Light>() const
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
//{
@@ -581,6 +610,9 @@ QNodeId Entity::componentUuid<ComputeCommand>() const { return m_computeComponen
template<>
QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const { return m_lightComponents; }
+template<>
+QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const { return m_environmentLightComponents; }
+
RenderEntityFunctor::RenderEntityFunctor(AbstractRenderer *renderer, NodeManagers *manager)
: m_nodeManagers(manager)
, m_renderer(renderer)
diff --git a/src/render/backend/entity_p.h b/src/render/backend/entity_p.h
index c86019444..4619314ad 100644
--- a/src/render/backend/entity_p.h
+++ b/src/render/backend/entity_p.h
@@ -190,6 +190,7 @@ private:
QVector<Qt3DCore::QNodeId> m_levelOfDetailComponents;
QVector<Qt3DCore::QNodeId> m_shaderDataComponents;
QVector<Qt3DCore::QNodeId> m_lightComponents;
+ QVector<Qt3DCore::QNodeId> m_environmentLightComponents;
Qt3DCore::QNodeId m_geometryRendererComponent;
Qt3DCore::QNodeId m_objectPickerComponent;
Qt3DCore::QNodeId m_boundingVolumeDebugComponent;
@@ -233,6 +234,9 @@ 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
@@ -246,10 +250,10 @@ template<>
Transform *Entity::renderComponent<Transform>() const;
template<>
-Q_AUTOTEST_EXPORT GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT GeometryRenderer *Entity::renderComponent<GeometryRenderer>() const;
template<>
-Q_AUTOTEST_EXPORT ObjectPicker *Entity::renderComponent<ObjectPicker>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT ObjectPicker *Entity::renderComponent<ObjectPicker>() const;
template<>
QVector<Layer *> Entity::renderComponents<Layer>() const;
@@ -267,6 +271,9 @@ template<>
QVector<Light *> Entity::renderComponents<Light>() const;
template<>
+QVector<EnvironmentLight *> Entity::renderComponents<EnvironmentLight>() const;
+
+template<>
Q_AUTOTEST_EXPORT ComputeCommand *Entity::renderComponent<ComputeCommand>() const;
// UUid
@@ -289,10 +296,10 @@ template<>
Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<ShaderData>() const;
template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<GeometryRenderer>() const;
template<>
-Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ObjectPicker>() const;
+QT3DRENDERSHARED_PRIVATE_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ObjectPicker>() const;
//template<>
//Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<BoundingVolumeDebug>() const;
@@ -303,6 +310,9 @@ Q_AUTOTEST_EXPORT Qt3DCore::QNodeId Entity::componentUuid<ComputeCommand>() cons
template<>
Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<Light>() const;
+template<>
+Q_AUTOTEST_EXPORT QVector<Qt3DCore::QNodeId> Entity::componentsUuid<EnvironmentLight>() const;
+
class RenderEntityFunctor : public Qt3DCore::QBackendNodeMapper
{
public:
diff --git a/src/render/backend/frameprofiler_p.h b/src/render/backend/frameprofiler_p.h
index 2412a8053..9e7bcd038 100644
--- a/src/render/backend/frameprofiler_p.h
+++ b/src/render/backend/frameprofiler_p.h
@@ -69,7 +69,7 @@ enum RecordingType
RenderTargetUpdate
};
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
class FrameTimeRecorder
{
@@ -218,33 +218,35 @@ public:
explicit GLTimeRecorder(RecordingType type)
: m_type(type)
{
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
frameProfiler.startRecordEvent();
#endif
}
~GLTimeRecorder()
{
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
frameProfiler.recordEvent(m_type);
+#else
+ Q_UNUSED(m_type);
#endif
}
static void writeResults()
{
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
frameProfiler.writeResults();
#endif
}
private:
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
static FrameProfiler frameProfiler;
#endif
RecordingType m_type;
};
-#ifdef QT3D_JOBS_RUN_STATS
+#ifdef QT3D_OPENGL_RUN_STATS
FrameProfiler GLTimeRecorder::frameProfiler;
#endif
diff --git a/src/render/backend/handle_types_p.h b/src/render/backend/handle_types_p.h
index c8c73b749..352519e75 100644
--- a/src/render/backend/handle_types_p.h
+++ b/src/render/backend/handle_types_p.h
@@ -90,6 +90,7 @@ class ObjectPicker;
class BoundingVolumeDebug;
class OpenGLVertexArrayObject;
class Light;
+class EnvironmentLight;
class ComputeCommand;
class GLBuffer;
class RenderStateNode;
@@ -122,6 +123,7 @@ typedef Qt3DCore::QHandle<GeometryRenderer, 16> HGeometryRenderer;
typedef Qt3DCore::QHandle<ObjectPicker, 16> HObjectPicker;
typedef Qt3DCore::QHandle<BoundingVolumeDebug, 16> HBoundingVolumeDebug;
typedef Qt3DCore::QHandle<Light, 16> HLight;
+typedef Qt3DCore::QHandle<EnvironmentLight, 16> HEnvironmentLight;
typedef Qt3DCore::QHandle<ComputeCommand, 16> HComputeCommand;
typedef Qt3DCore::QHandle<GLBuffer, 16> HGLBuffer;
typedef Qt3DCore::QHandle<RenderStateNode, 16> HRenderState;
diff --git a/src/render/backend/levelofdetail.cpp b/src/render/backend/levelofdetail.cpp
index 474133d1c..157bfc004 100644
--- a/src/render/backend/levelofdetail.cpp
+++ b/src/render/backend/levelofdetail.cpp
@@ -39,11 +39,9 @@
#include "levelofdetail_p.h"
#include <Qt3DRender/QLevelOfDetail>
-#include <Qt3DRender/QBoundingSphere>
#include <Qt3DRender/private/qlevelofdetail_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
#include <QVariant>
QT_BEGIN_NAMESPACE
@@ -56,8 +54,8 @@ namespace Render {
LevelOfDetail::LevelOfDetail()
: BackendNode(BackendNode::ReadWrite)
, m_currentIndex(0)
- , m_thresholdType(QLevelOfDetail::DistanceToCamera)
- , m_radius(1.f)
+ , m_thresholdType(QLevelOfDetail::DistanceToCameraThreshold)
+ , m_volumeOverride()
{
}
@@ -74,8 +72,7 @@ void LevelOfDetail::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
m_currentIndex = data.currentIndex;
m_thresholdType = data.thresholdType;
m_thresholds = data.thresholds;
- m_radius = data.radius;
- m_center = data.center;
+ m_volumeOverride = data.volumeOverride;
}
void LevelOfDetail::cleanup()
@@ -87,23 +84,16 @@ void LevelOfDetail::sceneChangeEvent(const QSceneChangePtr &e)
{
if (e->type() == PropertyUpdated) {
const QPropertyUpdatedChangePtr &propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex")) {
+ if (propertyChange->propertyName() == QByteArrayLiteral("currentIndex"))
m_currentIndex = propertyChange->value().value<int>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("camera")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("camera"))
m_camera = propertyChange->value().value<Qt3DCore::QNodeId>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("thresholdType"))
m_thresholdType = propertyChange->value().value<QLevelOfDetail::ThresholdType>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds")) {
+ else if (propertyChange->propertyName() == QByteArrayLiteral("thresholds"))
m_thresholds = propertyChange->value().value<QVector<qreal>>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("center")) {
- m_center = propertyChange->value().value<QVector3D>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("radius")) {
- m_radius = propertyChange->value().value<float>();
- } else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride")) {
- auto volumeOverride = propertyChange->value().value<Qt3DRender::QBoundingSphere*>();
- m_center = volumeOverride ? volumeOverride->center() : QVector3D();
- m_radius = volumeOverride ? volumeOverride->radius() : -1.f;
- }
+ else if (propertyChange->propertyName() == QByteArrayLiteral("volumeOverride"))
+ m_volumeOverride = propertyChange->value().value<Qt3DRender::QLevelOfDetailBoundingSphere>();
}
markDirty(AbstractRenderer::GeometryDirty);
@@ -119,7 +109,6 @@ void LevelOfDetail::setCurrentIndex(int currentIndex)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("currentIndex");
e->setValue(m_currentIndex);
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
}
diff --git a/src/render/backend/levelofdetail_p.h b/src/render/backend/levelofdetail_p.h
index 83809a631..05f5686bb 100644
--- a/src/render/backend/levelofdetail_p.h
+++ b/src/render/backend/levelofdetail_p.h
@@ -79,8 +79,9 @@ public:
int currentIndex() const { return m_currentIndex; }
QLevelOfDetail::ThresholdType thresholdType() const { return m_thresholdType; }
QVector<qreal> thresholds() const { return m_thresholds; }
- float radius() const { return m_radius; }
- QVector3D center() const { return m_center; }
+ float radius() const { return m_volumeOverride.radius(); }
+ QVector3D center() const { return m_volumeOverride.center(); }
+ bool hasBoundingVolumeOverride() const { return !m_volumeOverride.isEmpty(); }
void setCurrentIndex(int currentIndex);
@@ -90,8 +91,7 @@ private:
int m_currentIndex;
QLevelOfDetail::ThresholdType m_thresholdType;
QVector<qreal> m_thresholds;
- float m_radius;
- QVector3D m_center;
+ QLevelOfDetailBoundingSphere m_volumeOverride;
};
} // namespace Render
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h
index ce6767958..1c1a34b83 100644
--- a/src/render/backend/managers_p.h
+++ b/src/render/backend/managers_p.h
@@ -77,6 +77,7 @@
#include <Qt3DRender/private/boundingvolumedebug_p.h>
#include <Qt3DRender/private/openglvertexarrayobject_p.h>
#include <Qt3DRender/private/light_p.h>
+#include <Qt3DRender/private/environmentlight_p.h>
#include <Qt3DRender/private/computecommand_p.h>
QT_BEGIN_NAMESPACE
@@ -260,7 +261,7 @@ public:
class VAOManager : public Qt3DCore::QResourceManager<
OpenGLVertexArrayObject,
- QPair<HGeometry, HShader>,
+ VAOIdentifier,
16,
Qt3DCore::ArrayAllocatingPolicy,
Qt3DCore::NonLockingPolicy>
@@ -381,6 +382,17 @@ public:
LightManager() {}
};
+class EnvironmentLightManager : public Qt3DCore::QResourceManager<
+ EnvironmentLight,
+ Qt3DCore::QNodeId,
+ 16,
+ Qt3DCore::ArrayAllocatingPolicy,
+ Qt3DCore::NonLockingPolicy>
+{
+public:
+ EnvironmentLightManager() {}
+};
+
class ComputeCommandManager : public Qt3DCore::QResourceManager<
ComputeCommand,
Qt3DCore::QNodeId,
@@ -422,6 +434,7 @@ Q_DECLARE_RESOURCE_INFO(Qt3DRender::Render::BoundingVolumeDebug, Q_REQUIRES_CLEA
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)
QT_END_NAMESPACE
diff --git a/src/render/backend/nodemanagers.cpp b/src/render/backend/nodemanagers.cpp
index d83623ce2..2647bbb1a 100644
--- a/src/render/backend/nodemanagers.cpp
+++ b/src/render/backend/nodemanagers.cpp
@@ -46,6 +46,7 @@
#include <Qt3DRender/private/texturedatamanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
+#include <private/resourceaccessor_p.h>
#include <QOpenGLVertexArrayObject>
@@ -88,8 +89,10 @@ NodeManagers::NodeManagers()
, m_objectPickerManager(new ObjectPickerManager())
// , m_boundingVolumeDebugManager(new BoundingVolumeDebugManager())
, m_lightManager(new LightManager())
+ , m_environmentLightManager(new EnvironmentLightManager())
, m_computeJobManager(new ComputeCommandManager())
, m_renderStateManager(new RenderStateManager())
+ , m_resourceAccessor(new ResourceAccessor(this))
{
}
@@ -126,11 +129,17 @@ NodeManagers::~NodeManagers()
delete m_objectPickerManager;
// delete m_boundingVolumeDebugManager;
delete m_lightManager;
+ delete m_environmentLightManager;
delete m_computeJobManager;
delete m_renderStateManager;
delete m_renderNodesManager;
}
+QSharedPointer<ResourceAccessor> NodeManagers::resourceAccessor()
+{
+ return m_resourceAccessor;
+}
+
template<>
CameraManager *NodeManagers::manager<CameraLens>() const Q_DECL_NOTHROW
{
@@ -312,6 +321,12 @@ LightManager *NodeManagers::manager<Light>() const Q_DECL_NOTHROW
}
template<>
+EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const Q_DECL_NOTHROW
+{
+ return m_environmentLightManager;
+}
+
+template<>
ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const Q_DECL_NOTHROW
{
return m_computeJobManager;
diff --git a/src/render/backend/nodemanagers_p.h b/src/render/backend/nodemanagers_p.h
index b1ea2a0de..9e913eec4 100644
--- a/src/render/backend/nodemanagers_p.h
+++ b/src/render/backend/nodemanagers_p.h
@@ -96,6 +96,7 @@ class TextureImageDataManager;
class LayerManager;
class LevelOfDetailManager;
class LightManager;
+class EnvironmentLightManager;
class ComputeCommandManager;
class RenderStateManager;
@@ -127,10 +128,13 @@ class GeometryRenderer;
class ObjectPicker;
//class BoundingVolumeDebug;
class Light;
+class EnvironmentLight;
class ComputeCommand;
class RenderStateNode;
class OpenGLVertexArrayObject;
+class ResourceAccessor;
+
class QT3DRENDERSHARED_PRIVATE_EXPORT NodeManagers
{
public:
@@ -203,9 +207,12 @@ public:
inline ObjectPickerManager *objectPickerManager() const Q_DECL_NOEXCEPT { return m_objectPickerManager; }
// inline BoundingVolumeDebugManager *boundingVolumeDebugManager() const Q_DECL_NOEXCEPT { return m_boundingVolumeDebugManager; }
inline LightManager *lightManager() const Q_DECL_NOEXCEPT { return m_lightManager; }
+ 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; }
+ QSharedPointer<ResourceAccessor> resourceAccessor();
+
private:
CameraManager *m_cameraManager;
EntityManager *m_renderNodesManager;
@@ -239,8 +246,11 @@ private:
ObjectPickerManager *m_objectPickerManager;
// BoundingVolumeDebugManager *m_boundingVolumeDebugManager;
LightManager *m_lightManager;
+ EnvironmentLightManager *m_environmentLightManager;
ComputeCommandManager *m_computeJobManager;
RenderStateManager *m_renderStateManager;
+
+ QSharedPointer<ResourceAccessor> m_resourceAccessor;
};
// Specializations
@@ -336,6 +346,9 @@ template<>
LightManager *NodeManagers::manager<Light>() const Q_DECL_NOEXCEPT;
template<>
+EnvironmentLightManager *NodeManagers::manager<EnvironmentLight>() const Q_DECL_NOEXCEPT;
+
+template<>
QT3DRENDERSHARED_PRIVATE_EXPORT ComputeCommandManager *NodeManagers::manager<ComputeCommand>() const Q_DECL_NOEXCEPT;
template<>
diff --git a/src/render/backend/openglvertexarrayobject.cpp b/src/render/backend/openglvertexarrayobject.cpp
index 6120c7233..eefc208d5 100644
--- a/src/render/backend/openglvertexarrayobject.cpp
+++ b/src/render/backend/openglvertexarrayobject.cpp
@@ -52,15 +52,8 @@ OpenGLVertexArrayObject::OpenGLVertexArrayObject()
: m_ctx(nullptr)
, m_specified(false)
, m_supportsVao(false)
- , m_createdEmulatedVAO(false)
{}
-void OpenGLVertexArrayObject::setGraphicsContext(GraphicsContext *ctx)
-{
- m_ctx = ctx;
- m_supportsVao = m_ctx->supportsVAO();
-}
-
void OpenGLVertexArrayObject::bind()
{
Q_ASSERT(m_ctx);
@@ -75,7 +68,7 @@ void OpenGLVertexArrayObject::bind()
m_ctx->m_currentVAO = this;
// We need to specify array and vertex attributes
- for (const GraphicsContext::VAOVertexAttribute &attr : m_vertexAttributes)
+ for (const GraphicsContext::VAOVertexAttribute &attr : qAsConst(m_vertexAttributes))
m_ctx->enableAttribute(attr);
if (!m_indexAttribute.isNull())
m_ctx->bindGLBuffer(m_ctx->m_renderer->nodeManagers()->glBufferManager()->data(m_indexAttribute),
@@ -92,44 +85,58 @@ void OpenGLVertexArrayObject::release()
m_vao->release();
} else {
if (m_ctx->m_currentVAO == this) {
- for (const GraphicsContext::VAOVertexAttribute &attr : m_vertexAttributes)
+ for (const GraphicsContext::VAOVertexAttribute &attr : qAsConst(m_vertexAttributes))
m_ctx->disableAttribute(attr);
m_ctx->m_currentVAO = nullptr;
}
}
}
-void OpenGLVertexArrayObject::create()
+// called from Render thread
+void OpenGLVertexArrayObject::create(GraphicsContext *ctx, const VAOIdentifier &key)
{
- Q_ASSERT(m_ctx);
- if (m_supportsVao) {
- Q_ASSERT(!m_vao.isNull());
- m_vao->create();
- } else {
- m_createdEmulatedVAO = true;
- }
+ QMutexLocker lock(&m_mutex);
+
+ Q_ASSERT(!m_ctx && !m_vao);
+
+ m_ctx = ctx;
+ m_supportsVao = m_ctx->supportsVAO();
+ m_vao.reset(m_supportsVao ? new QOpenGLVertexArrayObject() : nullptr);
+ m_vao->create();
+ m_owners = key;
}
+// called from Render thread
void OpenGLVertexArrayObject::destroy()
{
+ QMutexLocker locker(&m_mutex);
+
Q_ASSERT(m_ctx);
- if (m_supportsVao) {
- Q_ASSERT(!m_vao.isNull());
- m_vao->destroy();
- }
+ cleanup();
+}
+
+void OpenGLVertexArrayObject::cleanup()
+{
+ m_vao.reset();
+ m_ctx = nullptr;
m_specified = false;
+ m_supportsVao = false;
m_indexAttribute = GraphicsContext::VAOIndexAttribute();
m_vertexAttributes.clear();
}
-bool OpenGLVertexArrayObject::isCreated() const
+// called from job
+bool OpenGLVertexArrayObject::isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr)
{
- if (m_supportsVao) {
- Q_ASSERT(!m_vao.isNull());
- return m_vao->isCreated();
- } else {
- return m_createdEmulatedVAO;
- }
+ QMutexLocker lock(&m_mutex);
+
+ if (!m_ctx)
+ return false;
+
+ const bool geometryExists = (geomMgr->data(m_owners.first) != nullptr);
+ const bool shaderExists = (shaderMgr->data(m_owners.second) != nullptr);
+
+ return !geometryExists || !shaderExists;
}
void OpenGLVertexArrayObject::saveVertexAttribute(const GraphicsContext::VAOVertexAttribute &attr)
diff --git a/src/render/backend/openglvertexarrayobject_p.h b/src/render/backend/openglvertexarrayobject_p.h
index 4f21497f0..a564175f6 100644
--- a/src/render/backend/openglvertexarrayobject_p.h
+++ b/src/render/backend/openglvertexarrayobject_p.h
@@ -59,31 +59,39 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
+class GeometryManager;
+class ShaderManager;
+
+typedef QPair<HGeometry, HShader> VAOIdentifier;
+
class OpenGLVertexArrayObject
{
public:
OpenGLVertexArrayObject();
- void setGraphicsContext(GraphicsContext *ctx);
void bind();
void release();
- void create();
+
+ void create(GraphicsContext *ctx, const VAOIdentifier &key);
void destroy();
- bool isCreated() const;
+ void cleanup();
+
+ bool isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr);
QOpenGLVertexArrayObject *vao() { return m_vao.data(); }
const QOpenGLVertexArrayObject *vao() const { return m_vao.data(); }
- void setVao(QOpenGLVertexArrayObject *vao) { m_vao.reset(vao); }
void setSpecified(bool b) { m_specified = b; }
bool isSpecified() const { return m_specified; }
+
private:
+ QMutex m_mutex;
GraphicsContext *m_ctx;
QScopedPointer<QOpenGLVertexArrayObject> m_vao;
bool m_specified;
bool m_supportsVao;
- bool m_createdEmulatedVAO;
+ VAOIdentifier m_owners;
friend class GraphicsContext;
diff --git a/src/render/backend/platformsurfacefilter.cpp b/src/render/backend/platformsurfacefilter.cpp
index 891e30c44..7458f607d 100644
--- a/src/render/backend/platformsurfacefilter.cpp
+++ b/src/render/backend/platformsurfacefilter.cpp
@@ -107,6 +107,10 @@ bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e)
// If we remove it, the call to isSurfaceValid will
// implicitely return false
PlatformSurfaceFilter::m_surfacesValidity.remove(m_surface);
+ if (m_obj) {
+ m_obj->removeEventFilter(this);
+ m_obj = nullptr;
+ }
break;
}
diff --git a/src/render/backend/platformsurfacefilter_p.h b/src/render/backend/platformsurfacefilter_p.h
index ec10327fe..dbdc07b01 100644
--- a/src/render/backend/platformsurfacefilter_p.h
+++ b/src/render/backend/platformsurfacefilter_p.h
@@ -51,6 +51,8 @@
// We mean it.
//
+#include <private/qt3drender_global_p.h>
+
#include <QtCore/qobject.h>
#include <QtGui/qsurface.h>
#include <QSemaphore>
@@ -106,7 +108,7 @@ private:
void markSurfaceAsValid();
};
-class SurfaceLocker
+class QT3DRENDERSHARED_PRIVATE_EXPORT SurfaceLocker
{
public:
explicit SurfaceLocker(QSurface *surface);
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index 93e323caa..5d515a173 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -1,6 +1,3 @@
-#DEFINES += QT3D_RENDER_VIEW_JOB_TIMING
-#DEFINES += QT3D_RENDER_DUMP_BACKEND_NODES
-
INCLUDEPATH += $$PWD
HEADERS += \
@@ -29,6 +26,8 @@ HEADERS += \
$$PWD/triangleboundingvolume_p.h \
$$PWD/openglvertexarrayobject_p.h \
$$PWD/trianglesextractor_p.h \
+ $$PWD/buffervisitor_p.h \
+ $$PWD/bufferutils_p.h \
$$PWD/trianglesvisitor_p.h \
$$PWD/abstractrenderer_p.h \
$$PWD/computecommand_p.h \
@@ -36,12 +35,13 @@ HEADERS += \
$$PWD/stringtoint_p.h \
$$PWD/backendnode_p.h \
$$PWD/rendertargetoutput_p.h \
- $$PWD/commandexecuter_p.h \
$$PWD/uniform_p.h \
$$PWD/shaderparameterpack_p.h \
$$PWD/renderviewbuilder_p.h \
$$PWD/frameprofiler_p.h \
- $$PWD/offscreensurfacehelper_p.h
+ $$PWD/offscreensurfacehelper_p.h \
+ $$PWD/resourceaccessor_p.h \
+ $$PWD/commandthread_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -70,10 +70,18 @@ SOURCES += \
$$PWD/backendnode.cpp \
$$PWD/rendertargetoutput.cpp \
$$PWD/attachmentpack.cpp \
- $$PWD/commandexecuter.cpp \
$$PWD/openglvertexarrayobject.cpp \
$$PWD/uniform.cpp \
$$PWD/shaderparameterpack.cpp \
$$PWD/renderviewbuilder.cpp \
- $$PWD/offscreensurfacehelper.cpp
+ $$PWD/offscreensurfacehelper.cpp \
+ $$PWD/resourceaccessor.cpp \
+ $$PWD/commandthread.cpp
+
+include($$OUT_PWD/../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 af73b1ae5..b89f21522 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -68,6 +68,7 @@
#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>
@@ -84,13 +85,19 @@
#include <Qt3DRender/private/loadbufferjob_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
#include <Qt3DRender/private/updatelevelofdetailjob_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
+#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)
#include <Qt3DCore/private/aspectcommanddebugger_p.h>
+#endif
#include <QStack>
#include <QOffscreenSurface>
@@ -146,6 +153,7 @@ namespace Render {
Renderer::Renderer(QRenderAspect::RenderType type)
: m_services(nullptr)
, m_nodesManager(nullptr)
+ , m_renderSceneRoot(nullptr)
, m_defaultRenderStateSet(nullptr)
, m_graphicsContext(nullptr)
, m_renderQueue(new RenderQueue())
@@ -157,6 +165,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_changeSet(0)
, m_lastFrameCorrect(0)
, m_glContext(nullptr)
+ , m_shareContext(nullptr)
, m_pickBoundingVolumeJob(PickBoundingVolumeJobPtr::create())
, m_time(0)
, m_settings(nullptr)
@@ -168,10 +177,12 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_updateWorldBoundingVolumeJob(Render::UpdateWorldBoundingVolumeJobPtr::create())
, m_updateTreeEnabledJob(Render::UpdateTreeEnabledJobPtr::create())
, m_sendRenderCaptureJob(Render::SendRenderCaptureJobPtr::create(this))
+ , m_sendBufferCaptureJob(Render::SendBufferCaptureJobPtr::create())
, m_updateLevelOfDetailJob(Render::UpdateLevelOfDetailJobPtr::create())
, m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create())
, m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create())
, m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering))
+ , m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering))
, m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering))
, m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering))
, m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
@@ -263,16 +274,35 @@ void Renderer::setNodeManagers(NodeManagers *managers)
m_pickBoundingVolumeJob->setManagers(m_nodesManager);
m_updateWorldBoundingVolumeJob->setManager(m_nodesManager->renderNodesManager());
m_sendRenderCaptureJob->setManagers(m_nodesManager);
+ m_sendBufferCaptureJob->setManagers(m_nodesManager);
m_updateLevelOfDetailJob->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;
}
+/*!
+ \internal
+
+ Return context which can be used to share resources safely
+ with qt3d main render context.
+*/
+QOpenGLContext *Renderer::shareContext() const
+{
+ return m_shareContext ? m_shareContext : m_graphicsContext->openGLContext();
+}
+
void Renderer::setOpenGLContext(QOpenGLContext *context)
{
m_glContext = context;
@@ -314,6 +344,10 @@ void Renderer::initialize()
// Context is not owned by us, so we need to know if it gets destroyed
m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
[this] { releaseGraphicsResources(); });
+ m_shareContext = new QOpenGLContext;
+ m_shareContext->setFormat(m_glContext->format());
+ m_shareContext->setShareContext(m_glContext);
+ m_shareContext->create();
}
// Note: we don't have a surface at this point
@@ -358,6 +392,7 @@ void Renderer::shutdown()
// to be ready. The isReadyToSubmit() function checks for a shutdown
// having been requested.
m_submitRenderViewsSemaphore.release(1);
+ m_renderThread->wait();
}
}
@@ -405,6 +440,13 @@ void Renderer::releaseGraphicsResources()
buffer->destroy(m_graphicsContext.data());
}
+ // Do the same thing with VAOs
+ const QVector<HVao> activeVaos = m_nodesManager->vaoManager()->activeHandles();
+ for (const HVao &vaoHandle : activeVaos) {
+ OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle);
+ vao->destroy();
+ }
+
context->doneCurrent();
} else {
qWarning() << "Failed to make context current: OpenGL resources will not be destroyed";
@@ -412,6 +454,8 @@ void Renderer::releaseGraphicsResources()
if (m_ownedContext)
delete context;
+ if (m_shareContext)
+ delete m_shareContext;
m_graphicsContext.reset(nullptr);
qCDebug(Backend) << Q_FUNC_INFO << "Renderer properly shutdown";
@@ -500,17 +544,26 @@ void Renderer::render()
void Renderer::doRender()
{
- bool submissionSucceeded = false;
- bool hasCleanedQueueAndProceeded = false;
Renderer::ViewSubmissionResultData submissionData;
+ bool hasCleanedQueueAndProceeded = false;
bool preprocessingComplete = false;
-
- if (isReadyToSubmit()) {
-
- // Lock the mutex to protect access to m_surface and check if we are still set
- // to the running state and that we have a valid surface on which to draw
- // TO DO: Is that still needed given the surface changes
- QMutexLocker locker(&m_mutex);
+ bool beganDrawing = false;
+ const bool canSubmit = isReadyToSubmit();
+
+ // Lock the mutex to protect access to the renderQueue while we look for its state
+ QMutexLocker locker(&m_renderQueueMutex);
+ const bool queueIsComplete = m_renderQueue->isFrameQueueComplete();
+ const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0;
+
+ // When using synchronous rendering (QtQuick)
+ // We are not sure that the frame queue is actually complete
+ // Since a call to render may not be synched with the completions
+ // of the RenderViewJobs
+ // In such a case we return early, waiting for a next call with
+ // the frame queue complete at this point
+
+ // RenderQueue is complete (but that means it may be of size 0)
+ if (canSubmit && (queueIsComplete && !queueIsEmpty)) {
const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue();
#ifdef QT3D_JOBS_RUN_STATS
@@ -525,8 +578,7 @@ void Renderer::doRender()
submissionStatsPart2.jobId.typeAndInstance[1] = 0;
submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId());
#endif
-
- if (canRender() && (submissionSucceeded = renderViews.size() > 0) == true) {
+ 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;
@@ -548,7 +600,8 @@ void Renderer::doRender()
// Reset state for each draw if we don't have complete control of the context
if (!m_ownedContext)
m_graphicsContext->setCurrentStateSet(nullptr);
- if (m_graphicsContext->beginDrawing(surface)) {
+ beganDrawing = m_graphicsContext->beginDrawing(surface);
+ if (beganDrawing) {
// 1) Execute commands for buffer uploads, texture updates, shader loading first
updateGLResources();
// 2) Update VAO and copy data into commands to allow concurrent submission
@@ -559,6 +612,7 @@ void Renderer::doRender()
}
// 2) Proceed to next frame and start preparing frame n + 1
m_renderQueue->reset();
+ locker.unlock(); // Done protecting RenderQueue
m_vsyncFrameAdvanceService->proceedToNextFrame();
hasCleanedQueueAndProceeded = true;
@@ -602,61 +656,57 @@ void Renderer::doRender()
#endif
}
- // Note: submissionSucceeded is false when
- // * we cannot render because a shutdown has been scheduled
- // * the renderqueue is incomplete (only when rendering with a Scene3D)
- // Otherwise returns true even for cases like
- // * No render view
- // * No surface set
- // * OpenGLContext failed to be set current
- // This behavior is important as we need to
- // call proceedToNextFrame despite rendering errors that aren't fatal
-
// Only reset renderQueue and proceed to next frame if the submission
- // succeeded or it we are using a render thread and that is wasn't performed
+ // succeeded or if we are using a render thread and that is wasn't performed
// already
- // If submissionSucceeded isn't true this implies that something went wrong
+ // If hasCleanedQueueAndProceeded isn't true this implies that something went wrong
// with the rendering and/or the renderqueue is incomplete from some reason
// (in the case of scene3d the render jobs may be taking too long ....)
- if (m_renderThread || submissionSucceeded) {
-
- if (!hasCleanedQueueAndProceeded) {
- // Reset the m_renderQueue so that we won't try to render
- // with a queue used by a previous frame with corrupted content
- // if the current queue was correctly submitted
- m_renderQueue->reset();
-
- // We allow the RenderTickClock service to proceed to the next frame
- // In turn this will allow the aspect manager to request a new set of jobs
- // to be performed for each aspect
- m_vsyncFrameAdvanceService->proceedToNextFrame();
- }
+ // or alternatively it could be complete but empty (RenderQueue of size 0)
+ if (!hasCleanedQueueAndProceeded &&
+ (m_renderThread || queueIsComplete || queueIsEmpty)) {
+ // RenderQueue was full but something bad happened when
+ // trying to render it and therefore proceedToNextFrame was not called
+ // Note: in this case the renderQueue mutex is still locked
+
+ // Reset the m_renderQueue so that we won't try to render
+ // with a queue used by a previous frame with corrupted content
+ // if the current queue was correctly submitted
+ m_renderQueue->reset();
+
+ // We allow the RenderTickClock service to proceed to the next frame
+ // In turn this will allow the aspect manager to request a new set of jobs
+ // to be performed for each aspect
+ m_vsyncFrameAdvanceService->proceedToNextFrame();
+ }
- // Perform the last swapBuffers calls after the proceedToNextFrame
- // as this allows us to gain a bit of time for the preparation of the
- // next frame
+ // Perform the last swapBuffers calls after the proceedToNextFrame
+ // as this allows us to gain a bit of time for the preparation of the
+ // next frame
+ // Finish up with last surface used in the list of RenderViews
+ if (beganDrawing) {
+ SurfaceLocker surfaceLock(submissionData.surface);
// Finish up with last surface used in the list of RenderViews
- if (submissionSucceeded) {
- SurfaceLocker surfaceLock(submissionData.surface);
- // Finish up with last surface used in the list of RenderViews
- m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO() && surfaceLock.isSurfaceValid());
- }
+ m_graphicsContext->endDrawing(submissionData.lastBoundFBOId == m_graphicsContext->defaultFBO() && surfaceLock.isSurfaceValid());
}
}
// Called by RenderViewJobs
+// When the frameQueue is complete and we are using a renderThread
+// we allow the render thread to proceed
void Renderer::enqueueRenderView(Render::RenderView *renderView, int submitOrder)
{
- QMutexLocker locker(&m_mutex); // Prevent out of order execution
+ QMutexLocker locker(&m_renderQueueMutex); // 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
// could be invalid since depending on the order of execution
// the counter could be complete but the renderview not yet added to the
// buffer depending on whichever order the cpu decides to process this
-
- if (m_renderQueue->queueRenderView(renderView, submitOrder)) {
+ const bool isQueueComplete = m_renderQueue->queueRenderView(renderView, submitOrder);
+ locker.unlock(); // We're done protecting the queue at this point
+ if (isQueueComplete) {
if (m_renderThread && m_running.load())
Q_ASSERT(m_submitRenderViewsSemaphore.available() == 0);
m_submitRenderViewsSemaphore.release(1);
@@ -695,16 +745,6 @@ bool Renderer::isReadyToSubmit()
// something to render
// The case of shutdown should have been handled just before
Q_ASSERT(m_renderQueue->isFrameQueueComplete());
- } else {
- // When using synchronous rendering (QtQuick)
- // We are not sure that the frame queue is actually complete
- // Since a call to render may not be synched with the completions
- // of the RenderViewJobs
- // In such a case we return early, waiting for a next call with
- // the frame queue complete at this point
- QMutexLocker locker(&m_mutex);
- if (!m_renderQueue->isFrameQueueComplete())
- return false;
}
return true;
}
@@ -898,6 +938,23 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
}
// Executed in a job
+void Renderer::lookForAbandonedVaos()
+{
+ const QVector<HVao> activeVaos = m_nodesManager->vaoManager()->activeHandles();
+ for (HVao handle : activeVaos) {
+ OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(handle);
+
+ // Make sure to only mark VAOs for deletion that were already created
+ // (ignore those that might be currently under construction in the render thread)
+ if (vao && vao->isAbandoned(m_nodesManager->geometryManager(), m_nodesManager->shaderManager())) {
+ m_abandonedVaosMutex.lock();
+ m_abandonedVaos.push_back(handle);
+ m_abandonedVaosMutex.unlock();
+ }
+ }
+}
+
+// Executed in a job
void Renderer::lookForDirtyBuffers()
{
const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles();
@@ -908,6 +965,17 @@ void Renderer::lookForDirtyBuffers()
}
}
+void Renderer::lookForDownloadableBuffers()
+{
+ m_downloadableBuffers.clear();
+ const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles();
+ for (HBuffer handle : activeBufferHandles) {
+ Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
+ if (buffer->access() & QBuffer::Read)
+ m_downloadableBuffers.push_back(handle);
+ }
+}
+
// Executed in a job
void Renderer::lookForDirtyTextures()
{
@@ -935,6 +1003,8 @@ 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);
+ if (Q_UNLIKELY(shader->hasPendingNotifications()))
+ shader->submitPendingNotifications();
if (shader != nullptr && !shader->isLoaded())
m_dirtyShaders.push_back(shaderHandle);
}
@@ -951,12 +1021,11 @@ void Renderer::updateGLResources()
const QVector<HBuffer> dirtyBufferHandles = std::move(m_dirtyBuffers);
for (HBuffer handle: dirtyBufferHandles) {
Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
- // Perform data upload
// Forces creation if it doesn't exit
if (!m_graphicsContext->hasGLBufferForBuffer(buffer))
m_graphicsContext->glBufferForRenderBuffer(buffer);
- else if (buffer->isDirty()) // Otherwise update the glBuffer
- m_graphicsContext->updateBuffer(buffer);
+ // Update the glBuffer data
+ m_graphicsContext->updateBuffer(buffer);
buffer->unsetDirty();
}
}
@@ -964,10 +1033,11 @@ void Renderer::updateGLResources()
{
Profiling::GLTimeRecorder recorder(Profiling::ShaderUpload);
const QVector<HShader> dirtyShaderHandles = std::move(m_dirtyShaders);
+ ShaderManager *shaderManager = m_nodesManager->shaderManager();
for (HShader handle: dirtyShaderHandles) {
- Shader *shader = m_nodesManager->shaderManager()->data(handle);
+ Shader *shader = shaderManager->data(handle);
// Compile shader
- m_graphicsContext->loadShader(shader);
+ m_graphicsContext->loadShader(shader, shaderManager);
}
}
@@ -990,13 +1060,16 @@ void Renderer::updateGLResources()
// We can really release the texture at this point
m_nodesManager->textureManager()->releaseResource(textureCleanedUpId);
}
-
-
}
// Render Thread
void Renderer::updateTexture(Texture *texture)
{
+ // Check that the current texture images are still in place, if not, do not update
+ const bool isValid = texture->isValid();
+ if (!isValid)
+ return;
+
// For implementing unique, non-shared, non-cached textures.
// for now, every texture is shared by default
@@ -1065,10 +1138,14 @@ void Renderer::updateTexture(Texture *texture)
!glTextureManager->setParameters(glTexture, texture->parameters()))
qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setParameters failed, should be non-shared";
- if (dirtyFlags.testFlag(Texture::DirtyGenerators) &&
+ if (dirtyFlags.testFlag(Texture::DirtyImageGenerators) &&
!glTextureManager->setImages(glTexture, texture->textureImages()))
qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared";
+ if (dirtyFlags.testFlag(Texture::DirtyDataGenerator) &&
+ !glTextureManager->setGenerator(glTexture, texture->dataGenerator()))
+ qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerator failed, should be non-shared";
+
// Unset the dirty flag on the texture
texture->unsetDirty();
}
@@ -1083,6 +1160,17 @@ void Renderer::cleanupTexture(const Texture *texture)
glTextureManager->abandon(glTexture, texture);
}
+void Renderer::downloadGLBuffers()
+{
+ lookForDownloadableBuffers();
+ const QVector<HBuffer> downloadableHandles = std::move(m_downloadableBuffers);
+ for (HBuffer handle : downloadableHandles) {
+ Buffer *buffer = m_nodesManager->bufferManager()->data(handle);
+ QByteArray content = m_graphicsContext->downloadBufferContent(buffer);
+ m_sendBufferCaptureJob->addRequest(QPair<Buffer*, QByteArray>(buffer, content));
+ }
+}
+
// Happens in RenderThread context when all RenderViewJobs are done
// Returns the id of the last bound FBO
@@ -1221,6 +1309,9 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
addRenderCaptureSendRequest(renderView->renderCaptureNodeId());
}
+ if (renderView->isDownloadBuffersEnable())
+ downloadGLBuffers();
+
frameElapsed = timer.elapsed() - frameElapsed;
qCDebug(Rendering) << Q_FUNC_INFO << "Submitted Renderview " << i + 1 << "/" << renderViewsCount << "in " << frameElapsed << "ms";
frameElapsed = timer.elapsed();
@@ -1311,6 +1402,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_pickBoundingVolumeJob->setFrameGraphRoot(frameGraphRoot());
m_pickBoundingVolumeJob->setRenderSettings(settings());
m_pickBoundingVolumeJob->setMouseEvents(pendingPickingEvents());
+ m_pickBoundingVolumeJob->setKeyEvents(pendingKeyEvents());
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
// Set dependencies of resource gatherer
@@ -1331,25 +1423,36 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_cleanupJob);
renderBinJobs.push_back(m_sendRenderCaptureJob);
+ renderBinJobs.push_back(m_sendBufferCaptureJob);
renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
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);
- // Traverse the current framegraph. For each leaf node create a
- // RenderView and set its configuration then create a job to
- // populate the RenderView with a set of RenderCommands that get
- // their details from the RenderNodes that are visible to the
- // Camera selected by the framegraph configuration
- FrameGraphVisitor visitor(this, m_nodesManager->frameGraphManager());
- visitor.traverse(frameGraphRoot(), &renderBinJobs);
+ QMutexLocker lock(&m_renderQueueMutex);
+ 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
+ // populate the RenderView with a set of RenderCommands that get
+ // their details from the RenderNodes that are visible to the
+ // Camera selected by the framegraph configuration
+ FrameGraphVisitor visitor(m_nodesManager->frameGraphManager());
+ const QVector<FrameGraphNode *> fgLeaves = visitor.traverse(frameGraphRoot());
+
+ const int fgBranchCount = fgLeaves.size();
+ for (int i = 0; i < fgBranchCount; ++i) {
+ RenderViewBuilder builder(fgLeaves.at(i), i, this);
+ renderBinJobs.append(builder.buildJobHierachy());
+ }
- // Set target number of RenderViews
- m_renderQueue->setTargetRenderViewCount(visitor.leafNodeCount());
+ // Set target number of RenderViews
+ m_renderQueue->setTargetRenderViewCount(fgBranchCount);
+ }
return renderBinJobs;
}
@@ -1364,6 +1467,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());
@@ -1474,16 +1582,15 @@ void Renderer::createOrUpdateVAO(RenderCommand *command,
HVao *previousVaoHandle,
OpenGLVertexArrayObject **vao)
{
+ const VAOIdentifier vaoKey(command->m_geometry, command->m_shader);
+
VAOManager *vaoManager = m_nodesManager->vaoManager();
- command->m_vao = vaoManager->lookupHandle(QPair<HGeometry, HShader>(command->m_geometry, command->m_shader));
+ command->m_vao = vaoManager->lookupHandle(vaoKey);
if (command->m_vao.isNull()) {
qCDebug(Rendering) << Q_FUNC_INFO << "Allocating new VAO";
- command->m_vao = vaoManager->getOrAcquireHandle(QPair<HGeometry, HShader>(command->m_geometry, command->m_shader));
- vaoManager->data(command->m_vao)->setGraphicsContext(m_graphicsContext.data());
- if (m_graphicsContext->supportsVAO())
- vaoManager->data(command->m_vao)->setVao(new QOpenGLVertexArrayObject());
- vaoManager->data(command->m_vao)->create();
+ command->m_vao = vaoManager->getOrAcquireHandle(vaoKey);
+ vaoManager->data(command->m_vao)->create(m_graphicsContext.data(), vaoKey);
}
if (*previousVaoHandle != command->m_vao) {
@@ -1679,11 +1786,30 @@ void Renderer::cleanGraphicsResources()
tex->destroyGLTexture();
delete tex;
}
+
+ // Delete abandoned VAOs
+ m_abandonedVaosMutex.lock();
+ const QVector<HVao> abandonedVaos = std::move(m_abandonedVaos);
+ m_abandonedVaosMutex.unlock();
+ for (HVao vaoHandle : abandonedVaos) {
+ // might have already been destroyed last frame, but added by the cleanup job before, so
+ // check if the VAO is really still existent
+ OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle);
+ if (vao) {
+ vao->destroy();
+ m_nodesManager->vaoManager()->release(vaoHandle);
+ }
+ }
}
QList<QMouseEvent> Renderer::pendingPickingEvents() const
{
- return m_pickEventFilter->pendingEvents();
+ return m_pickEventFilter->pendingMouseEvents();
+}
+
+QList<QKeyEvent> Renderer::pendingKeyEvents() const
+{
+ return m_pickEventFilter->pendingKeyEvents();
}
const GraphicsApiFilterData *Renderer::contextInfo() const
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index 9b5c35ed1..e311261e0 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -71,6 +71,7 @@
#include <Qt3DRender/private/updatetreeenabledjob_p.h>
#include <Qt3DRender/private/platformsurfacefilter_p.h>
#include <Qt3DRender/private/sendrendercapturejob_p.h>
+#include <Qt3DRender/private/sendbuffercapturejob_p.h>
#include <Qt3DRender/private/genericlambdajob_p.h>
#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
#include <Qt3DRender/private/filtercompatibletechniquejob_p.h>
@@ -156,7 +157,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;
@@ -188,11 +189,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; }
@@ -209,10 +210,12 @@ public:
virtual void setSettings(RenderSettings *settings) Q_DECL_OVERRIDE;
virtual RenderSettings *settings() const Q_DECL_OVERRIDE;
+ QOpenGLContext *shareContext() const Q_DECL_OVERRIDE;
void updateGLResources();
void updateTexture(Texture *texture);
void cleanupTexture(const Texture *texture);
+ void downloadGLBuffers();
void prepareCommandsSubmission(const QVector<RenderView *> &renderViews);
bool executeCommandsSubmission(const RenderView *rv);
@@ -230,8 +233,8 @@ public:
inline RenderStateSet *defaultRenderState() const { return m_defaultRenderStateSet; }
-
QList<QMouseEvent> pendingPickingEvents() const;
+ QList<QKeyEvent> pendingKeyEvents() const;
void addRenderCaptureSendRequest(Qt3DCore::QNodeId nodeId);
const QVector<Qt3DCore::QNodeId> takePendingRenderCaptureSendRequests();
@@ -256,12 +259,13 @@ public:
ViewSubmissionResultData submitRenderViews(const QVector<Render::RenderView *> &renderViews);
- QMutex* mutex() { return &m_mutex; }
+ QMutex* mutex() { return &m_renderQueueMutex; }
#ifdef QT3D_RENDER_UNIT_TESTS
public:
#else
+
private:
#endif
bool canRender() const;
@@ -286,7 +290,7 @@ private:
QScopedPointer<RenderThread> m_renderThread;
QScopedPointer<VSyncFrameAdvanceService> m_vsyncFrameAdvanceService;
- QMutex m_mutex;
+ QMutex m_renderQueueMutex;
QSemaphore m_submitRenderViewsSemaphore;
QSemaphore m_waitForInitializationToBeCompleted;
@@ -300,6 +304,7 @@ private:
BackendNodeDirtySet m_changeSet;
QAtomicInt m_lastFrameCorrect;
QOpenGLContext *m_glContext;
+ QOpenGLContext *m_shareContext;
PickBoundingVolumeJobPtr m_pickBoundingVolumeJob;
qint64 m_time;
@@ -314,6 +319,7 @@ private:
UpdateWorldBoundingVolumeJobPtr m_updateWorldBoundingVolumeJob;
UpdateTreeEnabledJobPtr m_updateTreeEnabledJob;
SendRenderCaptureJobPtr m_sendRenderCaptureJob;
+ SendBufferCaptureJobPtr m_sendBufferCaptureJob;
UpdateLevelOfDetailJobPtr m_updateLevelOfDetailJob;
UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob;
FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob;
@@ -327,16 +333,23 @@ private:
OpenGLVertexArrayObject **vao);
GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob;
+ GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob;
SynchronizerJobPtr m_syncTextureLoadingJob;
+ void lookForAbandonedVaos();
void lookForDirtyBuffers();
+ void lookForDownloadableBuffers();
void lookForDirtyTextures();
void lookForDirtyShaders();
+ QMutex m_abandonedVaosMutex;
+ QVector<HVao> m_abandonedVaos;
+
QVector<HBuffer> m_dirtyBuffers;
+ QVector<HBuffer> m_downloadableBuffers;
QVector<HShader> m_dirtyShaders;
QVector<HTexture> m_dirtyTextures;
diff --git a/src/render/backend/renderqueue.cpp b/src/render/backend/renderqueue.cpp
index 6ec7da464..2fa1cb7d2 100644
--- a/src/render/backend/renderqueue.cpp
+++ b/src/render/backend/renderqueue.cpp
@@ -49,6 +49,7 @@ namespace Render {
RenderQueue::RenderQueue()
: m_noRender(false)
+ , m_wasReset(true)
, m_targetRenderViewCount(0)
, m_currentRenderViewCount(0)
, m_currentWorkQueue(1)
@@ -70,6 +71,7 @@ void RenderQueue::reset()
m_targetRenderViewCount = 0;
m_currentWorkQueue.clear();
m_noRender = false;
+ m_wasReset = true;
}
void RenderQueue::setNoRender()
@@ -88,6 +90,7 @@ bool RenderQueue::queueRenderView(RenderView *renderView, uint submissionOrderIn
Q_ASSERT(!m_noRender);
m_currentWorkQueue[submissionOrderIndex] = renderView;
++m_currentRenderViewCount;
+ Q_ASSERT(m_currentRenderViewCount <= m_targetRenderViewCount);
return isFrameQueueComplete();
}
@@ -109,6 +112,7 @@ void RenderQueue::setTargetRenderViewCount(int targetRenderViewCount)
Q_ASSERT(!m_noRender);
m_targetRenderViewCount = targetRenderViewCount;
m_currentWorkQueue.resize(targetRenderViewCount);
+ m_wasReset = false;
}
/*!
@@ -119,7 +123,7 @@ void RenderQueue::setTargetRenderViewCount(int targetRenderViewCount)
bool RenderQueue::isFrameQueueComplete() const
{
return (m_noRender
- || (m_targetRenderViewCount && m_targetRenderViewCount == currentRenderViewCount()));
+ || (m_targetRenderViewCount > 0 && m_targetRenderViewCount == m_currentRenderViewCount));
}
} // namespace Render
diff --git a/src/render/backend/renderqueue_p.h b/src/render/backend/renderqueue_p.h
index 49316049b..611f5849a 100644
--- a/src/render/backend/renderqueue_p.h
+++ b/src/render/backend/renderqueue_p.h
@@ -77,9 +77,13 @@ public:
void reset();
void setNoRender();
+ inline bool isNoRender() const { return m_noRender; }
+
+ inline bool wasReset() const { return m_wasReset; }
private:
bool m_noRender;
+ bool m_wasReset;
int m_targetRenderViewCount;
int m_currentRenderViewCount;
QVector<RenderView *> m_currentWorkQueue;
diff --git a/src/render/backend/rendertargetoutput.cpp b/src/render/backend/rendertargetoutput.cpp
index faebfacb6..cba92596d 100644
--- a/src/render/backend/rendertargetoutput.cpp
+++ b/src/render/backend/rendertargetoutput.cpp
@@ -121,9 +121,14 @@ void RenderTargetOutput::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
BackendNode::sceneChangeEvent(e);
}
-Attachment RenderTargetOutput::attachment() const
+Qt3DRender::Render::Attachment *RenderTargetOutput::attachment()
{
- return m_attachmentData;
+ return &m_attachmentData;
+}
+
+const Attachment *RenderTargetOutput::attachment() const
+{
+ return &m_attachmentData;
}
} // namespace Render
diff --git a/src/render/backend/rendertargetoutput_p.h b/src/render/backend/rendertargetoutput_p.h
index 14daa84e9..b7867c2cb 100644
--- a/src/render/backend/rendertargetoutput_p.h
+++ b/src/render/backend/rendertargetoutput_p.h
@@ -77,7 +77,8 @@ public:
QAbstractTexture::CubeMapFace face() const;
QRenderTargetOutput::AttachmentPoint point() const;
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
- Attachment attachment() const;
+ Attachment *attachment();
+ const Attachment *attachment() const;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
diff --git a/src/render/backend/renderthread_p.h b/src/render/backend/renderthread_p.h
index 026a98609..8d7c083ed 100644
--- a/src/render/backend/renderthread_p.h
+++ b/src/render/backend/renderthread_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef RENDERTHREAD_H
-#define RENDERTHREAD_H
+#ifndef QT3DRENDER_RENDER_RENDERTHREAD_H
+#define QT3DRENDER_RENDER_RENDERTHREAD_H
//
// W A R N I N G
@@ -75,7 +75,7 @@ public:
Render::Renderer* renderer() const { return m_renderer; }
protected:
- void run();
+ void run() Q_DECL_OVERRIDE;
private:
Renderer* m_renderer;
@@ -88,4 +88,4 @@ private:
QT_END_NAMESPACE
-#endif // RENDERTHREAD_H
+#endif // QT3DRENDER_RENDER_RENDERTHREAD_H
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index bfdb68eb1..03f61b2d9 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -66,6 +66,7 @@
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DCore/qentity.h>
#include <QtGui/qsurface.h>
@@ -128,6 +129,8 @@ 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("exposure")), Exposure);
+ setters.insert(StringToInt::lookupId(QLatin1String("gamma")), Gamma);
setters.insert(StringToInt::lookupId(QLatin1String("time")), Time);
setters.insert(StringToInt::lookupId(QLatin1String("eyePosition")), EyePosition);
@@ -190,6 +193,10 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize));
return UniformValue(viewportMatrix.inverted());
}
+ case Exposure:
+ return UniformValue(m_data.m_renderCameraLens->exposure());
+ case Gamma:
+ return UniformValue(m_gamma);
case Time:
return UniformValue(float(m_renderer->time() / 1000000000.0f));
case EyePosition:
@@ -201,9 +208,11 @@ UniformValue RenderView::standardUniformValue(RenderView::StandardUniform standa
}
RenderView::RenderView()
- : m_renderer(nullptr)
+ : m_isDownloadBuffersEnable(false)
+ , m_renderer(nullptr)
, m_devicePixelRatio(1.)
, m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f))
+ , m_gamma(2.2f)
, m_surface(nullptr)
, m_clearBuffer(QClearBuffers::None)
, m_stateSet(nullptr)
@@ -211,6 +220,7 @@ RenderView::RenderView()
, m_compute(false)
, m_frustumCulling(false)
, m_memoryBarrier(QMemoryBarrier::None)
+ , m_environmentLight(nullptr)
{
m_workGroups[0] = 1;
m_workGroups[1] = 1;
@@ -352,6 +362,7 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
// is only accessed from the same thread
UniformBlockValueBuilder *builder = new UniformBlockValueBuilder();
builder->shaderDataManager = m_manager->shaderDataManager();
+ builder->textureManager = m_manager->textureManager();
m_localData.setLocalData(builder);
QVector<RenderCommand *> commands;
@@ -404,7 +415,12 @@ QVector<RenderCommand *> RenderView::buildDrawRenderCommands(const QVector<Entit
ParameterInfoList globalParameters = passData.parameterInfo;
// setShaderAndUniforms can initialize a localData
// make sure this is cleared before we leave this function
- setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)));
+ setShaderAndUniforms(command,
+ pass,
+ globalParameters,
+ *(node->worldTransform()),
+ lightSources.mid(0, std::max(lightSources.size(), MAX_LIGHTS)),
+ m_environmentLight);
// Store all necessary information for actual drawing if command is valid
command->m_isValid = !command->m_attributes.empty();
@@ -470,6 +486,7 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
// is only accessed from the same thread
UniformBlockValueBuilder *builder = new UniformBlockValueBuilder();
builder->shaderDataManager = m_manager->shaderDataManager();
+ builder->textureManager = m_manager->textureManager();
m_localData.setLocalData(builder);
// If the RenderView contains only a ComputeDispatch then it cares about
@@ -503,7 +520,8 @@ QVector<RenderCommand *> RenderView::buildComputeRenderCommands(const QVector<En
pass,
globalParameters,
*(node->worldTransform()),
- QVector<LightSource>());
+ QVector<LightSource>(),
+ nullptr);
commands.append(command);
}
}
@@ -579,7 +597,7 @@ void RenderView::setUniformBlockValue(ShaderParameterPack &uniformPack,
// If two shaders define the same block with the exact same layout, in that case the UBO could be shared
// but how do we know that ? We'll need to compare ShaderUniformBlocks
- // Note: we assume that if a buffer is shared accross multiple shaders
+ // Note: we assume that if a buffer is shared across multiple shaders
// then it implies that they share the same layout
// Temporarly disabled
@@ -691,7 +709,7 @@ void RenderView::buildSortingKey(RenderCommand *command) const
}
void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources) const
+ 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 :
@@ -812,13 +830,25 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
if (uniformNamesIds.contains(LIGHT_COUNT_NAME_ID))
setUniformValue(command->m_parameterPack, LIGHT_COUNT_NAME_ID, UniformValue(qMax(1, lightIdx)));
- if (activeLightSources.isEmpty()) {
+ // If no active light sources and no environment light, add a default light
+ if (activeLightSources.isEmpty() && !environmentLight) {
// Note: implicit conversion of values to UniformValue
setUniformValue(command->m_parameterPack, LIGHT_POSITION_NAMES[0], QVector3D(10.0f, 10.0f, 0.0f));
setUniformValue(command->m_parameterPack, LIGHT_TYPE_NAMES[0], int(QAbstractLight::PointLight));
setUniformValue(command->m_parameterPack, LIGHT_COLOR_NAMES[0], QVector3D(1.0f, 1.0f, 1.0f));
setUniformValue(command->m_parameterPack, LIGHT_INTENSITY_NAMES[0], 0.5f);
}
+
+ // Environment Light
+ int envLightCount = 0;
+ if (environmentLight && environmentLight->isEnabled()) {
+ ShaderData *shaderData = m_manager->shaderDataManager()->lookupResource(environmentLight->shaderData());
+ if (shaderData) {
+ setDefaultUniformBlockShaderDataValue(command->m_parameterPack, shader, shaderData, QStringLiteral("envLight"));
+ envLightCount = 1;
+ }
+ }
+ setUniformValue(command->m_parameterPack, StringToInt::lookupId(QStringLiteral("envLightCount")), envLightCount);
}
// Set frag outputs in the shaders if hash not empty
if (!fragOutputs.isEmpty())
@@ -830,6 +860,16 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass,
}
}
+bool RenderView::isDownloadBuffersEnable() const
+{
+ return m_isDownloadBuffersEnable;
+}
+
+void RenderView::setIsDownloadBuffersEnable(bool isDownloadBuffersEnable)
+{
+ m_isDownloadBuffersEnable = isDownloadBuffersEnable;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h
index 1f00e2aae..440d51638 100644
--- a/src/render/backend/renderview_p.h
+++ b/src/render/backend/renderview_p.h
@@ -181,6 +181,9 @@ public:
inline void setViewport(const QRectF &vp) Q_DECL_NOTHROW { m_viewport = vp; }
inline QRectF viewport() const Q_DECL_NOTHROW { return m_viewport; }
+ inline float gamma() const Q_DECL_NOTHROW { return m_gamma; }
+ inline void setGamma(float gamma) Q_DECL_NOTHROW { m_gamma = gamma; }
+
// depth and stencil ClearBuffers are cached locally
// color ClearBuffers are collected, as there may be multiple
// color buffers to be cleared. we need to apply all these at rendering
@@ -212,14 +215,15 @@ public:
QSurface *surface() const { return m_surface; }
void setLightSources(const QVector<LightSource> &lightSources) Q_DECL_NOTHROW { m_lightSources = lightSources; }
+ void setEnvironmentLight(EnvironmentLight *environmentLight) Q_DECL_NOTHROW { m_environmentLight = environmentLight; }
void updateMatrices();
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; }
- void setMemoryBarrier(QMemoryBarrier::BarrierTypes barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; }
- QMemoryBarrier::BarrierTypes memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; }
+ void setMemoryBarrier(QMemoryBarrier::Operations barrier) Q_DECL_NOTHROW { m_memoryBarrier = barrier; }
+ QMemoryBarrier::Operations memoryBarrier() const Q_DECL_NOTHROW { return m_memoryBarrier; }
// Helps making the size of RenderView smaller
// Contains all the data needed for the actual building of the RenderView
@@ -245,13 +249,17 @@ public:
QVector3D m_eyePos;
};
+ bool isDownloadBuffersEnable() const;
+ void setIsDownloadBuffersEnable(bool isDownloadBuffersEnable);
+
private:
void setShaderAndUniforms(RenderCommand *command, RenderPass *pass, ParameterInfoList &parameters, const QMatrix4x4 &worldTransform,
- const QVector<LightSource> &activeLightSources) const;
+ const QVector<LightSource> &activeLightSources, EnvironmentLight *environmentLight) const;
mutable QThreadStorage<UniformBlockValueBuilder*> m_localData;
Qt3DCore::QNodeId m_renderCaptureNodeId;
+ bool m_isDownloadBuffersEnable;
Renderer *m_renderer;
NodeManagers *m_manager;
@@ -261,6 +269,7 @@ private:
InnerData m_data;
QRectF m_viewport;
+ float m_gamma;
Qt3DCore::QNodeId m_renderTarget;
QSurface *m_surface;
AttachmentPack m_attachmentPack;
@@ -274,13 +283,14 @@ private:
bool m_compute:1;
bool m_frustumCulling:1;
int m_workGroups[3];
- QMemoryBarrier::BarrierTypes m_memoryBarrier;
+ QMemoryBarrier::Operations m_memoryBarrier;
// We do not use pointers to RenderNodes or Drawable's here so that the
// render aspect is free to change the drawables on the next frame whilst
// the render thread is submitting these commands.
QVector<RenderCommand *> m_commands;
mutable QVector<LightSource> m_lightSources;
+ EnvironmentLight *m_environmentLight;
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> m_parameters;
@@ -303,6 +313,8 @@ private:
ViewportMatrix,
InverseViewportMatrix,
Time,
+ Exposure,
+ Gamma,
EyePosition
};
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index 55d8ba462..f47c6f419 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -66,14 +66,14 @@ public:
RenderView *rv = m_renderViewJob->renderView();
int totalCommandCount = 0;
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
totalCommandCount += renderViewCommandBuilder->commands().size();
QVector<RenderCommand *> commands;
commands.reserve(totalCommandCount);
// Reduction
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
commands += std::move(renderViewCommandBuilder->commands());
rv->setCommands(commands);
@@ -139,13 +139,13 @@ public:
m_filterEntityByLayerJob->setLayers(rv->layerFilter());
// Material Parameter building
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) {
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
}
// Command builders
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs))
renderViewCommandBuilder->setRenderView(rv);
// Set whether frustum culling is enabled or not
@@ -188,8 +188,7 @@ public:
RenderView *rv = m_renderViewJob->renderView();
if (!rv->noDraw()) {
- // Set the light sources
- rv->setLightSources(std::move(m_lightGathererJob->lights()));
+ rv->setEnvironmentLight(m_lightGathererJob->takeEnvironmentLight());
// We sort the vector so that the removal can then be performed linearly
@@ -207,6 +206,14 @@ public:
QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, filteredEntities);
+ // Set the light sources, with layer filters applied.
+ QVector<LightSource> lightSources = m_lightGathererJob->lights();
+ for (int i = 0; i < lightSources.count(); ++i) {
+ if (!filteredEntities.contains(lightSources[i].entity))
+ lightSources.removeAt(i--);
+ }
+ rv->setLightSources(lightSources);
+
// Filter out frustum culled entity for drawable entities
if (isDraw && rv->frustumCulling())
RenderViewBuilder::removeEntitiesNotInSubset(renderableEntities, m_frustumCullingJob->visibleEntities());
@@ -224,7 +231,7 @@ public:
// Reduction
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params;
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs))
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs))
params.unite(materialGatherer->materialToPassAndParameter());
// Set all required data on the RenderView for final processing
rv->setMaterialParameterTable(std::move(params));
@@ -424,7 +431,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_filterEntityByLayerJob->addDependency(m_renderer->updateTreeEnabledJob());
m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) {
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->addDependency(m_syncRenderViewInitializationJob);
materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob());
m_syncRenderCommandBuildingJob->addDependency(materialGatherer);
@@ -435,7 +442,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
m_syncRenderCommandBuildingJob->addDependency(m_lightGathererJob);
m_syncRenderCommandBuildingJob->addDependency(m_frustumCullingJob);
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) {
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) {
renderViewCommandBuilder->addDependency(m_syncRenderCommandBuildingJob);
m_syncRenderViewCommandBuildersJob->addDependency(renderViewCommandBuilder);
}
@@ -457,13 +464,13 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
jobs.push_back(m_filterEntityByLayerJob); // Step 3
jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3
- for (const auto materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
+ for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
jobs.push_back(materialGatherer);
jobs.push_back(m_frustumCullingJob); // Step 4
jobs.push_back(m_syncRenderCommandBuildingJob); // Step 4
- for (const auto renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5
+ for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewBuilderJobs)) // Step 5
jobs.push_back(renderViewCommandBuilder);
jobs.push_back(m_syncRenderViewCommandBuildersJob); // Step 6
diff --git a/src/render/backend/resourceaccessor.cpp b/src/render/backend/resourceaccessor.cpp
new file mode 100644
index 000000000..7558eb4ad
--- /dev/null
+++ b/src/render/backend/resourceaccessor.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "resourceaccessor_p.h"
+
+#include <Qt3DRender/qrendertargetoutput.h>
+
+#include <private/qrendertargetoutput_p.h>
+#include <private/nodemanagers_p.h>
+#include <private/texture_p.h>
+#include <private/rendertargetoutput_p.h>
+#include <private/texturedatamanager_p.h>
+#include <private/gltexturemanager_p.h>
+#include <private/managers_p.h>
+#include <private/gltexture_p.h>
+
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+RenderBackendResourceAccessor::~RenderBackendResourceAccessor()
+{
+
+}
+
+ResourceAccessor::ResourceAccessor(NodeManagers *mgr)
+ : m_glTextureManager(mgr->glTextureManager())
+ , m_textureManager(mgr->textureManager())
+ , m_attachmentManager(mgr->attachmentManager())
+ , m_entityManager(mgr->renderNodesManager())
+{
+
+}
+
+// called by render plugins from arbitrary thread
+bool ResourceAccessor::accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock)
+{
+ switch (type) {
+
+ case RenderBackendResourceAccessor::OGLTexture: {
+ Texture *tex = m_textureManager->lookupResource(nodeId);
+ if (!tex)
+ return false;
+
+ GLTexture *glTex = m_glTextureManager->lookupResource(tex->peerId());
+ if (!glTex)
+ return false;
+
+ if (glTex->isDirty())
+ return false;
+
+ QOpenGLTexture **glTextureHandle = reinterpret_cast<QOpenGLTexture **>(handle);
+ *glTextureHandle = glTex->getOrCreateGLTexture();
+ *lock = glTex->textureLock();
+ return true;
+ }
+
+ case RenderBackendResourceAccessor::OutputAttachment: {
+ RenderTargetOutput *output = m_attachmentManager->lookupResource(nodeId);
+ if (output) {
+ Attachment **attachmentData = reinterpret_cast<Attachment **>(handle);
+ *attachmentData = output->attachment();
+ return true;
+ }
+ break;
+ }
+
+ case RenderBackendResourceAccessor::EntityHandle: {
+ Entity *entity = m_entityManager->lookupResource(nodeId);
+ if (entity) {
+ Entity **pEntity = reinterpret_cast<Entity **>(handle);
+ *pEntity = entity;
+ return true;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/resourceaccessor_p.h b/src/render/backend/resourceaccessor_p.h
new file mode 100644
index 000000000..b4ed2a3eb
--- /dev/null
+++ b/src/render/backend/resourceaccessor_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE: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_RESOURCEACCESSOR_P_H
+#define QT3DRENDER_RENDER_RESOURCEACCESSOR_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 <private/qt3drender_global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMutex;
+
+namespace Qt3DRender
+{
+namespace Render {
+
+class TextureManager;
+class AttachmentManager;
+class GLTextureManager;
+class EntityManager;
+class NodeManagers;
+
+class RenderBackendResourceAccessor
+{
+public:
+ enum ResourceType {
+ OGLTexture,
+ OutputAttachment,
+ EntityHandle,
+ };
+
+ virtual ~RenderBackendResourceAccessor();
+ virtual bool accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) = 0;
+};
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT ResourceAccessor : public RenderBackendResourceAccessor
+{
+public:
+ ResourceAccessor(NodeManagers *mgr);
+ bool accessResource(ResourceType type, Qt3DCore::QNodeId nodeId, void **handle, QMutex **lock) Q_DECL_FINAL;
+private:
+ GLTextureManager *m_glTextureManager;
+ TextureManager *m_textureManager;
+ AttachmentManager *m_attachmentManager;
+ EntityManager *m_entityManager;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_RESOURCEACCESSOR_P_H
diff --git a/src/render/backend/shadervariables_p.h b/src/render/backend/shadervariables_p.h
index 2177abe0e..e0fa07dff 100644
--- a/src/render/backend/shadervariables_p.h
+++ b/src/render/backend/shadervariables_p.h
@@ -81,6 +81,7 @@ struct ShaderUniform
{
ShaderUniform()
: m_nameId(-1)
+ , m_type(GL_NONE)
, m_size(0)
, m_offset(-1)
, m_location(-1)
diff --git a/src/render/backend/triangleboundingvolume.cpp b/src/render/backend/triangleboundingvolume.cpp
index 80a23572c..ca2d26897 100644
--- a/src/render/backend/triangleboundingvolume.cpp
+++ b/src/render/backend/triangleboundingvolume.cpp
@@ -112,15 +112,18 @@ Qt3DCore::QNodeId TriangleBoundingVolume::id() const
return m_id;
}
-bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q) const
+bool TriangleBoundingVolume::intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const
{
float t = 0.0f;
- QVector3D uvw;
- const bool intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvw, t);
-
- if (intersected && q != nullptr)
- *q = ray.point(t * ray.distance());
-
+ QVector3D uvwr;
+ const float intersected = intersectsSegmentTriangle(ray, m_c, m_b, m_a, uvwr, t);
+
+ if (intersected) {
+ if (q != nullptr)
+ *q = ray.point(t);
+ if (uvw != nullptr)
+ *uvw = uvwr;
+ }
return intersected;
}
diff --git a/src/render/backend/triangleboundingvolume_p.h b/src/render/backend/triangleboundingvolume_p.h
index 1163efc46..3192ad456 100644
--- a/src/render/backend/triangleboundingvolume_p.h
+++ b/src/render/backend/triangleboundingvolume_p.h
@@ -78,7 +78,7 @@ public:
const QVector3D &c);
Qt3DCore::QNodeId id() const Q_DECL_FINAL;
- bool intersects(const RayCasting::QRay3D &ray, QVector3D *q) const Q_DECL_FINAL;
+ bool intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const Q_DECL_FINAL;
Type type() const Q_DECL_FINAL;
QVector3D a() const;
diff --git a/src/render/backend/trianglesvisitor.cpp b/src/render/backend/trianglesvisitor.cpp
index 35cdecc29..036f43fa0 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/bufferutils_p.h>
QT_BEGIN_NAMESPACE
@@ -71,24 +72,6 @@ bool isTriangleBased(Qt3DRender::QGeometryRenderer::PrimitiveType type) Q_DECL_N
}
}
-struct BufferInfo
-{
- BufferInfo()
- : type(QAttribute::VertexBaseType::Float)
- , dataSize(0)
- , count(0)
- , byteStride(0)
- , byteOffset(0)
- {}
-
- QByteArray data;
- QAttribute::VertexBaseType type;
- uint dataSize;
- uint count;
- uint byteStride;
- uint byteOffset;
-};
-
// TO DO: Add methods for triangle strip adjacency
// What about primitive restart ?
@@ -328,48 +311,67 @@ void traverseTriangleAdjacency(Vertex *vertices,
}
}
-
-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)
+template<typename Coordinate>
+QVector4D readCoordinate(const BufferInfo &info, Coordinate *coordinates, uint index)
{
- return reinterpret_cast< typename EnumToType<v>::type *>(u.constData() + byteOffset);
+ const uint stride = info.byteStride / sizeof(Coordinate);
+ QVector4D ret(0, 0, 0, 1.0f);
+ coordinates += stride * index;
+ for (uint e = 0; e < info.dataSize; ++e)
+ ret[e] = coordinates[e];
+ return ret;
}
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));
+ case QAttribute::Byte: f(info, BufferTypeInfo::castToType<QAttribute::Byte>(info.data, info.byteOffset));
return;
- case QAttribute::UnsignedByte: f(info, castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
+ case QAttribute::UnsignedByte: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset));
return;
- case QAttribute::Short: f(info, castToType<QAttribute::Short>(info.data, info.byteOffset));
+ case QAttribute::Short: f(info, BufferTypeInfo::castToType<QAttribute::Short>(info.data, info.byteOffset));
return;
- case QAttribute::UnsignedShort: f(info, castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
+ case QAttribute::UnsignedShort: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset));
return;
- case QAttribute::Int: f(info, castToType<QAttribute::Int>(info.data, info.byteOffset));
+ case QAttribute::Int: f(info, BufferTypeInfo::castToType<QAttribute::Int>(info.data, info.byteOffset));
return;
- case QAttribute::UnsignedInt: f(info, castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
+ case QAttribute::UnsignedInt: f(info, BufferTypeInfo::castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset));
return;
- case QAttribute::Float: f(info, castToType<QAttribute::Float>(info.data, info.byteOffset));
+ case QAttribute::Float: f(info, BufferTypeInfo::castToType<QAttribute::Float>(info.data, info.byteOffset));
return;
- case QAttribute::Double: f(info, castToType<QAttribute::Double>(info.data, info.byteOffset));
+ case QAttribute::Double: f(info, BufferTypeInfo::castToType<QAttribute::Double>(info.data, info.byteOffset));
return;
default:
return;
}
}
+QVector4D readBuffer(const BufferInfo &info, uint index)
+{
+ switch (info.type) {
+ case QAttribute::Byte:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Byte>(info.data, info.byteOffset), index);
+ case QAttribute::UnsignedByte:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::UnsignedByte>(info.data, info.byteOffset), index);
+ case QAttribute::Short:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Short>(info.data, info.byteOffset), index);
+ case QAttribute::UnsignedShort:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::UnsignedShort>(info.data, info.byteOffset), index);
+ case QAttribute::Int:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Int>(info.data, info.byteOffset), index);
+ case QAttribute::UnsignedInt:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::UnsignedInt>(info.data, info.byteOffset), index);
+ case QAttribute::Float:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Float>(info.data, info.byteOffset), index);
+ case QAttribute::Double:
+ return readCoordinate(info, BufferTypeInfo::castToType<QAttribute::Double>(info.data, info.byteOffset), index);
+ default:
+ break;
+ }
+ return QVector4D();
+}
+
template<typename Index>
struct IndexedVertexExecutor
{
@@ -530,6 +532,53 @@ void TrianglesVisitor::apply(const GeometryRenderer *renderer, const Qt3DCore::Q
}
}
+bool CoordinateReader::setGeometry(const GeometryRenderer *renderer, const QString &attributeName)
+{
+ if (renderer == nullptr || renderer->instanceCount() != 1
+ || !isTriangleBased(renderer->primitiveType())) {
+ return false;
+ }
+
+ Geometry *geom = m_manager->lookupResource<Geometry, GeometryManager>(renderer->geometryId());
+
+ if (!geom)
+ return false;
+
+ 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() == attributeName
+ || (attributeName == QStringLiteral("default")
+ && attribute->name() == QAttribute::defaultTextureCoordinateAttributeName())) {
+ break;
+ }
+ }
+ attribute = nullptr;
+ }
+
+ if (!attribute)
+ return false;
+
+ m_attribute = attribute;
+ m_buffer = m_manager->lookupResource<Buffer, BufferManager>(attribute->bufferId());
+
+ m_bufferInfo.data = m_buffer->data();
+ m_bufferInfo.type = m_attribute->vertexBaseType();
+ m_bufferInfo.byteOffset = m_attribute->byteOffset();
+ m_bufferInfo.byteStride = m_attribute->byteStride();
+ m_bufferInfo.dataSize = m_attribute->vertexSize();
+ m_bufferInfo.count = m_attribute->count();
+ return true;
+}
+
+QVector4D CoordinateReader::getCoordinate(uint vertexIndex)
+{
+ return readBuffer(m_bufferInfo, vertexIndex);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/backend/trianglesvisitor_p.h b/src/render/backend/trianglesvisitor_p.h
index 5f7cff9c0..9428857ac 100644
--- a/src/render/backend/trianglesvisitor_p.h
+++ b/src/render/backend/trianglesvisitor_p.h
@@ -52,6 +52,10 @@
//
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DRender/QAttribute>
+#include <Qt3DRender/private/bufferutils_p.h>
+
+#include <private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +69,8 @@ namespace Render {
class GeometryRenderer;
class NodeManagers;
+class Attribute;
+class Buffer;
class Q_AUTOTEST_EXPORT TrianglesVisitor
{
@@ -84,6 +90,27 @@ protected:
Qt3DCore::QNodeId m_nodeId;
};
+class QT3DRENDERSHARED_PRIVATE_EXPORT CoordinateReader
+{
+public:
+ explicit CoordinateReader(NodeManagers *manager)
+ : m_manager(manager)
+ , m_attribute(nullptr)
+ , m_buffer(nullptr)
+ {
+ }
+
+ bool setGeometry(const GeometryRenderer *renderer, const QString &attributeName);
+
+ QVector4D getCoordinate(uint vertexIndex);
+
+protected:
+ NodeManagers *m_manager;
+ Attribute *m_attribute;
+ Buffer *m_buffer;
+ BufferInfo m_bufferInfo;
+};
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/framegraph/buffercapture.cpp b/src/render/framegraph/buffercapture.cpp
new file mode 100644
index 000000000..4e89150df
--- /dev/null
+++ b/src/render/framegraph/buffercapture.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Juan José Casafranca
+** 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/qbuffercapture_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+BufferCapture::BufferCapture()
+ : FrameGraphNode(FrameGraphNode::BufferCapture, QBackendNode::ReadWrite)
+{
+
+}
+
+} //Render
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/frontend/qboundingsphere_p.h b/src/render/framegraph/buffercapture_p.h
index 171e4440f..d638f35d5 100644
--- a/src/render/frontend/qboundingsphere_p.h
+++ b/src/render/framegraph/buffercapture_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2017 Juan José Casafranca
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_QBOUNDINGSPHERE_P_H
-#define QT3DRENDER_QBOUNDINGSPHERE_P_H
+#ifndef BUFFERCAPTURE_P_H
+#define BUFFERCAPTURE_P_H
//
// W A R N I N G
@@ -51,26 +51,25 @@
// We mean it.
//
-#include <private/qobject_p.h>
-#include <qboundingsphere.h>
+#include <Qt3DRender/private/qbuffercapture_p.h>
+#include <Qt3DRender/private/framegraphnode_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QT3DRENDERSHARED_EXPORT QBoundingSpherePrivate : public QObjectPrivate
+namespace Render {
+
+class Q_AUTOTEST_EXPORT BufferCapture : public FrameGraphNode
{
public:
- QBoundingSpherePrivate();
-
- Q_DECLARE_PUBLIC(QBoundingSphere)
-
- QVector3D m_center;
- float m_radius;
+ BufferCapture();
};
-} // namespace Qt3DRender
+} //Render
+
+} //Qt3DRender
QT_END_NAMESPACE
-#endif // QT3DRENDER_QBOUNDINGSPHERE_P_H
+#endif // BUFFERCAPTURE_P_H
diff --git a/src/render/framegraph/framegraph.pri b/src/render/framegraph/framegraph.pri
index 77d7dbc71..5e9ce68bf 100644
--- a/src/render/framegraph/framegraph.pri
+++ b/src/render/framegraph/framegraph.pri
@@ -45,6 +45,9 @@ HEADERS += \
$$PWD/qrendercapture.h \
$$PWD/qrendercapture_p.h \
$$PWD/rendercapture_p.h \
+ $$PWD/qbuffercapture.h \
+ $$PWD/qbuffercapture_p.h \
+ $$PWD/buffercapture_p.h \
$$PWD/qframegraphnodecreatedchange.h \
$$PWD/qframegraphnodecreatedchange_p.h \
$$PWD/qmemorybarrier.h \
@@ -83,6 +86,8 @@ SOURCES += \
$$PWD/rendersurfaceselector.cpp \
$$PWD/qrendercapture.cpp \
$$PWD/rendercapture.cpp \
+ $$PWD/qbuffercapture.cpp \
+ $$PWD/buffercapture.cpp \
$$PWD/qframegraphnodecreatedchange.cpp \
$$PWD/qmemorybarrier.cpp \
$$PWD/memorybarrier.cpp
diff --git a/src/render/framegraph/framegraphnode_p.h b/src/render/framegraph/framegraphnode_p.h
index ccdc47f12..c7b399f89 100644
--- a/src/render/framegraph/framegraphnode_p.h
+++ b/src/render/framegraph/framegraphnode_p.h
@@ -98,6 +98,7 @@ public:
ComputeDispatch,
Surface,
RenderCapture,
+ BufferCapture,
MemoryBarrier
};
FrameGraphNodeType nodeType() const { return m_nodeType; }
diff --git a/src/render/framegraph/framegraphvisitor.cpp b/src/render/framegraph/framegraphvisitor.cpp
index d31e9cddd..cd8b08219 100644
--- a/src/render/framegraph/framegraphvisitor.cpp
+++ b/src/render/framegraph/framegraphvisitor.cpp
@@ -43,7 +43,6 @@
#include "framegraphnode_p.h"
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/managers_p.h>
-#include <Qt3DRender/private/renderviewbuilder_p.h>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
@@ -53,24 +52,16 @@ using namespace Qt3DCore;
namespace Qt3DRender {
namespace Render {
-FrameGraphVisitor::FrameGraphVisitor(Renderer *renderer,
- const FrameGraphManager *manager)
- : m_renderer(renderer)
- , m_manager(manager)
- , m_jobs(nullptr)
- , m_renderviewIndex(0)
-
+FrameGraphVisitor::FrameGraphVisitor(const FrameGraphManager *manager)
+ : m_manager(manager)
{
+ m_leaves.reserve(8);
}
-void FrameGraphVisitor::traverse(FrameGraphNode *root,
- QVector<Qt3DCore::QAspectJobPtr> *jobs)
+QVector<FrameGraphNode *> FrameGraphVisitor::traverse(FrameGraphNode *root)
{
- m_jobs = jobs;
- m_renderviewIndex = 0;
+ m_leaves.clear();
- Q_ASSERT(m_renderer);
- Q_ASSERT(m_jobs);
Q_ASSERT_X(root, Q_FUNC_INFO, "The FrameGraphRoot is null");
// Kick off the traversal
@@ -78,6 +69,7 @@ void FrameGraphVisitor::traverse(FrameGraphNode *root,
if (node == nullptr)
qCritical() << Q_FUNC_INFO << "FrameGraph is null";
visit(node);
+ return m_leaves;
}
void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
@@ -97,10 +89,8 @@ void FrameGraphVisitor::visit(Render::FrameGraphNode *node)
// Leaf node - create a RenderView ready to be populated
// TODO: Pass in only framegraph config that has changed from previous
// index RenderViewJob.
- if (fgChildIds.empty()) {
- RenderViewBuilder builder(node, m_renderviewIndex++, m_renderer);
- m_jobs->append(builder.buildJobHierachy());
- }
+ if (fgChildIds.empty())
+ m_leaves.push_back(node);
}
} // namespace Render
diff --git a/src/render/framegraph/framegraphvisitor_p.h b/src/render/framegraph/framegraphvisitor_p.h
index af8f4caab..f4c0d7796 100644
--- a/src/render/framegraph/framegraphvisitor_p.h
+++ b/src/render/framegraph/framegraphvisitor_p.h
@@ -66,24 +66,18 @@ class FrameGraphNode;
class Renderer;
class FrameGraphManager;
-class FrameGraphVisitor
+class Q_AUTOTEST_EXPORT FrameGraphVisitor
{
public:
- explicit FrameGraphVisitor(Renderer *renderer,
- const FrameGraphManager *nodeManager);
+ explicit FrameGraphVisitor(const FrameGraphManager *nodeManager);
- void traverse(FrameGraphNode *root,
- QVector<Qt3DCore::QAspectJobPtr> *jobs);
-
- inline int leafNodeCount() Q_DECL_NOTHROW { return m_renderviewIndex; }
+ QVector<FrameGraphNode *> traverse(FrameGraphNode *root);
private:
void visit(Render::FrameGraphNode *node);
- Renderer *m_renderer;
const FrameGraphManager *m_manager;
- QVector<Qt3DCore::QAspectJobPtr> *m_jobs;
- int m_renderviewIndex;
+ QVector<FrameGraphNode *> m_leaves;
};
} // namespace Render
diff --git a/src/render/framegraph/memorybarrier.cpp b/src/render/framegraph/memorybarrier.cpp
index c82f6eae8..ee8f156e3 100644
--- a/src/render/framegraph/memorybarrier.cpp
+++ b/src/render/framegraph/memorybarrier.cpp
@@ -49,7 +49,7 @@ namespace Render {
MemoryBarrier::MemoryBarrier()
: FrameGraphNode(FrameGraphNode::MemoryBarrier)
- , m_barrierTypes(QMemoryBarrier::None)
+ , m_waitOperations(QMemoryBarrier::None)
{
}
@@ -57,17 +57,17 @@ MemoryBarrier::~MemoryBarrier()
{
}
-QMemoryBarrier::BarrierTypes MemoryBarrier::barrierTypes() const
+QMemoryBarrier::Operations MemoryBarrier::waitOperations() const
{
- return m_barrierTypes;
+ return m_waitOperations;
}
void MemoryBarrier::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == Qt3DCore::PropertyUpdated) {
Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- if (propertyChange->propertyName() == QByteArrayLiteral("barrierTypes")) {
- m_barrierTypes = propertyChange->value().value<QMemoryBarrier::BarrierTypes>();
+ if (propertyChange->propertyName() == QByteArrayLiteral("waitOperations")) {
+ m_waitOperations = propertyChange->value().value<QMemoryBarrier::Operations>();
markDirty(AbstractRenderer::AllDirty);
}
}
@@ -79,7 +79,7 @@ void MemoryBarrier::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr
FrameGraphNode::initializeFromPeer(change);
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QMemoryBarrierData>>(change);
const QMemoryBarrierData &data = typedChange->data;
- m_barrierTypes = data.barrierTypes;
+ m_waitOperations = data.waitOperations;
}
} // Render
diff --git a/src/render/framegraph/memorybarrier_p.h b/src/render/framegraph/memorybarrier_p.h
index 4c0242476..66a3ae823 100644
--- a/src/render/framegraph/memorybarrier_p.h
+++ b/src/render/framegraph/memorybarrier_p.h
@@ -66,12 +66,12 @@ public:
MemoryBarrier();
~MemoryBarrier();
- QMemoryBarrier::BarrierTypes barrierTypes() const;
+ QMemoryBarrier::Operations waitOperations() const;
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
- QMemoryBarrier::BarrierTypes m_barrierTypes;
+ QMemoryBarrier::Operations m_waitOperations;
};
} // Render
diff --git a/src/render/framegraph/qbuffercapture.cpp b/src/render/framegraph/qbuffercapture.cpp
new file mode 100644
index 000000000..602ad5d6d
--- /dev/null
+++ b/src/render/framegraph/qbuffercapture.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Juan José Casafranca
+** 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/qbuffercapture.h>
+#include <Qt3DRender/private/qbuffercapture_p.h>
+#include <Qt3DCore/QSceneChange>
+#include <Qt3DCore/QPropertyUpdatedChange>
+#include <Qt3DRender/QFrameGraphNodeCreatedChange>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+//Documentation here
+
+/*!
+ * \internal
+ */
+QBufferCapturePrivate::QBufferCapturePrivate()
+ : QFrameGraphNodePrivate()
+{
+
+}
+
+QBufferCapture::QBufferCapture(Qt3DCore::QNode *parent)
+ : QFrameGraphNode(*new QBufferCapturePrivate, parent)
+{
+
+}
+
+QBufferCapture::~QBufferCapture()
+{
+}
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/framegraph/qbuffercapture.h b/src/render/framegraph/qbuffercapture.h
new file mode 100644
index 000000000..d77266828
--- /dev/null
+++ b/src/render/framegraph/qbuffercapture.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Juan José Casafranca
+** 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_QBUFFERCAPTURE_H
+#define QT3DRENDER_QBUFFERCAPTURE_H
+
+#include <Qt3DRender/QFrameGraphNode>
+#include <Qt3DRender/QBuffer>
+#include <QByteArray>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+class QBufferCapturePrivate;
+
+class QT3DRENDERSHARED_EXPORT QBufferCapture : public QFrameGraphNode
+{
+ Q_OBJECT
+public:
+ explicit QBufferCapture(Qt3DCore::QNode *parent = nullptr);
+ ~QBufferCapture();
+
+private:
+ Q_DECLARE_PRIVATE(QBufferCapture)
+};
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QBUFFERCAPTURE_H
diff --git a/src/render/framegraph/qbuffercapture_p.h b/src/render/framegraph/qbuffercapture_p.h
new file mode 100644
index 000000000..5e642aca3
--- /dev/null
+++ b/src/render/framegraph/qbuffercapture_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Juan José Casafranca
+** 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_QBUFFERCAPTURE_P_H
+#define QT3DRENDER_QBUFFERCAPTURE_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/qbuffercapture.h>
+#include <Qt3DRender/private/qframegraphnode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+class QBufferCapturePrivate : public QFrameGraphNodePrivate
+{
+public:
+ QBufferCapturePrivate();
+
+ Q_DECLARE_PUBLIC(QBufferCapture)
+};
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QBUFFERCAPTURE_P_H
diff --git a/src/render/framegraph/qmemorybarrier.cpp b/src/render/framegraph/qmemorybarrier.cpp
index 9aa3ba560..4c1685ef7 100644
--- a/src/render/framegraph/qmemorybarrier.cpp
+++ b/src/render/framegraph/qmemorybarrier.cpp
@@ -97,30 +97,31 @@ namespace Qt3DRender {
*/
/*!
- \enum QMemoryBarrier::BarrierType
+ \enum QMemoryBarrier::Operation
This enum type describes types of buffer to be cleared.
\value None
- \value ElementArrayBarrier
- \value UniformBarrier
- \value TextureFetchBarrier
- \value ShaderImageAccessBarrier
- \value CommandBarrier
- \value PixelBufferBarrier
- \value TextureUpdateBarrier
- \value BufferUpdateBarrier
- \value FrameBufferBarrier
- \value TransformFeedbackBarrier
- \value AtomicCounterBarrier
- \value ShaderStorageBarrier
- \value QueryBufferBarrier
- \value AllBarrier
+ \value ElementArray
+ \value Uniform
+ \value TextureFetch
+ \value ShaderImageAccess
+ \value Command
+ \value PixelBuffer
+ \value TextureUpdate
+ \value BufferUpdate
+ \value FrameBuffer
+ \value TransformFeedback
+ \value AtomicCounter
+ \value ShaderStorage
+ \value QueryBuffer
+ \value VertexAttributeArray
+ \value All
*/
QMemoryBarrierPrivate::QMemoryBarrierPrivate()
: QFrameGraphNodePrivate()
- , m_barrierTypes(QMemoryBarrier::None)
+ , m_waitOperations(QMemoryBarrier::None)
{
}
@@ -133,20 +134,20 @@ QMemoryBarrier::~QMemoryBarrier()
{
}
-void QMemoryBarrier::setBarrierTypes(QMemoryBarrier::BarrierTypes barrierTypes)
+void QMemoryBarrier::setWaitOperations(QMemoryBarrier::Operations waitOperations)
{
Q_D(QMemoryBarrier);
- if (barrierTypes != d->m_barrierTypes) {
- d->m_barrierTypes = barrierTypes;
- emit barrierTypesChanged(barrierTypes);
- d->notifyPropertyChange("barrierTypes", QVariant::fromValue(barrierTypes));
+ if (waitOperations != d->m_waitOperations) {
+ d->m_waitOperations = waitOperations;
+ emit waitOperationsChanged(waitOperations);
+ d->notifyPropertyChange("waitOperations", QVariant::fromValue(waitOperations));
}
}
-QMemoryBarrier::BarrierTypes QMemoryBarrier::barrierTypes() const
+QMemoryBarrier::Operations QMemoryBarrier::waitOperations() const
{
Q_D(const QMemoryBarrier);
- return d->m_barrierTypes;
+ return d->m_waitOperations;
}
QMemoryBarrier::QMemoryBarrier(QMemoryBarrierPrivate &dd, Qt3DCore::QNode *parent)
@@ -159,7 +160,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QMemoryBarrier::createNodeCreationChange() c
auto creationChange = QFrameGraphNodeCreatedChangePtr<QMemoryBarrierData>::create(this);
QMemoryBarrierData &data = creationChange->data;
Q_D(const QMemoryBarrier);
- data.barrierTypes = d->m_barrierTypes;
+ data.waitOperations = d->m_waitOperations;
return creationChange;
}
diff --git a/src/render/framegraph/qmemorybarrier.h b/src/render/framegraph/qmemorybarrier.h
index 8b73c86bf..bb439a9a5 100644
--- a/src/render/framegraph/qmemorybarrier.h
+++ b/src/render/framegraph/qmemorybarrier.h
@@ -55,33 +55,34 @@ public:
explicit QMemoryBarrier(Qt3DCore::QNode *parent = nullptr);
~QMemoryBarrier();
- enum BarrierType {
+ enum Operation {
None = 0,
- VertexAttributeArrayBarrier = (1 << 0),
- ElementArrayBarrier = (1 << 1),
- UniformBarrier = (1 << 2),
- TextureFetchBarrier = (1 << 3),
- ShaderImageAccessBarrier = (1 << 4),
- CommandBarrier = (1 << 5),
- PixelBufferBarrier = (1 << 6),
- TextureUpdateBarrier = (1 << 7),
- BufferUpdateBarrier = (1 << 8),
- FrameBufferBarrier = (1 << 9),
- TransformFeedbackBarrier = (1 << 10),
- AtomicCounterBarrier = (1 << 11),
- ShaderStorageBarrier = (1 << 12),
- QueryBufferBarrier = (1 << 13),
- AllBarrier = 0xFFFFFFFF
+ VertexAttributeArray = (1 << 0),
+ ElementArray = (1 << 1),
+ Uniform = (1 << 2),
+ TextureFetch = (1 << 3),
+ ShaderImageAccess = (1 << 4),
+ Command = (1 << 5),
+ PixelBuffer = (1 << 6),
+ TextureUpdate = (1 << 7),
+ BufferUpdate = (1 << 8),
+ FrameBuffer = (1 << 9),
+ TransformFeedback = (1 << 10),
+ AtomicCounter = (1 << 11),
+ ShaderStorage = (1 << 12),
+ QueryBuffer = (1 << 13),
+ All = 0xFFFFFFFF
};
- Q_ENUM(BarrierType)
- Q_DECLARE_FLAGS(BarrierTypes, BarrierType)
+ Q_ENUM(Operation)
+ Q_DECLARE_FLAGS(Operations, Operation)
+
+ Operations waitOperations() const;
public Q_SLOTS:
- void setBarrierTypes(QMemoryBarrier::BarrierTypes barrierTypes);
- BarrierTypes barrierTypes() const;
+ void setWaitOperations(QMemoryBarrier::Operations operations);
Q_SIGNALS:
- void barrierTypesChanged(QMemoryBarrier::BarrierTypes barrierTypes);
+ void waitOperationsChanged(QMemoryBarrier::Operations barrierTypes);
protected:
explicit QMemoryBarrier(QMemoryBarrierPrivate &dd, Qt3DCore::QNode *parent = nullptr);
@@ -95,6 +96,6 @@ private:
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(Qt3DRender::QMemoryBarrier::BarrierTypes)
+Q_DECLARE_METATYPE(Qt3DRender::QMemoryBarrier::Operations)
#endif // QT3DRENDER_QMEMORYBARRIER_H
diff --git a/src/render/framegraph/qmemorybarrier_p.h b/src/render/framegraph/qmemorybarrier_p.h
index 09df0c89c..384dbee3d 100644
--- a/src/render/framegraph/qmemorybarrier_p.h
+++ b/src/render/framegraph/qmemorybarrier_p.h
@@ -63,12 +63,12 @@ public:
QMemoryBarrierPrivate();
Q_DECLARE_PUBLIC(QMemoryBarrier)
- QMemoryBarrier::BarrierTypes m_barrierTypes;
+ QMemoryBarrier::Operations m_waitOperations;
};
struct QMemoryBarrierData
{
- QMemoryBarrier::BarrierTypes barrierTypes;
+ QMemoryBarrier::Operations waitOperations;
};
} // namespace Qt3DRender
diff --git a/src/render/framegraph/qrendercapture.cpp b/src/render/framegraph/qrendercapture.cpp
index a4a5dabcb..f3e5d53ee 100644
--- a/src/render/framegraph/qrendercapture.cpp
+++ b/src/render/framegraph/qrendercapture.cpp
@@ -40,6 +40,8 @@
#include <Qt3DCore/QPropertyUpdatedChange>
#include <Qt3DRender/qframegraphnodecreatedchange.h>
+#include <QPointer>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
@@ -108,19 +110,41 @@ namespace Qt3DRender {
*/
/*!
+ * \qmlmethod bool Qt3D.Render::RenderCaptureReply::saveImage(fileName)
+ *
+ * Saves the render capture result as an image to \a fileName.
+ * Returns true if the image was successfully saved; otherwise returns false.
+ *
+ * \since 5.9
+ */
+
+/*!
* \qmlmethod void Qt3D.Render::RenderCaptureReply::saveToFile(fileName)
+ * \deprecated
*
* Saves the render capture result as an image to \a fileName.
+ *
+ * Deprecated in 5.9. Use saveImage().
*/
/*!
* \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(int captureId)
+ * \deprecated
*
* Used to request render capture. User can specify a \a captureId to identify
* the request. The requestId does not have to be unique. 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 reponsible for deallocating the returned object.
+ * when it is done. The user is responsible for deallocating the returned object.
+ */
+
+/*!
+ * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::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.
*/
/*!
@@ -178,6 +202,25 @@ bool QRenderCaptureReply::isComplete() const
/*!
* Saves the render capture result as an image to \a fileName.
+ *
+ * Returns true if the image was successfully saved; otherwise returns false.
+ * \since 5.9
+ */
+bool QRenderCaptureReply::saveImage(const QString &fileName) const
+{
+ Q_D(const QRenderCaptureReply);
+ if (d->m_complete)
+ {
+ return d->m_image.save(fileName);
+ }
+ return false;
+}
+
+/*!
+ * \deprecated
+ * Saves the render capture result as an image to \a fileName.
+ *
+ * Deprecated in 5.9. Use saveImage().
*/
void QRenderCaptureReply::saveToFile(const QString &fileName) const
{
@@ -212,7 +255,7 @@ QRenderCaptureReply *QRenderCapturePrivate::takeReply(int captureId)
{
QRenderCaptureReply *reply = nullptr;
for (int i = 0; i < m_waitingReplies.size(); ++i) {
- if (m_waitingReplies[i]->captureId() == captureId) {
+ if (m_waitingReplies[i]->d_func()->m_captureId == captureId) {
reply = m_waitingReplies[i];
m_waitingReplies.remove(i);
break;
@@ -239,11 +282,12 @@ QRenderCapture::QRenderCapture(Qt3DCore::QNode *parent)
}
/*!
+ * \deprecated
* Used to request render capture. User can specify a \a captureId to identify
* the request. The requestId does not have to be unique. 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 reponsible for deallocating the returned object.
+ * when it is done. The user is responsible for deallocating the returned object.
*/
QRenderCaptureReply *QRenderCapture::requestCapture(int captureId)
{
@@ -259,6 +303,28 @@ QRenderCaptureReply *QRenderCapture::requestCapture(int captureId)
}
/*!
+ * 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.
+ */
+QRenderCaptureReply *QRenderCapture::requestCapture()
+{
+ Q_D(QRenderCapture);
+ static int captureId = 1;
+ QRenderCaptureReply *reply = d->createReply(captureId);
+
+ Qt3DCore::QPropertyUpdatedChangePtr change(new Qt3DCore::QPropertyUpdatedChange(id()));
+ change->setPropertyName(QByteArrayLiteral("renderCaptureRequest"));
+ change->setValue(QVariant::fromValue(captureId));
+ d->notifyObservers(change);
+
+ captureId++;
+
+ return reply;
+}
+
+/*!
* \internal
*/
void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
@@ -268,10 +334,15 @@ void QRenderCapture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
if (propertyChange->type() == Qt3DCore::PropertyUpdated) {
if (propertyChange->propertyName() == QByteArrayLiteral("renderCaptureData")) {
RenderCaptureDataPtr data = propertyChange->value().value<RenderCaptureDataPtr>();
- QRenderCaptureReply *reply = d->takeReply(data.data()->captureId);
+ QPointer<QRenderCaptureReply> reply = d->takeReply(data.data()->captureId);
if (reply) {
d->setImage(reply, data.data()->image);
- emit reply->completeChanged(true);
+ emit reply->completed();
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ if (reply)
+ emit reply->completeChanged(true);
+QT_WARNING_POP
}
}
}
diff --git a/src/render/framegraph/qrendercapture.h b/src/render/framegraph/qrendercapture.h
index f3be273f3..5b768b593 100644
--- a/src/render/framegraph/qrendercapture.h
+++ b/src/render/framegraph/qrendercapture.h
@@ -52,18 +52,23 @@ class QT3DRENDERSHARED_EXPORT QRenderCaptureReply : public QObject
Q_OBJECT
Q_PROPERTY(QImage image READ image CONSTANT)
Q_PROPERTY(int captureId READ captureId CONSTANT)
- Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged)
+ Q_PROPERTY(bool complete READ isComplete NOTIFY completed)
public:
QImage image() const;
- int captureId() const;
+ Q_DECL_DEPRECATED int captureId() const;
bool isComplete() const;
- Q_INVOKABLE void saveToFile(const QString &fileName) const;
+ Q_INVOKABLE bool saveImage(const QString &fileName) const;
+#if QT_DEPRECATED_SINCE(5, 9)
+ // ### Qt 6: remove this
+ Q_DECL_DEPRECATED_X("Use saveImage instead") Q_INVOKABLE void saveToFile(const QString &fileName) const;
+#endif
Q_SIGNALS:
- void completeChanged(bool isComplete);
+ Q_DECL_DEPRECATED_X("Use completed instead") void completeChanged(bool isComplete);
+ void completed();
private:
Q_DECLARE_PRIVATE(QRenderCaptureReply)
@@ -79,7 +84,9 @@ class QT3DRENDERSHARED_EXPORT QRenderCapture : public QFrameGraphNode
public:
explicit QRenderCapture(Qt3DCore::QNode *parent = nullptr);
- Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture(int captureId);
+ Q_INVOKABLE Q_DECL_DEPRECATED_X("Use the overload with no parameter")
+ Qt3DRender::QRenderCaptureReply *requestCapture(int captureId);
+ Q_REVISION(9) Q_INVOKABLE Qt3DRender::QRenderCaptureReply *requestCapture();
protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
diff --git a/src/render/framegraph/qsortpolicy.cpp b/src/render/framegraph/qsortpolicy.cpp
index 2eb0dff19..b1e0f4956 100644
--- a/src/render/framegraph/qsortpolicy.cpp
+++ b/src/render/framegraph/qsortpolicy.cpp
@@ -65,7 +65,7 @@ QSortPolicyPrivate::QSortPolicyPrivate()
The sort types determine how drawable entities are sorted before drawing to
determine the drawing order. When QSortPolicy is present in the FrameGraph,
the sorting mechanism is determined by the SortTypes list. Multiple sort types
- can be used simultanously. If QSortPolicy is not present in the FrameGraph,
+ can be used simultaneously. If QSortPolicy is not present in the FrameGraph,
entities are drawn in the order they appear in the entity hierarchy.
*/
@@ -81,7 +81,7 @@ QSortPolicyPrivate::QSortPolicyPrivate()
The sort types determine how drawable entities are sorted before drawing to
determine the drawing order. When SortPolicy is present in the FrameGraph,
the sorting mechanism is determined by the SortTypes list. Multiple sort
- types can be used simultanously. If SortPolicy is not present in the FrameGraph,
+ types can be used simultaneously. If SortPolicy is not present in the FrameGraph,
entities are drawn in the order they appear in the entity hierarchy.
*/
diff --git a/src/render/framegraph/qviewport.cpp b/src/render/framegraph/qviewport.cpp
index a78e260a5..8c1ebe67c 100644
--- a/src/render/framegraph/qviewport.cpp
+++ b/src/render/framegraph/qviewport.cpp
@@ -50,6 +50,7 @@ namespace Qt3DRender {
QViewportPrivate::QViewportPrivate()
: QFrameGraphNodePrivate()
, m_normalizedRect(QRectF(0.0f, 0.0f, 1.0f, 1.0f))
+ , m_gamma(2.2f)
{
}
@@ -62,7 +63,8 @@ QViewportPrivate::QViewportPrivate()
\inherits Qt3DRender::QFrameGraphNode
Qt3DRender::QViewport of the scene specifies at which portion of the render surface Qt3D
- is rendering to. Area outside the viewport is left untouched.
+ is rendering to. Area outside the viewport is left untouched. It also controls global parameters
+ to the rendering in that viewport like gamma.
*/
/*!
@@ -74,7 +76,8 @@ QViewportPrivate::QViewportPrivate()
\brief A viewport on the Qt3D Scene
Viewport of the scene specifies at which portion of the render surface Qt3D is
- rendering to. Area outside the viewport is left untouched.
+ rendering to. Area outside the viewport is left untouched. It also controls global parameters
+ to the rendering in that viewport like gamma.
*/
/*!
@@ -86,6 +89,12 @@ QViewportPrivate::QViewportPrivate()
*/
/*!
+ \qmlproperty rect Viewport::gamma
+
+ Specifies the gamma factor for the viewport. The default is 2.2 which should give proper result on most screens.
+ */
+
+/*!
Constructs QViewport with given \a parent.
*/
QViewport::QViewport(QNode *parent)
@@ -111,6 +120,12 @@ QRectF QViewport::normalizedRect() const
return d->m_normalizedRect;
}
+float QViewport::gamma() const
+{
+ Q_D(const QViewport);
+ return d->m_gamma;
+}
+
/*!
\property QViewport::normalizedRect
@@ -127,12 +142,27 @@ void QViewport::setNormalizedRect(const QRectF &normalizedRect)
}
}
+/*!
+ \property QViewport::gamma
+
+ Specifies the gamma factor for the viewport. The default is 2.2 which should give proper result on most screens.
+ */
+void QViewport::setGamma(float gamma)
+{
+ Q_D(QViewport);
+ if (gamma != d->m_gamma) {
+ d->m_gamma = gamma;
+ emit gammaChanged(gamma);
+ }
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QViewport::createNodeCreationChange() const
{
auto creationChange = QFrameGraphNodeCreatedChangePtr<QViewportData>::create(this);
auto &data = creationChange->data;
Q_D(const QViewport);
data.normalizedRect = d->m_normalizedRect;
+ data.gamma = d->m_gamma;
return creationChange;
}
diff --git a/src/render/framegraph/qviewport.h b/src/render/framegraph/qviewport.h
index 5959ed791..66a3428c5 100644
--- a/src/render/framegraph/qviewport.h
+++ b/src/render/framegraph/qviewport.h
@@ -54,18 +54,22 @@ class QT3DRENDERSHARED_EXPORT QViewport : public QFrameGraphNode
{
Q_OBJECT
Q_PROPERTY(QRectF normalizedRect READ normalizedRect WRITE setNormalizedRect NOTIFY normalizedRectChanged)
+ Q_PROPERTY(float gamma READ gamma WRITE setGamma NOTIFY gammaChanged REVISION 9)
public:
explicit QViewport(Qt3DCore::QNode *parent = nullptr);
~QViewport();
QRectF normalizedRect() const;
+ float gamma() const;
public Q_SLOTS:
void setNormalizedRect(const QRectF& normalizedRect);
+ void setGamma(float gamma);
Q_SIGNALS:
void normalizedRectChanged(const QRectF& normalizedRect);
+ void gammaChanged(float gamma);
protected:
explicit QViewport(QViewportPrivate &dd, Qt3DCore::QNode *parent = nullptr);
diff --git a/src/render/framegraph/qviewport_p.h b/src/render/framegraph/qviewport_p.h
index 790cd3d06..4c82f38b3 100644
--- a/src/render/framegraph/qviewport_p.h
+++ b/src/render/framegraph/qviewport_p.h
@@ -67,11 +67,13 @@ public :
Q_DECLARE_PUBLIC(QViewport)
QRectF m_normalizedRect;
QColor m_clearColor;
+ float m_gamma;
};
struct QViewportData
{
QRectF normalizedRect;
+ float gamma;
};
} // namespace Qt3DRender
diff --git a/src/render/framegraph/rendercapture.cpp b/src/render/framegraph/rendercapture.cpp
index 6b6c48375..dea1cf565 100644
--- a/src/render/framegraph/rendercapture.cpp
+++ b/src/render/framegraph/rendercapture.cpp
@@ -92,7 +92,7 @@ void RenderCapture::sendRenderCaptures()
{
QMutexLocker lock(&m_mutex);
- for (const RenderCaptureDataPtr data : m_renderCaptureData) {
+ for (const RenderCaptureDataPtr &data : qAsConst(m_renderCaptureData)) {
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("renderCaptureData");
diff --git a/src/render/framegraph/viewportnode.cpp b/src/render/framegraph/viewportnode.cpp
index ccdb68918..b68f7b55b 100644
--- a/src/render/framegraph/viewportnode.cpp
+++ b/src/render/framegraph/viewportnode.cpp
@@ -55,6 +55,7 @@ ViewportNode::ViewportNode()
, m_yMin(0.0f)
, m_xMax(1.0f)
, m_yMax(1.0f)
+ , m_gamma(2.2f)
{
}
@@ -67,6 +68,7 @@ void ViewportNode::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr
m_xMax = data.normalizedRect.width();
m_yMin = data.normalizedRect.y();
m_yMax = data.normalizedRect.height();
+ m_gamma = data.gamma;
}
float ViewportNode::xMin() const
@@ -106,16 +108,28 @@ void ViewportNode::setYMax(float yMax)
m_yMax = yMax;
}
+float ViewportNode::gamma() const
+{
+ return m_gamma;
+}
+
+void ViewportNode::setGamma(float gamma)
+{
+ m_gamma = gamma;
+}
+
void ViewportNode::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == PropertyUpdated) {
QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
if (propertyChange->propertyName() == QByteArrayLiteral("normalizedRect")) {
- QRectF normalizedRect = propertyChange->value().value<QRectF>();
+ QRectF normalizedRect = propertyChange->value().toRectF();
setXMin(normalizedRect.x());
setYMin(normalizedRect.y());
setXMax(normalizedRect.width());
setYMax(normalizedRect.height());
+ } else if (propertyChange->propertyName() == QByteArrayLiteral("gamma")) {
+ setGamma(propertyChange->value().toFloat());
}
markDirty(AbstractRenderer::AllDirty);
}
diff --git a/src/render/framegraph/viewportnode_p.h b/src/render/framegraph/viewportnode_p.h
index 882aa4d86..85003ff36 100644
--- a/src/render/framegraph/viewportnode_p.h
+++ b/src/render/framegraph/viewportnode_p.h
@@ -81,6 +81,9 @@ public:
float yMax() const;
void setYMax(float yMax);
+ float gamma() const;
+ void setGamma(float gamma);
+
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE;
private:
@@ -90,6 +93,7 @@ private:
float m_yMin;
float m_xMax;
float m_yMax;
+ float m_gamma;
};
QRectF computeViewport(const QRectF &childViewport, const ViewportNode *parentViewport);
diff --git a/src/render/frontend/qabstractfunctor.h b/src/render/frontend/qabstractfunctor.h
index d9c4d65a4..95f6aee51 100644
--- a/src/render/frontend/qabstractfunctor.h
+++ b/src/render/frontend/qabstractfunctor.h
@@ -80,6 +80,7 @@ public:
virtual ~QAbstractFunctor();
virtual qintptr id() const = 0;
+ // TODO: Remove when moving a copy of this to Qt3DCore
template<class T>
const T *functor_cast(const QAbstractFunctor *other) const
{
diff --git a/src/render/frontend/qcamera.cpp b/src/render/frontend/qcamera.cpp
index b9e180b97..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.
@@ -346,6 +378,11 @@ QCameraPrivate::QCameraPrivate()
*/
/*!
+ * \property QCamera::exposure
+ * Holds the current exposure of the camera.
+ */
+
+/*!
* \property QCamera::position
* Holds the camera's position.
*/
@@ -387,6 +424,8 @@ QCamera::QCamera(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, 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);
@@ -415,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);
@@ -630,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)
@@ -773,12 +861,27 @@ void QCamera::setProjectionMatrix(const QMatrix4x4 &projectionMatrix)
d->m_lens->setProjectionMatrix(projectionMatrix);
}
+/*!
+ * Sets the camera's exposure to \a exposure.
+ */
+void QCamera::setExposure(float exposure)
+{
+ Q_D(QCamera);
+ d->m_lens->setExposure(exposure);
+}
+
QMatrix4x4 QCamera::projectionMatrix() const
{
Q_D(const QCamera);
return d->m_lens->projectionMatrix();
}
+float QCamera::exposure() const
+{
+ Q_D(const QCamera);
+ return d->m_lens->exposure();
+}
+
/*!
* Sets the camera's position in 3D space to \a position.
*/
diff --git a/src/render/frontend/qcamera.h b/src/render/frontend/qcamera.h
index f5bd49fa2..5c86ea122 100644
--- a/src/render/frontend/qcamera.h
+++ b/src/render/frontend/qcamera.h
@@ -72,6 +72,7 @@ class QT3DRENDERSHARED_EXPORT QCamera : public Qt3DCore::QEntity
Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged)
Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged)
Q_PROPERTY(QMatrix4x4 projectionMatrix READ projectionMatrix WRITE setProjectionMatrix NOTIFY projectionMatrixChanged)
+ Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged REVISION 9)
// LookAt
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY upVectorChanged)
@@ -126,6 +127,7 @@ public:
float bottom() const;
float top() const;
QMatrix4x4 projectionMatrix() const;
+ float exposure() const;
QVector3D position() const;
QVector3D upVector() const;
QVector3D viewCenter() const;
@@ -143,10 +145,15 @@ public Q_SLOTS:
void setBottom(float bottom);
void setTop(float top);
void setProjectionMatrix(const QMatrix4x4 &projectionMatrix);
+ void setExposure(float exposure);
void setPosition(const QVector3D &position);
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);
@@ -158,6 +165,7 @@ Q_SIGNALS:
void bottomChanged(float bottom);
void topChanged(float top);
void projectionMatrixChanged(const QMatrix4x4 &projectionMatrix);
+ void exposureChanged(float exposure);
void positionChanged(const QVector3D &position);
void upVectorChanged(const QVector3D &upVector);
void viewCenterChanged(const QVector3D &viewCenter);
diff --git a/src/render/frontend/qcameralens.cpp b/src/render/frontend/qcameralens.cpp
index 269bc8d16..c9be49484 100644
--- a/src/render/frontend/qcameralens.cpp
+++ b/src/render/frontend/qcameralens.cpp
@@ -202,6 +202,11 @@ namespace Qt3DRender {
*/
/*!
+ * \property QCameraLens::exposure
+ * Holds the current exposure of the camera lens.
+ */
+
+/*!
* \internal
*/
QCameraLensPrivate::QCameraLensPrivate()
@@ -215,7 +220,45 @@ QCameraLensPrivate::QCameraLensPrivate()
, m_right(0.5f)
, m_bottom(-0.5f)
, m_top(0.5f)
+ , m_exposure(0.0f)
+{
+}
+
+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();
}
/*!
@@ -559,14 +602,50 @@ QMatrix4x4 QCameraLens::projectionMatrix() const
return d->m_projectionMatrix;
}
+/*!
+ * Sets the camera lens' \a exposure
+ */
+void QCameraLens::setExposure(float exposure)
+{
+ Q_D(QCameraLens);
+ if (qFuzzyCompare(d->m_exposure, exposure))
+ return;
+ d->m_exposure = exposure;
+
+ emit exposureChanged(exposure);
+}
+
+float QCameraLens::exposure() const
+{
+ Q_D(const QCameraLens);
+ return d->m_exposure;
+}
+
Qt3DCore::QNodeCreatedChangeBasePtr QCameraLens::createNodeCreationChange() const
{
auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QCameraLensData>::create(this);
auto &data = creationChange->data;
data.projectionMatrix = d_func()->m_projectionMatrix;
+ data.exposure = d_func()->m_exposure;
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 ad414cada..0cd22e348 100644
--- a/src/render/frontend/qcameralens.h
+++ b/src/render/frontend/qcameralens.h
@@ -66,6 +66,7 @@ class QT3DRENDERSHARED_EXPORT QCameraLens : public Qt3DCore::QComponent
Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged)
Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged)
Q_PROPERTY(QMatrix4x4 projectionMatrix READ projectionMatrix WRITE setProjectionMatrix NOTIFY projectionMatrixChanged)
+ Q_PROPERTY(float exposure READ exposure WRITE setExposure NOTIFY exposureChanged REVISION 9)
public:
explicit QCameraLens(QNode *parent = nullptr);
@@ -102,6 +103,11 @@ public:
void setPerspectiveProjection(float fieldOfView, float aspect,
float nearPlane, float farPlane);
+ 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);
@@ -113,6 +119,7 @@ public Q_SLOTS:
void setBottom(float bottom);
void setTop(float top);
void setProjectionMatrix(const QMatrix4x4 &projectionMatrix);
+ void setExposure(float exposure);
Q_SIGNALS:
void projectionTypeChanged(QCameraLens::ProjectionType projectionType);
@@ -125,6 +132,8 @@ Q_SIGNALS:
void bottomChanged(float bottom);
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);
@@ -132,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 ecaa45b68..d78579b70 100644
--- a/src/render/frontend/qcameralens_p.h
+++ b/src/render/frontend/qcameralens_p.h
@@ -51,7 +51,8 @@
// We mean it.
//
-#include <Qt3DCore/private/qcomponent_p.h>
+#include <private/qcomponent_p.h>
+#include <private/qnodecommand_p.h>
#include "qcameralens.h"
#include <Qt3DCore/qpropertyupdatedchange.h>
@@ -101,6 +102,11 @@ public:
mutable QMatrix4x4 m_projectionMatrix;
+ float m_exposure;
+
+ Qt3DCore::QNodeCommand::CommandId m_pendingViewAllCommand;
+ void processViewAllCommand(Qt3DCore::QNodeCommand::CommandId commandId, const QVariant &data);
+
private:
inline void updatePerpectiveProjection()
{
@@ -130,6 +136,7 @@ private:
struct QCameraLensData
{
QMatrix4x4 projectionMatrix;
+ float exposure;
};
} // namespace Qt3DRender
diff --git a/src/render/frontend/qlevelofdetail.cpp b/src/render/frontend/qlevelofdetail.cpp
index 0d70803ca..03df4e6a8 100644
--- a/src/render/frontend/qlevelofdetail.cpp
+++ b/src/render/frontend/qlevelofdetail.cpp
@@ -37,7 +37,6 @@
**
****************************************************************************/
-#include "qboundingsphere.h"
#include "qlevelofdetail.h"
#include "qlevelofdetail_p.h"
#include "qcamera.h"
@@ -51,23 +50,9 @@ QLevelOfDetailPrivate::QLevelOfDetailPrivate()
: QComponentPrivate()
, m_camera(nullptr)
, m_currentIndex(0)
- , m_thresholdType(QLevelOfDetail::DistanceToCamera)
- , m_volumeOverride(nullptr)
+ , m_thresholdType(QLevelOfDetail::DistanceToCameraThreshold)
+ , m_volumeOverride()
{
- Q_Q(QLevelOfDetail);
- m_volumeOverride = new QBoundingSphere(q);
- QObject::connect(m_volumeOverride, SIGNAL(radiusChanged(float)), q, SLOT(_q_radiusChanged(float)));
- QObject::connect(m_volumeOverride, SIGNAL(centerChanged(const QVector3D &)), q, SLOT(_q_centerChanged(const QVector3D&)));
-}
-
-void QLevelOfDetailPrivate::_q_radiusChanged(float radius)
-{
- notifyPropertyChange("radius", radius);
-}
-
-void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
-{
- notifyPropertyChange("center", center);
}
/*!
@@ -92,7 +77,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
The currentIndex property can then be used, for example, to enable or
disable entities, change material, etc.
- The LevelOfDetail component is not shareable between multiple Entity's.
+ The LevelOfDetail component is not shareable between multiple \l [QML]{Entity}{entities}.
\code
#include <Qt3DCore/QEntity>
@@ -156,7 +141,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
id: lod
camera: mainCamera
thresholds: [20, 35, 50, 65]
- thresholdType: LevelOfDetail.DistanceToCamera
+ thresholdType: LevelOfDetail.DistanceToCameraThreshold
}
CylinderMesh {
@@ -180,8 +165,8 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
*
* Specifies how the values in the thresholds are interpreted
*
- * \value DistanceToCamera Distance from the entity to the selected camera
- * \value ProjectedScreenPixelSize Size of the entity when projected on the
+ * \value DistanceToCameraThreshold Distance from the entity to the selected camera
+ * \value ProjectedScreenPixelSizeThreshold Size of the entity when projected on the
* screen as seen from the selected camera, expressed in number of
* pixels on the side of the bounding square in screen space.
*/
@@ -192,43 +177,14 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
* Specifies how the values in the thresholds are interpreted
*
* \list
- * \li DistanceToCamera Distance from the entity to the selected camera
- * \li ProjectedScreenPixelSize Size of the entity when projected on the
+ * \li DistanceToCameraThreshold Distance from the entity to the selected camera
+ * \li ProjectedScreenPixelSizeThreshold Size of the entity when projected on the
* screen as seen from the selected camera, expressed in number of
* pixels on the side of the bounding square in screen space.
* \endlist
* \sa Qt3DRender::QLevelOfDetail::ThresholdType
*/
-
-/*!
- * \enum Qt3DRender::QLevelOfDetail::SizeProxyMode
- *
- * Specifies what is used as a proxy for the entity when computing distance
- * or size.
- *
- * \value BoundingSphere use the bounding sphere specified by the center
- * and radius properties.
- * \value ChildrenBoundingSphere use the bounding sphere of the entity the
- * component is attached to.
- */
-
-/*!
- * \qmlproperty enumeration LevelOfDetail::SizeProxyMode
- *
- * Specifies what is used as a proxy for the entity when computing distance
- * or size.
- *
- * \list
- * \li BoundingSphere use the bounding sphere specified by the center
- * and radius properties.
- * \li ChildrenBoundingSphere use the bounding sphere of the entity the
- * component is attached to.
- * \endlist
- * \sa Qt3DRender::QLevelOfDetail::SizeProxyMode
- */
-
-
/*!
* \qmlproperty Camera LevelOfDetail::camera
*
@@ -272,11 +228,11 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
* Array of range values as float point numbers. The value for the most detailed representation
* should be specified first.
*
- * If LevelOfDetail::thresholdType is set to LevelOfDetail.Distance, values should be specified in
- * ascending order, in camera space coordinates
+ * If LevelOfDetail::thresholdType is set to LevelOfDetail.DistanceToCameraThreshold, values should
+ * be specified in ascending order, in camera space coordinates
*
- * If LevelOfDetail::thresholdType is set to LevelOfDetail.ProjectedScreenPixelSize, values should
- * be specified in descending order, in screen space pixels.
+ * If LevelOfDetail::thresholdType is set to LevelOfDetail.ProjectedScreenPixelSizeThreshold, values
+ * should be specified in descending order, in screen space pixels.
*/
/*!
@@ -285,10 +241,12 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
* Array of range values as float point numbers. The value for the most detailed representation
* should be specified first.
*
- * If Qt3DRender::QLevelOfDetail::thresholdType is set to Qt3DRender::QLevelOfDetail::Distance, values should be specified in
+ * If Qt3DRender::QLevelOfDetail::thresholdType is set to
+ * Qt3DRender::QLevelOfDetail::DistanceToCameraThreshold, values should be specified in
* ascending order, in camera space coordinates
*
- * If Qt3DRender::QLevelOfDetail::thresholdType is set to Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSize, values should
+ * If Qt3DRender::QLevelOfDetail::thresholdType is set to
+ * Qt3DRender::QLevelOfDetail::ProjectedScreenPixelSizeThreshold, values should
* be specified in descending order, in screen space pixels.
*
* \sa Qt3DRender::QLevelOfDetail::ThresholdType
@@ -306,7 +264,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
* If this value to null, the bounding volume of the entity is used. Care must be
* taken that this bounding volume never becomes invalid.
*
- * \sa BoundingSphere
+ * \sa Qt3DRender::QLevelOfDetailBoundingSphere
*/
/*!
@@ -319,7 +277,7 @@ void QLevelOfDetailPrivate::_q_centerChanged(const QVector3D &center)
* If this value to nullptr, the bounding volume of the entity is used. Care must be
* taken that this bounding volume never becomes invalid.
*
- * \sa QBoundingSphere
+ * \sa Qt3dRender::QLevelOfDetailBoundingSphere
*/
@@ -354,8 +312,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QLevelOfDetail::createNodeCreationChange() c
data.currentIndex = d->m_currentIndex;
data.thresholdType = d->m_thresholdType;
data.thresholds = d->m_thresholds;
- data.radius = d->m_volumeOverride ? d->m_volumeOverride->radius() : -1.f;
- data.center = d->m_volumeOverride ? d->m_volumeOverride->center() : QVector3D();
+ data.volumeOverride = d->m_volumeOverride;
return creationChange;
}
@@ -381,7 +338,7 @@ QCamera *QLevelOfDetail::camera() const
}
/*!
- * Sets the camera relative to which distance and size are computed.
+ * Sets the \a camera relative to which distance and size are computed.
*/
void QLevelOfDetail::setCamera(QCamera *camera)
{
@@ -399,7 +356,7 @@ int QLevelOfDetail::currentIndex() const
}
/*!
- * Sets the current index.
+ * Sets the \a currentIndex.
*
* \note This should not normally be set by the user.
*
@@ -424,6 +381,7 @@ QLevelOfDetail::ThresholdType QLevelOfDetail::thresholdType() const
/*!
* Sets the way thresholds values are interpreted
+ * with parameter \a thresholdType
* \sa Qt3DRender::QLevelOfDetail::ThresholdType
*/
void QLevelOfDetail::setThresholdType(QLevelOfDetail::ThresholdType thresholdType)
@@ -441,36 +399,35 @@ QVector<qreal> QLevelOfDetail::thresholds() const
return d->m_thresholds;
}
+QLevelOfDetailBoundingSphere QLevelOfDetail::createBoundingSphere(const QVector3D &center, float radius)
+{
+ return QLevelOfDetailBoundingSphere(center, radius);
+}
+
/*!
- * Sets the range values.
+ * Sets the range values in \a thresholds.
* \sa Qt3DRender::QLevelOfDetail::thresholdType
*/
-void QLevelOfDetail::setThresholds(QVector<qreal> thresholds)
+void QLevelOfDetail::setThresholds(const QVector<qreal> &thresholds)
{
Q_D(QLevelOfDetail);
if (d->m_thresholds != thresholds) {
d->m_thresholds = thresholds;
- thresholdsChanged(d->m_thresholds);
+ emit thresholdsChanged(d->m_thresholds);
}
}
-QBoundingSphere *QLevelOfDetail::volumeOverride() const
+QLevelOfDetailBoundingSphere QLevelOfDetail::volumeOverride() const
{
Q_D(const QLevelOfDetail);
return d->m_volumeOverride;
}
-void QLevelOfDetail::setVolumeOverride(QBoundingSphere *volumeOverride)
+void QLevelOfDetail::setVolumeOverride(const QLevelOfDetailBoundingSphere &volumeOverride)
{
Q_D(QLevelOfDetail);
if (d->m_volumeOverride != volumeOverride) {
- if (d->m_volumeOverride)
- disconnect(d->m_volumeOverride);
d->m_volumeOverride = volumeOverride;
- if (d->m_volumeOverride) {
- connect(d->m_volumeOverride, SIGNAL(radiusChanged(float)), this, SLOT(_q_radiusChanged(float)));
- connect(d->m_volumeOverride, SIGNAL(centerChanged(const QVector3D &)), this, SLOT(_q_centerChanged(const QVector3D&)));
- }
emit volumeOverrideChanged(volumeOverride);
}
}
diff --git a/src/render/frontend/qlevelofdetail.h b/src/render/frontend/qlevelofdetail.h
index f3325aea0..2e752d962 100644
--- a/src/render/frontend/qlevelofdetail.h
+++ b/src/render/frontend/qlevelofdetail.h
@@ -42,6 +42,7 @@
#include <Qt3DCore/qcomponent.h>
#include <Qt3DRender/qt3drender_global.h>
+#include <Qt3DRender/qlevelofdetailboundingsphere.h>
#include <QVector3D>
@@ -50,7 +51,6 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
class QCamera;
-class QBoundingSphere;
class QLevelOfDetailPrivate;
class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent
@@ -60,12 +60,12 @@ class QT3DRENDERSHARED_EXPORT QLevelOfDetail : public Qt3DCore::QComponent
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
Q_PROPERTY(ThresholdType thresholdType READ thresholdType WRITE setThresholdType NOTIFY thresholdTypeChanged)
Q_PROPERTY(QVector<qreal> thresholds READ thresholds WRITE setThresholds NOTIFY thresholdsChanged)
- Q_PROPERTY(Qt3DRender::QBoundingSphere *volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged)
+ Q_PROPERTY(Qt3DRender::QLevelOfDetailBoundingSphere volumeOverride READ volumeOverride WRITE setVolumeOverride NOTIFY volumeOverrideChanged)
public:
enum ThresholdType {
- DistanceToCamera,
- ProjectedScreenPixelSize,
+ DistanceToCameraThreshold,
+ ProjectedScreenPixelSizeThreshold,
};
Q_ENUM(ThresholdType) // LCOV_EXCL_LINE
@@ -76,21 +76,23 @@ public:
int currentIndex() const;
ThresholdType thresholdType() const;
QVector<qreal> thresholds() const;
- QBoundingSphere *volumeOverride() const;
+ QLevelOfDetailBoundingSphere volumeOverride() const;
+
+ Q_INVOKABLE QLevelOfDetailBoundingSphere createBoundingSphere(const QVector3D &center, float radius);
public Q_SLOTS:
void setCamera(QCamera *camera);
void setCurrentIndex(int currentIndex);
void setThresholdType(ThresholdType thresholdType);
- void setThresholds(QVector<qreal> thresholds);
- void setVolumeOverride(QBoundingSphere *volumeOverride);
+ void setThresholds(const QVector<qreal> &thresholds);
+ void setVolumeOverride(const QLevelOfDetailBoundingSphere &volumeOverride);
Q_SIGNALS:
void cameraChanged(QCamera *camera);
void currentIndexChanged(int currentIndex);
void thresholdTypeChanged(ThresholdType thresholdType);
- void thresholdsChanged(QVector<qreal> thresholds);
- void volumeOverrideChanged(QBoundingSphere *volumeOverride);
+ void thresholdsChanged(const QVector<qreal> &thresholds);
+ void volumeOverrideChanged(const QLevelOfDetailBoundingSphere &volumeOverride);
protected:
explicit QLevelOfDetail(QLevelOfDetailPrivate &dd, Qt3DCore::QNode *parent = nullptr);
@@ -99,12 +101,12 @@ protected:
private:
Q_DECLARE_PRIVATE(QLevelOfDetail)
- Q_PRIVATE_SLOT(d_func(), void _q_radiusChanged(float))
- Q_PRIVATE_SLOT(d_func(), void _q_centerChanged(const QVector3D&))
};
} // namespace Qt3DRender
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(Qt3DRender::QLevelOfDetailBoundingSphere)
+
#endif // QT3DRENDER_QLEVELOFDETAIL_H
diff --git a/src/render/frontend/qlevelofdetail_p.h b/src/render/frontend/qlevelofdetail_p.h
index ab25e9ad3..1d7a05a71 100644
--- a/src/render/frontend/qlevelofdetail_p.h
+++ b/src/render/frontend/qlevelofdetail_p.h
@@ -53,6 +53,7 @@
#include <private/qcomponent_p.h>
#include <qlevelofdetail.h>
+#include <Qt3DRender/qlevelofdetailboundingsphere.h>
#include <QVector3D>
@@ -74,7 +75,7 @@ public:
int m_currentIndex;
QLevelOfDetail::ThresholdType m_thresholdType;
QVector<qreal> m_thresholds;
- QPointer<QBoundingSphere> m_volumeOverride;
+ QLevelOfDetailBoundingSphere m_volumeOverride;
};
struct QLevelOfDetailData
@@ -83,8 +84,7 @@ struct QLevelOfDetailData
int currentIndex;
QLevelOfDetail::ThresholdType thresholdType;
QVector<qreal> thresholds;
- float radius;
- QVector3D center;
+ QLevelOfDetailBoundingSphere volumeOverride;
};
} // namespace Qt3DRender
diff --git a/src/render/frontend/qboundingsphere.cpp b/src/render/frontend/qlevelofdetailboundingsphere.cpp
index 4d8b1aba8..abf8081d3 100644
--- a/src/render/frontend/qboundingsphere.cpp
+++ b/src/render/frontend/qlevelofdetailboundingsphere.cpp
@@ -37,110 +37,121 @@
**
****************************************************************************/
-#include "qboundingsphere.h"
-#include "qboundingsphere_p.h"
+#include "qlevelofdetailboundingsphere.h"
+#include <QSharedData>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-QBoundingSpherePrivate::QBoundingSpherePrivate()
- : QObjectPrivate()
- , m_radius(1.f)
+class QLevelOfDetailBoundingSpherePrivate: public QSharedData
{
+public:
+ QLevelOfDetailBoundingSpherePrivate()
+ : QSharedData()
+ , m_radius(0.0f)
+ {}
-}
+ QLevelOfDetailBoundingSpherePrivate(QVector3D center, float radius)
+ : QSharedData()
+ , m_center(center)
+ , m_radius(radius)
+ {}
+
+ ~QLevelOfDetailBoundingSpherePrivate()
+ {}
+
+ QVector3D m_center;
+ float m_radius;
+};
/*!
- \class Qt3DRender::QBoundingSphere
+ \class Qt3DRender::QLevelOfDetailBoundingSphere
\inmodule Qt3DRender
\since 5.9
- \brief The QBoundingSphere class provides a simple spherical volume, defined by it's center and radius.
+ \brief The QLevelOfDetailBoundingSphere class provides a simple spherical volume, defined by it's center and radius.
*/
/*!
\qmltype LevelOfDetail
- \instantiates Qt3DRender::QLevelOfDetail
+ \instantiates Qt3DRender::QLevelOfDetailBoundingSphere
\inherits Component3D
\inqmlmodule Qt3D.Render
- \brief The BoundingSphere class provides a simple spherical volume, defined by it's center and radius.
+ \brief The LevelOfDetailBoundingSphere class provides a simple spherical volume, defined by it's center and radius.
*/
/*!
- * \qmlproperty QVector3D BoundingSphere::center
+ * \qmlproperty QVector3D LevelOfDetailBoundingSphere::center
*
* Specifies the center of the bounding sphere
*/
/*!
- * \property QBoundingSphere::center
+ * \property QLevelOfDetailBoundingSphere::center
*
* Specifies the center of the bounding sphere
*/
/*!
- * \qmlproperty qreal BoundingSphere::radius
+ * \qmlproperty qreal LevelOfDetailBoundingSphere::radius
*
* Specifies the radius of the bounding sphere
*/
/*!
- * \property QBoundingSphere::radius
+ * \property QLevelOfDetailBoundingSphere::radius
*
* Specifies the radius of the bounding sphere
*/
-/*! \fn Qt3DRender::QBoundingSphere::QBoundingSphere(QObject *parent)
- Constructs a new QBoundingSphere with the specified \a parent.
+/*! \fn Qt3DRender::QLevelOfDetailBoundingSphere::QLevelOfDetailBoundingSphere(const QVector3D &center = QVector3D(), float radius = -1.0f)
+ Constructs a new QLevelOfDetailBoundingSphere with the specified \a center and \a radius.
*/
-QBoundingSphere::QBoundingSphere(QObject *parent)
- : QObject(*new QBoundingSpherePrivate, parent)
+
+
+QLevelOfDetailBoundingSphere::QLevelOfDetailBoundingSphere(QVector3D center, float radius)
+ : d_ptr(new QLevelOfDetailBoundingSpherePrivate(center, radius))
{
+}
+QLevelOfDetailBoundingSphere::QLevelOfDetailBoundingSphere(const QLevelOfDetailBoundingSphere &other)
+ : d_ptr(other.d_ptr)
+{
}
-QBoundingSphere::QBoundingSphere(const QVector3D &center, float radius, QObject *parent)
- : QBoundingSphere(parent)
+QLevelOfDetailBoundingSphere::~QLevelOfDetailBoundingSphere()
{
- Q_D(QBoundingSphere);
- d->m_center = center;
- d->m_radius = radius;
}
-QVector3D QBoundingSphere::center() const
+QLevelOfDetailBoundingSphere &QLevelOfDetailBoundingSphere::operator =(const QLevelOfDetailBoundingSphere &other)
{
- Q_D(const QBoundingSphere);
- return d->m_center;
+ d_ptr = other.d_ptr;
+ return *this;
}
-float QBoundingSphere::radius() const
+QVector3D QLevelOfDetailBoundingSphere::center() const
{
- Q_D(const QBoundingSphere);
- return d->m_radius;
+ return d_ptr->m_center;
}
-/*!
- * Sets the radius of the bounding sphere.
- */
-void QBoundingSphere::setRadius(float radius)
+float QLevelOfDetailBoundingSphere::radius() const
{
- Q_D(QBoundingSphere);
- if (d->m_radius != radius) {
- d->m_radius = radius;
- emit radiusChanged(radius);
- }
+ return d_ptr->m_radius;
}
-/*!
- * Sets the center of the bounding sphere.
- */
-void QBoundingSphere::setCenter(const QVector3D &center)
+bool QLevelOfDetailBoundingSphere::isEmpty() const
+{
+ return d_ptr->m_radius <= 0.0f;
+}
+
+bool QLevelOfDetailBoundingSphere::operator ==(const QLevelOfDetailBoundingSphere &other) const
+{
+ return d_ptr->m_center == other.center() && other.d_ptr->m_radius == other.radius();
+}
+
+bool QLevelOfDetailBoundingSphere::operator !=(const QLevelOfDetailBoundingSphere &other) const
{
- Q_D(QBoundingSphere);
- if (d->m_center != center) {
- d->m_center = center;
- emit centerChanged(center);
- }
+ return !(*this == other);
}
} // namespace Qt3DRender
diff --git a/src/render/frontend/qboundingsphere.h b/src/render/frontend/qlevelofdetailboundingsphere.h
index e7f9b7784..b35df95e8 100644
--- a/src/render/frontend/qboundingsphere.h
+++ b/src/render/frontend/qlevelofdetailboundingsphere.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_QBOUNDINGSPHERE_H
-#define QT3DRENDER_QBOUNDINGSPHERE_H
+#ifndef QT3DRENDER_QLEVELOFDETAILBOUNDINGSPHERE_H
+#define QT3DRENDER_QLEVELOFDETAILBOUNDINGSPHERE_H
#include <Qt3DCore/qcomponent.h>
#include <Qt3DRender/qt3drender_global.h>
@@ -49,34 +49,33 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QBoundingSpherePrivate;
+class QLevelOfDetailBoundingSpherePrivate;
-class QT3DRENDERSHARED_EXPORT QBoundingSphere : public QObject
+class QT3DRENDERSHARED_EXPORT QLevelOfDetailBoundingSphere
{
- Q_OBJECT
- Q_PROPERTY(QVector3D center READ center WRITE setCenter NOTIFY centerChanged)
- Q_PROPERTY(float radius READ radius WRITE setRadius NOTIFY radiusChanged)
+ Q_GADGET
+ Q_PROPERTY(QVector3D center READ center CONSTANT)
+ Q_PROPERTY(float radius READ radius CONSTANT)
public:
- explicit QBoundingSphere(QObject *parent = nullptr);
- QBoundingSphere(const QVector3D &center, float radius, QObject *parent = nullptr);
+ explicit QLevelOfDetailBoundingSphere(QVector3D center = QVector3D(), float radius = 1.0f);
+ QLevelOfDetailBoundingSphere(const QLevelOfDetailBoundingSphere &other);
+ ~QLevelOfDetailBoundingSphere();
+
+ QLevelOfDetailBoundingSphere &operator =(const QLevelOfDetailBoundingSphere &other);
QVector3D center() const;
float radius() const;
-public Q_SLOTS:
- void setRadius(float radius);
- void setCenter(const QVector3D &center);
-
-Q_SIGNALS:
- void radiusChanged(float radius);
- void centerChanged(const QVector3D &center);
+ bool isEmpty() const;
+ bool operator ==(const QLevelOfDetailBoundingSphere &other) const;
+ bool operator !=(const QLevelOfDetailBoundingSphere &other) const;
private:
- Q_DECLARE_PRIVATE(QBoundingSphere)
+ QSharedDataPointer<QLevelOfDetailBoundingSpherePrivate> d_ptr;
};
} // namespace Qt3DRender
QT_END_NAMESPACE
-#endif // QT3DRENDER_QBOUNDINGSPHERE_H
+#endif // QT3DRENDER_QLEVELOFDETAILBOUNDINGSPHERE_H
diff --git a/src/render/frontend/qlevelofdetailswitch.cpp b/src/render/frontend/qlevelofdetailswitch.cpp
index 9a63343ed..845fdd5a6 100644
--- a/src/render/frontend/qlevelofdetailswitch.cpp
+++ b/src/render/frontend/qlevelofdetailswitch.cpp
@@ -69,11 +69,17 @@ namespace Qt3DRender {
This component is assigned to an entity. When the entity changes distance relative
to the camera, the LevelOfDetailSwitch will disable all the child entities except
- the one matching index \l LevelOfDetailSwitch::currentIndex.
+ the one matching index \l currentIndex.
\sa LevelOfDetail
*/
+/*!
+ \qmlproperty int LevelOfDetailSwitch::currentIndex
+
+ The index of the presently selected child entity.
+*/
+
/*! \fn Qt3DRender::QLevelOfDetailSwitch::QLevelOfDetailSwitch(Qt3DCore::QNode *parent)
Constructs a new QLevelOfDetailSwitch with the specified \a parent.
*/
@@ -107,8 +113,10 @@ void QLevelOfDetailSwitch::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &cha
emit currentIndexChanged(ndx);
int entityIndex = 0;
- for (Qt3DCore::QEntity *entity : entities()) {
- for (Qt3DCore::QNode *childNode : entity->childNodes()) {
+ const auto entities = this->entities();
+ for (Qt3DCore::QEntity *entity : entities) {
+ const auto childNodes = entity->childNodes();
+ for (Qt3DCore::QNode *childNode : childNodes) {
Qt3DCore::QEntity *childEntity = qobject_cast<Qt3DCore::QEntity *>(childNode);
if (childEntity) {
childEntity->setEnabled(entityIndex == ndx);
diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp
index db6840d7f..1cda638cb 100644
--- a/src/render/frontend/qpickingsettings.cpp
+++ b/src/render/frontend/qpickingsettings.cpp
@@ -53,6 +53,11 @@ namespace Qt3DRender {
The picking settings determine how the entity picking is handled. For more details about
entity picking, see QObjectPicker component documentation.
+
+ Picking is triggered by mouse events. It will cast a ray through the scene and look for
+ geometry intersecting the ray.
+
+ \sa QObjectPicker, QPickEvent, QPickTriangleEvent
*/
/*!
@@ -64,6 +69,11 @@ namespace Qt3DRender {
The picking settings determine how the entity picking is handled. For more details about
entity picking, see Qt3DRender::QObjectPicker component documentation.
+
+ Picking is triggered by mouse events. It will cast a ray through the scene and look for
+ geometry intersecting the ray.
+
+ \sa ObjectPicker
*/
QPickingSettingsPrivate::QPickingSettingsPrivate()
@@ -104,9 +114,6 @@ QPickingSettings::PickResultMode QPickingSettings::pickResultMode() const
return d->m_pickResultMode;
}
-/*!
- * \return the back facing picking flag
- */
QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPickingMode() const
{
Q_D(const QPickingSettings);
@@ -119,7 +126,7 @@ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPi
* Specifies the picking method.
*
* \value BoundingVolumePicking An entity is considered picked if the picking ray intersects
- * the bounding volume of the entity.
+ * the bounding volume of the entity (default).
* \value TrianglePicking An entity is considered picked if the picking ray intersects with
* any triangle of the entity's mesh component.
*/
@@ -140,6 +147,12 @@ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPi
\property QPickingSettings::pickMethod
Holds the current pick method.
+
+ By default, for performance reasons, ray casting will use bounding volume picking.
+ This may however lead to unexpected results if a small object is englobed
+ in the bounding sphere of a large object behind it.
+
+ Triangle picking will produce exact results but is computationally more expensive.
*/
void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod)
{
@@ -157,8 +170,10 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod)
* Specifies what is included into the picking results.
*
* \value NearestPick Only the nearest entity to picking ray origin intersected by the picking ray
- * is picked.
+ * is picked (default).
* \value AllPicks All entities that intersect the picking ray are picked.
+ *
+ * \sa Qt3DRender::QPickEvent
*/
/*!
@@ -177,6 +192,14 @@ void QPickingSettings::setPickMethod(QPickingSettings::PickMethod pickMethod)
\property QPickingSettings::pickResultMode
Holds the current pick results mode.
+
+ By default, pick results will only be produced for the entity closest to the camera.
+
+ When setting the pick method to AllPicks, events will be triggered for all the
+ entities with a QObjectPicker along the ray.
+
+ If a QObjectPicker is assigned to an entity with multiple children, an event will
+ be triggered for each child entity that intersects the ray.
*/
void QPickingSettings::setPickResultMode(QPickingSettings::PickResultMode pickResultMode)
{
@@ -189,8 +212,31 @@ void QPickingSettings::setPickResultMode(QPickingSettings::PickResultMode pickRe
}
/*!
- * \a faceOrientationPickingMode determines whether back facing faces are picked or not.
- */
+ \enum Qt3DRender::QPickingSettings::FaceOrientationPickingMode
+
+ Specifies how face orientation affects triangle picking
+
+ \value FrontFace Only front-facing triangles will be picked (default).
+ \value BackFace Only back-facing triangles will be picked.
+ \value FrontAndBackFace Both front- and back-facing triangles will be picked.
+*/
+
+/*!
+ \qmlproperty enumeration PickingSettings::faceOrientationPickingMode
+
+ Specifies how face orientation affects triangle picking
+
+ \list
+ \li PickingSettings.FrontFace Only front-facing triangles will be picked (default).
+ \li PickingSettings.BackFace Only back-facing triangles will be picked.
+ \li PickingSettings.FrontAndBackFace Both front- and back-facing triangles will be picked.
+ \endlist
+*/
+/*!
+ \property QPickingSettings::faceOrientationPickingMode
+
+ Specifies how face orientation affects triangle picking
+*/
void QPickingSettings::setFaceOrientationPickingMode(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode)
{
Q_D(QPickingSettings);
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp
index d9b45b7a7..4d775aeb3 100644
--- a/src/render/frontend/qrenderaspect.cpp
+++ b/src/render/frontend/qrenderaspect.cpp
@@ -75,14 +75,18 @@
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qfrustumculling.h>
#include <Qt3DRender/qabstractlight.h>
+#include <Qt3DRender/qenvironmentlight.h>
#include <Qt3DRender/qdispatchcompute.h>
#include <Qt3DRender/qcomputecommand.h>
#include <Qt3DRender/qrendersurfaceselector.h>
#include <Qt3DRender/qrendersettings.h>
#include <Qt3DRender/qrendercapture.h>
+#include <Qt3DRender/qbuffercapture.h>
#include <Qt3DRender/qmemorybarrier.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>
@@ -118,20 +122,26 @@
#include <Qt3DRender/private/qsceneimportfactory_p.h>
#include <Qt3DRender/private/frustumculling_p.h>
#include <Qt3DRender/private/light_p.h>
+#include <Qt3DRender/private/environmentlight_p.h>
#include <Qt3DRender/private/dispatchcompute_p.h>
#include <Qt3DRender/private/computecommand_p.h>
#include <Qt3DRender/private/rendersurfaceselector_p.h>
#include <Qt3DRender/private/rendersettings_p.h>
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/technique_p.h>
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DRender/private/memorybarrier_p.h>
+#include <private/qrenderpluginfactory_p.h>
+#include <private/qrenderplugin_p.h>
+
#include <Qt3DCore/qentity.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/qnode.h>
+#include <Qt3DCore/QAspectEngine>
#include <Qt3DCore/private/qservicelocator_p.h>
#include <QDebug>
@@ -162,7 +172,7 @@ QRenderAspectPrivate::QRenderAspectPrivate(QRenderAspect::RenderType type)
, m_renderType(type)
, m_offscreenHelper(nullptr)
{
- // Load the scene parsers
+ m_instances.append(this);
loadSceneParsers();
}
@@ -175,6 +185,18 @@ QRenderAspectPrivate::~QRenderAspectPrivate()
if (m_renderer != nullptr)
qWarning() << Q_FUNC_INFO << "The renderer should have been deleted when reaching this point (this warning may be normal when running tests)";
delete m_nodeManagers;
+ m_instances.removeAll(this);
+}
+
+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 */
@@ -190,7 +212,7 @@ void QRenderAspectPrivate::registerBackendTypes()
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));
@@ -215,6 +237,7 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QEffect>(QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(m_renderer));
q->registerBackendType<QFilterKey>(QSharedPointer<Render::NodeFunctor<Render::FilterKey, Render::FilterKeyManager> >::create(m_renderer));
q->registerBackendType<QAbstractLight>(QSharedPointer<Render::RenderLightFunctor>::create(m_renderer, m_nodeManagers));
+ q->registerBackendType<QEnvironmentLight>(QSharedPointer<Render::NodeFunctor<Render::EnvironmentLight, Render::EnvironmentLightManager> >::create(m_renderer));
q->registerBackendType<QMaterial>(QSharedPointer<Render::NodeFunctor<Render::Material, Render::MaterialManager> >::create(m_renderer));
q->registerBackendType<QParameter>(QSharedPointer<Render::NodeFunctor<Render::Parameter, Render::ParameterManager> >::create(m_renderer));
q->registerBackendType<QRenderPass>(QSharedPointer<Render::NodeFunctor<Render::RenderPass, Render::RenderPassManager> >::create(m_renderer));
@@ -238,15 +261,21 @@ void QRenderAspectPrivate::registerBackendTypes()
q->registerBackendType<QTechniqueFilter>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::TechniqueFilter, QTechniqueFilter> >::create(m_renderer));
q->registerBackendType<QViewport>(QSharedPointer<Render::FrameGraphNodeFunctor<Render::ViewportNode, QViewport> >::create(m_renderer));
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));
// Picking
q->registerBackendType<QObjectPicker>(QSharedPointer<Render::NodeFunctor<Render::ObjectPicker, Render::ObjectPickerManager> >::create(m_renderer));
+
+ // Plugins
+ for (const QString &plugin : m_pluginConfig)
+ loadRenderPlugin(plugin);
}
/*! \internal */
void QRenderAspectPrivate::unregisterBackendTypes()
{
+ Q_Q(QRenderAspect);
unregisterBackendType<Qt3DCore::QEntity>();
unregisterBackendType<Qt3DCore::QTransform>();
@@ -273,6 +302,7 @@ void QRenderAspectPrivate::unregisterBackendTypes()
unregisterBackendType<QEffect>();
unregisterBackendType<QFilterKey>();
unregisterBackendType<QAbstractLight>();
+ unregisterBackendType<QEnvironmentLight>();
unregisterBackendType<QMaterial>();
unregisterBackendType<QParameter>();
unregisterBackendType<QRenderPass>();
@@ -295,10 +325,22 @@ void QRenderAspectPrivate::unregisterBackendTypes()
unregisterBackendType<QTechniqueFilter>();
unregisterBackendType<QViewport>();
unregisterBackendType<QRenderCapture>();
+ unregisterBackendType<QBufferCapture>();
unregisterBackendType<QMemoryBarrier>();
// Picking
unregisterBackendType<QObjectPicker>();
+
+ // Plugins
+ for (Render::QRenderPlugin *plugin : qAsConst(m_renderPlugins))
+ plugin->unregisterBackendTypes(q);
+}
+
+void QRenderAspectPrivate::registerBackendType(const QMetaObject &obj,
+ const QBackendNodeMapperPtr &functor)
+{
+ Q_Q(QRenderAspect);
+ q->registerBackendType(obj, functor);
}
/*!
@@ -360,7 +402,7 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
d->m_renderer->dumpInfo();
#endif
- // Create jobs that will get exectued by the threadpool
+ // Create jobs that will get executed by the threadpool
QVector<QAspectJobPtr> jobs;
// 1 LoadBufferJobs, GeometryJobs, SceneLoaderJobs, LoadTextureJobs
@@ -379,6 +421,7 @@ QVector<Qt3DCore::QAspectJobPtr> QRenderAspect::jobsToExecute(qint64 time)
// don't spawn any jobs, if the renderer decides to skip this frame
if (!d->m_renderer->shouldRender()) {
d->m_renderer->skipNextFrame();
+ QThread::msleep(1);
return jobs;
}
@@ -456,7 +499,7 @@ void QRenderAspect::onRegistered()
d->m_renderer->setNodeManagers(d->m_nodeManagers);
// Create a helper for deferring creation of an offscreen surface used during cleanup
- // to the main thread, after we knwo what the surface format in use is.
+ // to the main thread, after we know what the surface format in use is.
d->m_offscreenHelper = new Render::OffscreenSurfaceHelper(d->m_renderer);
d->m_offscreenHelper->moveToThread(QCoreApplication::instance()->thread());
d->m_renderer->setOffscreenSurfaceHelper(d->m_offscreenHelper);
@@ -475,7 +518,8 @@ void QRenderAspect::onRegistered()
advanceService);
}
- d->m_renderer->setServices(d->services());
+ if (d->services())
+ d->m_renderer->setServices(d->services());
d->m_initialized = true;
}
@@ -537,6 +581,39 @@ void QRenderAspectPrivate::loadSceneParsers()
}
}
+void QRenderAspectPrivate::loadRenderPlugin(const QString &pluginName)
+{
+ Q_Q(QRenderAspect);
+ const QStringList keys = Render::QRenderPluginFactory::keys();
+ if (!keys.contains(pluginName))
+ return;
+
+ if (m_pluginConfig.contains(pluginName) && !m_loadedPlugins.contains(pluginName)) {
+ Render::QRenderPlugin *plugin
+ = Render::QRenderPluginFactory::create(pluginName, QStringList());
+ if (plugin != nullptr) {
+ m_loadedPlugins.append(pluginName);
+ m_renderPlugins.append(plugin);
+ plugin->registerBackendTypes(q, m_renderer);
+ }
+ }
+}
+
+QVector<QString> QRenderAspectPrivate::m_pluginConfig;
+QMutex QRenderAspectPrivate::m_pluginLock;
+QVector<QRenderAspectPrivate *> QRenderAspectPrivate::m_instances;
+
+void QRenderAspectPrivate::configurePlugin(const QString &plugin)
+{
+ QMutexLocker lock(&m_pluginLock);
+ if (!m_pluginConfig.contains(plugin)) {
+ m_pluginConfig.append(plugin);
+
+ for (QRenderAspectPrivate *instance : qAsConst(m_instances))
+ instance->loadRenderPlugin(plugin);
+ }
+}
+
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qrenderaspect.h b/src/render/frontend/qrenderaspect.h
index 72e8e4bdb..48ef5b164 100644
--- a/src/render/frontend/qrenderaspect.h
+++ b/src/render/frontend/qrenderaspect.h
@@ -56,6 +56,7 @@ class TestAspect;
namespace Render {
class Renderer;
+class QRenderPlugin;
}
class QRenderAspectPrivate;
@@ -92,6 +93,7 @@ private:
void onEngineStartup() Q_DECL_OVERRIDE;
friend class Render::Renderer;
+ friend class Render::QRenderPlugin;
#if defined(QT_BUILD_INTERNAL)
friend class QRenderAspectTester;
friend class TestAspect;
diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h
index 72183ef87..b8c8538ee 100644
--- a/src/render/frontend/qrenderaspect_p.h
+++ b/src/render/frontend/qrenderaspect_p.h
@@ -55,6 +55,8 @@
#include <Qt3DCore/private/qabstractaspect_p.h>
#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <QtCore/qmutex.h>
+
QT_BEGIN_NAMESPACE
class QSurface;
@@ -62,9 +64,11 @@ class QSurface;
namespace Qt3DRender {
class QSceneImporter;
+
namespace Render {
class AbstractRenderer;
class NodeManagers;
+class QRenderPlugin;
}
namespace Render {
@@ -79,12 +83,16 @@ public:
Q_DECLARE_PUBLIC(QRenderAspect)
+ static QRenderAspectPrivate* findPrivate(Qt3DCore::QAspectEngine *engine);
+
void registerBackendTypes();
void unregisterBackendTypes();
void loadSceneParsers();
+ void loadRenderPlugin(const QString &pluginName);
void renderInitialize(QOpenGLContext *context);
void renderSynchronous();
void renderShutdown();
+ void registerBackendType(const QMetaObject &, const Qt3DCore::QBackendNodeMapperPtr &functor);
QVector<Qt3DCore::QAspectJobPtr> createGeometryRendererJobs();
Render::NodeManagers *m_nodeManagers;
@@ -92,8 +100,15 @@ public:
bool m_initialized;
QList<QSceneImporter *> m_sceneImporter;
+ QVector<QString> m_loadedPlugins;
+ QVector<Render::QRenderPlugin *> m_renderPlugins;
QRenderAspect::RenderType m_renderType;
Render::OffscreenSurfaceHelper *m_offscreenHelper;
+
+ static QMutex m_pluginLock;
+ static QVector<QString> m_pluginConfig;
+ static QVector<QRenderAspectPrivate *> m_instances;
+ static void configurePlugin(const QString &plugin);
};
}
diff --git a/src/render/frontend/qrenderplugin_p.h b/src/render/frontend/qrenderplugin_p.h
new file mode 100644
index 000000000..5144448c1
--- /dev/null
+++ b/src/render/frontend/qrenderplugin_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_QRENDERPLUGIN_P_H
+#define QT3DRENDER_RENDER_QRENDERPLUGIN_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/qt3drender_global_p.h>
+
+#include <Qt3DCore/qbackendnode.h>
+#include <Qt3DRender/qrenderaspect.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class AbstractRenderer;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPlugin
+{
+public:
+ virtual bool registerBackendTypes(QRenderAspect *aspect, AbstractRenderer *renderer) = 0;
+ virtual bool unregisterBackendTypes(QRenderAspect *aspect) = 0;
+
+protected:
+ void registerBackendType(QRenderAspect *aspect, const QMetaObject &obj, const Qt3DCore::QBackendNodeMapperPtr &functor)
+ {
+ aspect->registerBackendType(obj, functor);
+ }
+ void unregisterBackendType(QRenderAspect *aspect, const QMetaObject &obj)
+ {
+ aspect->unregisterBackendType(obj);
+ }
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_QRENDERPLUGIN_P_H
diff --git a/src/render/frontend/qrenderpluginfactory.cpp b/src/render/frontend/qrenderpluginfactory.cpp
new file mode 100644
index 000000000..51fa068c6
--- /dev/null
+++ b/src/render/frontend/qrenderpluginfactory.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qrenderpluginfactory_p.h"
+#include "qrenderpluginfactoryif_p.h"
+#include "qrenderplugin_p.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdir.h>
+
+#include <private/qfactoryloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QRenderPluginFactoryInterface_iid, QLatin1String("/renderplugins"), Qt::CaseInsensitive))
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader, (QRenderPluginFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
+#endif
+
+QStringList QRenderPluginFactory::keys(const QString &pluginPath)
+{
+#ifndef QT_NO_LIBRARY
+ QStringList list;
+ if (!pluginPath.isEmpty()) {
+ QCoreApplication::addLibraryPath(pluginPath);
+ list = directLoader()->keyMap().values();
+ if (!list.isEmpty()) {
+ const QString postFix = QLatin1String(" (from ")
+ + QDir::toNativeSeparators(pluginPath)
+ + QLatin1Char(')');
+ const QStringList::iterator end = list.end();
+ for (QStringList::iterator it = list.begin(); it != end; ++it)
+ (*it).append(postFix);
+ }
+ }
+ list.append(loader()->keyMap().values());
+ return list;
+#else
+ return QStringList();
+#endif
+}
+
+QRenderPlugin *QRenderPluginFactory::create(const QString &name, const QStringList &args,
+ const QString &pluginPath)
+{
+#ifndef QT_NO_LIBRARY
+ if (!pluginPath.isEmpty()) {
+ QCoreApplication::addLibraryPath(pluginPath);
+ if (QRenderPlugin *ret
+ = qLoadPlugin<QRenderPlugin, QRenderPluginFactoryIf>(directLoader(), name, args)) {
+ return ret;
+ }
+ }
+ if (QRenderPlugin *ret = qLoadPlugin<QRenderPlugin, QRenderPluginFactoryIf>(loader(), name, args))
+ return ret;
+#endif
+ return nullptr;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/frontend/qrenderpluginfactory_p.h b/src/render/frontend/qrenderpluginfactory_p.h
new file mode 100644
index 000000000..9cffd500a
--- /dev/null
+++ b/src/render/frontend/qrenderpluginfactory_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_P_H
+#define QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_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/qt3drender_global_p.h>
+
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class QRenderPlugin;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPluginFactory
+{
+public:
+ static QStringList keys(const QString &pluginPath = QString());
+ static QRenderPlugin *create(const QString &name, const QStringList &args,
+ const QString &pluginPath = QString());
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_QRENDERPLUGINFACTORY_P_H
diff --git a/src/render/frontend/qrenderpluginfactoryif.cpp b/src/render/frontend/qrenderpluginfactoryif.cpp
new file mode 100644
index 000000000..af567084c
--- /dev/null
+++ b/src/render/frontend/qrenderpluginfactoryif.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qrenderpluginfactoryif_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+QRenderPluginFactoryIf::QRenderPluginFactoryIf(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+QRenderPluginFactoryIf::~QRenderPluginFactoryIf()
+{
+
+}
+
+QRenderPlugin *QRenderPluginFactoryIf::create(const QString &key, const QStringList &paramList)
+{
+ Q_UNUSED(key)
+ Q_UNUSED(paramList)
+ return nullptr;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/frontend/qrenderpluginfactoryif_p.h b/src/render/frontend/qrenderpluginfactoryif_p.h
new file mode 100644
index 000000000..d5f0008d2
--- /dev/null
+++ b/src/render/frontend/qrenderpluginfactoryif_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_QRENDERPLUGINFACTORYIF_P_H
+#define QT3DRENDER_RENDER_QRENDERPLUGINFACTORYIF_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 <QtCore/qobject.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+#include <private/qt3drender_global_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+#define QRenderPluginFactoryInterface_iid "org.qt-project.Qt3DRender.QRenderPluginFactoryInterface 5.9"
+
+class QRenderPlugin;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT QRenderPluginFactoryIf : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QRenderPluginFactoryIf(QObject *parent = nullptr);
+ ~QRenderPluginFactoryIf();
+
+ virtual QRenderPlugin *create(const QString &key, const QStringList &paramList);
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QRENDERPLUGINFACTORYIF_P_H
diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp
index 4fb348617..b73fed77b 100644
--- a/src/render/frontend/qrendersettings.cpp
+++ b/src/render/frontend/qrendersettings.cpp
@@ -73,13 +73,6 @@ namespace Qt3DRender {
\l{Qt 3D Render Framegraph}{FrameGraph}.
*/
-/*!
- \enum QRenderSettings::RenderPolicy
-
- This enum type describes types of render policies available.
- \value Always Always try to render (default)
- \value OnDemand Only render when something changes
-*/
/*! \internal */
QRenderSettingsPrivate::QRenderSettingsPrivate()
diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri
index 0e78f9cff..75666a270 100644
--- a/src/render/frontend/render-frontend.pri
+++ b/src/render/frontend/render-frontend.pri
@@ -2,8 +2,6 @@ INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qabstractfunctor.h \
- $$PWD/qboundingsphere.h \
- $$PWD/qboundingsphere_p.h \
$$PWD/qrenderaspect.h \
$$PWD/qrenderaspect_p.h \
$$PWD/qitemmodelbuffer_p.h \
@@ -26,11 +24,14 @@ HEADERS += \
$$PWD/qpickingsettings.h \
$$PWD/qpickingsettings_p.h \
$$PWD/qcomputecommand_p.h \
- $$PWD/qcomputecommand.h
+ $$PWD/qcomputecommand.h \
+ $$PWD/qrenderplugin_p.h \
+ $$PWD/qrenderpluginfactory_p.h \
+ $$PWD/qrenderpluginfactoryif_p.h \
+ $$PWD/qlevelofdetailboundingsphere.h
SOURCES += \
$$PWD/qabstractfunctor.cpp \
- $$PWD/qboundingsphere.cpp \
$$PWD/qrenderaspect.cpp \
$$PWD/qitemmodelbuffer.cpp \
$$PWD/sphere.cpp \
@@ -43,5 +44,8 @@ SOURCES += \
$$PWD/qrendersettings.cpp \
$$PWD/qpickingsettings.cpp \
$$PWD/qrendertargetoutput.cpp \
- $$PWD/qcomputecommand.cpp
+ $$PWD/qcomputecommand.cpp \
+ $$PWD/qrenderpluginfactory.cpp \
+ $$PWD/qrenderpluginfactoryif.cpp \
+ $$PWD/qlevelofdetailboundingsphere.cpp
diff --git a/src/render/frontend/sphere.cpp b/src/render/frontend/sphere.cpp
index 80926efb9..2c22e0da4 100644
--- a/src/render/frontend/sphere.cpp
+++ b/src/render/frontend/sphere.cpp
@@ -223,8 +223,9 @@ Qt3DCore::QNodeId Sphere::id() const
return m_id;
}
-bool Sphere::intersects(const RayCasting::QRay3D &ray, QVector3D *q) const
+bool Sphere::intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw) const
{
+ Q_UNUSED(uvw);
return intersectRaySphere(ray, *this, q);
}
diff --git a/src/render/frontend/sphere_p.h b/src/render/frontend/sphere_p.h
index 1defbf059..1587aecab 100644
--- a/src/render/frontend/sphere_p.h
+++ b/src/render/frontend/sphere_p.h
@@ -106,7 +106,7 @@ public:
}
Qt3DCore::QNodeId id() const Q_DECL_FINAL;
- bool intersects(const RayCasting::QRay3D &ray, QVector3D *q) const Q_DECL_FINAL;
+ bool intersects(const RayCasting::QRay3D &ray, QVector3D *q, QVector3D *uvw = nullptr) const Q_DECL_FINAL;
Type type() const Q_DECL_FINAL;
static Sphere fromPoints(const QVector<QVector3D> &points);
diff --git a/src/render/geometry/attribute.cpp b/src/render/geometry/attribute.cpp
index 7e1ea79dd..6c8c0113a 100644
--- a/src/render/geometry/attribute.cpp
+++ b/src/render/geometry/attribute.cpp
@@ -108,7 +108,7 @@ void Attribute::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
QByteArray propertyName = propertyChange->propertyName();
if (propertyName == QByteArrayLiteral("name")) {
- m_name = propertyChange->value().value<QString>();
+ m_name = propertyChange->value().toString();
m_nameId = StringToInt::lookupId(m_name);
m_attributeDirty = true;
} else if (propertyName == QByteArrayLiteral("vertexBaseType")) {
diff --git a/src/render/geometry/buffer.cpp b/src/render/geometry/buffer.cpp
index df0bc3c92..55c86910f 100644
--- a/src/render/geometry/buffer.cpp
+++ b/src/render/geometry/buffer.cpp
@@ -41,7 +41,6 @@
#include <Qt3DCore/qpropertyupdatedchange.h>
#include <Qt3DRender/private/buffermanager_p.h>
#include <Qt3DRender/private/qbuffer_p.h>
-#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
QT_BEGIN_NAMESPACE
@@ -56,6 +55,7 @@ Buffer::Buffer()
, m_usage(QBuffer::StaticDraw)
, m_bufferDirty(false)
, m_syncData(false)
+ , m_access(QBuffer::Write)
, m_manager(nullptr)
{
// Maybe it could become read write if we want to inform
@@ -75,6 +75,7 @@ void Buffer::cleanup()
m_functor.reset();
m_bufferDirty = false;
m_syncData = false;
+ m_access = QBuffer::Write;
}
@@ -87,17 +88,33 @@ void Buffer::executeFunctor()
{
Q_ASSERT(m_functor);
m_data = (*m_functor)();
+ // Request data to be loaded
+ forceDataUpload();
+
if (m_syncData) {
// Send data back to the frontend
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("data");
e->setValue(QVariant::fromValue(m_data));
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
}
+//Called from th sendBufferJob
+void Buffer::updateDataFromGPUToCPU(QByteArray data)
+{
+ // Note: when this is called, data is what's currently in GPU memory
+ // so m_data shouldn't be reuploaded
+ m_data = data;
+ // Send data back to the frontend
+ auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("downloadedData");
+ e->setValue(QVariant::fromValue(m_data));
+ notifyObservers(e);
+}
+
void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QBufferData>>(change);
@@ -106,23 +123,40 @@ void Buffer::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chang
m_type = data.type;
m_usage = data.usage;
m_syncData = data.syncData;
+ m_access = data.access;
m_bufferDirty = true;
+ if (!m_data.isEmpty())
+ forceDataUpload();
+
m_functor = data.functor;
Q_ASSERT(m_manager);
if (m_functor)
m_manager->addDirtyBuffer(peerId());
}
+void Buffer::forceDataUpload()
+{
+ // We push back an update with offset = -1
+ // As this is the way to force data to be loaded
+ QBufferUpdate updateNewData;
+ updateNewData.offset = -1;
+ m_bufferUpdates.clear(); //previous updates are pointless
+ m_bufferUpdates.push_back(updateNewData);
+}
+
void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == PropertyUpdated) {
QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<QPropertyUpdatedChange>(e);
QByteArray propertyName = propertyChange->propertyName();
if (propertyName == QByteArrayLiteral("data")) {
- QByteArray newData = propertyChange->value().value<QByteArray>();
- m_bufferDirty |= m_data != newData;
+ QByteArray newData = propertyChange->value().toByteArray();
+ bool dirty = m_data != newData;
+ m_bufferDirty |= dirty;
m_data = newData;
+ if (dirty)
+ forceDataUpload();
} else if (propertyName == QByteArrayLiteral("updateData")) {
Qt3DRender::QBufferUpdate updateData = propertyChange->value().value<Qt3DRender::QBufferUpdate>();
m_bufferUpdates.push_back(updateData);
@@ -133,6 +167,8 @@ void Buffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
} else if (propertyName == QByteArrayLiteral("usage")) {
m_usage = static_cast<QBuffer::UsageType>(propertyChange->value().value<int>());
m_bufferDirty = true;
+ } else if (propertyName == QByteArrayLiteral("accessType")) {
+ m_access = static_cast<QBuffer::AccessType>(propertyChange->value().value<int>());
} else if (propertyName == QByteArrayLiteral("dataGenerator")) {
QBufferDataGeneratorPtr newGenerator = propertyChange->value().value<QBufferDataGeneratorPtr>();
m_bufferDirty |= !(newGenerator && m_functor && *newGenerator == *m_functor);
diff --git a/src/render/geometry/buffer_p.h b/src/render/geometry/buffer_p.h
index d474c1720..691d6cc60 100644
--- a/src/render/geometry/buffer_p.h
+++ b/src/render/geometry/buffer_p.h
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QBufferUpdate;
+struct QBufferUpdate;
namespace Render {
@@ -77,6 +77,7 @@ 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; }
@@ -84,10 +85,12 @@ public:
inline bool isDirty() const { return m_bufferDirty; }
inline QBufferDataGeneratorPtr dataGenerator() const { return m_functor; }
inline bool isSyncData() const { return m_syncData; }
+ inline QBuffer::AccessType access() const { return m_access; }
void unsetDirty();
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+ void forceDataUpload();
QBuffer::BufferType m_type;
QBuffer::UsageType m_usage;
@@ -95,6 +98,7 @@ private:
QVector<Qt3DRender::QBufferUpdate> m_bufferUpdates;
bool m_bufferDirty;
bool m_syncData;
+ QBuffer::AccessType m_access;
QBufferDataGeneratorPtr m_functor;
BufferManager *m_manager;
};
diff --git a/src/render/geometry/geometryrenderer.cpp b/src/render/geometry/geometryrenderer.cpp
index 54fe61831..4f5432e1d 100644
--- a/src/render/geometry/geometryrenderer.cpp
+++ b/src/render/geometry/geometryrenderer.cpp
@@ -153,7 +153,7 @@ void GeometryRenderer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_verticesPerPatch = propertyChange->value().value<int>();
m_dirty = true;
} else if (propertyName == QByteArrayLiteral("primitiveRestartEnabled")) {
- m_primitiveRestartEnabled = propertyChange->value().value<bool>();
+ m_primitiveRestartEnabled = propertyChange->value().toBool();
m_dirty = true;
} else if (propertyName == QByteArrayLiteral("primitiveType")) {
m_primitiveType = static_cast<QGeometryRenderer::PrimitiveType>(propertyChange->value().value<int>());
diff --git a/src/render/geometry/qbuffer.cpp b/src/render/geometry/qbuffer.cpp
index 0d3be8fdd..b978e0e0b 100644
--- a/src/render/geometry/qbuffer.cpp
+++ b/src/render/geometry/qbuffer.cpp
@@ -42,6 +42,7 @@
#include <Qt3DRender/private/renderlogging_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt3DCore;
@@ -50,8 +51,10 @@ namespace Qt3DRender {
QBufferPrivate::QBufferPrivate()
: QNodePrivate()
+ , m_type(QBuffer::VertexBuffer)
, m_usage(QBuffer::StaticDraw)
, m_syncData(false)
+ , m_access(QBuffer::Write)
{
}
@@ -189,7 +192,8 @@ QBufferPrivate::QBufferPrivate()
/*!
\fn Qt3DRender::QBufferDataGenerator::operator ==(const QBufferDataGenerator &other) const
- Should be reimplemented to return true when two generators are identical,
+ Should be reimplemented to return true when two generators (the one you are
+ comparing against and the \a other generator) are identical,
false otherwise.
\note The renderer uses this comparison to decide whether data for a buffer
@@ -270,11 +274,19 @@ QBuffer::~QBuffer()
*/
void QBuffer::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
{
- QPropertyUpdatedChangePtr e = qSharedPointerCast<QPropertyUpdatedChange>(change);
- if (e->type() == PropertyUpdated && e->propertyName() == QByteArrayLiteral("data")) {
- const bool blocked = blockNotifications(true);
- setData(e->value().toByteArray());
- blockNotifications(blocked);
+ if (change->type() == PropertyUpdated) {
+ QPropertyUpdatedChangePtr e = qSharedPointerCast<QPropertyUpdatedChange>(change);
+ const QByteArray propertyName = e->propertyName();
+ if (propertyName == QByteArrayLiteral("data")) {
+ const bool blocked = blockNotifications(true);
+ setData(e->value().toByteArray());
+ blockNotifications(blocked);
+ } else if (propertyName == QByteArrayLiteral("downloadedData")) {
+ const bool blocked = blockNotifications(true);
+ setData(e->value().toByteArray());
+ blockNotifications(blocked);
+ Q_EMIT dataAvailable();
+ }
}
}
@@ -400,12 +412,27 @@ void QBuffer::setSyncData(bool syncData)
}
}
+void QBuffer::setAccessType(QBuffer::AccessType access)
+{
+ Q_D(QBuffer);
+ if (d->m_access != access) {
+ d->m_access = access;
+ Q_EMIT accessTypeChanged(access);
+ }
+}
+
bool QBuffer::isSyncData() const
{
Q_D(const QBuffer);
return d->m_syncData;
}
+QBuffer::AccessType QBuffer::accessType() const
+{
+ Q_D(const QBuffer);
+ return d->m_access;
+}
+
void QBuffer::setType(QBuffer::BufferType type)
{
Q_D(QBuffer);
@@ -425,6 +452,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QBuffer::createNodeCreationChange() const
data.usage = d->m_usage;
data.functor = d->m_functor;
data.syncData = d->m_syncData;
+ data.access = d->m_access;
return creationChange;
}
diff --git a/src/render/geometry/qbuffer.h b/src/render/geometry/qbuffer.h
index 8b47de918..7cb5acb0a 100644
--- a/src/render/geometry/qbuffer.h
+++ b/src/render/geometry/qbuffer.h
@@ -59,6 +59,7 @@ class QT3DRENDERSHARED_EXPORT QBuffer : public Qt3DCore::QNode
Q_PROPERTY(BufferType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(UsageType usage READ usage WRITE setUsage NOTIFY usageChanged)
Q_PROPERTY(bool syncData READ isSyncData WRITE setSyncData NOTIFY syncDataChanged)
+ Q_PROPERTY(AccessType accessType READ accessType WRITE setAccessType NOTIFY accessTypeChanged REVISION 9)
public:
enum BufferType
@@ -87,12 +88,20 @@ public:
};
Q_ENUM(UsageType) // LCOV_EXCL_LINE
+ enum AccessType {
+ Write = 0x1,
+ Read = 0x2,
+ ReadWrite = Write|Read
+ };
+ Q_ENUM(AccessType) // LCOV_EXCL_LINE
+
explicit QBuffer(BufferType ty = QBuffer::VertexBuffer, Qt3DCore::QNode *parent = nullptr);
~QBuffer();
UsageType usage() const;
BufferType type() const;
bool isSyncData() const;
+ AccessType accessType() const;
void setData(const QByteArray &bytes);
QByteArray data() const;
@@ -106,6 +115,7 @@ public Q_SLOTS:
void setType(BufferType type);
void setUsage(UsageType usage);
void setSyncData(bool syncData);
+ void setAccessType(AccessType access);
protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
@@ -115,6 +125,8 @@ Q_SIGNALS:
void typeChanged(BufferType type);
void usageChanged(UsageType usage);
void syncDataChanged(bool syncData);
+ void accessTypeChanged(AccessType access);
+ void dataAvailable();
private:
Q_DECLARE_PRIVATE(QBuffer)
diff --git a/src/render/geometry/qbuffer_p.h b/src/render/geometry/qbuffer_p.h
index eb69730b8..a722675ab 100644
--- a/src/render/geometry/qbuffer_p.h
+++ b/src/render/geometry/qbuffer_p.h
@@ -74,6 +74,7 @@ public:
QBuffer::UsageType m_usage;
QBufferDataGeneratorPtr m_functor;
bool m_syncData;
+ QBuffer::AccessType m_access;
};
struct QBufferData
@@ -83,6 +84,7 @@ struct QBufferData
QBuffer::UsageType usage;
QBufferDataGeneratorPtr functor;
bool syncData;
+ QBuffer::AccessType access;
};
struct QBufferUpdate
diff --git a/src/render/geometry/qgeometry.cpp b/src/render/geometry/qgeometry.cpp
index 95405d64d..3d281866d 100644
--- a/src/render/geometry/qgeometry.cpp
+++ b/src/render/geometry/qgeometry.cpp
@@ -94,7 +94,13 @@ QGeometryPrivate::~QGeometryPrivate()
/*!
\qmlproperty Attribute Geometry::boundingVolumePositionAttribute
- Holds the attribute used to compute the bounding volume.
+ Holds the attribute used to compute the bounding volume. The bounding volume is used internally
+ for picking and view frustum culling.
+
+ If unspecified, the system will look for the attribute using the name returned by
+ QAttribute::defaultPositionAttributeName.
+
+ \sa Attribute
*/
/*!
\qmlproperty list<Attribute> Geometry::attributes
@@ -105,7 +111,13 @@ QGeometryPrivate::~QGeometryPrivate()
/*!
\property QGeometry::boundingVolumePositionAttribute
- Holds the attribute used to compute the bounding volume.
+ Holds the attribute used to compute the bounding volume. The bounding volume is used internally
+ for picking and view frustum culling.
+
+ If unspecified, the system will look for the attribute using the name returned by
+ QAttribute::defaultPositionAttributeName.
+
+ \sa Qt3DRender::QAttribute
*/
diff --git a/src/render/geometry/qmesh.cpp b/src/render/geometry/qmesh.cpp
index 2d9bb54b4..40a4c2f52 100644
--- a/src/render/geometry/qmesh.cpp
+++ b/src/render/geometry/qmesh.cpp
@@ -45,30 +45,63 @@
#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
namespace Qt3DRender {
-#ifndef QT_NO_LIBRARY
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, geometryLoader, (QGeometryLoaderFactory_iid, QLatin1String("/geometryloaders"), Qt::CaseInsensitive))
-#endif
QMeshPrivate::QMeshPrivate()
: QGeometryRendererPrivate()
{
}
+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;
+ q->setGeometryFactory(QGeometryFactoryPtr(new MeshLoaderFunctor(q, engine)));
+}
+
/*!
* \qmltype Mesh
* \instantiates Qt3DRender::QMesh
* \inqmlmodule Qt3D.Render
- * \brief A custom mesh.
+ * \brief A custom mesh loader.
+ *
+ * Loads mesh data from external files in a variety of formats.
+ *
+ * In Qt3D 5.9, Mesh supports the following formats: Wavefront OBJ, Stanford Triangle Format PLY, STL (STereoLithography).
+ * QMesh will also support Autodesk FBX files if the SDK is installed and the fbx geometry loader plugin is built and found.
*/
/*!
@@ -80,7 +113,17 @@ QMeshPrivate::QMeshPrivate()
/*!
* \qmlproperty string Mesh::meshName
*
- * Holds the name of the mesh.
+ * Filter indicating which part of the mesh should be loaded.
+ *
+ * If meshName is empty (the default), then the entire mesh is loaded.
+ *
+ * If meshName is a plain string, then only the sub-mesh matching that name, if present, will be loaded.
+ *
+ * If meshName is a regular expression, than all sub-meshes matching the expression will be loaded.
+ *
+ * \note Only Wavefront OBJ files support sub-meshes.
+ *
+ * \sa QRegularExpression
*/
/*!
@@ -90,7 +133,17 @@ QMeshPrivate::QMeshPrivate()
*
* \inherits Qt3DRender::QGeometryRenderer
*
- * \brief A custom mesh.
+ * \brief A custom mesh loader.
+ *
+ * Loads mesh data from external files in a variety of formats.
+ * Qt3DRender::QMesh loads data into a single mesh.
+ *
+ * In Qt3D 5.9, QMesh supports the following formats: Wavefront OBJ, Stanford Triangle Format PLY, STL (STereoLithography).
+ * QMesh will also support Autodesk FBX files if the SDK is installed and the fbx geometry loader plugin is built and found.
+ *
+ * If you wish to load an entire scene made of several objects, you should rather use the Qt3DRender::QSceneLoader instead.
+ *
+ * \sa Qt3DRender::QSceneLoader
*/
/*!
@@ -118,8 +171,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);
@@ -142,8 +194,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);
@@ -163,49 +214,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();
+ 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;
}
@@ -213,14 +304,47 @@ 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);
+ const MeshLoaderFunctor *otherFunctor = functor_cast<MeshLoaderFunctor>(&other);
if (otherFunctor != nullptr)
- return (otherFunctor->m_sourcePath == m_sourcePath);
+ return (otherFunctor->m_sourcePath == m_sourcePath &&
+ otherFunctor->m_sourceData.isEmpty() == m_sourceData.isEmpty() &&
+ 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 a621525cc..f7f8079eb 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 <QUrl>
@@ -66,23 +67,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/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index dea8c1fc6..80e8267da 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -81,6 +81,14 @@
QT_BEGIN_NAMESPACE
+#ifndef GL_READ_FRAMEBUFFER
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
namespace {
QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
@@ -154,6 +162,7 @@ GraphicsContext::GraphicsContext()
, m_ownCurrent(true)
, m_activeShader(nullptr)
, m_activeShaderDNA(0)
+ , m_renderTargetFormat(QAbstractTexture::NoFormat)
, m_currClearStencilValue(0)
, m_currClearDepthValue(1.f)
, m_currClearColorValue(0,0,0,0)
@@ -207,7 +216,7 @@ void GraphicsContext::initialize()
void GraphicsContext::resolveRenderTargetFormat()
{
const QSurfaceFormat format = m_gl->format();
- const uint a = format.alphaBufferSize();
+ const uint a = (format.alphaBufferSize() == -1) ? 0 : format.alphaBufferSize();
const uint r = format.redBufferSize();
const uint g = format.greenBufferSize();
const uint b = format.blueBufferSize();
@@ -459,11 +468,14 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode)
// Compile shaders
const auto shaderCode = shaderNode->shaderCode();
+ QString logs;
for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) {
QShaderProgram::ShaderType type = static_cast<const QShaderProgram::ShaderType>(i);
- if (!shaderCode.at(i).isEmpty() &&
- !shaderProgram->addShaderFromSourceCode(shaderType(type), shaderCode.at(i))) {
- qWarning().noquote() << "Failed to compile shader:" << shaderProgram->log();
+ 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)))
+ logs += shaderProgram->log();
}
}
@@ -471,17 +483,31 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode)
// Since we are sharing shaders in the backend, we assume that if using custom
// fragOutputs, they should all be the same for a given shader
bindFragOutputs(shaderProgram->programId(), shaderNode->fragOutputs());
- if (!shaderProgram->link()) {
- qWarning().noquote() << "Failed to link shader program:" << shaderProgram->log();
+
+ const bool linkSucceeded = shaderProgram->link();
+ logs += shaderProgram->log();
+ shaderNode->setLog(logs);
+ shaderNode->setStatus(linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error);
+
+ if (!linkSucceeded)
return nullptr;
- }
// take from scoped-pointer so it doesn't get deleted
return shaderProgram.take();
}
// That assumes that the shaderProgram in Shader stays the same
-void GraphicsContext::loadShader(Shader *shader)
+void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderProgram *shaderProgram)
+{
+ shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId()));
+ shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId()));
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject))
+ shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId()));
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject))
+ shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId()));
+}
+
+void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager)
{
QOpenGLShaderProgram *shaderProgram = m_shaderCache.getShaderProgramAndAddRef(shader->dna(), shader->peerId());
if (!shaderProgram) {
@@ -493,20 +519,31 @@ void GraphicsContext::loadShader(Shader *shader)
}
// Ensure the Shader node knows about the program interface
- // TODO: Improve this so we only introspect once per actual OpenGL shader program
- // rather than once per ShaderNode. Could cache the interface description along
- // with the QOpenGLShaderProgram in the ShaderCache.
if (Q_LIKELY(shaderProgram != nullptr) && !shader->isLoaded()) {
- // Introspect and set up interface description on Shader backend node
- shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId()));
- shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId()));
- if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject))
- shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId()));
- if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject))
- shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId()));
+
+ // Find an already loaded shader that shares the same QOpenGLShaderProgram
+ Shader *refShader = nullptr;
+ const QVector<Qt3DCore::QNodeId> sharedShaderIds = m_shaderCache.shaderIdsForProgram(shader->dna());
+ for (const Qt3DCore::QNodeId sharedShaderId : sharedShaderIds) {
+ Shader *sharedShader = manager->lookupResource(sharedShaderId);
+ // Note: no need to check if shader->peerId != sharedShader->peerId
+ // as we are sure that this code path is executed only if !shared->isLoaded
+ if (sharedShader->isLoaded()) {
+ refShader = sharedShader;
+ break;
+ }
+ }
+
+ // We only introspect once per actual OpenGL shader program
+ // rather than once per ShaderNode.
+ if (refShader != nullptr)
+ shader->initializeFromReference(*refShader);
+ else // Introspect and set up interface description on Shader backend node
+ introspectShaderInterface(shader, shaderProgram);
shader->setGraphicsContext(this);
shader->setLoaded(true);
+ shader->markDirty(AbstractRenderer::AllDirty);
}
}
@@ -1045,6 +1082,16 @@ void GraphicsContext::dispatchCompute(int x, int y, int z)
m_glHelper->dispatchCompute(x, y, z);
}
+GLboolean GraphicsContext::unmapBuffer(GLenum target)
+{
+ return m_glHelper->unmapBuffer(target);
+}
+
+char *GraphicsContext::mapBuffer(GLenum target)
+{
+ return m_glHelper->mapBuffer(target);
+}
+
void GraphicsContext::enablei(GLenum cap, GLuint index)
{
m_glHelper->enablei(cap, index);
@@ -1273,16 +1320,16 @@ void GraphicsContext::applyUniform(const ShaderUniform &description, const Unifo
break;
case UniformType::UInt:
- applyUniformHelper<UniformType::Int>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UInt>(description.m_location, description.m_size, v);
break;
case UniformType::UIVec2:
- applyUniformHelper<UniformType::IVec2>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UIVec2>(description.m_location, description.m_size, v);
break;
case UniformType::UIVec3:
- applyUniformHelper<UniformType::IVec3>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UIVec3>(description.m_location, description.m_size, v);
break;
case UniformType::UIVec4:
- applyUniformHelper<UniformType::IVec4>(description.m_location, description.m_size, v);
+ applyUniformHelper<UniformType::UIVec4>(description.m_location, description.m_size, v);
break;
case UniformType::Bool:
@@ -1398,6 +1445,16 @@ void GraphicsContext::updateBuffer(Buffer *buffer)
uploadDataToGLBuffer(buffer, m_renderer->nodeManagers()->glBufferManager()->data(it.value()));
}
+QByteArray GraphicsContext::downloadBufferContent(Buffer *buffer)
+{
+ const QHash<Qt3DCore::QNodeId, HGLBuffer>::iterator it = m_renderBufferHash.find(buffer->peerId());
+ if (it != m_renderBufferHash.end())
+ return downloadDataFromGLBuffer(buffer, m_renderer->nodeManagers()->glBufferManager()->data(it.value()));
+ return QByteArray();
+}
+
+
+
void GraphicsContext::releaseBuffer(Qt3DCore::QNodeId bufferId)
{
auto it = m_renderBufferHash.find(bufferId);
@@ -1421,7 +1478,7 @@ bool GraphicsContext::hasGLBufferForBuffer(Buffer *buffer)
return (it != m_renderBufferHash.end());
}
-void GraphicsContext::memoryBarrier(QMemoryBarrier::BarrierTypes barriers)
+void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers)
{
m_glHelper->memoryBarrier(barriers);
}
@@ -1444,8 +1501,6 @@ HGLBuffer GraphicsContext::createGLBufferFor(Buffer *buffer)
if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type())))
qCWarning(Render::Io) << Q_FUNC_INFO << "buffer binding failed";
- // TO DO: Handle usage pattern
- b->allocate(this, buffer->data().constData(), buffer->data().size(), false);
return m_renderer->nodeManagers()->glBufferManager()->lookupHandle(buffer->peerId());
}
@@ -1471,21 +1526,39 @@ void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool rel
// * setData was called changing the whole data or functor (or the usage pattern)
// * partial buffer updates where received
- // Note: we assume the case where both setData/functor and updates are called to be a misuse
- // with unexpected behavior
- const QVector<Qt3DRender::QBufferUpdate> updates = std::move(buffer->pendingBufferUpdates());
- if (!updates.empty()) {
- for (const Qt3DRender::QBufferUpdate &update : updates) {
+ // TO DO: Handle usage pattern
+ QVector<Qt3DRender::QBufferUpdate> updates = std::move(buffer->pendingBufferUpdates());
+ for (auto it = updates.begin(); it != updates.end(); ++it) {
+ auto update = it;
+ // We have a partial update
+ if (update->offset >= 0) {
+ //accumulate sequential updates as single one
+ int bufferSize = update->data.size();
+ auto it2 = it + 1;
+ while ((it2 != updates.end())
+ && (it2->offset - update->offset == bufferSize)) {
+ bufferSize += it2->data.size();
+ ++it2;
+ }
+ update->data.resize(bufferSize);
+ while (it + 1 != it2) {
+ ++it;
+ update->data.replace(it->offset - update->offset, it->data.size(), it->data);
+ it->data.clear();
+ }
// TO DO: based on the number of updates .., it might make sense to
// sometime use glMapBuffer rather than glBufferSubData
- b->update(this, update.data.constData(), update.data.size(), update.offset);
+ b->update(this, update->data.constData(), update->data.size(), update->offset);
+ } else {
+ // We have an update that was done by calling QBuffer::setData
+ // which is used to resize or entirely clear the buffer
+ // Note: we use the buffer data directly in that case
+ const int bufferSize = buffer->data().size();
+ b->allocate(this, bufferSize, false); // orphan the buffer
+ b->allocate(this, buffer->data().constData(), bufferSize, false);
}
- } else {
- const int bufferSize = buffer->data().size();
- // TO DO: Handle usage pattern
- b->allocate(this, bufferSize, false); // orphan the buffer
- b->allocate(this, buffer->data().constData(), bufferSize, false);
}
+
if (releaseBuffer) {
b->release(this);
if (bufferTypeToGLBufferType(buffer->type()) == GLBuffer::ArrayBuffer)
@@ -1494,6 +1567,15 @@ void GraphicsContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool rel
qCDebug(Render::Io) << "uploaded buffer size=" << buffer->data().size();
}
+QByteArray GraphicsContext::downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b)
+{
+ if (!bindGLBuffer(b, bufferTypeToGLBufferType(buffer->type())))
+ qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed";
+
+ QByteArray data = b->download(this, buffer->data().size());
+ return data;
+}
+
GLint GraphicsContext::elementType(GLint type)
{
switch (type) {
@@ -1649,10 +1731,8 @@ QImage GraphicsContext::readFramebuffer(QSize size)
QImage::Format imageFormat;
uint stride;
-#ifndef QT_OPENGL_ES_2
/* format value should match GL internalFormat */
GLenum internalFormat = m_renderTargetFormat;
-#endif
switch (m_renderTargetFormat) {
case QAbstractTexture::RGBAFormat:
@@ -1728,18 +1808,15 @@ QImage GraphicsContext::readFramebuffer(QSize size)
return img;
}
-#ifndef QT_OPENGL_ES_2
GLint samples = 0;
m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples);
if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer))
return img;
-#endif
img = QImage(size.width(), size.height(), imageFormat);
QScopedArrayPointer<uchar> data(new uchar [bytes]);
-#ifndef QT_OPENGL_ES_2
if (samples > 0) {
// resolve multisample-framebuffer to renderbuffer and read pixels from it
GLuint fbo, rb;
@@ -1771,14 +1848,10 @@ QImage GraphicsContext::readFramebuffer(QSize size)
gl->glBindFramebuffer(GL_FRAMEBUFFER, m_activeFBO);
gl->glDeleteFramebuffers(1, &fbo);
} else {
-#endif
// read pixels directly from framebuffer
m_gl->functions()->glReadPixels(0,0,size.width(), size.height(), format, type, data.data());
copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat);
-
-#ifndef QT_OPENGL_ES_2
}
-#endif
return img;
}
diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h
index 133c84b8c..4358da999 100644
--- a/src/render/graphicshelpers/graphicscontext_p.h
+++ b/src/render/graphicshelpers/graphicscontext_p.h
@@ -91,6 +91,7 @@ class RenderTarget;
class AttachmentPack;
class Attribute;
class Buffer;
+class ShaderManager;
enum TextureScope
{
@@ -130,9 +131,10 @@ public:
bool isInitialized() const;
QOpenGLShaderProgram *createShaderProgram(Shader *shaderNode);
- void loadShader(Shader* shader);
+ void loadShader(Shader* shader, ShaderManager *manager);
bool activateShader(ProgramDNA shaderDNA);
void removeShaderProgramReference(Shader *shaderNode);
+ void introspectShaderInterface(Shader *shader, QOpenGLShaderProgram *shaderProgram);
GLuint activeFBO() const { return m_activeFBO; }
GLuint defaultFBO() const { return m_defaultFBO; }
@@ -157,10 +159,11 @@ public:
void specifyAttribute(const Attribute *attribute, Buffer *buffer, int attributeLocation);
void specifyIndices(Buffer *buffer);
void updateBuffer(Buffer *buffer);
+ QByteArray downloadBufferContent(Buffer *buffer);
void releaseBuffer(Qt3DCore::QNodeId bufferId);
bool hasGLBufferForBuffer(Buffer *buffer);
- void memoryBarrier(QMemoryBarrier::BarrierTypes barriers);
+ void memoryBarrier(QMemoryBarrier::Operations barriers);
void setParameters(ShaderParameterPack &parameterPack);
@@ -208,6 +211,8 @@ public:
void disablei(GLenum cap, GLuint index);
void disablePrimitiveRestart();
void dispatchCompute(int x, int y, int z);
+ char * mapBuffer(GLenum target);
+ GLboolean unmapBuffer(GLenum target);
void drawArrays(GLenum primitiveType, GLint first, GLsizei count);
void drawArraysIndirect(GLenum mode,void *indirect);
void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances);
@@ -252,6 +257,7 @@ private:
void activateDrawBuffers(const AttachmentPack &attachments);
HGLBuffer createGLBufferFor(Buffer *buffer);
void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false);
+ QByteArray downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b);
bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type);
void resolveRenderTargetFormat();
diff --git a/src/render/graphicshelpers/graphicshelperes2.cpp b/src/render/graphicshelpers/graphicshelperes2.cpp
index a89f0ff8b..3b821f804 100644
--- a/src/render/graphicshelpers/graphicshelperes2.cpp
+++ b/src/render/graphicshelpers/graphicshelperes2.cpp
@@ -65,8 +65,9 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-GraphicsHelperES2::GraphicsHelperES2() :
- m_funcs(0)
+GraphicsHelperES2::GraphicsHelperES2()
+ : m_funcs(0)
+ , m_supportFramebufferBlit(false)
{
}
@@ -80,6 +81,9 @@ void GraphicsHelperES2::initializeHelper(QOpenGLContext *context,
Q_ASSERT(context);
m_funcs = context->functions();
Q_ASSERT(m_funcs);
+ m_ext.reset(new QOpenGLExtensions(context));
+ if (m_ext->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
+ m_supportFramebufferBlit = true;
}
void GraphicsHelperES2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
@@ -366,6 +370,8 @@ bool GraphicsHelperES2::supportsFeature(GraphicsHelperInterface::Feature feature
switch (feature) {
case RenderBufferDimensionRetrieval:
return true;
+ case BlitFramebuffer:
+ return m_supportFramebufferBlit;
default:
return false;
}
@@ -492,7 +498,7 @@ GLint GraphicsHelperES2::maxClipPlaneCount()
return 0;
}
-void GraphicsHelperES2::memoryBarrier(QMemoryBarrier::BarrierTypes barriers)
+void GraphicsHelperES2::memoryBarrier(QMemoryBarrier::Operations barriers)
{
Q_UNUSED(barriers);
qWarning() << "memory barrier is not supported by OpenGL ES 2.0 (since 4.3)";
@@ -575,6 +581,20 @@ 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)
+{
+ Q_UNUSED(target);
+ qWarning() << "Map buffer is not a core requirement for ES 2.0";
+ return nullptr;
+}
+
+GLboolean GraphicsHelperES2::unmapBuffer(GLenum target)
+{
+ Q_UNUSED(target);
+ qWarning() << "unMap buffer is not a core requirement for ES 2.0";
+ return false;
+}
+
void GraphicsHelperES2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
@@ -725,17 +745,10 @@ UniformType GraphicsHelperES2::uniformTypeFromGLType(GLenum type)
void GraphicsHelperES2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
{
- Q_UNUSED(srcX0);
- Q_UNUSED(srcX1);
- Q_UNUSED(srcY0);
- Q_UNUSED(srcY1);
- Q_UNUSED(dstX0);
- Q_UNUSED(dstX1);
- Q_UNUSED(dstY0);
- Q_UNUSED(dstY1);
- Q_UNUSED(mask);
- Q_UNUSED(filter);
- qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)";
+ if (!m_supportFramebufferBlit)
+ qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)";
+ else
+ m_ext->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
}
} // namespace Render
diff --git a/src/render/graphicshelpers/graphicshelperes2_p.h b/src/render/graphicshelpers/graphicshelperes2_p.h
index 2a1f3cf05..f34eb7f87 100644
--- a/src/render/graphicshelpers/graphicshelperes2_p.h
+++ b/src/render/graphicshelpers/graphicshelperes2_p.h
@@ -57,6 +57,8 @@
QT_BEGIN_NAMESPACE
+class QOpenGLExtensions;
+
namespace Qt3DRender {
namespace Render {
@@ -89,6 +91,8 @@ 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;
+ 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;
void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE;
@@ -106,7 +110,7 @@ public:
void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE;
GLint maxClipPlaneCount() Q_DECL_OVERRIDE;
- void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE;
QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE;
@@ -151,6 +155,8 @@ public:
protected:
QOpenGLFunctions *m_funcs;
+ bool m_supportFramebufferBlit;
+ QScopedPointer<QOpenGLExtensions> m_ext;
};
} // namespace Render
diff --git a/src/render/graphicshelpers/graphicshelpergl2.cpp b/src/render/graphicshelpers/graphicshelpergl2.cpp
index 765a12f42..5f798f94e 100644
--- a/src/render/graphicshelpers/graphicshelpergl2.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl2.cpp
@@ -518,7 +518,7 @@ GLint GraphicsHelperGL2::maxClipPlaneCount()
return max;
}
-void GraphicsHelperGL2::memoryBarrier(QMemoryBarrier::BarrierTypes barriers)
+void GraphicsHelperGL2::memoryBarrier(QMemoryBarrier::Operations barriers)
{
Q_UNUSED(barriers);
qWarning() << "memory barrier is not supported by OpenGL 2.0 (since 4.3)";
@@ -541,15 +541,11 @@ void GraphicsHelperGL2::clearBufferf(GLint drawbuffer, const QVector4D &values)
void GraphicsHelperGL2::pointSize(bool programmable, GLfloat value)
{
- // Print a warning once for trying to set GL_PROGRAM_POINT_SIZE
- if (programmable) {
- static bool warned = false;
- if (!warned) {
- qWarning() << "GL_PROGRAM_POINT_SIZE is not supported by OpenGL 2.0 (since 3.2)";
- warned = true;
- }
- }
- m_funcs->glPointSize(value);
+ m_funcs->glEnable(GL_POINT_SPRITE);
+ if (programmable)
+ m_funcs->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ else
+ m_funcs->glPointSize(value);
}
void GraphicsHelperGL2::enablei(GLenum cap, GLuint index)
@@ -600,6 +596,16 @@ 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)
+{
+ return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+}
+
+GLboolean GraphicsHelperGL2::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
void GraphicsHelperGL2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
diff --git a/src/render/graphicshelpers/graphicshelpergl2_p.h b/src/render/graphicshelpers/graphicshelpergl2_p.h
index a6fa6dba5..8966e48b2 100644
--- a/src/render/graphicshelpers/graphicshelpergl2_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl2_p.h
@@ -91,6 +91,8 @@ 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;
+ 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;
void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE;
@@ -108,7 +110,7 @@ public:
void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE;
GLint maxClipPlaneCount() Q_DECL_OVERRIDE;
- void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE;
QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl3_2.cpp b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
index 382078ac6..6c768e94e 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_2.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_2.cpp
@@ -82,7 +82,7 @@ GraphicsHelperGL3_2::~GraphicsHelperGL3_2()
}
void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context,
- QAbstractOpenGLFunctions *functions)
+ QAbstractOpenGLFunctions *functions)
{
m_funcs = static_cast<QOpenGLFunctions_3_2_Core*>(functions);
const bool ok = m_funcs->initializeOpenGLFunctions();
@@ -96,12 +96,12 @@ void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context,
}
void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
- GLsizei primitiveCount,
- GLint indexType,
- void *indices,
- GLsizei instances,
- GLint baseVertex,
- GLint baseInstance)
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
{
if (baseInstance != 0)
qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2";
@@ -116,9 +116,9 @@ void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum pri
}
void GraphicsHelperGL3_2::drawArraysInstanced(GLenum primitiveType,
- GLint first,
- GLsizei count,
- GLsizei instances)
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
{
// glDrawArraysInstanced OpenGL 3.1 or greater
m_funcs->glDrawArraysInstanced(primitiveType,
@@ -138,10 +138,10 @@ void GraphicsHelperGL3_2::drawArraysInstancedBaseInstance(GLenum primitiveType,
}
void GraphicsHelperGL3_2::drawElements(GLenum primitiveType,
- GLsizei primitiveCount,
- GLint indexType,
- void *indices,
- GLint baseVertex)
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
{
m_funcs->glDrawElementsBaseVertex(primitiveType,
primitiveCount,
@@ -151,8 +151,8 @@ void GraphicsHelperGL3_2::drawElements(GLenum primitiveType,
}
void GraphicsHelperGL3_2::drawArrays(GLenum primitiveType,
- GLint first,
- GLsizei count)
+ GLint first,
+ GLsizei count)
{
m_funcs->glDrawArrays(primitiveType,
first,
@@ -797,7 +797,7 @@ GLint GraphicsHelperGL3_2::maxClipPlaneCount()
return max;
}
-void GraphicsHelperGL3_2::memoryBarrier(QMemoryBarrier::BarrierTypes barriers)
+void GraphicsHelperGL3_2::memoryBarrier(QMemoryBarrier::Operations barriers)
{
Q_UNUSED(barriers);
qWarning() << "memory barrier is not supported by OpenGL 3.0 (since 4.3)";
@@ -882,6 +882,16 @@ 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)
+{
+ return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+}
+
+GLboolean GraphicsHelperGL3_2::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
void GraphicsHelperGL3_2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
diff --git a/src/render/graphicshelpers/graphicshelpergl3_2_p.h b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
index d10bda40b..fbca14361 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_2_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_2_p.h
@@ -93,6 +93,8 @@ 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;
+ 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;
void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE;
@@ -110,7 +112,7 @@ public:
void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE;
GLint maxClipPlaneCount() Q_DECL_OVERRIDE;
- void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE;
QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl3_3.cpp b/src/render/graphicshelpers/graphicshelpergl3_3.cpp
index 023e90965..6959bdc6b 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_3.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl3_3.cpp
@@ -794,7 +794,7 @@ GLint GraphicsHelperGL3_3::maxClipPlaneCount()
return max;
}
-void GraphicsHelperGL3_3::memoryBarrier(QMemoryBarrier::BarrierTypes barriers)
+void GraphicsHelperGL3_3::memoryBarrier(QMemoryBarrier::Operations barriers)
{
Q_UNUSED(barriers);
qWarning() << "memory barrier is not supported by OpenGL 3.3 (since 4.3)";
@@ -879,6 +879,16 @@ 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)
+{
+ return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+}
+
+GLboolean GraphicsHelperGL3_3::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
void GraphicsHelperGL3_3::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
{
m_funcs->glUniform1fv(location, count, values);
diff --git a/src/render/graphicshelpers/graphicshelpergl3_3_p.h b/src/render/graphicshelpers/graphicshelpergl3_3_p.h
index 9e97f3dc4..c093c801e 100644
--- a/src/render/graphicshelpers/graphicshelpergl3_3_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl3_3_p.h
@@ -93,6 +93,8 @@ 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;
+ 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;
void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE;
@@ -110,7 +112,7 @@ public:
void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE;
GLint maxClipPlaneCount() Q_DECL_OVERRIDE;
- void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE;
QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelpergl4.cpp b/src/render/graphicshelpers/graphicshelpergl4.cpp
index 6972864cf..26f03ac8a 100644
--- a/src/render/graphicshelpers/graphicshelpergl4.cpp
+++ b/src/render/graphicshelpers/graphicshelpergl4.cpp
@@ -88,42 +88,42 @@ namespace Render {
namespace {
-GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::BarrierTypes barriers)
+GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::Operations barriers)
{
GLbitfield bits = 0;
- if (barriers.testFlag(QMemoryBarrier::AllBarrier)) {
+ if (barriers.testFlag(QMemoryBarrier::All)) {
bits |= GL_ALL_BARRIER_BITS;
return bits;
}
- if (barriers.testFlag(QMemoryBarrier::VertexAttributeArrayBarrier))
+ if (barriers.testFlag(QMemoryBarrier::VertexAttributeArray))
bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::ElementArrayBarrier))
+ if (barriers.testFlag(QMemoryBarrier::ElementArray))
bits |= GL_ELEMENT_ARRAY_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::UniformBarrier))
+ if (barriers.testFlag(QMemoryBarrier::Uniform))
bits |= GL_UNIFORM_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::TextureFetchBarrier))
+ if (barriers.testFlag(QMemoryBarrier::TextureFetch))
bits |= GL_TEXTURE_FETCH_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::ShaderImageAccessBarrier))
+ if (barriers.testFlag(QMemoryBarrier::ShaderImageAccess))
bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::CommandBarrier))
+ if (barriers.testFlag(QMemoryBarrier::Command))
bits |= GL_COMMAND_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::PixelBufferBarrier))
+ if (barriers.testFlag(QMemoryBarrier::PixelBuffer))
bits |= GL_PIXEL_BUFFER_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::TextureUpdateBarrier))
+ if (barriers.testFlag(QMemoryBarrier::TextureUpdate))
bits |= GL_TEXTURE_UPDATE_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::BufferUpdateBarrier))
+ if (barriers.testFlag(QMemoryBarrier::BufferUpdate))
bits |= GL_BUFFER_UPDATE_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::FrameBufferBarrier))
+ if (barriers.testFlag(QMemoryBarrier::FrameBuffer))
bits |= GL_FRAMEBUFFER_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::TransformFeedbackBarrier))
+ if (barriers.testFlag(QMemoryBarrier::TransformFeedback))
bits |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::AtomicCounterBarrier))
+ if (barriers.testFlag(QMemoryBarrier::AtomicCounter))
bits |= GL_ATOMIC_COUNTER_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::ShaderStorageBarrier))
+ if (barriers.testFlag(QMemoryBarrier::ShaderStorage))
bits |= GL_SHADER_STORAGE_BARRIER_BIT;
- if (barriers.testFlag(QMemoryBarrier::QueryBufferBarrier))
+ if (barriers.testFlag(QMemoryBarrier::QueryBuffer))
bits |= GL_QUERY_BUFFER_BARRIER_BIT;
return bits;
@@ -1047,7 +1047,7 @@ GLint GraphicsHelperGL4::maxClipPlaneCount()
return max;
}
-void GraphicsHelperGL4::memoryBarrier(QMemoryBarrier::BarrierTypes barriers)
+void GraphicsHelperGL4::memoryBarrier(QMemoryBarrier::Operations barriers)
{
m_funcs->glMemoryBarrier(memoryBarrierGLBitfield(barriers));
}
@@ -1128,6 +1128,16 @@ void GraphicsHelperGL4::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
m_funcs->glDispatchCompute(wx, wy, wz);
}
+char *GraphicsHelperGL4::mapBuffer(GLenum target)
+{
+ return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+}
+
+GLboolean GraphicsHelperGL4::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
void GraphicsHelperGL4::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
{
m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
diff --git a/src/render/graphicshelpers/graphicshelpergl4_p.h b/src/render/graphicshelpers/graphicshelpergl4_p.h
index df4cf5dd9..6b3385838 100644
--- a/src/render/graphicshelpers/graphicshelpergl4_p.h
+++ b/src/render/graphicshelpers/graphicshelpergl4_p.h
@@ -91,6 +91,8 @@ 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;
+ 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;
void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) Q_DECL_OVERRIDE;
@@ -108,7 +110,7 @@ public:
void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) Q_DECL_OVERRIDE;
void pointSize(bool programmable, GLfloat value) Q_DECL_OVERRIDE;
GLint maxClipPlaneCount() Q_DECL_OVERRIDE;
- void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) Q_DECL_OVERRIDE;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) Q_DECL_OVERRIDE;
QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) Q_DECL_OVERRIDE;
QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) Q_DECL_OVERRIDE;
diff --git a/src/render/graphicshelpers/graphicshelperinterface_p.h b/src/render/graphicshelpers/graphicshelperinterface_p.h
index 847b2fc9e..4b2569263 100644
--- a/src/render/graphicshelpers/graphicshelperinterface_p.h
+++ b/src/render/graphicshelpers/graphicshelperinterface_p.h
@@ -80,7 +80,8 @@ public:
Compute,
DrawBuffersBlend,
BlitFramebuffer,
- IndirectDrawing
+ IndirectDrawing,
+ MapBuffer
};
virtual ~GraphicsHelperInterface() {}
@@ -106,6 +107,8 @@ 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 GLboolean unmapBuffer(GLenum target) = 0;
virtual void drawArrays(GLenum primitiveType, GLint first, GLsizei count) = 0;
virtual void drawArraysIndirect(GLenum mode,void *indirect) = 0;
virtual void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) = 0;
@@ -122,7 +125,7 @@ public:
virtual QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) = 0;
virtual void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) = 0;
virtual GLint maxClipPlaneCount() = 0;
- virtual void memoryBarrier(QMemoryBarrier::BarrierTypes barriers) = 0;
+ virtual void memoryBarrier(QMemoryBarrier::Operations barriers) = 0;
virtual void pointSize(bool programmable, GLfloat value) = 0;
virtual QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) = 0;
virtual QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) = 0;
diff --git a/src/render/io/glbuffer.cpp b/src/render/io/glbuffer.cpp
index 074868528..4918f9a56 100644
--- a/src/render/io/glbuffer.cpp
+++ b/src/render/io/glbuffer.cpp
@@ -140,6 +140,18 @@ void GLBuffer::update(GraphicsContext *ctx, const void *data, uint size, int off
ctx->openGLContext()->functions()->glBufferSubData(m_lastTarget, offset, size, data);
}
+QByteArray GLBuffer::download(GraphicsContext *ctx, uint size)
+{
+ char *gpu_ptr = ctx->mapBuffer(m_lastTarget);
+ QByteArray data;
+ if (gpu_ptr != nullptr) {
+ data.resize(size);
+ std::copy(gpu_ptr, gpu_ptr+size, data.data());
+ }
+ ctx->unmapBuffer(m_lastTarget);
+ return data;
+}
+
void GLBuffer::bindBufferBase(GraphicsContext *ctx, int bindingPoint, GLBuffer::Type t)
{
ctx->bindBufferBase(glBufferTypes[t], bindingPoint, m_bufferId);
diff --git a/src/render/io/glbuffer_p.h b/src/render/io/glbuffer_p.h
index e800d2bc4..731634b6b 100644
--- a/src/render/io/glbuffer_p.h
+++ b/src/render/io/glbuffer_p.h
@@ -53,6 +53,7 @@
#include <QOpenGLContext>
#include <Qt3DCore/qnodeid.h>
+#include <qbytearray.h>
QT_BEGIN_NAMESPACE
@@ -85,6 +86,7 @@ public:
void allocate(GraphicsContext *ctx, uint size, bool dynamic = true);
void allocate(GraphicsContext *ctx, const void *data, uint size, bool dynamic = true);
void update(GraphicsContext *ctx, const void *data, uint size, int offset = 0);
+ QByteArray download(GraphicsContext *ctx, uint size);
void bindBufferBase(GraphicsContext *ctx, int bindingPoint, Type t);
void bindBufferBase(GraphicsContext *ctx, int bindingPoint);
diff --git a/src/render/io/qgeometryloaderfactory_p.h b/src/render/io/qgeometryloaderfactory_p.h
index c6a7344ce..6e0044c4a 100644
--- a/src/render/io/qgeometryloaderfactory_p.h
+++ b/src/render/io/qgeometryloaderfactory_p.h
@@ -68,6 +68,7 @@ class QGeometryLoaderInterface;
class QT3DRENDERSHARED_PRIVATE_EXPORT QGeometryLoaderFactory : public QObject, public QFactoryInterface
{
Q_OBJECT
+ Q_INTERFACES(QFactoryInterface)
public:
explicit QGeometryLoaderFactory(QObject *parent = nullptr);
virtual ~QGeometryLoaderFactory();
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/qsceneloader.cpp b/src/render/io/qsceneloader.cpp
index b9408298f..3bc842c3d 100644
--- a/src/render/io/qsceneloader.cpp
+++ b/src/render/io/qsceneloader.cpp
@@ -198,7 +198,8 @@ void QSceneLoaderPrivate::populateEntityMap(QEntity *parentEntity)
{
// Topmost parent entity is not considered part of the scene as that is typically
// an unnamed entity inserted by importer.
- for (auto childNode : parentEntity->childNodes()) {
+ const QNodeVector childNodes = parentEntity->childNodes();
+ for (auto childNode : childNodes) {
auto childEntity = qobject_cast<QEntity *>(childNode);
if (childEntity) {
m_entityMap.insert(childEntity->objectName(), childEntity);
@@ -207,6 +208,17 @@ void QSceneLoaderPrivate::populateEntityMap(QEntity *parentEntity)
}
}
+void QSceneLoaderPrivate::setStatus(QSceneLoader::Status status)
+{
+ if (m_status != status) {
+ Q_Q(QSceneLoader);
+ m_status = status;
+ const bool wasBlocked = q->blockNotifications(true);
+ emit q->statusChanged(status);
+ q->blockNotifications(wasBlocked);
+ }
+}
+
/*!
The constructor creates an instance with the specified \a parent.
*/
@@ -253,7 +265,7 @@ void QSceneLoader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
d->populateEntityMap(d->m_subTreeRoot);
}
} else if (e->propertyName() == QByteArrayLiteral("status")) {
- setStatus(e->value().value<QSceneLoader::Status>());
+ d->setStatus(e->value().value<QSceneLoader::Status>());
}
}
}
@@ -328,7 +340,7 @@ QStringList QSceneLoader::entityNames() const
\sa Qt3DRender::QSceneLoader::ComponentType
*/
/*!
- Returns a component matching \a componentType of a loaded entity with an \a objectName matching
+ Returns a component matching \a componentType of a loaded entity with an objectName matching
the \a entityName.
If the entity has multiple matching components, the first match in the component list of
the entity is returned.
@@ -338,7 +350,8 @@ QComponent *QSceneLoader::component(const QString &entityName,
QSceneLoader::ComponentType componentType) const
{
QEntity *e = entity(entityName);
- for (auto component : e->components()) {
+ const QComponentVector components = e->components();
+ for (auto component : components) {
switch (componentType) {
case GeometryRendererComponent:
if (qobject_cast<Qt3DRender::QGeometryRenderer *>(component))
@@ -371,12 +384,7 @@ QComponent *QSceneLoader::component(const QString &entityName,
void QSceneLoader::setStatus(QSceneLoader::Status status)
{
Q_D(QSceneLoader);
- if (d->m_status != status) {
- d->m_status = status;
- const bool wasBlocked = blockNotifications(true);
- emit statusChanged(status);
- blockNotifications(wasBlocked);
- }
+ d->setStatus(status);
}
Qt3DCore::QNodeCreatedChangeBasePtr QSceneLoader::createNodeCreationChange() const
diff --git a/src/render/io/qsceneloader.h b/src/render/io/qsceneloader.h
index 76f8c4d80..31ec47ac0 100644
--- a/src/render/io/qsceneloader.h
+++ b/src/render/io/qsceneloader.h
@@ -82,10 +82,10 @@ public:
QUrl source() const;
Status status() const;
- Q_INVOKABLE Qt3DCore::QEntity *entity(const QString &entityName) const;
- Q_INVOKABLE QStringList entityNames() const;
- Q_INVOKABLE Qt3DCore::QComponent *component(const QString &entityName,
- ComponentType componentType) const;
+ Q_REVISION(9) Q_INVOKABLE Qt3DCore::QEntity *entity(const QString &entityName) const;
+ Q_REVISION(9) Q_INVOKABLE QStringList entityNames() const;
+ Q_REVISION(9) Q_INVOKABLE Qt3DCore::QComponent *component(const QString &entityName,
+ ComponentType componentType) const;
public Q_SLOTS:
void setSource(const QUrl &arg);
diff --git a/src/render/io/qsceneloader_p.h b/src/render/io/qsceneloader_p.h
index 13569ea70..45a6a1a4e 100644
--- a/src/render/io/qsceneloader_p.h
+++ b/src/render/io/qsceneloader_p.h
@@ -66,6 +66,8 @@ class QT3DRENDERSHARED_PRIVATE_EXPORT QSceneLoaderPrivate : public Qt3DCore::QCo
public:
QSceneLoaderPrivate();
+ void setStatus(QSceneLoader::Status status);
+
Q_DECLARE_PUBLIC(QSceneLoader)
void populateEntityMap(Qt3DCore::QEntity *parentEntity);
diff --git a/src/render/io/scene.cpp b/src/render/io/scene.cpp
index 2057ffd3d..7ae6f9473 100644
--- a/src/render/io/scene.cpp
+++ b/src/render/io/scene.cpp
@@ -42,11 +42,11 @@
#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>
#include <QtCore/qcoreapplication.h>
-#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
QT_BEGIN_NAMESPACE
@@ -73,7 +73,6 @@ void Scene::setStatus(QSceneLoader::Status status)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("status");
e->setValue(QVariant::fromValue(status));
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -83,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)
@@ -92,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);
@@ -116,7 +121,6 @@ void Scene::setSceneSubtree(Qt3DCore::QEntity *subTree)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("scene");
e->setValue(QVariant::fromValue(subTree));
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
diff --git a/src/render/io/scenemanager.cpp b/src/render/io/scenemanager.cpp
index d59391a87..b0a595905 100644
--- a/src/render/io/scenemanager.cpp
+++ b/src/render/io/scenemanager.cpp
@@ -44,18 +44,34 @@ QT_BEGIN_NAMESPACE
namespace Qt3DRender {
namespace Render {
-SceneManager::SceneManager() : Qt3DCore::QResourceManager<Scene,
- Qt3DCore::QNodeId,
- 8,
- Qt3DCore::ArrayAllocatingPolicy,
- Qt3DCore::ObjectLevelLockingPolicy>()
+SceneManager::SceneManager()
+ : Qt3DCore::QResourceManager<Scene,
+ Qt3DCore::QNodeId,
+ 8,
+ Qt3DCore::ArrayAllocatingPolicy,
+ 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())
@@ -70,6 +86,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 164f82590..9993c85fc 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,
@@ -74,12 +91,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 9e373c655..e81836502 100644
--- a/src/render/jobs/calcboundingvolumejob.cpp
+++ b/src/render/jobs/calcboundingvolumejob.cpp
@@ -50,6 +50,7 @@
#include <Qt3DRender/private/attribute_p.h>
#include <Qt3DRender/private/buffer_p.h>
#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/buffervisitor_p.h>
#include <QtCore/qmath.h>
#include <QtConcurrent/QtConcurrent>
@@ -73,6 +74,114 @@ struct UpdateBoundFunctor {
}
};
+class BoundingVolumeCalculator
+{
+public:
+ BoundingVolumeCalculator(NodeManagers *manager) : m_manager(manager) { }
+
+ const Sphere& result() { return m_volume; }
+
+ bool apply(Qt3DRender::Render::Attribute *positionAttribute)
+ {
+ FindExtremePoints findExtremePoints(m_manager);
+ if (!findExtremePoints.apply(positionAttribute))
+ return false;
+
+ // Calculate squared distance for the pairs of points
+ const float xDist2 = (findExtremePoints.xMaxPt - findExtremePoints.xMinPt).lengthSquared();
+ const float yDist2 = (findExtremePoints.yMaxPt - findExtremePoints.yMinPt).lengthSquared();
+ const float zDist2 = (findExtremePoints.zMaxPt - findExtremePoints.zMinPt).lengthSquared();
+
+ // Select most distant pair
+ QVector3D p = findExtremePoints.xMinPt;
+ QVector3D q = findExtremePoints.xMaxPt;
+ if (yDist2 > xDist2 && yDist2 > zDist2) {
+ p = findExtremePoints.yMinPt;
+ q = findExtremePoints.yMaxPt;
+ }
+ if (zDist2 > xDist2 && zDist2 > yDist2) {
+ p = findExtremePoints.zMinPt;
+ q = findExtremePoints.zMaxPt;
+ }
+
+ const QVector3D c = 0.5f * (p + q);
+ m_volume.setCenter(c);
+ m_volume.setRadius((q - c).length());
+
+ ExpandSphere expandSphere(m_manager, m_volume);
+ if (!expandSphere.apply(positionAttribute))
+ return false;
+
+ return true;
+ }
+
+private:
+ Sphere m_volume;
+ NodeManagers *m_manager;
+
+ class FindExtremePoints : public Buffer3fVisitor
+ {
+ public:
+ FindExtremePoints(NodeManagers *manager)
+ : Buffer3fVisitor(manager)
+ , xMin(0.0f), xMax(0.0f), yMin(0.0f), yMax(0.0f), zMin(0.0f), zMax(0.0f)
+ { }
+
+ float xMin, xMax, yMin, yMax, zMin, zMax;
+ QVector3D xMinPt, xMaxPt, yMinPt, yMaxPt, zMinPt, zMaxPt;
+
+ void visit(uint ndx, float x, float y, float z) override
+ {
+ if (ndx) {
+ if (x < xMin) {
+ xMin = x;
+ xMinPt = QVector3D(x, y, z);
+ }
+ if (x > xMax) {
+ xMax = x;
+ xMaxPt = QVector3D(x, y, z);
+ }
+ if (y < yMin) {
+ yMin = y;
+ yMinPt = QVector3D(x, y, z);
+ }
+ if (y > yMax) {
+ yMax = y;
+ yMaxPt = QVector3D(x, y, z);
+ }
+ if (z < zMin) {
+ zMin = z;
+ zMinPt = QVector3D(x, y, z);
+ }
+ if (z > zMax) {
+ zMax = z;
+ zMaxPt = QVector3D(x, y, z);
+ }
+ } else {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ zMin = zMax = z;
+ xMinPt = xMaxPt = yMinPt = yMaxPt = zMinPt = zMaxPt = QVector3D(x, y, z);
+ }
+ }
+ };
+
+ class ExpandSphere : public Buffer3fVisitor
+ {
+ public:
+ ExpandSphere(NodeManagers *manager, Sphere& volume)
+ : Buffer3fVisitor(manager), m_volume(volume)
+ { }
+
+ Sphere& m_volume;
+ void visit(uint ndx, float x, float y, float z) override
+ {
+ Q_UNUSED(ndx);
+ m_volume.expandToContain(QVector3D(x, y, z));
+ }
+ };
+};
+
void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
{
// The Bounding volume will only be computed if the position Buffer
@@ -86,63 +195,48 @@ void calculateLocalBoundingVolume(NodeManagers *manager, Entity *node)
Geometry *geom = manager->lookupResource<Geometry, GeometryManager>(gRenderer->geometryId());
if (geom) {
- Qt3DRender::Render::Attribute *pickVolumeAttribute = manager->lookupResource<Attribute, AttributeManager>(geom->boundingPositionAttribute());
+ Qt3DRender::Render::Attribute *positionAttribute = manager->lookupResource<Attribute, AttributeManager>(geom->boundingPositionAttribute());
// Use the default position attribute if attribute is null
- if (!pickVolumeAttribute) {
+ if (!positionAttribute) {
const auto attrIds = geom->attributes();
for (const Qt3DCore::QNodeId attrId : attrIds) {
- pickVolumeAttribute = manager->lookupResource<Attribute, AttributeManager>(attrId);
- if (pickVolumeAttribute &&
- pickVolumeAttribute->name() == QAttribute::defaultPositionAttributeName())
+ positionAttribute = manager->lookupResource<Attribute, AttributeManager>(attrId);
+ if (positionAttribute &&
+ positionAttribute->name() == QAttribute::defaultPositionAttributeName())
break;
}
}
- if (pickVolumeAttribute) {
- if (!pickVolumeAttribute
- || pickVolumeAttribute->attributeType() != QAttribute::VertexAttribute
- || pickVolumeAttribute->vertexBaseType() != QAttribute::Float
- || pickVolumeAttribute->vertexSize() < 3) {
- qWarning() << "QGeometry::boundingVolumePositionAttribute pickVolume Attribute not suited for bounding volume computation";
- return;
- }
+ if (!positionAttribute
+ || positionAttribute->attributeType() != QAttribute::VertexAttribute
+ || positionAttribute->vertexBaseType() != QAttribute::Float
+ || positionAttribute->vertexSize() < 3) {
+ qWarning() << "QGeometry::boundingVolumePositionAttribute position Attribute not suited for bounding volume computation";
+ return;
+ }
- Buffer *buf = manager->lookupResource<Buffer, BufferManager>(pickVolumeAttribute->bufferId());
- // No point in continuing if the positionAttribute doesn't have a suitable buffer
- if (!buf) {
- qWarning() << "ObjectPicker pickVolume 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()) {
- // 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() ||
- pickVolumeAttribute->isDirty() ||
- geom->isDirty() ||
- gRenderer->isDirty()) {
-
- const QByteArray buffer = buf->data();
- const char *rawBuffer = buffer.constData();
- rawBuffer += pickVolumeAttribute->byteOffset();
- const int stride = pickVolumeAttribute->byteStride() ? pickVolumeAttribute->byteStride() : sizeof(float) * pickVolumeAttribute->vertexSize();
- QVector<QVector3D> vertices(pickVolumeAttribute->count());
-
- // TODO avoid copying the vertices
- for (int c = 0, vC = vertices.size(); c < vC; ++c) {
- QVector3D v;
- const float *fptr = reinterpret_cast<const float*>(rawBuffer);
- // TODO unwrap loop (switch?)
- for (uint i = 0, m = qMin(pickVolumeAttribute->vertexSize(), 3U); i < m; ++i)
- v[i] = fptr[i];
- vertices[c] = v;
- rawBuffer += stride;
- }
-
- node->localBoundingVolume()->initializeFromPoints(vertices);
+ 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/job_common_p.h b/src/render/jobs/job_common_p.h
index 90e29d0dc..332b62547 100644
--- a/src/render/jobs/job_common_p.h
+++ b/src/render/jobs/job_common_p.h
@@ -86,9 +86,11 @@ namespace JobTypes {
UpdateWorldBoundingVolume,
FrameSubmissionPart2,
DirtyBufferGathering,
+ DirtyVaoGathering,
DirtyTextureGathering,
DirtyShaderGathering,
SendRenderCapture,
+ SendBufferCapture,
SyncRenderViewCommandBuilding,
SyncRenderViewInitialization,
SyncRenderViewCommandBuilder,
diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri
index d7f05ec4c..66c98b1c0 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 \
@@ -28,7 +29,8 @@ HEADERS += \
$$PWD/updatemeshtrianglelistjob_p.h \
$$PWD/pickboundingvolumeutils_p.h \
$$PWD/filtercompatibletechniquejob_p.h \
- $$PWD/updatetreeenabledjob_p.h
+ $$PWD/updatetreeenabledjob_p.h \
+ $$PWD/sendbuffercapturejob_p.h
SOURCES += \
$$PWD/updateworldtransformjob.cpp \
@@ -41,6 +43,7 @@ SOURCES += \
$$PWD/calcboundingvolumejob.cpp \
$$PWD/pickboundingvolumejob.cpp \
$$PWD/calcgeometrytrianglevolumes.cpp \
+ $$PWD/computefilteredboundingvolumejob.cpp \
$$PWD/filterlayerentityjob.cpp \
$$PWD/materialparametergathererjob.cpp \
$$PWD/renderviewbuilderjob.cpp \
@@ -55,4 +58,6 @@ SOURCES += \
$$PWD/updatelevelofdetailjob.cpp \
$$PWD/pickboundingvolumeutils.cpp \
$$PWD/filtercompatibletechniquejob.cpp \
- $$PWD/updatetreeenabledjob.cpp
+ $$PWD/updatetreeenabledjob.cpp \
+ $$PWD/sendbuffercapturejob.cpp
+
diff --git a/src/render/jobs/lightgatherer.cpp b/src/render/jobs/lightgatherer.cpp
index 39023bc35..e62544f15 100644
--- a/src/render/jobs/lightgatherer.cpp
+++ b/src/render/jobs/lightgatherer.cpp
@@ -51,6 +51,7 @@ namespace Render {
LightGatherer::LightGatherer()
: Qt3DCore::QAspectJob()
, m_manager(nullptr)
+ , m_environmentLight(nullptr)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::LightGathering, 0);
}
@@ -58,13 +59,21 @@ LightGatherer::LightGatherer()
void LightGatherer::run()
{
const QVector<HEntity> handles = m_manager->activeHandles();
+ int envLightCount = 0;
for (const HEntity handle : handles) {
Entity *node = m_manager->data(handle);
const QVector<Light *> lights = node->renderComponents<Light>();
if (!lights.isEmpty())
m_lights.push_back(LightSource(node, lights));
+ const QVector<EnvironmentLight *> envLights = node->renderComponents<EnvironmentLight>();
+ envLightCount += envLights.size();
+ if (!envLights.isEmpty() && !m_environmentLight)
+ m_environmentLight = envLights.first();
}
+
+ if (envLightCount > 1)
+ qWarning() << "More than one environment light found, extra instances are ignored";
}
} // Render
diff --git a/src/render/jobs/lightgatherer_p.h b/src/render/jobs/lightgatherer_p.h
index e2954fd07..4eaeb8f19 100644
--- a/src/render/jobs/lightgatherer_p.h
+++ b/src/render/jobs/lightgatherer_p.h
@@ -61,6 +61,7 @@ namespace Qt3DRender {
namespace Render {
class EntityManager;
+class EnvironmentLight;
class Q_AUTOTEST_EXPORT LightGatherer : public Qt3DCore::QAspectJob
{
@@ -69,12 +70,19 @@ public:
inline void setManager(EntityManager *manager) Q_DECL_NOTHROW { m_manager = manager; }
inline QVector<LightSource> &lights() { return m_lights; }
+ inline EnvironmentLight *takeEnvironmentLight()
+ {
+ auto envLight = m_environmentLight;
+ m_environmentLight = nullptr;
+ return envLight;
+ }
void run() Q_DECL_FINAL;
private:
EntityManager *m_manager;
QVector<LightSource> m_lights;
+ EnvironmentLight *m_environmentLight;
};
typedef QSharedPointer<LightGatherer> LightGathererPtr;
diff --git a/src/render/jobs/loadscenejob.cpp b/src/render/jobs/loadscenejob.cpp
index 9b3374627..3d6326e93 100644
--- a/src/render/jobs/loadscenejob.cpp
+++ b/src/render/jobs/loadscenejob.cpp
@@ -44,6 +44,7 @@
#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>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,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 +101,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/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 6b8b93647..f9c7a390c 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -49,6 +49,7 @@
#include <Qt3DRender/private/rendersettings_p.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/qpickevent_p.h>
QT_BEGIN_NAMESPACE
@@ -59,6 +60,8 @@ namespace Render {
namespace {
+typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList;
+
void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
{
switch (event.button()) {
@@ -120,6 +123,11 @@ void PickBoundingVolumeJob::setMouseEvents(const QList<QMouseEvent> &pendingEven
m_pendingMouseEvents = pendingEvents;
}
+void PickBoundingVolumeJob::setKeyEvents(const QList<QKeyEvent> &pendingEvents)
+{
+ m_pendingKeyEvents = pendingEvents;
+}
+
void PickBoundingVolumeJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot)
{
m_frameGraphRoot = frameGraphRoot;
@@ -159,7 +167,8 @@ bool PickBoundingVolumeJob::runHelper()
m_oneEnabledAtLeast = false;
m_oneHoverAtLeast = false;
- for (auto handle : m_manager->objectPickerManager()->activeHandles()) {
+ const auto activeHandles = m_manager->objectPickerManager()->activeHandles();
+ for (auto handle : activeHandles) {
auto picker = m_manager->objectPickerManager()->data(handle);
m_oneEnabledAtLeast |= picker->isEnabled();
m_oneHoverAtLeast |= picker->isHoverEnabled();
@@ -214,11 +223,6 @@ 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
- // Gather the entities for the frame
- // TO DO: We could skip doing that every frame and only do it when we know for sure
- // that the tree structure has changed
- PickingUtils::EntityGatherer entitiesGatherer(m_node);
-
// Store the reducer function which varies depending on the picking settings set on the renderer
using ReducerFunction = PickingUtils::CollisionVisitor::HitList (*)(PickingUtils::CollisionVisitor::HitList &results, const PickingUtils::CollisionVisitor::HitList &intermediate);
@@ -244,25 +248,30 @@ bool PickBoundingVolumeJob::runHelper()
// For each triplet of Viewport / Camera and Area
for (const PickingUtils::ViewportCameraAreaTriplet &vca : vcaTriplets) {
- typedef PickingUtils::AbstractCollisionGathererFunctor::result_type HitList;
HitList sphereHits;
QRay3D ray = rayForViewportAndCamera(vca.area, event.pos(), vca.viewport, vca.cameraId);
- if (trianglePickingRequested) {
- PickingUtils::TriangleCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_frontFaceRequested = frontFaceRequested;
- gathererFunctor.m_backFaceRequested = backFaceRequested;
- gathererFunctor.m_manager = m_manager;
- gathererFunctor.m_ray = ray;
- sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp);
- } else {
- PickingUtils::EntityCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_manager = m_manager;
- gathererFunctor.m_ray = ray;
- sphereHits = QtConcurrent::blockingMappedReduced<HitList>(entitiesGatherer.entities(), gathererFunctor, reducerOp);
+
+ PickingUtils::HierarchicalEntityPicker entityPicker(ray);
+ if (entityPicker.collectHits(m_node)) {
+ if (trianglePickingRequested) {
+ PickingUtils::TriangleCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_frontFaceRequested = frontFaceRequested;
+ 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();
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ if (!allHitsRequested)
+ sphereHits = { sphereHits.front() };
+ }
}
// Dispatch events based on hit results
- dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, trianglePickingRequested, allHitsRequested);
+ dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers,
+ trianglePickingRequested, allHitsRequested);
}
}
@@ -331,17 +340,18 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
// Send the corresponding event
QVector3D localIntersection = hit.m_intersection;
if (entity && entity->worldTransform())
- localIntersection = hit.m_intersection * entity->worldTransform()->inverted();
+ localIntersection = entity->worldTransform()->inverted() * hit.m_intersection;
QPickEventPtr pickEvent;
- if (trianglePickingRequested)
+ if (trianglePickingRequested) {
pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2],
- eventButton, eventButtons, eventModifiers));
- else
+ eventButton, eventButtons, eventModifiers, hit.m_uvw));
+ QPickEventPrivate::get(pickEvent.data())->m_entity = hit.m_entityId;
+ } else {
pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
eventButton, eventButtons, eventModifiers));
-
+ }
switch (event.type()) {
case QEvent::MouseButtonPress: {
// Store pressed object handle
@@ -352,24 +362,23 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
}
case QEvent::MouseButtonRelease: {
- if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle)
- m_currentPicker = HObjectPicker();
// Only send the release event if it was pressed
- if (objectPicker->isPressed()) {
- if (lastCurrentPicker == objectPicker)
- objectPicker->onClicked(pickEvent);
+ if (objectPicker->isPressed())
objectPicker->onReleased(pickEvent);
+ if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle) {
+ objectPicker->onClicked(pickEvent);
+ m_currentPicker = HObjectPicker();
}
break;
}
-
+#if QT_CONFIG(gestures)
case Qt::TapGesture: {
objectPicker->onClicked(pickEvent);
break;
}
-
+#endif
case QEvent::MouseMove: {
- if (objectPicker->isPressed() && objectPicker->isDragEnabled()) {
+ if ((objectPicker->isPressed() || objectPicker->isHoverEnabled()) && objectPicker->isDragEnabled()) {
objectPicker->onMoved(pickEvent);
}
// fallthrough
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index 9f52943d1..5239c5c6c 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -59,6 +59,7 @@
#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
#include <Qt3DRender/qpickevent.h>
#include <QMouseEvent>
+#include <QKeyEvent>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
@@ -82,6 +83,7 @@ public:
void setRoot(Entity *root);
void setMouseEvents(const QList<QMouseEvent> &pendingEvents);
+ void setKeyEvents(const QList<QKeyEvent> &pendingEvents);
void setFrameGraphRoot(FrameGraphNode *frameGraphRoot);
void setRenderSettings(RenderSettings *settings);
void setManagers(NodeManagers *manager);
@@ -102,8 +104,10 @@ protected:
void run() Q_DECL_FINAL;
void dispatchPickEvents(const QMouseEvent &event, const PickingUtils::CollisionVisitor::HitList &sphereHits,
QPickEvent::Buttons eventButton,
- int eventButtons, int eventModifiers,
- bool trianglePickingRequested, bool allHitsRequested);
+ int eventButtons,
+ int eventModifiers,
+ bool trianglePickingRequested,
+ bool allHitsRequested);
private:
NodeManagers *m_manager;
@@ -115,6 +119,8 @@ private:
bool m_oneEnabledAtLeast;
bool m_oneHoverAtLeast;
+ QList<QKeyEvent> m_pendingKeyEvents;
+
void viewMatrixForCamera(Qt3DCore::QNodeId cameraId,
QMatrix4x4 &viewMatrix,
QMatrix4x4 &projectionMatrix) const;
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index 1573aa112..f08398a5a 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -175,6 +175,7 @@ bool CollisionVisitor::intersectsSegmentTriangle(uint andx, const QVector3D &a,
queryResult.m_vertexIndex[0] = andx;
queryResult.m_vertexIndex[1] = bndx;
queryResult.m_vertexIndex[2] = cndx;
+ queryResult.m_uvw = uvw;
queryResult.m_intersection = m_ray.point(t * m_ray.distance());
queryResult.m_distance = m_ray.projectedDistance(queryResult.m_intersection);
hits.push_back(queryResult);
@@ -212,6 +213,15 @@ AbstractCollisionGathererFunctor::result_type AbstractCollisionGathererFunctor::
return pick(&rayCasting, entity);
}
+void AbstractCollisionGathererFunctor::sortHits(CollisionVisitor::HitList &results)
+{
+ auto compareHitsDistance = [](const CollisionVisitor::HitList::value_type &a,
+ const CollisionVisitor::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
{
result_type result;
@@ -236,14 +246,7 @@ AbstractCollisionGathererFunctor::result_type TriangleCollisionGathererFunctor::
visitor.apply(gRenderer, entity->peerId());
result = visitor.hits;
- struct
- {
- bool operator()(const result_type::value_type &a, const result_type::value_type &b)
- {
- return a.m_distance < b.m_distance;
- }
- } compareHitsDistance;
- std::sort(result.begin(), result.end(), compareHitsDistance);
+ sortHits(result);
}
return result;
@@ -281,6 +284,44 @@ CollisionVisitor::HitList reduceToAllHits(CollisionVisitor::HitList &results, co
return results;
}
+HierarchicalEntityPicker::HierarchicalEntityPicker(const QRay3D &ray)
+ : m_ray(ray)
+{
+
+}
+
+bool HierarchicalEntityPicker::collectHits(Entity *root)
+{
+ m_hits.clear();
+ m_entities.clear();
+
+ QRayCastingService rayCasting;
+ QVector<Entity *> worklist;
+ worklist << root;
+
+ while (!worklist.empty()) {
+ Entity *current = worklist.takeLast();
+
+ // first pick entry sub-scene-graph
+ QCollisionQueryResult::Hit queryResult =
+ rayCasting.query(m_ray, current->worldBoundingVolumeWithChildren());
+ if (queryResult.m_distance < 0.f)
+ continue;
+
+ // if we get a hit, we check again for this specific entity
+ queryResult = rayCasting.query(m_ray, current->worldBoundingVolume());
+ if (queryResult.m_distance >= 0.f) {
+ m_entities.push_back(current);
+ m_hits.push_back(queryResult);
+ }
+
+ // and pick children
+ worklist << current->children();
+ }
+
+ return !m_hits.empty();
+}
+
} // PickingUtils
} // Render
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index 0a65c58cc..08615c094 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -136,6 +136,21 @@ private:
uint cndx, const QVector3D &c);
};
+class Q_AUTOTEST_EXPORT HierarchicalEntityPicker
+{
+public:
+ explicit HierarchicalEntityPicker(const RayCasting::QRay3D &ray);
+
+ bool collectHits(Entity *root);
+ inline CollisionVisitor::HitList hits() const { return m_hits; }
+ inline QVector<Entity *> entities() const { return m_entities; }
+
+private:
+ RayCasting::QRay3D m_ray;
+ CollisionVisitor::HitList m_hits;
+ QVector<Entity *> m_entities;
+};
+
struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
{
AbstractCollisionGathererFunctor();
@@ -148,6 +163,8 @@ struct Q_AUTOTEST_EXPORT AbstractCollisionGathererFunctor
typedef CollisionVisitor::HitList result_type;
result_type operator ()(const Entity *entity) const;
virtual result_type pick(RayCasting::QAbstractCollisionQueryService *rayCasting, const Entity *entity) const = 0;
+
+ static void sortHits(CollisionVisitor::HitList &results);
};
struct Q_AUTOTEST_EXPORT EntityCollisionGathererFunctor : public AbstractCollisionGathererFunctor
diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp
index e587dd828..9f1b51cc1 100644
--- a/src/render/jobs/renderviewjobutils.cpp
+++ b/src/render/jobs/renderviewjobutils.cpp
@@ -63,6 +63,7 @@
#include <Qt3DRender/private/dispatchcompute_p.h>
#include <Qt3DRender/private/rendersurfaceselector_p.h>
#include <Qt3DRender/private/rendercapture_p.h>
+#include <Qt3DRender/private/buffercapture_p.h>
#include <Qt3DRender/private/stringtoint_p.h>
#include <Qt3DRender/private/techniquemanager_p.h>
#include <Qt3DRender/private/memorybarrier_p.h>
@@ -164,6 +165,7 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
// a subregion relative to that of the parent viewport
const ViewportNode *vpNode = static_cast<const ViewportNode *>(node);
rv->setViewport(computeViewport(rv->viewport(), vpNode));
+ rv->setGamma(vpNode->gamma());
break;
}
@@ -238,7 +240,15 @@ void setRenderViewConfigFromFrameGraphLeafNode(RenderView *rv, const FrameGraphN
case FrameGraphNode::MemoryBarrier: {
const Render::MemoryBarrier *barrier = static_cast<const Render::MemoryBarrier *>(node);
- rv->setMemoryBarrier(barrier->barrierTypes()|rv->memoryBarrier());
+ rv->setMemoryBarrier(barrier->waitOperations()|rv->memoryBarrier());
+ break;
+ }
+
+ case FrameGraphNode::BufferCapture: {
+ auto *bufferCapture = const_cast<Render::BufferCapture *>(
+ static_cast<const Render::BufferCapture *>(node));
+ if (bufferCapture != nullptr)
+ rv->setIsDownloadBuffersEnable(bufferCapture->isEnabled());
break;
}
@@ -404,7 +414,9 @@ const int qNodeIdTypeId = qMetaTypeId<QNodeId>();
}
UniformBlockValueBuilder::UniformBlockValueBuilder()
- : shaderDataManager(nullptr)
+ : updatedPropertiesOnly(false)
+ , shaderDataManager(nullptr)
+ , textureManager(nullptr)
{
}
@@ -420,12 +432,16 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData *
QVariantList list = value.value<QVariantList>();
if (list.at(0).userType() == qNodeIdTypeId) { // Array of struct qmlPropertyName[i].structMember
for (int i = 0; i < list.size(); ++i) {
+ const QVariant variantElement = list.at(i);
if (list.at(i).userType() == qNodeIdTypeId) {
- ShaderData *subShaderData = shaderDataManager->lookupResource(list.at(i).value<QNodeId>());
- if (subShaderData)
+ const auto nodeId = variantElement.value<QNodeId>();
+ ShaderData *subShaderData = shaderDataManager->lookupResource(nodeId);
+ if (subShaderData) {
buildActiveUniformNameValueMapStructHelper(subShaderData,
blockName + QLatin1Char('.') + qmlPropertyName + blockArray.arg(i),
QLatin1String(""));
+ }
+ // Note: we only handle ShaderData as nested container nodes here
}
}
} else { // Array of scalar/vec qmlPropertyName[0]
@@ -436,11 +452,16 @@ void UniformBlockValueBuilder::buildActiveUniformNameValueMapHelper(ShaderData *
}
}
} else if (value.userType() == qNodeIdTypeId) { // Struct qmlPropertyName.structMember
- ShaderData *rSubShaderData = shaderDataManager->lookupResource(value.value<QNodeId>());
- if (rSubShaderData)
+ const auto nodeId = value.value<QNodeId>();
+ ShaderData *rSubShaderData = shaderDataManager->lookupResource(nodeId);
+ if (rSubShaderData) {
buildActiveUniformNameValueMapStructHelper(rSubShaderData,
blockName,
qmlPropertyName);
+ } else if (textureManager->contains(nodeId)) {
+ const auto varId = StringToInt::lookupId(blockName + QLatin1Char('.') + qmlPropertyName);
+ activeUniformNamesToValue.insert(varId, value);
+ }
} else { // Scalar / Vec
QString varName = blockName + QLatin1Char('.') + qmlPropertyName;
if (uniforms.contains(varName)) {
diff --git a/src/render/jobs/renderviewjobutils_p.h b/src/render/jobs/renderviewjobutils_p.h
index bc042a582..c1d37b28a 100644
--- a/src/render/jobs/renderviewjobutils_p.h
+++ b/src/render/jobs/renderviewjobutils_p.h
@@ -83,6 +83,7 @@ class NodeManagers;
class ShaderDataManager;
struct ShaderUniform;
class ShaderData;
+class TextureManager;
class RenderStateManager;
class RenderStateCollection;
@@ -169,6 +170,7 @@ struct Q_AUTOTEST_EXPORT UniformBlockValueBuilder
QHash<QString, ShaderUniform> uniforms;
UniformBlockValueBuilderHash activeUniformNamesToValue;
ShaderDataManager *shaderDataManager;
+ TextureManager *textureManager;
QMatrix4x4 viewMatrix;
};
diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp
new file mode 100644
index 000000000..7829931f7
--- /dev/null
+++ b/src/render/jobs/sendbuffercapturejob.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Juan José Casafranca
+** 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 "sendbuffercapturejob_p.h"
+
+
+#include "Qt3DRender/private/renderer_p.h"
+#include "Qt3DRender/private/nodemanagers_p.h"
+#include <Qt3DRender/private/job_common_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+SendBufferCaptureJob::SendBufferCaptureJob()
+ : Qt3DCore::QAspectJob()
+{
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0);
+}
+
+SendBufferCaptureJob::~SendBufferCaptureJob()
+{
+}
+
+void SendBufferCaptureJob::setManagers(NodeManagers *managers)
+{
+ m_managers = managers;
+}
+
+void SendBufferCaptureJob::addRequest(QPair<Buffer *, QByteArray> request)
+{
+ QMutexLocker locker(&m_mutex);
+ m_pendingSendBufferCaptures.push_back(request);
+}
+
+void SendBufferCaptureJob::run()
+{
+ QMutexLocker locker(&m_mutex);
+ for (const QPair<Buffer*, QByteArray> &pendingCapture : qAsConst(m_pendingSendBufferCaptures)) {
+ pendingCapture.first->updateDataFromGPUToCPU(pendingCapture.second);
+ }
+
+ m_pendingSendBufferCaptures.clear();
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/jobs/sendbuffercapturejob_p.h b/src/render/jobs/sendbuffercapturejob_p.h
new file mode 100644
index 000000000..d01ecec72
--- /dev/null
+++ b/src/render/jobs/sendbuffercapturejob_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Juan José Casafranca
+** 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_SENDBUFFERCAPTUREJOB_P_H
+#define QT3DRENDER_SENDBUFFERCAPTUREJOB_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 <Qt3DRender/qt3drender_global.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
+#include <QMutex>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class NodeManagers;
+class Entity;
+class Renderer;
+class Buffer;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT SendBufferCaptureJob : public Qt3DCore::QAspectJob
+{
+public:
+ explicit SendBufferCaptureJob();
+ ~SendBufferCaptureJob();
+
+ void setManagers(NodeManagers *managers);
+
+ void addRequest(QPair<Buffer*, QByteArray> request);
+
+ void run() Q_DECL_FINAL;
+
+private:
+ NodeManagers *m_managers;
+ QMutex m_mutex;
+
+ QVector<QPair<Buffer*, QByteArray> > m_pendingSendBufferCaptures;
+};
+
+typedef QSharedPointer<SendBufferCaptureJob> SendBufferCaptureJobPtr;
+
+} //Render
+
+} //Qt3DRender
+
+QT_END_NAMESPACE
+
+
+#endif // QT3DRENDER_SENDBUFFERCAPTUREJOB_P_H
diff --git a/src/render/jobs/updatelevelofdetailjob.cpp b/src/render/jobs/updatelevelofdetailjob.cpp
index 940d26850..24891f9b8 100644
--- a/src/render/jobs/updatelevelofdetailjob.cpp
+++ b/src/render/jobs/updatelevelofdetailjob.cpp
@@ -135,10 +135,10 @@ void UpdateLevelOfDetailJob::updateEntityLod(Entity *entity)
if (lod->isEnabled() && !lod->thresholds().isEmpty()) {
switch (lod->thresholdType()) {
- case QLevelOfDetail::DistanceToCamera:
+ case QLevelOfDetail::DistanceToCameraThreshold:
updateEntityLodByDistance(entity, lod);
break;
- case QLevelOfDetail::ProjectedScreenPixelSize:
+ case QLevelOfDetail::ProjectedScreenPixelSizeThreshold:
updateEntityLodByScreenArea(entity, lod);
break;
default:
@@ -162,7 +162,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByDistance(Entity *entity, LevelOfDe
const QVector<qreal> thresholds = lod->thresholds();
QVector3D center = lod->center();
- if (lod->radius() > 0.f || entity->worldBoundingVolume() == nullptr) {
+ if (lod->hasBoundingVolumeOverride() || entity->worldBoundingVolume() == nullptr) {
center = *entity->worldTransform() * center;
} else {
center = entity->worldBoundingVolume()->center();
@@ -198,7 +198,7 @@ void UpdateLevelOfDetailJob::updateEntityLodByScreenArea(Entity *entity, LevelOf
const QVector<qreal> thresholds = lod->thresholds();
Sphere bv(lod->center(), lod->radius());
- if (lod->radius() <= 0.f && entity->worldBoundingVolume() != nullptr) {
+ if (!lod->hasBoundingVolumeOverride() && entity->worldBoundingVolume() != nullptr) {
bv = *(entity->worldBoundingVolume());
} else {
bv.transform(*entity->worldTransform());
diff --git a/src/render/framegraph/qsortcriterion.cpp b/src/render/lights/environmentlight.cpp
index f5252b1f7..d4245fb6e 100644
--- a/src/render/framegraph/qsortcriterion.cpp
+++ b/src/render/lights/environmentlight.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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.
@@ -37,46 +37,30 @@
**
****************************************************************************/
-#include "qsortcriterion.h"
-#include "qsortcriterion_p.h"
-#include <Qt3DCore/qnodepropertychange.h>
+#include "environmentlight_p.h"
+#include "qenvironmentlight.h"
+#include "qenvironmentlight_p.h"
QT_BEGIN_NAMESPACE
-namespace Qt3DRender {
-
-QSortCriterionPrivate::QSortCriterionPrivate()
- : QNodePrivate()
- , m_sort(QSortCriterion::StateChangeCost)
-{
-}
-
-QSortCriterion::QSortCriterion(QNode *parent)
- : QNode(*new QSortCriterionPrivate, parent)
-{
-}
+using namespace Qt3DCore;
-QSortCriterion::SortType QSortCriterion::sort() const
-{
- Q_D(const QSortCriterion);
- return d->m_sort;
-}
+namespace Qt3DRender {
+namespace Render {
-void QSortCriterion::setSort(QSortCriterion::SortType sort)
+QNodeId EnvironmentLight::shaderData() const
{
- Q_D(QSortCriterion);
- if (d->m_sort != sort) {
- d->m_sort = sort;
- emit sortChanged(sort);
- }
+ return m_shaderDataId;
}
-/*! \internal */
-QSortCriterion::QSortCriterion(QSortCriterionPrivate &dd, QNode *parent)
- : QNode(dd, parent)
+void EnvironmentLight::initializeFromPeer(const QNodeCreatedChangeBasePtr &change)
{
+ const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QEnvironmentLightData>>(change);
+ const auto &data = typedChange->data;
+ m_shaderDataId = data.shaderDataId;
}
+} // namespace Render
} // namespace Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/framegraph/qsortcriterion.h b/src/render/lights/environmentlight_p.h
index 230f111f9..2ebe72b12 100644
--- a/src/render/framegraph/qsortcriterion.h
+++ b/src/render/lights/environmentlight_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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.
@@ -37,49 +37,45 @@
**
****************************************************************************/
-#ifndef QT3DRENDER_QSORTCRITERION_H
-#define QT3DRENDER_QSORTCRITERION_H
+#ifndef QT3DRENDER_RENDER_ENVIRONMENTLIGHT_P_H
+#define QT3DRENDER_RENDER_ENVIRONMENTLIGHT_P_H
-#include <Qt3DCore/qnode.h>
-#include <Qt3DRender/qt3drender_global.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>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QSortCriterionPrivate;
+namespace Render {
-class QT3DRENDERSHARED_EXPORT QSortCriterion : public Qt3DCore::QNode
+class Q_AUTOTEST_EXPORT EnvironmentLight : public BackendNode
{
- Q_OBJECT
- Q_PROPERTY(Qt3DRender::QSortCriterion::SortType sort READ sort WRITE setSort NOTIFY sortChanged)
public:
- explicit QSortCriterion(Qt3DCore::QNode *parent = Q_NULLPTR);
-
- enum SortType {
- StateChangeCost = (1 << 0),
- BackToFront = (1 << 1),
- Material = (1 << 2)
- };
- Q_ENUM(SortType) // LCOV_EXCL_LINE
-
- SortType sort() const;
-
-public Q_SLOTS:
- void setSort(SortType sort);
-
-Q_SIGNALS:
- void sortChanged(SortType sort);
-
-protected:
- QSortCriterion(QSortCriterionPrivate &dd, Qt3DCore::QNode *parent = Q_NULLPTR);
+ Qt3DCore::QNodeId shaderData() const;
private:
- Q_DECLARE_PRIVATE(QSortCriterion)
+ void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
+
+ Qt3DCore::QNodeId m_shaderDataId;
};
+} // namespace Render
+
} // namespace Qt3DRender
QT_END_NAMESPACE
-#endif // QSORTCRITERION_H
+Q_DECLARE_METATYPE(Qt3DRender::Render::EnvironmentLight*) // LCOV_EXCL_LINE
+
+#endif // QT3DRENDER_RENDER_ENVIRONMENTLIGHT_P_H
diff --git a/src/render/lights/lights.pri b/src/render/lights/lights.pri
index 408253d74..dbaa4352f 100644
--- a/src/render/lights/lights.pri
+++ b/src/render/lights/lights.pri
@@ -5,17 +5,22 @@ HEADERS += \
$$PWD/qabstractlight_p.h \
$$PWD/qdirectionallight.h \
$$PWD/qdirectionallight_p.h \
+ $$PWD/qenvironmentlight.h \
+ $$PWD/qenvironmentlight_p.h \
$$PWD/qpointlight.h \
$$PWD/qpointlight_p.h \
$$PWD/qspotlight.h \
$$PWD/qspotlight_p.h \
+ $$PWD/environmentlight_p.h \
$$PWD/light_p.h \
$$PWD/lightsource_p.h
SOURCES += \
$$PWD/qabstractlight.cpp \
$$PWD/qdirectionallight.cpp \
+ $$PWD/qenvironmentlight.cpp \
$$PWD/qpointlight.cpp \
$$PWD/qspotlight.cpp \
+ $$PWD/environmentlight.cpp \
$$PWD/light.cpp \
$$PWD/lightsource.cpp
diff --git a/src/render/lights/qenvironmentlight.cpp b/src/render/lights/qenvironmentlight.cpp
new file mode 100644
index 000000000..a094af7b2
--- /dev/null
+++ b/src/render/lights/qenvironmentlight.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** 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 "qenvironmentlight.h"
+#include "qenvironmentlight_p.h"
+#include "qabstracttexture.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender
+{
+
+/*!
+ * \qmltype EnvironmentLight
+ * \inqmlmodule Qt3D.Render
+ * \instantiates Qt3DRender::QEnvironmentLight
+ * \brief Encapsulate an environment light object in a Qt 3D scene.
+ * \since 5.9
+ */
+
+QEnvironmentLightPrivate::QEnvironmentLightPrivate()
+ : m_shaderData(new QShaderData)
+ , m_irradiance(nullptr)
+ , m_specular(nullptr)
+{
+}
+
+QEnvironmentLightPrivate::~QEnvironmentLightPrivate()
+{
+}
+
+Qt3DCore::QNodeCreatedChangeBasePtr QEnvironmentLight::createNodeCreationChange() const
+{
+ auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QEnvironmentLightData>::create(this);
+ auto &data = creationChange->data;
+ Q_D(const QEnvironmentLight);
+ data.shaderDataId = qIdForNode(d->m_shaderData);
+ return creationChange;
+}
+
+/*!
+ \class Qt3DRender::QEnvironmentLight
+ \inmodule Qt3DRender
+ \brief Encapsulate an environment light object in a Qt 3D scene.
+ \since 5.9
+*/
+
+QEnvironmentLight::QEnvironmentLight(Qt3DCore::QNode *parent)
+ : QComponent(*new QEnvironmentLightPrivate, parent)
+{
+ Q_D(QEnvironmentLight);
+ d->m_shaderData->setParent(this);
+}
+
+/*! \internal */
+QEnvironmentLight::QEnvironmentLight(QEnvironmentLightPrivate &dd, QNode *parent)
+ : QComponent(dd, parent)
+{
+ Q_D(QEnvironmentLight);
+ d->m_shaderData->setParent(this);
+}
+
+QEnvironmentLight::~QEnvironmentLight()
+{
+}
+
+/*!
+ \qmlproperty Texture EnvironmentLight::irradiance
+
+ Holds the current environment irradiance map texture.
+
+ By default, the environment irradiance texture is null.
+*/
+
+/*!
+ \property QEnvironmentLight::irradiance
+
+ Holds the current environment irradiance map texture.
+
+ By default, the environment irradiance texture is null.
+*/
+QAbstractTexture *QEnvironmentLight::irradiance() const
+{
+ Q_D(const QEnvironmentLight);
+ return d->m_irradiance;
+}
+
+/*!
+ \qmlproperty Texture EnvironmentLight::specular
+
+ Holds the current environment specular map texture.
+
+ By default, the environment specular texture is null.
+*/
+
+/*!
+ \property QEnvironmentLight::specular
+
+ Holds the current environment specular map texture.
+
+ By default, the environment specular texture is null.
+*/
+QAbstractTexture *QEnvironmentLight::specular() const
+{
+ Q_D(const QEnvironmentLight);
+ return d->m_specular;
+}
+
+void QEnvironmentLight::setIrradiance(QAbstractTexture *i)
+{
+ Q_D(QEnvironmentLight);
+ if (irradiance() == i)
+ return;
+
+ if (irradiance())
+ d->unregisterDestructionHelper(irradiance());
+
+ if (i && !i->parent())
+ i->setParent(this);
+
+ d->m_irradiance = i;
+ d->m_shaderData->setProperty("irradiance", QVariant::fromValue(i));
+
+ if (i)
+ d->registerDestructionHelper(i, &QEnvironmentLight::setIrradiance, i);
+
+ emit irradianceChanged(i);
+}
+
+void QEnvironmentLight::setSpecular(QAbstractTexture *s)
+{
+ Q_D(QEnvironmentLight);
+ if (specular() == s)
+ return;
+
+ if (irradiance())
+ d->unregisterDestructionHelper(specular());
+
+ if (s && !s->parent())
+ s->setParent(this);
+
+ d->m_specular = s;
+ d->m_shaderData->setProperty("specular", QVariant::fromValue(s));
+
+ if (s)
+ d->registerDestructionHelper(s, &QEnvironmentLight::setSpecular, s);
+
+ emit specularChanged(s);
+}
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/lights/qenvironmentlight.h b/src/render/lights/qenvironmentlight.h
new file mode 100644
index 000000000..0a5087c42
--- /dev/null
+++ b/src/render/lights/qenvironmentlight.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QENVIRONMENTLIGHT_H
+#define QT3DRENDER_QENVIRONMENTLIGHT_H
+
+#include <Qt3DRender/qt3drender_global.h>
+#include <Qt3DCore/qcomponent.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+class QEnvironmentLightPrivate;
+
+class QT3DRENDERSHARED_EXPORT QEnvironmentLight : public Qt3DCore::QComponent
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt3DRender::QAbstractTexture *irradiance READ irradiance WRITE setIrradiance NOTIFY irradianceChanged)
+ Q_PROPERTY(Qt3DRender::QAbstractTexture *specular READ specular WRITE setSpecular NOTIFY specularChanged)
+
+public:
+ explicit QEnvironmentLight(Qt3DCore::QNode *parent = nullptr);
+ ~QEnvironmentLight();
+
+ Qt3DRender::QAbstractTexture *irradiance() const;
+ Qt3DRender::QAbstractTexture *specular() const;
+
+public Q_SLOTS:
+ void setIrradiance(Qt3DRender::QAbstractTexture *irradiance);
+ void setSpecular(Qt3DRender::QAbstractTexture *specular);
+
+protected:
+ explicit QEnvironmentLight(QEnvironmentLightPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+
+Q_SIGNALS:
+ void irradianceChanged(Qt3DRender::QAbstractTexture *environmentIrradiance);
+ void specularChanged(Qt3DRender::QAbstractTexture *environmentSpecular);
+
+private:
+ Q_DECLARE_PRIVATE(QEnvironmentLight)
+ Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
+};
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QENVIRONMENTLIGHT_H
diff --git a/src/render/lights/qenvironmentlight_p.h b/src/render/lights/qenvironmentlight_p.h
new file mode 100644
index 000000000..e98da5f59
--- /dev/null
+++ b/src/render/lights/qenvironmentlight_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QENVIRONMENTLIGHT_P_H
+#define QT3DRENDER_QENVIRONMENTLIGHT_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/qcomponent_p.h>
+#include <qshaderdata.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QAbstractTexture;
+class QEnvironmentLight;
+
+class Q_AUTOTEST_EXPORT QEnvironmentLightPrivate : public Qt3DCore::QComponentPrivate
+{
+public:
+ explicit QEnvironmentLightPrivate();
+ ~QEnvironmentLightPrivate();
+
+ Q_DECLARE_PUBLIC(QEnvironmentLight)
+ QShaderData *m_shaderData;
+ QAbstractTexture *m_irradiance;
+ QAbstractTexture *m_specular;
+};
+
+struct QEnvironmentLightData
+{
+ Qt3DCore::QNodeId shaderDataId;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QENVIRONMENTLIGHT_P_H
diff --git a/src/render/materialsystem/qeffect.cpp b/src/render/materialsystem/qeffect.cpp
index 7778b5621..b611657c4 100644
--- a/src/render/materialsystem/qeffect.cpp
+++ b/src/render/materialsystem/qeffect.cpp
@@ -67,6 +67,35 @@ QEffectPrivate::QEffectPrivate()
The QEffect class combines a set of techniques and parameters used by those techniques to
produce a rendering effect for a material.
+ An QEffect instance should be shared among several QMaterial instances when possible.
+
+ \code
+ QEffect *effect = new QEffect();
+
+ // Create technique, render pass and shader
+ QTechnique *gl3Technique = new QTechnique();
+ QRenderPass *gl3Pass = new QRenderPass();
+ QShaderProgram *glShader = new QShaderProgram();
+
+ // Set the shader on the render pass
+ gl3Pass->setShaderProgram(glShader);
+
+ // Add the pass to the technique
+ gl3Technique->addRenderPass(gl3Pass);
+
+ // Set the targeted GL version for the technique
+ gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ // Add the technique to the effect
+ effect->addTechnique(gl3Technique);
+ \endcode
+
+ A QParameter defined on an Effect is overridden by a QParameter (of the same
+ name) defined in a QMaterial, QTechniqueFilter, QRenderPassFilter.
+
\sa QMaterial, QTechnique, QParameter
*/
@@ -81,6 +110,37 @@ QEffectPrivate::QEffectPrivate()
The Effect type combines a set of techniques and parameters used by those techniques to
produce a rendering effect for a material.
+ An Effect instance should be shared among several Material instances when possible.
+
+ A Parameter defined on an Effect is overridden by a QParameter (of the same
+ name) defined in a Material, TechniqueFilter, RenderPassFilter.
+
+ \code
+ Effect {
+ id: effect
+
+ technique: [
+ Technique {
+ id: gl3Technique
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 1
+ }
+ renderPasses: [
+ RenderPass {
+ id: gl3Pass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ }
+ ]
+ }
+ ]
+ }
+ \endcode
+
\sa Material, Technique, Parameter
*/
diff --git a/src/render/materialsystem/qmaterial.cpp b/src/render/materialsystem/qmaterial.cpp
index ca0f86463..c6913441e 100644
--- a/src/render/materialsystem/qmaterial.cpp
+++ b/src/render/materialsystem/qmaterial.cpp
@@ -60,7 +60,58 @@
sound should reflect off an element, the temperature of a surface,
and so on.
- \sa Effect
+ In itself, a Material doesn't do anything. It's only when it references an
+ Effect node that a Material becomes useful.
+
+ In practice, it often happens that a single Effect is being referenced by
+ several Material components. This allows to only create the effect,
+ techniques, passes and shaders once while allowing to specify the material
+ by adding Parameter instances.
+
+ A Parameter defined on a Material is overridden by a Parameter (of the same
+ name) defined in a TechniqueFilter or a RenderPassFilter.
+
+ \code
+ Effect {
+ id: effect
+
+ technique: [
+ Technique {
+ id: gl3Technique
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 1
+ }
+ renderPasses: [
+ RenderPass {
+ id: gl3Pass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ }
+ ]
+ }
+ ]
+ }
+
+ Material {
+ id: material1
+ parameters: [
+ Parameter { name: "color"; value: "green" }
+ ]
+ }
+
+ Material {
+ id: material2
+ parameters: [
+ Parameter { name: "color"; value: "white" }
+ ]
+ }
+ \endcode
+
+ \sa Effect, Technique, Parameter
*/
/*!
@@ -77,7 +128,54 @@
sound should reflect off an element, the temperature of a surface,
and so on.
- \sa QEffect
+ In itself, a QMaterial doesn't do anything. It's only when it references a
+ QEffect node that a QMaterial becomes useful.
+
+ In practice, it often happens that a single QEffect is being referenced by
+ several QMaterial components. This allows to only create the effect,
+ techniques, passes and shaders once while allowing to specify the material
+ by adding QParameter instances.
+
+ A QParameter defined on a QMaterial is overridden by a QParameter (of the same
+ name) defined in a QTechniqueFilter or a QRenderPassFilter.
+
+ \code
+ QMaterial *material1 = new QMaterial();
+ QMaterial *material2 = new QMaterial();
+
+ // Create effect, technique, render pass and shader
+ QEffect *effect = new QEffect();
+ QTechnique *gl3Technique = new QTechnique();
+ QRenderPass *gl3Pass = new QRenderPass();
+ QShaderProgram *glShader = new QShaderProgram();
+
+ // Set the shader on the render pass
+ gl3Pass->setShaderProgram(glShader);
+
+ // Add the pass to the technique
+ gl3Technique->addRenderPass(gl3Pass);
+
+ // Set the targeted GL version for the technique
+ gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ // Add the technique to the effect
+ effect->addTechnique(gl3Technique);
+
+ // Set the effect on the materials
+ material1->setEffect(effect);
+ material2->setEffect(effect);
+
+ // Set different parameters on the materials
+ const QString parameterName = QStringLiteral("color");
+ material1->addParameter(new QParameter(parameterName, QColor::fromRgbF(0.0f, 1.0f, 0.0f, 1.0f);
+ material2->addParameter(new QParameter(parameterName, QColor::fromRgbF(1.0f, 1.0f, 1.0f, 1.0f);
+
+ \endcode
+
+ \sa QEffect, QTechnique, QParameter
*/
QT_BEGIN_NAMESPACE
diff --git a/src/render/materialsystem/qparameter.cpp b/src/render/materialsystem/qparameter.cpp
index 8f83fd02e..2ca7d176b 100644
--- a/src/render/materialsystem/qparameter.cpp
+++ b/src/render/materialsystem/qparameter.cpp
@@ -45,18 +45,127 @@
/*!
- * \qmltype Parameter
- * \instantiates Qt3DRender::QParameter
- * \inqmlmodule Qt3D.Render
- * \brief Provides storage for a name and value pair.
+ \qmltype Parameter
+ \instantiates Qt3DRender::QParameter
+ \inqmlmodule Qt3D.Render
+ \brief Provides storage for a name and value pair. This maps to a shader uniform.
+
+ A Parameter can be referenced by a RenderPass, Technique, Effect, Material,
+ TechniqueFilter, RenderPassFilter. At runtime, depending on which shader is
+ selected for a given step of the rendering, the value contained in a
+ Parameter will be converted and uploaded if the shader contains a uniform
+ with a name matching that of the Parameter.
+
+ \code
+ Parameter {
+ name: "diffuseColor"
+ value: "blue"
+ }
+
+ // Works with the following GLSL uniform shader declarations
+ // uniform vec4 diffuseColor;
+ // uniform vec3 diffuseColor;
+ // uniform vec2 diffuseColor;
+ // uniform float diffuseColor;
+ \endcode
+
+ \note some care must be taken to ensure the value wrapped by a Parameter
+ can actually be converted to what the real uniform expect. Giving a value
+ stored as an int where the actual shader uniform is of type float could
+ result in undefined behaviors.
+
+ \note when the targeted uniform is an array, the name should be the name
+ of the uniform with [0] appended to it.
+
+ \code
+ Parameter {
+ name: "diffuseValues[0]"
+ value: [0.0, 1.0. 2.0, 3.0, 4.0, 883.0, 1340.0, 1584.0]
+ }
+
+ // Matching GLSL shader uniform declaration
+ // uniform float diffuseValues[8];
+ \endcode
+
+ When it comes to texture support, the Parameter value should be set to the
+ appropriate Texture subclass that matches the sampler type of the shader
+ uniform.
+
+ \code
+ Parameter {
+ name: "diffuseTexture"
+ value: Texture2D { ... }
+ }
+
+ // Works with the following GLSL uniform shader declaration
+ // uniform sampler2D diffuseTexture
+ \endcode
+
+ \sa Texture
*/
/*!
- * \class Qt3DRender::QParameter
- * \inheaderfile Qt3DRender/QParameter
- * \inmodule Qt3DRender
- *
- * \brief Provides storage for a name and value pair.
+ \class Qt3DRender::QParameter
+ \inheaderfile Qt3DRender/QParameter
+ \inmodule Qt3DRender
+ \brief Provides storage for a name and value pair. This maps to a shader uniform.
+
+ A QParameter can be referenced by a QRenderPass, QTechnique, QEffect, QMaterial,
+ QTechniqueFilter, QRenderPassFilter. At runtime, depending on which shader is
+ selected for a given step of the rendering, the value contained in a
+ QParameter will be converted and uploaded if the shader contains a uniform
+ with a name matching that of the QParameter.
+
+ \code
+ QParameter *param = new QParameter();
+ param->setName(QStringLiteral("diffuseColor"));
+ param->setValue(QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Alternatively you can create and set a QParameter this way
+ QParameter *param2 = new QParameter(QStringLiteral("diffuseColor"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Such QParameters will work with the following GLSL uniform shader declarations
+ // uniform vec4 diffuseColor;
+ // uniform vec3 diffuseColor;
+ // uniform vec2 diffuseColor;
+ // uniform float diffuseColor;
+ \endcode
+
+ \note some care must be taken to ensure the value wrapped by a QParameter
+ can actually be converted to what the real uniform expect. Giving a value
+ stored as an int where the actual shader uniform is of type float could
+ result in undefined behaviors.
+
+ \note when the targeted uniform is an array, the name should be the name
+ of the uniform with [0] appended to it.
+
+ \code
+ QParameter *param = new QParameter();
+ QVariantList values = QVariantList() << 0.0f << 1.0f << 2.0f << 3.0f << 4.0f << 883.0f << 1340.0f << 1584.0f;
+
+ param->setName(QStringLiteral("diffuseValues[0]"));
+ param->setValue(values);
+
+ // Matching GLSL shader uniform declaration
+ // uniform float diffuseValues[8];
+ \endcode
+
+ When it comes to texture support, the QParameter value should be set to the
+ appropriate QAbstractTexture subclass that matches the sampler type of the shader
+ uniform.
+
+ \code
+ QTexture2D *texture = new QTexture2D();
+ ...
+ QParameter *param = new QParameter();
+ param->setName(QStringLiteral("diffuseTexture"));
+ param->setValue(QVariant::fromValue(texture));
+
+ // Works with the following GLSL uniform shader declaration
+ // uniform sampler2D diffuseTexture
+ \endcode
+
+ \sa QAbstractTexture
*/
QT_BEGIN_NAMESPACE
diff --git a/src/render/materialsystem/qrenderpass.cpp b/src/render/materialsystem/qrenderpass.cpp
index dd6363816..61f844be3 100644
--- a/src/render/materialsystem/qrenderpass.cpp
+++ b/src/render/materialsystem/qrenderpass.cpp
@@ -72,9 +72,40 @@ QRenderPassPrivate::QRenderPassPrivate()
a list of FilterKey objects, a list of RenderState objects and a list
of \l Parameter objects.
- RenderPass executes the ShaderProgram using the given render states and parameters
- when its filter keys match the filter keys in RenderPassFilter or when no filter
- keys are specified and no RenderPassFilter is present in the FrameGraph.
+ RenderPass executes the ShaderProgram using the given RenderState and
+ Parameter nodes when at least one of FilterKey nodes being referenced
+ matches any of the FilterKey nodes in RenderPassFilter or when no FilterKey
+ nodes are specified and no RenderPassFilter is present in the FrameGraph.
+
+ If the RenderPass defines a Parameter, it will be overridden by a Parameter
+ with the same name if it exists in any of the Technique, Effect, Material,
+ TechniqueFilter, RenderPassFilter associated with the pass at runtime. This
+ still can be useful to define sane default values.
+
+ At render time, for each leaf node of the FrameGraph a base render state is
+ recorded by accumulating states defined by all RenderStateSet nodes in the
+ FrameGraph branch. Each RenderPass can overload this base render state by
+ specifying its own RenderState nodes.
+
+ \code
+ RenderPass {
+ id: pass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ parameters: [
+ Parameters { name: "color"; value: "red" }
+ ]
+ filterKeys: [
+ FilterKey { name: "name"; value: "zFillPass" }
+ ]
+ renderStates: [
+ DepthTest { }
+ ]
+ }
+ \endcode
+
+ \sa RenderPassFilter, FilterKey, Parameter, RenderState, Effect, Technique
*/
/*!
@@ -88,10 +119,54 @@ QRenderPassPrivate::QRenderPassPrivate()
of a Qt3DRender::QShaderProgram and a list of Qt3DRender::QFilterKey objects,
a list of Qt3DRender::QRenderState objects and a list of Qt3DRender::QParameter objects.
- QRenderPass executes the QShaderProgram using the given render states and parameters
- when its filter keys match the filter keys in Qt3DRender::QRenderPassFilter or
- when no filter keys are specified and no QRenderPassFilter is present
- in the FrameGraph.
+ QRenderPass executes the QShaderProgram using the given QRenderState and
+ QParameter nodes when at least one of QFilterKey nodes being referenced
+ matches any of the QFilterKey nodes in QRenderPassFilter or when no
+ QFilterKey nodes are specified and no QRenderPassFilter is present in the
+ FrameGraph.
+
+ If the QRenderPass defines a QParameter, it will be overridden by a
+ QParameter with the same name if it exists in any of the QTechnique,
+ QEffect, QMaterial, QTechniqueFilter, QRenderPassFilter associated with the
+ pass at runtime. This still can be useful to define sane default values.
+
+ At render time, for each leaf node of the FrameGraph a base render state is
+ recorded by accumulating states defined by all QRenderStateSet nodes in the
+ FrameGraph branch. Each QRenderPass can overload this base render state by
+ specifying its own QRenderState nodes.
+
+ \code
+ // Create the render passes
+ QRenderPass *pass = new QRenderPass();
+
+ // Create shader program
+ QShaderProgram *glShader = new QShaderProgram();
+
+ // Set the shader on the render pass
+ pass->setShaderProgram(glShader);
+
+ // Create a FilterKey
+ QFilterKey *filterKey = new QFilterKey();
+ filterKey->setName(QStringLiteral("name"));
+ fitlerKey->setValue(QStringLiteral("zFillPass"));
+
+ // Add the FilterKey to the pass
+ pass->addFilterKey(filterKey);
+
+ // Create a QParameter
+ QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Add parameter to pass
+ pass->addParameter(colorParameter);
+
+ // Create a QRenderState
+ QDepthTest *depthTest = new QDepthTest();
+
+ // Add the render state to the pass
+ pass->addRenderState(depthTest);
+ \endcode
+
+ \sa QRenderPassFilter, QFilterKey, QParameter, QRenderState, QEffect, QTechnique
*/
/*!
\typedef ParameterList
@@ -236,7 +311,7 @@ QVector<QFilterKey *> QRenderPass::filterKeys() const
/*!
Adds a render \a state to the rendering pass. That implies that
when the pass is executed at render time, the globally set render state will
- be modifed by the states defined locally by the Qt3DRender::QRenderPass.
+ be modified by the states defined locally by the Qt3DRender::QRenderPass.
\note not defining any Qt3DRender::QRenderState in a pass will result in the pass using
the globally set render state for a given FrameGraph branch execution path.
diff --git a/src/render/materialsystem/qshaderdata_p.h b/src/render/materialsystem/qshaderdata_p.h
index bfa139890..17faee9ed 100644
--- a/src/render/materialsystem/qshaderdata_p.h
+++ b/src/render/materialsystem/qshaderdata_p.h
@@ -62,7 +62,6 @@ namespace Qt3DRender {
namespace {
const int qVectorShaderDataTypeId = qMetaTypeId<QVector<QShaderData*> >();
-const int qShaderDataTypeId = qMetaTypeId<QShaderData*>();
}
@@ -70,10 +69,10 @@ class QShaderDataPropertyReader: public PropertyReaderInterface
{
QVariant readProperty(const QVariant &v) Q_DECL_OVERRIDE
{
- QShaderData *shaderData = nullptr;
+ const auto node = v.value<Qt3DCore::QNode *>();
- if (v.userType() == qShaderDataTypeId && (shaderData = v.value<QShaderData *>()) != nullptr) {
- return QVariant::fromValue(shaderData->id());
+ if (node) {
+ return QVariant::fromValue(node->id());
} else if (v.userType() == qVectorShaderDataTypeId) {
QVariantList vlist;
const auto data_ = v.value<QVector<QShaderData *> >();
diff --git a/src/render/materialsystem/qshaderprogram.cpp b/src/render/materialsystem/qshaderprogram.cpp
index 522f021aa..2a65d257c 100644
--- a/src/render/materialsystem/qshaderprogram.cpp
+++ b/src/render/materialsystem/qshaderprogram.cpp
@@ -80,15 +80,48 @@
\value Compute Compute shader
*/
+/*!
+ \enum QShaderProgram::ShaderStatus
+
+ This enum identifies the status of shader used.
+
+ \value NotReady The shader hasn't been compiled and linked yet
+ \value Ready The shader was successfully compiled
+ \value Error An error occurred while compiling the shader
+*/
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
QShaderProgramPrivate::QShaderProgramPrivate()
: QNodePrivate()
+ , m_status(QShaderProgram::NotReady)
{
}
+void QShaderProgramPrivate::setLog(const QString &log)
+{
+ Q_Q(QShaderProgram);
+ if (log != m_log) {
+ m_log = log;
+ const bool blocked = q->blockNotifications(true);
+ emit q->logChanged(m_log);
+ q->blockNotifications(blocked);
+ }
+}
+
+void QShaderProgramPrivate::setStatus(QShaderProgram::Status status)
+{
+ Q_Q(QShaderProgram);
+ if (status != m_status) {
+ m_status = status;
+ const bool blocked = q->blockNotifications(true);
+ emit q->statusChanged(m_status);
+ q->blockNotifications(blocked);
+ }
+}
+
QShaderProgram::QShaderProgram(QNode *parent)
: QNode(*new QShaderProgramPrivate, parent)
{
@@ -104,6 +137,18 @@ QShaderProgram::QShaderProgram(QShaderProgramPrivate &dd, QNode *parent)
{
}
+void QShaderProgram::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
+{
+ Q_D(QShaderProgram);
+ if (change->type() == Qt3DCore::PropertyUpdated) {
+ const Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
+ if (e->propertyName() == QByteArrayLiteral("log"))
+ d->setLog(e->value().toString());
+ else if (e->propertyName() == QByteArrayLiteral("status"))
+ d->setStatus(static_cast<QShaderProgram::Status>(e->value().toInt()));
+ }
+}
+
/*!
\qmlproperty string ShaderProgram::vertexShaderCode
@@ -308,6 +353,40 @@ QByteArray QShaderProgram::shaderCode(ShaderType type) const
}
}
+/*!
+ \qmlproperty string ShaderProgram::log
+
+ Holds the log of the current shader program. This is useful to diagnose a
+ compilation failure of the shader program.
+*/
+/*!
+ \property QShaderProgram::log
+
+ Holds the log of the current shader program. This is useful to diagnose a
+ compilation failure of the shader program.
+*/
+QString QShaderProgram::log() const
+{
+ Q_D(const QShaderProgram);
+ return d->m_log;
+}
+
+/*!
+ \qmlproperty string ShaderProgram::status
+
+ Holds the status of the current shader program.
+*/
+/*!
+ \property QShaderProgram::status
+
+ Holds the status of the current shader program.
+*/
+QShaderProgram::Status QShaderProgram::status() const
+{
+ Q_D(const QShaderProgram);
+ return d->m_status;
+}
+
static QByteArray deincludify(const QString &filePath)
{
QFile f(filePath);
diff --git a/src/render/materialsystem/qshaderprogram.h b/src/render/materialsystem/qshaderprogram.h
index 442a25b2e..8c3da1a4a 100644
--- a/src/render/materialsystem/qshaderprogram.h
+++ b/src/render/materialsystem/qshaderprogram.h
@@ -58,6 +58,8 @@ class QT3DRENDERSHARED_EXPORT QShaderProgram : public Qt3DCore::QNode
Q_PROPERTY(QByteArray geometryShaderCode READ geometryShaderCode WRITE setGeometryShaderCode NOTIFY geometryShaderCodeChanged)
Q_PROPERTY(QByteArray fragmentShaderCode READ fragmentShaderCode WRITE setFragmentShaderCode NOTIFY fragmentShaderCodeChanged)
Q_PROPERTY(QByteArray computeShaderCode READ computeShaderCode WRITE setComputeShaderCode NOTIFY computeShaderCodeChanged)
+ Q_PROPERTY(QString log READ log NOTIFY logChanged REVISION 9)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged REVISION 9)
public:
explicit QShaderProgram(Qt3DCore::QNode *parent = nullptr);
@@ -73,6 +75,13 @@ public:
};
Q_ENUM(ShaderType) // LCOV_EXCL_LINE
+ enum Status {
+ NotReady = 0,
+ Ready,
+ Error
+ };
+ Q_ENUM(Status) // LCOV_EXCL_LINE
+
// Source code in-line
QByteArray vertexShaderCode() const;
QByteArray tessellationControlShaderCode() const;
@@ -84,6 +93,9 @@ public:
void setShaderCode(ShaderType type, const QByteArray &shaderCode);
QByteArray shaderCode(ShaderType type) const;
+ QString log() const;
+ Status status() const;
+
Q_INVOKABLE static QByteArray loadSource(const QUrl &sourceUrl);
public Q_SLOTS:
@@ -101,9 +113,12 @@ Q_SIGNALS:
void geometryShaderCodeChanged(const QByteArray &geometryShaderCode);
void fragmentShaderCodeChanged(const QByteArray &fragmentShaderCode);
void computeShaderCodeChanged(const QByteArray &computeShaderCode);
+ void logChanged(const QString &log);
+ void statusChanged(Status status);
protected:
explicit QShaderProgram(QShaderProgramPrivate &dd, Qt3DCore::QNode *parent = nullptr);
+ void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(QShaderProgram)
diff --git a/src/render/materialsystem/qshaderprogram_p.h b/src/render/materialsystem/qshaderprogram_p.h
index 5f695a279..6bdde68f1 100644
--- a/src/render/materialsystem/qshaderprogram_p.h
+++ b/src/render/materialsystem/qshaderprogram_p.h
@@ -52,13 +52,12 @@
//
#include <private/qnode_p.h>
+#include <Qt3DRender/qshaderprogram.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QShaderProgram;
-
class QShaderProgramPrivate : public Qt3DCore::QNodePrivate
{
public:
@@ -77,6 +76,11 @@ public:
QByteArray m_geometryShaderCode;
QByteArray m_fragmentShaderCode;
QByteArray m_computeShaderCode;
+ QString m_log;
+ QShaderProgram::Status m_status;
+
+ void setLog(const QString &log);
+ void setStatus(QShaderProgram::Status status);
};
struct QShaderProgramData
diff --git a/src/render/materialsystem/qtechnique.cpp b/src/render/materialsystem/qtechnique.cpp
index 74505bfbd..df142cdee 100644
--- a/src/render/materialsystem/qtechnique.cpp
+++ b/src/render/materialsystem/qtechnique.cpp
@@ -68,14 +68,61 @@ QTechniquePrivate::~QTechniquePrivate()
\since 5.7
\brief Encapsulates a Technique.
- A Technique specifies a set of RenderPass objects, FilterKey objects, Parameter objects
- and a GraphicsApiFilter, which together define a rendering technique the given
- graphics API can render. The filter keys are used by TechniqueFilter
- to select specific techinques at specific parts of the FrameGraph.
- If the same parameter is specified both in Technique and RenderPass, the one
- in Technique overrides the one used in the RenderPass.
-
- \sa Qt3D.Render::Effect
+ A Technique specifies a set of RenderPass objects, FilterKey objects,
+ Parameter objects and a GraphicsApiFilter, which together define a
+ rendering technique the given graphics API can render. The filter keys are
+ used by TechniqueFilter to select specific techniques at specific parts of
+ the FrameGraph. If two Parameter instances with the same name are specified
+ in a Technique and a RenderPass, the one in Technique overrides the one
+ used in the RenderPass.
+
+ When creating an Effect that targets several versions of a graphics API, it
+ is useful to create several Technique nodes each with a graphicsApiFilter
+ set to match one of the targeted versions. At runtime, the Qt3D renderer
+ will select the most appropriate Technique based on which graphics API
+ versions are supported and (if specified) the FilterKey nodes that satisfy
+ a given TechniqueFilter in the FrameGraph.
+
+ \note When using OpenGL as the graphics API for rendering, Qt3D relies on
+ the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
+ to decide what is the most appropriate GL version available. If you need to
+ customize the QSurfaceFormat, do not forget to apply it with
+ QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
+ will likely have no effect on Qt3D related rendering.
+
+ \code
+ Technique {
+ id: gl3Technique
+ parameters: [
+ Parameter { name: "color"; value: "orange" }
+ ]
+ filterKeys: [
+ FilterKey { name: "name"; value: "zFillTechnique" }
+ ]
+ graphicsApiFilter {
+ api: GraphicsApiFilter.OpenGL
+ profile: GraphicsApiFilter.CoreProfile
+ majorVersion: 3
+ minorVersion: 1
+ }
+ renderPasses: [
+ RenderPass {
+ id: firstPass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ },
+ RenderPass {
+ id: secondPass
+ shaderProgram: ShaderProgram {
+ ...
+ }
+ }
+ ]
+ }
+ \endcode
+
+ \sa Effect, RenderPass, TechniqueFilter
*/
/*!
@@ -85,15 +132,62 @@ QTechniquePrivate::~QTechniquePrivate()
\since 5.7
\brief Encapsulates a Technique.
- A Qt3DRender::QTechnique specifies a set of Qt3DRender::QRenderPass objects,
- Qt3DRender::QFilterKey objects, Qt3DRender::QParameter objects and
- a Qt3DRender::QGraphicsApiFilter, which together define a rendering technique the given
- graphics API can render. The filter keys are used by Qt3DRender::QTechniqueFilter
- to select specific techinques at specific parts of the FrameGraph.
- If the same parameter is specified both in QTechnique and QRenderPass, the one
- in QTechnique overrides the one used in the QRenderPass.
-
- \sa Qt3DRender::QEffect
+ A Qt3DRender::QTechnique specifies a set of Qt3DRender::QRenderPass
+ objects, Qt3DRender::QFilterKey objects, Qt3DRender::QParameter objects and
+ a Qt3DRender::QGraphicsApiFilter, which together define a rendering
+ technique the given graphics API can render. The filter keys are used by
+ Qt3DRender::QTechniqueFilter to select specific techniques at specific
+ parts of the FrameGraph. If two QParameter instances with the same name are
+ specified in a QTechnique and a QRenderPass, the one in Technique overrides
+ the one used in the QRenderPass.
+
+ When creating an QEffect that targets several versions of a graphics API,
+ it is useful to create several QTechnique nodes each with a
+ graphicsApiFilter set to match one of the targeted GL versions. At runtime,
+ the Qt3D renderer will select the most appropriate QTechnique based on
+ which graphics API versions are supported and (if specified) the QFilterKey
+ nodes that satisfy a given QTechniqueFilter in the FrameGraph.
+
+ \note When using OpenGL as the graphics API for rendering, Qt3D relies on
+ the QSurfaceFormat returned by QSurfaceFormat::defaultFormat() at runtime
+ to decide what is the most appropriate GL version available. If you need to
+ customize the QSurfaceFormat, do not forget to apply it with
+ QSurfaceFormat::setDefaultFormat(). Setting the QSurfaceFormat on the view
+ will likely have no effect on Qt3D related rendering.
+
+ \code
+ QTechnique *gl3Technique = new QTechnique();
+
+ // Create the render passes
+ QRenderPass *firstPass = new QRenderPass();
+ QRenderPass *secondPass = new QRenderPass();
+
+ // Add the passes to the technique
+ gl3Technique->addRenderPass(firstPass);
+ gl3Technique->addRenderPass(secondPass);
+
+ // Set the targeted GL version for the technique
+ gl3Technique->graphicsApiFilter()->setApi(QGraphicsApiFilter::OpenGL);
+ gl3Technique->graphicsApiFilter()->setMajorVersion(3);
+ gl3Technique->graphicsApiFilter()->setMinorVersion(1);
+ gl3Technique->graphicsApiFilter()->setProfile(QGraphicsApiFilter::CoreProfile);
+
+ // Create a FilterKey
+ QFilterKey *filterKey = new QFilterKey();
+ filterKey->setName(QStringLiteral("name"));
+ fitlerKey->setValue(QStringLiteral("zFillPass"));
+
+ // Add the FilterKey to the Technique
+ gl3Technique->addFilterKey(filterKey);
+
+ // Create a QParameter
+ QParameter *colorParameter = new QParameter(QStringLiteral("color"), QColor::fromRgbF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ // Add parameter to technique
+ gl3Technique->addParameter(colorParameter);
+ \endcode
+
+ \sa QEffect, QRenderPass, QTechniqueFilter
*/
/*!
diff --git a/src/render/materialsystem/shader.cpp b/src/render/materialsystem/shader.cpp
index bd0af0bed..915ca1d54 100644
--- a/src/render/materialsystem/shader.cpp
+++ b/src/render/materialsystem/shader.cpp
@@ -59,10 +59,11 @@ namespace Qt3DRender {
namespace Render {
Shader::Shader()
- : BackendNode()
+ : BackendNode(ReadWrite)
, m_isLoaded(false)
, m_dna(0)
, m_graphicsContext(nullptr)
+ , m_status(QShaderProgram::NotReady)
{
m_shaderCode.resize(static_cast<int>(QShaderProgram::Compute) + 1);
}
@@ -71,8 +72,8 @@ Shader::~Shader()
{
// TO DO: ShaderProgram is leaked as of now
// Fix that taking care that they may be shared given a same dna
-
- QObject::disconnect(m_contextConnection);
+ if (m_graphicsContext)
+ QObject::disconnect(m_contextConnection);
}
void Shader::cleanup()
@@ -84,6 +85,7 @@ void Shader::cleanup()
if (m_graphicsContext)
m_graphicsContext->removeShaderProgramReference(this);
m_graphicsContext = nullptr;
+ QObject::disconnect(m_contextConnection);
}
QBackendNode::setEnabled(false);
@@ -96,6 +98,7 @@ void Shader::cleanup()
m_uniforms.clear();
m_attributes.clear();
m_uniformBlocks.clear();
+ m_status = QShaderProgram::NotReady;
}
void Shader::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
@@ -183,8 +186,10 @@ void Shader::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_shaderCode[QShaderProgram::Compute] = propertyValue.toByteArray();
m_isLoaded = false;
}
- if (!m_isLoaded)
+ if (!m_isLoaded) {
+ setStatus(QShaderProgram::NotReady);
updateDNA();
+ }
markDirty(AbstractRenderer::AllDirty);
}
@@ -253,6 +258,14 @@ ShaderStorageBlock Shader::storageBlockForBlockName(const QString &blockName)
return ShaderStorageBlock();
}
+// To be called from a worker thread
+void Shader::submitPendingNotifications()
+{
+ const QVector<Qt3DCore::QPropertyUpdatedChangePtr> notifications = std::move(m_pendingNotifications);
+ for (const Qt3DCore::QPropertyUpdatedChangePtr &notification : notifications)
+ notifyObservers(notification);
+}
+
void Shader::prepareUniforms(ShaderParameterPack &pack)
{
const PackUniformHash &values = pack.uniforms();
@@ -261,7 +274,7 @@ void Shader::prepareUniforms(ShaderParameterPack &pack)
const auto end = values.cend();
while (it != end) {
// Find if there's a uniform with the same name id
- for (const ShaderUniform &uniform : m_uniforms) {
+ for (const ShaderUniform &uniform : qAsConst(m_uniforms)) {
if (uniform.m_nameId == it.key()) {
pack.setSubmissionUniform(uniform);
break;
@@ -298,8 +311,8 @@ void Shader::updateDNA()
QMutexLocker locker(&m_mutex);
uint attachmentHash = 0;
- QHash<QString, int>::const_iterator it = m_fragOutputs.begin();
- QHash<QString, int>::const_iterator end = m_fragOutputs.end();
+ QHash<QString, int>::const_iterator it = m_fragOutputs.cbegin();
+ QHash<QString, int>::const_iterator end = m_fragOutputs.cend();
while (it != end) {
attachmentHash += ::qHash(it.value()) + ::qHash(it.key());
++it;
@@ -360,11 +373,11 @@ void Shader::initializeUniformBlocks(const QVector<ShaderUniformBlock> &uniformB
qCDebug(Shaders) << "Initializing Uniform Block {" << m_uniformBlockNames[i] << "}";
// Find all active uniforms for the shader block
- QVector<ShaderUniform>::const_iterator uniformsIt = m_uniforms.begin();
- const QVector<ShaderUniform>::const_iterator uniformsEnd = m_uniforms.end();
+ QVector<ShaderUniform>::const_iterator uniformsIt = m_uniforms.cbegin();
+ const QVector<ShaderUniform>::const_iterator uniformsEnd = m_uniforms.cend();
- QVector<QString>::const_iterator uniformNamesIt = m_uniformsNames.begin();
- const QVector<QString>::const_iterator uniformNamesEnd = m_attributesNames.end();
+ QVector<QString>::const_iterator uniformNamesIt = m_uniformsNames.cbegin();
+ const QVector<QString>::const_iterator uniformNamesEnd = m_attributesNames.cend();
QHash<QString, ShaderUniform> activeUniformsInBlock;
@@ -402,7 +415,7 @@ void Shader::initializeShaderStorageBlocks(const QVector<ShaderStorageBlock> &sh
Initializes this Shader's state relating to attributes, global block uniforms and
and named uniform blocks by copying these details from \a other.
*/
-void Shader::initialize(const Shader &other)
+void Shader::initializeFromReference(const Shader &other)
{
Q_ASSERT(m_dna == other.m_dna);
m_uniformsNamesIds = other.m_uniformsNamesIds;
@@ -420,6 +433,32 @@ void Shader::initialize(const Shader &other)
m_shaderStorageBlockNames = other.m_shaderStorageBlockNames;
m_shaderStorageBlocks = other.m_shaderStorageBlocks;
m_isLoaded = other.m_isLoaded;
+ setStatus(other.status());
+ setLog(other.log());
+}
+
+void Shader::setLog(const QString &log)
+{
+ if (log != m_log) {
+ m_log = log;
+ Qt3DCore::QPropertyUpdatedChangePtr e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
+ e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
+ e->setPropertyName("log");
+ e->setValue(QVariant::fromValue(m_log));
+ m_pendingNotifications.push_back(e);
+ }
+}
+
+void Shader::setStatus(QShaderProgram::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));
+ m_pendingNotifications.push_back(e);
+ }
}
} // namespace Render
diff --git a/src/render/materialsystem/shader_p.h b/src/render/materialsystem/shader_p.h
index ad68a3bd6..b5127f5ec 100644
--- a/src/render/materialsystem/shader_p.h
+++ b/src/render/materialsystem/shader_p.h
@@ -54,6 +54,8 @@
#include <Qt3DRender/private/backendnode_p.h>
#include <Qt3DRender/private/shaderparameterpack_p.h>
#include <Qt3DRender/private/shadervariables_p.h>
+#include <Qt3DRender/qshaderprogram.h>
+#include <Qt3DCore/qpropertyupdatedchange.h>
#include <QMutex>
#include <QVector>
@@ -63,8 +65,6 @@ class QOpenGLShaderProgram;
namespace Qt3DRender {
-class QShaderProgram;
-
namespace Render {
class ShaderManager;
@@ -118,6 +118,12 @@ public:
ShaderStorageBlock storageBlockForBlockNameId(int blockNameId);
ShaderStorageBlock storageBlockForBlockName(const QString &blockName);
+ inline QString log() const { return m_log; }
+ inline QShaderProgram::Status status() const { return m_status; }
+
+ void submitPendingNotifications();
+ inline bool hasPendingNotifications() const { return !m_pendingNotifications.empty(); }
+
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -148,6 +154,10 @@ private:
mutable QMutex m_mutex;
GraphicsContext *m_graphicsContext;
QMetaObject::Connection m_contextConnection;
+ QString m_log;
+ QShaderProgram::Status m_status;
+
+ QVector<Qt3DCore::QPropertyUpdatedChangePtr> m_pendingNotifications;
void updateDNA();
@@ -157,7 +167,9 @@ private:
void initializeUniformBlocks(const QVector<ShaderUniformBlock> &uniformBlockDescription);
void initializeShaderStorageBlocks(const QVector<ShaderStorageBlock> &shaderStorageBlockDescription);
- void initialize(const Shader &other);
+ void initializeFromReference(const Shader &other);
+ void setLog(const QString &log);
+ void setStatus(QShaderProgram::Status status);
friend class GraphicsContext;
};
diff --git a/src/render/materialsystem/shadercache.cpp b/src/render/materialsystem/shadercache.cpp
index de3842386..4ddf26799 100644
--- a/src/render/materialsystem/shadercache.cpp
+++ b/src/render/materialsystem/shadercache.cpp
@@ -151,6 +151,11 @@ QOpenGLShaderProgram *ShaderCache::getShaderProgramForDNA(ProgramDNA dna) const
return m_programHash.value(dna, nullptr);
}
+QVector<Qt3DCore::QNodeId> ShaderCache::shaderIdsForProgram(ProgramDNA dna) const
+{
+ return m_programRefs.value(dna);
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/materialsystem/shadercache_p.h b/src/render/materialsystem/shadercache_p.h
index 3cbc6bd0c..24a55876e 100644
--- a/src/render/materialsystem/shadercache_p.h
+++ b/src/render/materialsystem/shadercache_p.h
@@ -79,6 +79,7 @@ public:
// Only ever used from the OpenGL submission thread
QOpenGLShaderProgram *getShaderProgramForDNA(ProgramDNA dna) const;
+ QVector<Qt3DCore::QNodeId> shaderIdsForProgram(ProgramDNA dna) const;
private:
// Only ever used from the OpenGL submission thread
diff --git a/src/render/picking/objectpicker.cpp b/src/render/picking/objectpicker.cpp
index 453bd5dc1..13d6d505c 100644
--- a/src/render/picking/objectpicker.cpp
+++ b/src/render/picking/objectpicker.cpp
@@ -44,7 +44,6 @@
#include <Qt3DRender/private/qobjectpicker_p.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
-#include <Qt3DCore/private/qpropertyupdatedchangebase_p.h>
QT_BEGIN_NAMESPACE
@@ -93,17 +92,11 @@ void ObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
{
if (e->type() == Qt3DCore::PropertyUpdated) {
const Qt3DCore::QPropertyUpdatedChangePtr propertyChange = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(e);
- bool notifyPickJob = false;
if (propertyChange->propertyName() == QByteArrayLiteral("hoverEnabled")) {
m_hoverEnabled = propertyChange->value().toBool();
- notifyPickJob = true;
} else if (propertyChange->propertyName() == QByteArrayLiteral("dragEnabled")) {
m_dragEnabled = propertyChange->value().toBool();
- notifyPickJob = true;
- } else if (propertyChange->propertyName() == QByteArrayLiteral("enabled")) {
- notifyPickJob = true;
- // actual value change handled in BackendNode::sceneChangeEvent
}
markDirty(AbstractRenderer::AllDirty);
@@ -134,7 +127,6 @@ void ObjectPicker::onClicked(QPickEventPtr event)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("clicked");
e->setValue(QVariant::fromValue(event));
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -144,7 +136,6 @@ void ObjectPicker::onMoved(QPickEventPtr event)
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("moved");
e->setValue(QVariant::fromValue(event));
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -155,7 +146,6 @@ void ObjectPicker::onPressed(QPickEventPtr event)
e->setPropertyName("pressed");
e->setValue(QVariant::fromValue(event));
m_isPressed = true;
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -166,7 +156,6 @@ void ObjectPicker::onReleased(QPickEventPtr event)
e->setPropertyName("released");
e->setValue(QVariant::fromValue(event));
m_isPressed = false;
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -175,7 +164,6 @@ void ObjectPicker::onEntered()
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("entered");
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
@@ -184,7 +172,6 @@ void ObjectPicker::onExited()
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("exited");
- Qt3DCore::QPropertyUpdatedChangeBasePrivate::get(e.data())->m_isFinal = true;
notifyObservers(e);
}
diff --git a/src/render/picking/pickeventfilter.cpp b/src/render/picking/pickeventfilter.cpp
index a1ae52068..19d3b6b6e 100644
--- a/src/render/picking/pickeventfilter.cpp
+++ b/src/render/picking/pickeventfilter.cpp
@@ -61,11 +61,19 @@ PickEventFilter::~PickEventFilter()
Called from a worker thread in the thread pool so be sure to
mutex protect the data.
*/
-QList<QMouseEvent> PickEventFilter::pendingEvents()
+QList<QMouseEvent> PickEventFilter::pendingMouseEvents()
{
QMutexLocker locker(&m_mutex);
- QList<QMouseEvent> pendingEvents(m_pendingEvents);
- m_pendingEvents.clear();
+ QList<QMouseEvent> pendingEvents(m_pendingMouseEvents);
+ m_pendingMouseEvents.clear();
+ return pendingEvents;
+}
+
+QList<QKeyEvent> PickEventFilter::pendingKeyEvents()
+{
+ QMutexLocker locker(&m_mutex);
+ QList<QKeyEvent> pendingEvents(m_pendingKeyEvents);
+ m_pendingKeyEvents.clear();
return pendingEvents;
}
@@ -82,7 +90,12 @@ bool PickEventFilter::eventFilter(QObject *obj, QEvent *e)
case QEvent::MouseMove:
case QEvent::HoverMove: {
QMutexLocker locker(&m_mutex);
- m_pendingEvents.push_back(QMouseEvent(*static_cast<QMouseEvent *>(e)));
+ m_pendingMouseEvents.push_back(QMouseEvent(*static_cast<QMouseEvent *>(e)));
+ } break;
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease: {
+ QMutexLocker locker(&m_mutex);
+ m_pendingKeyEvents.push_back(QKeyEvent(*static_cast<QKeyEvent *>(e)));
}
default:
break;
diff --git a/src/render/picking/pickeventfilter_p.h b/src/render/picking/pickeventfilter_p.h
index df94a3085..fc4b00ddc 100644
--- a/src/render/picking/pickeventfilter_p.h
+++ b/src/render/picking/pickeventfilter_p.h
@@ -53,6 +53,7 @@
#include <QObject>
#include <QMouseEvent>
+#include <QKeyEvent>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
@@ -68,13 +69,15 @@ public:
explicit PickEventFilter(QObject *parent = nullptr);
~PickEventFilter();
- QList<QMouseEvent> pendingEvents();
+ QList<QMouseEvent> pendingMouseEvents();
+ QList<QKeyEvent> pendingKeyEvents();
protected:
bool eventFilter(QObject *obj, QEvent *e) Q_DECL_FINAL;
private:
- QList<QMouseEvent> m_pendingEvents;
+ QList<QMouseEvent> m_pendingMouseEvents;
+ QList<QKeyEvent> m_pendingKeyEvents;
QMutex m_mutex;
};
diff --git a/src/render/picking/qobjectpicker.cpp b/src/render/picking/qobjectpicker.cpp
index 1842b7fee..49f608a67 100644
--- a/src/render/picking/qobjectpicker.cpp
+++ b/src/render/picking/qobjectpicker.cpp
@@ -55,14 +55,25 @@ namespace Qt3DRender {
\brief The QObjectPicker class instantiates a component that can
be used to interact with a QEntity by a process known as picking.
+ For every combination of viewport and camera, picking casts a ray through the scene to
+ find entities who's bounding volume intersects the ray. The bounding volume is computed using
+ the values in the attribute buffer specified by the boundingVolumePositionAttribute of the
+ geometry.
+
The signals pressed(), released(), clicked(), moved(), entered(), and exited() are
emitted when the bounding volume defined by the pickAttribute property intersects
with a ray.
+ Most signals carry a QPickEvent instance. If QPickingSettings::pickMode() is set to
+ QPickingSettings::TrianglePicking, the actual type of the pick parameter will be
+ QPickTriangleEvent.
+
Pick queries are performed on mouse press and mouse release.
If drag is enabled, queries also happen on each mouse move while any button is pressed.
If hover is enabled, queries happen on every mouse move even if no button is pressed.
- \sa QPickingSettings
+
+ \sa Qt3DRender::QPickingSettings, Qt3DRender::QGeometry, Qt3DRender::QAttribute,
+ Qt3DRender::QPickEvent, Qt3DRender::QPickTriangleEvent
\note Instances of this component shouldn't be shared, not respecting that
condition will most likely result in undefined behavior.
@@ -76,28 +87,51 @@ namespace Qt3DRender {
* \inqmlmodule Qt3D.Render
* \brief The ObjectPicker class instantiates a component that can
be used to interact with an Entity by a process known as picking.
+
+ For every combination of viewport and camera, picking casts a ray through the scene to
+ find entities who's bounding volume intersects the ray. The bounding volume is computed using
+ the values in the attribute buffer specified by the boundingVolumePositionAttribute of the
+ geometry.
+
+ The signals pressed(), released(), clicked(), moved(), entered(), and exited() are
+ emitted when the bounding volume defined by the pickAttribute property intersects
+ with a ray.
+
+ Most signals carry a PickEvent instance. If PickingSettings.pickMode is set to
+ PickingSettings.TrianglePicking, the actual type of the pick parameter will be
+ PickTriangleEvent.
+
+ Pick queries are performed on mouse press and mouse release.
+ If drag is enabled, queries also happen on each mouse move while any button is pressed.
+ If hover is enabled, queries happen on every mouse move even if no button is pressed.
+
+ \sa PickingSettings, Geometry, Attribute, PickEvent, PickTriangleEvent
+
+ \note Instances of this component shouldn't be shared, not respecting that
+ condition will most likely result in undefined behavior.
+
*/
/*!
- \qmlsignal Qt3D.Render::ObjectPicker::pressed()
+ \qmlsignal Qt3D.Render::ObjectPicker::pressed(PickEvent pick)
This signal is emitted when the bounding volume defined by the pickAttribute property intersects
with a ray on a mouse press.
*/
/*!
- \qmlsignal Qt3D.Render::ObjectPicker::released()
+ \qmlsignal Qt3D.Render::ObjectPicker::released(PickEvent pick)
This signal is emitted when the bounding volume defined by the pickAttribute property intersects
with a ray on a mouse release.
*/
/*!
- \qmlsignal Qt3D.Render::ObjectPicker::clicked()
+ \qmlsignal Qt3D.Render::ObjectPicker::clicked(PickEvent pick)
This signal is emitted when the bounding volume defined by the pickAttribute property intersects
with a ray on a mouse click.
*/
/*!
- \qmlsignal Qt3D.Render::ObjectPicker::moved()
+ \qmlsignal Qt3D.Render::ObjectPicker::moved(PickEvent pick)
This signal is emitted when the bounding volume defined by the pickAttribute property intersects
with a ray on a mouse move with a button pressed.
*/
diff --git a/src/render/picking/qpickevent.cpp b/src/render/picking/qpickevent.cpp
index c7abf639c..148850baf 100644
--- a/src/render/picking/qpickevent.cpp
+++ b/src/render/picking/qpickevent.cpp
@@ -50,6 +50,10 @@ namespace Qt3DRender {
\inmodule Qt3DRender
\brief The QPickEvent class holds information when an object is picked
+
+ This is received as a parameter in most of the QObjectPicker component signals when picking
+ succeeds.
+
\sa QPickingSettings, QPickTriangleEvent, QObjectPicker
\since 5.7
@@ -61,9 +65,10 @@ namespace Qt3DRender {
* \inqmlmodule Qt3D.Render
* \sa ObjectPicker PickingSettings
* \brief PickEvent holds information when an object is picked.
+ * This is received as a parameter in most of the QObjectPicker component signals when picking
+ * succeeds.
*/
-
/*!
\fn Qt3DRender::QPickEvent::QPickEvent()
Constructs a new QPickEvent.
@@ -73,6 +78,11 @@ QPickEvent::QPickEvent()
{
}
+QPickEventPrivate *QPickEventPrivate::get(QPickEvent *object)
+{
+ return object->d_func();
+}
+
/*!
\fn Qt3DRender::QPickEvent::QPickEvent(const QPointF &position, const QVector3D &intersection, const QVector3D &localIntersection, float distance)
Constructs a new QPickEvent with the given parameters: \a position, \a intersection, \a localIntersection and \a distance
@@ -147,11 +157,11 @@ void QPickEvent::setAccepted(bool accepted)
/*!
\qmlproperty bool Qt3D.Render::PickEvent::position
- Specifies the position of the event
+ Specifies the mouse position with respect to the render area (window or quick item)
*/
/*!
\property Qt3DRender::QPickEvent::position
- Specifies the position of the event
+ Specifies the mouse position with respect to the render area (window or quick item)
*/
/*!
* \brief QPickEvent::position
@@ -165,11 +175,11 @@ QPointF QPickEvent::position() const
/*!
\qmlproperty bool Qt3D.Render::PickEvent::distance
- Specifies the distance of the event
+ Specifies the distance of the hit to the camera
*/
/*!
\property Qt3DRender::QPickEvent::distance
- Specifies the distance of the event
+ Specifies the distance of the hit to the camera
*/
/*!
* \brief QPickEvent::distance
@@ -183,15 +193,15 @@ float QPickEvent::distance() const
/*!
\qmlproperty bool Qt3D.Render::PickEvent::worldIntersection
- Specifies the world intersection of the event
+ Specifies the coordinates of the hit in world coordinate system
*/
/*!
\property Qt3DRender::QPickEvent::worldIntersection
- Specifies the world intersection of the event
+ Specifies the coordinates of the hit in world coordinate system
*/
/*!
* \brief QPickEvent::worldIntersection
- * \return world coordinate of the pick point
+ * \return coordinates of the hit in world coordinate system
*/
QVector3D QPickEvent::worldIntersection() const
{
@@ -201,15 +211,15 @@ QVector3D QPickEvent::worldIntersection() const
/*!
\qmlproperty bool Qt3D.Render::PickEvent::localIntersection
- Specifies the world local intersection of the event
+ Specifies the coordinates of the hit in the local coordinate system of the picked entity
*/
/*!
\property Qt3DRender::QPickEvent::localIntersection
- Specifies the local intersection of the event
+ Specifies the coordinates of the hit in the local coordinate system of the picked entity
*/
/*!
* \brief QPickEvent::localIntersection
- * \return local coordinate of pick point
+ * \return coordinates of the hit in the local coordinate system of the picked entity
*/
QVector3D QPickEvent::localIntersection() const
{
diff --git a/src/render/picking/qpickevent_p.h b/src/render/picking/qpickevent_p.h
index 399795619..ced36c9bb 100644
--- a/src/render/picking/qpickevent_p.h
+++ b/src/render/picking/qpickevent_p.h
@@ -48,13 +48,19 @@
// We mean it.
//
+#include <Qt3DCore/qnodeid.h>
+
#include <private/qobject_p.h>
+#include <private/qt3drender_global_p.h>
+
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class QPickEventPrivate : public QObjectPrivate
+class QPickEvent;
+
+class QT3DRENDERSHARED_PRIVATE_EXPORT QPickEventPrivate : public QObjectPrivate
{
public:
QPickEventPrivate()
@@ -75,6 +81,9 @@ public:
QPickEvent::Buttons m_button;
int m_buttons;
int m_modifiers;
+ Qt3DCore::QNodeId m_entity;
+
+ static QPickEventPrivate *get(QPickEvent *object);
};
} // Qt3DRender
diff --git a/src/render/picking/qpicktriangleevent.cpp b/src/render/picking/qpicktriangleevent.cpp
index ae96d5d2b..2a4cdfea2 100644
--- a/src/render/picking/qpicktriangleevent.cpp
+++ b/src/render/picking/qpicktriangleevent.cpp
@@ -61,6 +61,7 @@ public:
uint m_vertex1Index;
uint m_vertex2Index;
uint m_vertex3Index;
+ QVector3D m_uvw;
};
/*!
@@ -69,7 +70,15 @@ public:
\brief The QPickTriangleEvent class holds information when a triangle is picked
- \sa QPickEvent
+ When QPickingSettings::pickMode() is set to QPickingSettings::TrianglePicking, the signals
+ on QObjectPicker will carry an instance of QPickTriangleEvent.
+
+ This contains the details of the triangle that was picked.
+
+ \note In the case of indexed rendering, the point indices are relative to the
+ array of coordinates, not the array of indices.
+
+ \sa QPickingSettings, QPickEvent, QObjectPicker, QAttribute
\since 5.7
*/
@@ -78,7 +87,16 @@ public:
* \instantiates Qt3DRender::QPickTriangleEvent
* \inqmlmodule Qt3D.Render
* \brief PickTriangleEvent holds information when a triangle is picked.
- * \sa ObjectPicker
+ *
+ * When QPickingSettings::pickMode() is set to QPickingSettings::TrianglePicking, the signals
+ * on QObjectPicker will carry an instance of QPickTriangleEvent.
+ *
+ * This contains the details of the triangle that was picked.
+ *
+ * \note In case of indexed rendering, the point indices are relative to the
+ * array of indices, not the array of coordinates.
+ *
+ * \sa PickingSettings, PickEvent, ObjectPicker, Attribute
*/
@@ -104,7 +122,8 @@ QPickTriangleEvent::QPickTriangleEvent()
*/
// NOTE: remove in Qt6
QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance,
- uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index)
+ uint triangleIndex, uint vertex1Index, uint vertex2Index,
+ uint vertex3Index)
: QPickEvent(*new QPickTriangleEventPrivate())
{
Q_D(QPickTriangleEvent);
@@ -118,7 +137,11 @@ QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D
d->m_vertex3Index = vertex3Index;
}
-QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection, const QVector3D &localIntersection, float distance, uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, QPickEvent::Buttons button, int buttons, int modifiers)
+QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D &worldIntersection,
+ const QVector3D &localIntersection, float distance,
+ uint triangleIndex, uint vertex1Index, uint vertex2Index,
+ uint vertex3Index, QPickEvent::Buttons button, int buttons,
+ int modifiers, const QVector3D &uvw)
: QPickEvent(*new QPickTriangleEventPrivate())
{
Q_D(QPickTriangleEvent);
@@ -133,6 +156,7 @@ QPickTriangleEvent::QPickTriangleEvent(const QPointF &position, const QVector3D
d->m_button = button;
d->m_buttons = buttons;
d->m_modifiers = modifiers;
+ d->m_uvw = uvw;
}
/*! \internal */
@@ -160,11 +184,11 @@ uint QPickTriangleEvent::triangleIndex() const
/*!
\qmlproperty uint Qt3D.Render::PickTriangleEvent::vertex1Index
- Specifies the vertex 1 index of the event
+ Specifies the index of the first vertex in the triangle
*/
/*!
\property Qt3DRender::QPickTriangleEvent::vertex1Index
- Specifies the vertex 1 index of the event
+ Specifies the index of the first vertex in the triangle
*/
/*!
* \brief QPickTriangleEvent::vertex1Index
@@ -178,11 +202,11 @@ uint QPickTriangleEvent::vertex1Index() const
/*!
\qmlproperty uint Qt3D.Render::PickTriangleEvent::vertex2Index
- Specifies the vertex 2 index of the event
+ Specifies the index of the second vertex in the triangle
*/
/*!
\property Qt3DRender::QPickTriangleEvent::vertex2Index
- Specifies the vertex 2 index of the event
+ Specifies the index of the second vertex in the triangle
*/
/*!
* \brief QPickTriangleEvent::vertex2Index
@@ -196,15 +220,15 @@ uint QPickTriangleEvent::vertex2Index() const
/*!
\qmlproperty uint Qt3D.Render::PickTriangleEvent::vertex3Index
- Specifies the vertex 3 index of the event
+ Specifies the index of the third vertex in the triangle
*/
/*!
\property Qt3DRender::QPickTriangleEvent::vertex3Index
- Specifies the vertex 3 index of the event
+ Specifies the index of the third vertex in the triangle
*/
/*!
* \brief QPickTriangleEvent::vertex3Index
- * \returns index of third point of picked triangle
+ * Returns index of third point of picked triangle
*/
uint QPickTriangleEvent::vertex3Index() const
{
@@ -212,6 +236,12 @@ uint QPickTriangleEvent::vertex3Index() const
return d->m_vertex3Index;
}
+QVector3D QPickTriangleEvent::uvw() const
+{
+ Q_D(const QPickTriangleEvent);
+ return d->m_uvw;
+}
+
} // Qt3DRender
QT_END_NAMESPACE
diff --git a/src/render/picking/qpicktriangleevent.h b/src/render/picking/qpicktriangleevent.h
index 7cafa1aeb..7655a0b94 100644
--- a/src/render/picking/qpicktriangleevent.h
+++ b/src/render/picking/qpicktriangleevent.h
@@ -54,12 +54,14 @@ class QT3DRENDERSHARED_EXPORT QPickTriangleEvent : public QPickEvent
Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT)
Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT)
Q_PROPERTY(uint vertex3Index READ vertex3Index CONSTANT)
+ Q_PROPERTY(QVector3D uvw READ uvw CONSTANT)
public:
QPickTriangleEvent();
QPickTriangleEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance,
uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index);
QPickTriangleEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance,
- uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, Buttons button, int buttons, int modifiers);
+ uint triangleIndex, uint vertex1Index, uint vertex2Index, uint vertex3Index, Buttons button, int buttons, int modifiers,
+ const QVector3D &uvw);
~QPickTriangleEvent();
public:
@@ -67,6 +69,7 @@ public:
uint vertex1Index() const;
uint vertex2Index() const;
uint vertex3Index() const;
+ QVector3D uvw() const;
private:
Q_DECLARE_PRIVATE(QPickTriangleEvent)
diff --git a/src/render/raycasting/qabstractcollisionqueryservice.cpp b/src/render/raycasting/qabstractcollisionqueryservice.cpp
index 132af00c9..993ad840e 100644
--- a/src/render/raycasting/qabstractcollisionqueryservice.cpp
+++ b/src/render/raycasting/qabstractcollisionqueryservice.cpp
@@ -61,9 +61,11 @@ void QAbstractCollisionQueryService::setResultHandle(QCollisionQueryResult &resu
result.d_func()->setHandle(handle);
}
-void QAbstractCollisionQueryService::addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance)
+void QAbstractCollisionQueryService::addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity,
+ const QVector3D& intersection, float distance,
+ const QVector3D& uvw)
{
- result.d_func()->addEntityHit(entity, intersection, distance);
+ result.d_func()->addEntityHit(entity, intersection, distance, uvw);
}
} // RayCasting
diff --git a/src/render/raycasting/qabstractcollisionqueryservice_p.h b/src/render/raycasting/qabstractcollisionqueryservice_p.h
index e2f9fb65a..1c1261937 100644
--- a/src/render/raycasting/qabstractcollisionqueryservice_p.h
+++ b/src/render/raycasting/qabstractcollisionqueryservice_p.h
@@ -79,6 +79,7 @@ public:
class QT3DRENDERSHARED_EXPORT QAbstractCollisionQueryService : public Qt3DCore::QAbstractServiceProvider
{
+ Q_OBJECT
public:
enum QueryMode {
FirstHit,
@@ -96,7 +97,8 @@ protected:
QAbstractCollisionQueryService(QAbstractCollisionQueryServicePrivate &dd);
void setResultHandle(QCollisionQueryResult &result, const QQueryHandle &handle);
- void addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance);
+ void addEntityHit(QCollisionQueryResult &result, Qt3DCore::QNodeId entity, const QVector3D &intersection,
+ float distance, const QVector3D &uvw);
private:
Q_DECLARE_PRIVATE(QAbstractCollisionQueryService)
diff --git a/src/render/raycasting/qboundingvolume_p.h b/src/render/raycasting/qboundingvolume_p.h
index f29d08d52..8267c2b18 100644
--- a/src/render/raycasting/qboundingvolume_p.h
+++ b/src/render/raycasting/qboundingvolume_p.h
@@ -72,7 +72,8 @@ public:
};
virtual Qt3DCore::QNodeId id() const = 0;
- virtual bool intersects(const QRay3D &ray, QVector3D *q = nullptr) const = 0;
+ virtual bool intersects(const QRay3D &ray, QVector3D *q = nullptr,
+ QVector3D *uvw = nullptr) const = 0;
virtual Type type() const = 0;
};
diff --git a/src/render/raycasting/qcollisionqueryresult.cpp b/src/render/raycasting/qcollisionqueryresult.cpp
index 4d887d287..62975200c 100644
--- a/src/render/raycasting/qcollisionqueryresult.cpp
+++ b/src/render/raycasting/qcollisionqueryresult.cpp
@@ -56,9 +56,10 @@ QCollisionQueryResultPrivate::QCollisionQueryResultPrivate(const QCollisionQuery
{
}
-void QCollisionQueryResultPrivate::addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance)
+void QCollisionQueryResultPrivate::addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection,
+ float distance, const QVector3D& uvw)
{
- m_hits.append(QCollisionQueryResult::Hit(entity, intersection, distance));
+ m_hits.append(QCollisionQueryResult::Hit(entity, intersection, distance, uvw));
}
void QCollisionQueryResultPrivate::setHandle(const QQueryHandle &handle)
diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h
index 18b45370a..e13dda74a 100644
--- a/src/render/raycasting/qcollisionqueryresult_p.h
+++ b/src/render/raycasting/qcollisionqueryresult_p.h
@@ -69,13 +69,27 @@ class QT3DRENDERSHARED_EXPORT QCollisionQueryResult
{
public:
struct Hit {
- Hit() : m_distance(-1.f), m_triangleIndex(0) { m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0; }
- Hit(const Qt3DCore::QNodeId &entity, const QVector3D &intersection, float distance) : m_entityId(entity), m_intersection(intersection), m_distance(distance) { }
+ Hit()
+ : m_distance(-1.f)
+ , m_triangleIndex(0)
+ {
+ m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0;
+ }
+
+ Hit(Qt3DCore::QNodeId entity, const QVector3D &intersection, float distance, const QVector3D &uvw)
+ : m_entityId(entity)
+ , m_intersection(intersection)
+ , m_distance(distance)
+ , m_uvw(uvw)
+ {
+ }
+
Qt3DCore::QNodeId m_entityId;
QVector3D m_intersection;
float m_distance;
uint m_triangleIndex;
uint m_vertexIndex[3];
+ QVector3D m_uvw;
};
QCollisionQueryResult();
@@ -123,7 +137,8 @@ public:
explicit QCollisionQueryResultPrivate(const QCollisionQueryResultPrivate &copy);
void setHandle(const QQueryHandle &handle);
- void addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance);
+ void addEntityHit(Qt3DCore::QNodeId entity, const QVector3D& intersection, float distance,
+ const QVector3D& uvw);
QQueryHandle m_handle;
QVector<QCollisionQueryResult::Hit> m_hits;
diff --git a/src/render/raycasting/qraycastingservice.cpp b/src/render/raycasting/qraycastingservice.cpp
index e92234836..e0c7b6199 100644
--- a/src/render/raycasting/qraycastingservice.cpp
+++ b/src/render/raycasting/qraycastingservice.cpp
@@ -68,6 +68,7 @@ struct Hit
float distance;
Qt3DCore::QNodeId id;
QVector3D intersection;
+ QVector3D uvw;
};
bool compareHitsDistance(const Hit &a, const Hit &b)
@@ -78,7 +79,7 @@ bool compareHitsDistance(const Hit &a, const Hit &b)
Hit volumeRayIntersection(const QBoundingVolume *volume, const QRay3D &ray)
{
Hit hit;
- if ((hit.intersects = volume->intersects(ray, &hit.intersection))) {
+ if ((hit.intersects = volume->intersects(ray, &hit.intersection, &hit.uvw))) {
hit.distance = ray.projectedDistance(hit.intersection);
hit.id = volume->id();
}
@@ -134,12 +135,12 @@ QCollisionQueryResult QRayCastingServicePrivate::collides(const QRay3D &ray, QBo
if (mode == QAbstractCollisionQueryService::FirstHit) {
Hit firstHit = QtConcurrent::blockingMappedReduced<Hit>(volumes, gathererFunctor, reduceToFirstHit);
if (firstHit.intersects)
- q->addEntityHit(result, firstHit.id, firstHit.intersection, firstHit.distance);
+ q->addEntityHit(result, firstHit.id, firstHit.intersection, firstHit.distance, firstHit.uvw);
} else {
QVector<Hit> hits = QtConcurrent::blockingMappedReduced<QVector<Hit> >(volumes, gathererFunctor, reduceToAllHits);
std::sort(hits.begin(), hits.end(), compareHitsDistance);
for (const Hit &hit : qAsConst(hits))
- q->addEntityHit(result, hit.id, hit.intersection, hit.distance);
+ q->addEntityHit(result, hit.id, hit.intersection, hit.distance, hit.uvw);
}
return result;
@@ -154,6 +155,7 @@ QCollisionQueryResult::Hit QRayCastingServicePrivate::collides(const QRay3D &ray
result.m_distance = hit.distance;
result.m_entityId = hit.id;
result.m_intersection = hit.intersection;
+ result.m_uvw = hit.uvw;
}
return result;
}
diff --git a/src/render/render.pro b/src/render/render.pro
index 1b90af82f..c31db94b7 100644
--- a/src/render/render.pro
+++ b/src/render/render.pro
@@ -41,6 +41,7 @@ SOURCES += \
MODULE_PLUGIN_TYPES = \
sceneparsers \
- geometryloaders
+ geometryloaders \
+ renderplugins
load(qt_module)
diff --git a/src/render/renderlogging.cpp b/src/render/renderlogging.cpp
index 820392b68..b9d423163 100644
--- a/src/render/renderlogging.cpp
+++ b/src/render/renderlogging.cpp
@@ -45,17 +45,17 @@ namespace Qt3DRender {
namespace Render {
-Q_LOGGING_CATEGORY(Backend, "Qt3D.Renderer.Backend")
-Q_LOGGING_CATEGORY(Frontend, "Qt3D.Renderer.Frontend")
-Q_LOGGING_CATEGORY(Io, "Qt3D.Renderer.IO")
-Q_LOGGING_CATEGORY(Jobs, "Qt3D.Renderer.Jobs")
-Q_LOGGING_CATEGORY(Framegraph, "Qt3D.Renderer.Framegraph")
-Q_LOGGING_CATEGORY(RenderNodes, "Qt3D.Renderer.RenderNodes")
-Q_LOGGING_CATEGORY(Rendering, "Qt3D.Renderer.Rendering")
-Q_LOGGING_CATEGORY(Memory, "Qt3D.Renderer.Memory")
-Q_LOGGING_CATEGORY(Shaders, "Qt3D.Renderer.Shaders")
-Q_LOGGING_CATEGORY(RenderStates, "Qt3D.Renderer.RenderStates")
-Q_LOGGING_CATEGORY(VSyncAdvanceService, "Qt3D.Renderer.VsyncAdvanceService")
+Q_LOGGING_CATEGORY(Backend, "Qt3D.Renderer.Backend", QtWarningMsg)
+Q_LOGGING_CATEGORY(Frontend, "Qt3D.Renderer.Frontend", QtWarningMsg)
+Q_LOGGING_CATEGORY(Io, "Qt3D.Renderer.IO", QtWarningMsg)
+Q_LOGGING_CATEGORY(Jobs, "Qt3D.Renderer.Jobs", QtWarningMsg)
+Q_LOGGING_CATEGORY(Framegraph, "Qt3D.Renderer.Framegraph", QtWarningMsg)
+Q_LOGGING_CATEGORY(RenderNodes, "Qt3D.Renderer.RenderNodes", QtWarningMsg)
+Q_LOGGING_CATEGORY(Rendering, "Qt3D.Renderer.Rendering", QtWarningMsg)
+Q_LOGGING_CATEGORY(Memory, "Qt3D.Renderer.Memory", QtWarningMsg)
+Q_LOGGING_CATEGORY(Shaders, "Qt3D.Renderer.Shaders", QtWarningMsg)
+Q_LOGGING_CATEGORY(RenderStates, "Qt3D.Renderer.RenderStates", QtWarningMsg)
+Q_LOGGING_CATEGORY(VSyncAdvanceService, "Qt3D.Renderer.VsyncAdvanceService", QtWarningMsg)
} // namespace Render
diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h
index 2fd340e7e..91747b3bc 100644
--- a/src/render/texture/apitexturemanager_p.h
+++ b/src/render/texture/apitexturemanager_p.h
@@ -237,6 +237,21 @@ public:
return true;
}
+ // Change the texture data generator for given texture, if it is a non-shared texture
+ // Return true, if it was changed successfully, false otherwise
+ bool setGenerator(APITexture *tex, const QTextureGeneratorPtr &generator)
+ {
+ Q_ASSERT(tex);
+
+ if (isShared(tex))
+ return false;
+
+ tex->setGenerator(generator);
+ m_updatedTextures.push_back(tex);
+
+ return true;
+ }
+
// Retrieves abandoned textures. This should be regularly called from the OpenGL thread
// to make sure needed GL resources are de-allocated.
QVector<APITexture*> takeAbandonedTextures()
@@ -258,7 +273,7 @@ public:
if (impl->isUnique())
return false;
- auto it = m_sharedTextures.find(impl);
+ auto it = m_sharedTextures.constFind(impl);
if (it == m_sharedTextures.cend())
return false;
diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp
index 0fc37891d..854789e94 100644
--- a/src/render/texture/gltexture.cpp
+++ b/src/render/texture/gltexture.cpp
@@ -120,7 +120,7 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture()
if (m_properties.target != QAbstractTexture::TargetAutomatic)
qWarning() << "[Qt3DRender::GLTexture] When a texture provides a generator, it's target is expected to be TargetAutomatic";
- m_properties.target = m_textureData->target();
+ m_actualTarget = m_textureData->target();
m_properties.width = m_textureData->width();
m_properties.height = m_textureData->height();
m_properties.depth = m_textureData->depth();
@@ -188,6 +188,8 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture()
if (!m_gl) {
m_gl = buildGLTexture();
+ if (!m_gl)
+ return nullptr;
m_gl->allocateStorage();
if (!m_gl->isStorageAllocated()) {
qWarning() << Q_FUNC_INFO << "texture storage allocation failed";
@@ -224,6 +226,7 @@ void GLTexture::setProperties(const TextureProperties &props)
if (m_properties != props) {
m_properties = props;
QMutexLocker locker(&m_dirtyFlagMutex);
+ m_actualTarget = props.target;
m_dirty |= Properties;
}
}
@@ -278,6 +281,26 @@ void GLTexture::setImages(const QVector<Image> &images)
}
}
+void GLTexture::setGenerator(const QTextureGeneratorPtr &generator)
+{
+ // 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;
+
+ 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();
@@ -286,12 +309,14 @@ QOpenGLTexture *GLTexture::buildGLTexture()
return nullptr;
}
- if (m_properties.target == QAbstractTexture::TargetAutomatic) {
- qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point";
+ if (m_actualTarget == QAbstractTexture::TargetAutomatic) {
+ // 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;
}
- QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_properties.target));
+ QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_actualTarget));
// m_format may not be ES2 compatible. Now it's time to convert it, if necessary.
QAbstractTexture::TextureFormat format = m_properties.format;
@@ -329,16 +354,16 @@ QOpenGLTexture *GLTexture::buildGLTexture()
static_cast<QOpenGLTexture::TextureFormat>(format));
glTex->setSize(m_properties.width, m_properties.height, m_properties.depth);
// Set layers count if texture array
- if (m_properties.target == QAbstractTexture::Target1DArray ||
- m_properties.target == QAbstractTexture::Target2DArray ||
- m_properties.target == QAbstractTexture::Target3D ||
- m_properties.target == QAbstractTexture::Target2DMultisampleArray ||
- m_properties.target == QAbstractTexture::TargetCubeMapArray) {
+ if (m_actualTarget == QAbstractTexture::Target1DArray ||
+ m_actualTarget == QAbstractTexture::Target2DArray ||
+ m_actualTarget == QAbstractTexture::Target3D ||
+ m_actualTarget == QAbstractTexture::Target2DMultisampleArray ||
+ m_actualTarget == QAbstractTexture::TargetCubeMapArray) {
glTex->setLayers(m_properties.layers);
}
- if (m_properties.target == QAbstractTexture::Target2DMultisample ||
- m_properties.target == QAbstractTexture::Target2DMultisampleArray) {
+ if (m_actualTarget == QAbstractTexture::Target2DMultisample ||
+ m_actualTarget == QAbstractTexture::Target2DMultisampleArray) {
// Set samples count if multisampled texture
// (multisampled textures don't have mipmaps)
glTex->setSamples(m_properties.samples);
@@ -384,7 +409,7 @@ void GLTexture::uploadGLTextureData()
for (int layer = 0; layer < data->layers(); layer++) {
for (int face = 0; face < data->faces(); face++) {
for (int level = 0; level < mipLevels; level++) {
- // ensure we don't accidently cause a detach / copy of the raw bytes
+ // ensure we don't accidentally cause a detach / copy of the raw bytes
const QByteArray bytes(data->data(layer, face, level));
uploadGLData(m_gl, level, layer,
static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face),
@@ -399,7 +424,7 @@ void GLTexture::uploadGLTextureData()
for (int i = 0; i < m_images.size(); i++) {
const QTextureImageDataPtr &imgData = m_imageData.at(i);
- // ensure we don't accidently cause a detach / copy of the raw bytes
+ // ensure we don't accidentally cause a detach / copy of the raw bytes
const QByteArray bytes(imgData->data());
uploadGLData(m_gl, m_images[i].mipLevel, m_images[i].layer,
static_cast<QOpenGLTexture::CubeMapFace>(m_images[i].face),
@@ -410,11 +435,11 @@ void GLTexture::uploadGLTextureData()
void GLTexture::updateGLTextureParameters()
{
m_gl->setWrapMode(QOpenGLTexture::DirectionS, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeX));
- if (m_properties.target != QAbstractTexture::Target1D &&
- m_properties.target != QAbstractTexture::Target1DArray &&
- m_properties.target != QAbstractTexture::TargetBuffer)
+ if (m_actualTarget != QAbstractTexture::Target1D &&
+ m_actualTarget != QAbstractTexture::Target1DArray &&
+ m_actualTarget != QAbstractTexture::TargetBuffer)
m_gl->setWrapMode(QOpenGLTexture::DirectionT, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeY));
- if (m_properties.target == QAbstractTexture::Target3D)
+ if (m_actualTarget == QAbstractTexture::Target3D)
m_gl->setWrapMode(QOpenGLTexture::DirectionR, static_cast<QOpenGLTexture::WrapMode>(m_parameters.wrapModeZ));
m_gl->setMinMagFilters(static_cast<QOpenGLTexture::Filter>(m_parameters.minificationFilter),
static_cast<QOpenGLTexture::Filter>(m_parameters.magnificationFilter));
diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h
index 424e77854..4c0957f76 100644
--- a/src/render/texture/gltexture_p.h
+++ b/src/render/texture/gltexture_p.h
@@ -148,6 +148,16 @@ public:
m_dirty |= TextureData;
}
+ bool isDirty()
+ {
+ QMutexLocker locker(&m_dirtyFlagMutex);
+ return m_dirty == 0 ? false : true;
+ }
+
+ QMutex *textureLock()
+ {
+ return &m_dirtyFlagMutex;
+ }
protected:
template<class APITexture, class APITextureImage>
@@ -164,11 +174,12 @@ protected:
void setParameters(const TextureParameters &params);
void setProperties(const TextureProperties &props);
void setImages(const QVector<Image> &images);
+ void setGenerator(const QTextureGeneratorPtr &generator);
private:
enum DirtyFlag {
- TextureData = 0x01, // one or more generators have been executed, data needs uploading to GPU
+ TextureData = 0x01, // one or more image generators have been executed, data needs uploading to GPU
Properties = 0x02, // texture needs to be (re-)created
Parameters = 0x04 // texture parameters need to be (re-)set
@@ -188,6 +199,8 @@ private:
TextureDataManager *m_textureDataManager;
TextureImageDataManager *m_textureImageDataManager;
+ // target which is actually used for GL texture
+ QAbstractTexture::Target m_actualTarget;
TextureProperties m_properties;
TextureParameters m_parameters;
diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp
index 7703933a4..1bd002104 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) {
diff --git a/src/render/texture/qabstracttexture_p.h b/src/render/texture/qabstracttexture_p.h
index 7f5a32c94..a27ae3729 100644
--- a/src/render/texture/qabstracttexture_p.h
+++ b/src/render/texture/qabstracttexture_p.h
@@ -56,12 +56,13 @@
#include <Qt3DRender/qabstracttexture.h>
#include <Qt3DRender/qtexturewrapmode.h>
#include <Qt3DRender/qtexturegenerator.h>
+#include <Qt3DRender/private/qt3drender_global_p.h>
QT_BEGIN_NAMESPACE
namespace Qt3DRender {
-class Q_AUTOTEST_EXPORT QAbstractTexturePrivate : public Qt3DCore::QNodePrivate
+class QT3DRENDERSHARED_PRIVATE_EXPORT QAbstractTexturePrivate : public Qt3DCore::QNodePrivate
{
public :
QAbstractTexturePrivate();
@@ -86,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/qpaintedtextureimage.cpp b/src/render/texture/qpaintedtextureimage.cpp
index 9ae43378a..4d03eb809 100644
--- a/src/render/texture/qpaintedtextureimage.cpp
+++ b/src/render/texture/qpaintedtextureimage.cpp
@@ -104,14 +104,9 @@ QPaintedTextureImage::~QPaintedTextureImage()
/*!
\property QPaintedTextureImage::width
- Holds the width of the texture image
- */
-
-/*!
- \property QPaintedTextureImage::width
-
- \return the width of the texture image.
- */
+ This property holds the width of the texture image.
+ The width must be greater than or equal to 1.
+*/
int QPaintedTextureImage::width() const
{
Q_D(const QPaintedTextureImage);
@@ -121,14 +116,9 @@ int QPaintedTextureImage::width() const
/*!
\property QPaintedTextureImage::height
- Holds the height of the texture image
- */
-
-/*!
- \property QPaintedTextureImage::height
-
- \return the height of the texture image.
- */
+ This property holds the height of the texture image.
+ The height must be greater than or equal to 1.
+*/
int QPaintedTextureImage::height() const
{
Q_D(const QPaintedTextureImage);
@@ -138,14 +128,11 @@ int QPaintedTextureImage::height() const
/*!
\property QPaintedTextureImage::size
- Holds the width and height of the texture image
- */
+ This property holds the size of the texture image.
-/*!
- \property QPaintedTextureImage::size
+ \sa height, width
- \return the size of the texture image.
- */
+*/
QSize QPaintedTextureImage::size() const
{
Q_D(const QPaintedTextureImage);
@@ -153,7 +140,7 @@ QSize QPaintedTextureImage::size() const
}
/*!
- Sets the width of the texture image. Triggers an update, if the size changes.
+ Sets the width (\a w) of the texture image. Triggers an update, if the size changes.
*/
void QPaintedTextureImage::setWidth(int w)
{
@@ -165,7 +152,7 @@ void QPaintedTextureImage::setWidth(int w)
}
/*!
- Sets the height of the texture image. Triggers an update, if the size changes.
+ Sets the height (\a h) of the texture image. Triggers an update, if the size changes.
*/
void QPaintedTextureImage::setHeight(int h)
{
@@ -177,7 +164,7 @@ void QPaintedTextureImage::setHeight(int h)
}
/*!
- Sets the width and height of the texture image. Triggers an update, if the size changes.
+ Sets the width and height of the texture image. Triggers an update, if the \a size changes.
*/
void QPaintedTextureImage::setSize(QSize size)
{
@@ -206,9 +193,10 @@ void QPaintedTextureImage::setSize(QSize size)
}
/*!
- Will trigger an update of the texture image, meaning the paint() method will
- be invoked.
- */
+ Schedules the painted texture's paint() function to be called,
+ which in turn uploads the new image to the GPU.
+ Parameter \a rect is currently unused.
+*/
void QPaintedTextureImage::update(const QRect &rect)
{
Q_UNUSED(rect)
diff --git a/src/render/texture/qtexture.cpp b/src/render/texture/qtexture.cpp
index 7dc071833..931d66c64 100644
--- a/src/render/texture/qtexture.cpp
+++ b/src/render/texture/qtexture.cpp
@@ -44,7 +44,17 @@
#include "qtexture.h"
#include "qtexture_p.h"
#include <QFileInfo>
+#include <QMimeDatabase>
+#include <QMimeType>
#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
@@ -390,7 +400,7 @@ const struct DX10Format
{ DXGI_FORMAT_R8_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, 1, false } },
{ DXGI_FORMAT_R8G8_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG8_UNorm, QOpenGLTexture::UInt8, 2, false } },
{ DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R16_UNorm, QOpenGLTexture::UInt16, 2, false } },
-{ DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_UNorm, QOpenGLTexture::UInt16, 4, false } },
+{ DXGI_FORMAT_R16G16_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_UNorm, QOpenGLTexture::UInt16, 4, false } },
// depth formats
{ DXGI_FORMAT_D16_UNORM, { QOpenGLTexture::Depth, QOpenGLTexture::D16, QOpenGLTexture::NoPixelType, 2, false } },
@@ -424,9 +434,8 @@ enum CompressedFormatExtension {
PKM
};
-CompressedFormatExtension texturedCompressedFormat(const QString &source)
+CompressedFormatExtension texturedCompressedFormat(const QString &suffix)
{
- const QString suffix = QFileInfo(source).suffix();
if (suffix == QStringLiteral("pkm"))
return PKM;
if (suffix == QStringLiteral("dds"))
@@ -434,19 +443,14 @@ 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;
- return imageData;
- }
- // ETC1 in PKM, as generated by f.ex. Android's etc1tool
+ // ETC1 in PKM, as generated by source->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);
+ const QByteArray header = source->read(pkmHeaderSize);
if (header.size() >= pkmHeaderSize && !qstrncmp(header.constData(), pkmMagic, 6)) {
imageData = QTextureImageDataPtr::create();
imageData->setTarget(QOpenGLTexture::Target2D);
@@ -455,7 +459,7 @@ QTextureImageDataPtr setPkmFile(const QString &source)
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();
+ const QByteArray data = source->readAll();
if (data.size() < (imageData->width() / 4) * (imageData->height() / 4) * 8)
qWarning() << "Unexpected end of ETC1 data in" << source;
const bool isCompressed = true;
@@ -467,17 +471,12 @@ QTextureImageDataPtr setPkmFile(const QString &source)
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 +489,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 +581,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 +625,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(), 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 +665,43 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
{
QTextureDataPtr generatedData = QTextureDataPtr::create();
m_status = QAbstractTexture::Loading;
+ QTextureImageDataPtr textureData;
+
+ 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();
+ }
- const QTextureImageDataPtr textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored);
+ 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);
+ }
if (textureData && textureData->data().length() > 0) {
generatedData->setTarget(static_cast<QAbstractTexture::Target>(textureData->target()));
@@ -672,12 +719,55 @@ QTextureDataPtr QTextureFromSourceGenerator::operator ()()
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);
+}
+
QTextureLoaderPrivate::QTextureLoaderPrivate()
: QAbstractTexturePrivate()
, m_mirrored(true)
{
}
+void QTextureLoaderPrivate::setScene(Qt3DCore::QScene *scene)
+{
+ QAbstractTexturePrivate::setScene(scene);
+ updateFunctor();
+}
+
+void QTextureLoaderPrivate::updateFunctor()
+{
+ Qt3DCore::QAspectEngine *engine = m_scene ? m_scene->engine() : nullptr;
+ setDataFunctor(QTextureFromSourceGeneratorPtr::create(m_id, m_source, m_mirrored, engine));
+}
+
/*!
\class Qt3DRender::QTexture1D
\inmodule Qt3DRender
@@ -900,10 +990,25 @@ QTextureBuffer::~QTextureBuffer()
/*!
* Constructs a new Qt3DRender::QTextureLoader instance with \a parent as parent.
+ *
+ * Note that by default, if not contradicted by the file metadata, the loaded texture
+ * will have the following properties set:
+ * - wrapMode set to Repeat
+ * - minificationFilter set to LinearMipMapLinear
+ * - magnificationFilter set to Linear
+ * - generateMipMaps set to true
+ * - maximumAnisotropy set to 16.0f
+ * - target set to TargetAutomatic
*/
QTextureLoader::QTextureLoader(QNode *parent)
: QAbstractTexture(*new QTextureLoaderPrivate, parent)
{
+ d_func()->m_wrapMode.setX(QTextureWrapMode::Repeat);
+ d_func()->m_wrapMode.setY(QTextureWrapMode::Repeat);
+ d_func()->m_minFilter = LinearMipMapLinear;
+ d_func()->m_magFilter = Linear;
+ d_func()->m_autoMipMap = true;
+ d_func()->m_maximumAnisotropy = 16.0f;
d_func()->m_target = TargetAutomatic;
}
@@ -936,7 +1041,7 @@ void QTextureLoader::setSource(const QUrl& source)
Q_D(QTextureLoader);
if (source != d->m_source) {
d->m_source = source;
- d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored));
+ d->updateFunctor();
const bool blocked = blockNotifications(true);
emit sourceChanged(source);
blockNotifications(blocked);
@@ -984,7 +1089,7 @@ void QTextureLoader::setMirrored(bool mirrored)
Q_D(QTextureLoader);
if (mirrored != d->m_mirrored) {
d->m_mirrored = mirrored;
- d->setDataFunctor(QTextureFromSourceGeneratorPtr::create(d->m_source, d->m_mirrored));
+ d->updateFunctor();
const bool blocked = blockNotifications(true);
emit mirroredChanged(mirrored);
blockNotifications(blocked);
@@ -1000,7 +1105,8 @@ bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) co
const QTextureFromSourceGenerator *otherFunctor = functor_cast<QTextureFromSourceGenerator>(&other);
return (otherFunctor != nullptr &&
otherFunctor->m_url == m_url &&
- otherFunctor->m_mirrored == m_mirrored);
+ otherFunctor->m_mirrored == m_mirrored &&
+ otherFunctor->m_engine == m_engine);
}
QUrl QTextureFromSourceGenerator::url() const
@@ -1018,16 +1124,18 @@ bool QTextureFromSourceGenerator::isMirrored() const
* instance with \a url.
* \param url
*/
-QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QUrl &url, bool mirrored)
+QTextureFromSourceGenerator::QTextureFromSourceGenerator(Qt3DCore::QNodeId texture,
+ const QUrl &url, bool mirrored,
+ Qt3DCore::QAspectEngine *engine)
: QTextureGenerator()
, m_url(url)
, m_status(QAbstractTexture::None)
, m_mirrored(mirrored)
+ , m_texture(texture)
+ , m_engine(engine)
{
}
} // namespace Qt3DRender
QT_END_NAMESPACE
-
-
diff --git a/src/render/texture/qtexture_p.h b/src/render/texture/qtexture_p.h
index a0ea71a58..4afb14d62 100644
--- a/src/render/texture/qtexture_p.h
+++ b/src/render/texture/qtexture_p.h
@@ -51,8 +51,11 @@
// 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>
QT_BEGIN_NAMESPACE
@@ -63,14 +66,30 @@ class QTextureLoaderPrivate : public QAbstractTexturePrivate
public:
QTextureLoaderPrivate();
+ void setScene(Qt3DCore::QScene *scene) override;
+ void updateFunctor();
+
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(const QUrl &url, bool mirrored);
+ explicit QTextureFromSourceGenerator(Qt3DCore::QNodeId texture, const QUrl &url,
+ bool mirrored, Qt3DCore::QAspectEngine *engine);
QTextureDataPtr operator ()() Q_DECL_OVERRIDE;
bool operator ==(const QTextureGenerator &other) const Q_DECL_OVERRIDE;
inline QAbstractTexture::Status status() const { return m_status; }
@@ -81,9 +100,14 @@ public:
bool isMirrored() const;
private:
+ friend class TextureDownloadRequest;
+
QUrl m_url;
QAbstractTexture::Status m_status;
bool m_mirrored;
+ QByteArray m_sourceData;
+ Qt3DCore::QNodeId m_texture;
+ Qt3DCore::QAspectEngine *m_engine;
};
typedef QSharedPointer<QTextureFromSourceGenerator> QTextureFromSourceGeneratorPtr;
@@ -91,6 +115,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/texture.cpp b/src/render/texture/texture.cpp
index 863733523..21f29d0b6 100644
--- a/src/render/texture/texture.cpp
+++ b/src/render/texture/texture.cpp
@@ -61,7 +61,7 @@ namespace Render {
Texture::Texture()
// We need backend -> frontend notifications to update the status of the texture
: BackendNode(ReadWrite)
- , m_dirty(DirtyGenerators|DirtyProperties|DirtyParameters)
+ , m_dirty(DirtyImageGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator)
, m_textureImageManager(nullptr)
{
}
@@ -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;
}
@@ -101,7 +109,7 @@ void Texture::addTextureImage(Qt3DCore::QNodeId id)
qWarning() << "[Qt3DRender::TextureNode] addTextureImage: image handle is NULL";
} else if (!m_textureImages.contains(handle)) {
m_textureImages << handle;
- addDirtyFlag(DirtyGenerators);
+ addDirtyFlag(DirtyImageGenerators);
}
}
@@ -117,7 +125,7 @@ void Texture::removeTextureImage(Qt3DCore::QNodeId id)
qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: image handle is NULL";
} else {
m_textureImages.removeAll(handle);
- addDirtyFlag(DirtyGenerators);
+ addDirtyFlag(DirtyImageGenerators);
}
}
@@ -214,7 +222,7 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
dirty = DirtyProperties;
} else if (propertyChange->propertyName() == QByteArrayLiteral("generator")) {
m_dataFunctor = propertyChange->value().value<QTextureGeneratorPtr>();
- dirty = DirtyGenerators;
+ dirty = DirtyDataGenerator;
}
}
break;
@@ -246,6 +254,16 @@ void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
BackendNode::sceneChangeEvent(e);
}
+bool Texture::isValid() const
+{
+ for (const auto handle : m_textureImages) {
+ TextureImage *img = m_textureImageManager->data(handle);
+ if (img == nullptr)
+ return false;
+ }
+ return true;
+}
+
void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change)
{
const auto typedChange = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<QAbstractTextureData>>(change);
@@ -269,7 +287,7 @@ void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan
m_parameters.comparisonMode = data.comparisonMode;
m_dataFunctor = data.dataFunctor;
- addDirtyFlag(DirtyFlags(DirtyGenerators|DirtyProperties|DirtyParameters));
+ addDirtyFlag(DirtyFlags(DirtyImageGenerators|DirtyProperties|DirtyParameters));
}
diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h
index 8f5300552..1f3ba729c 100644
--- a/src/render/texture/texture_p.h
+++ b/src/render/texture/texture_p.h
@@ -135,14 +135,15 @@ public:
NotDirty = 0,
DirtyProperties = 0x1,
DirtyParameters = 0x2,
- DirtyGenerators = 0x4
+ DirtyImageGenerators = 0x4,
+ DirtyDataGenerator = 0x8
};
Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
void setTextureImageManager(TextureImageManager *manager);
void addDirtyFlag(DirtyFlags flags);
- inline DirtyFlags dirtyFlags() const { return m_dirty; }
+ DirtyFlags dirtyFlags();
void unsetDirty();
void addTextureImage(Qt3DCore::QNodeId id);
@@ -156,6 +157,7 @@ public:
inline const QVector<HTextureImage>& textureImages() const { return m_textureImages; }
inline const QTextureGeneratorPtr& dataGenerator() const { return m_dataFunctor; }
+ bool isValid() const;
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -167,6 +169,7 @@ private:
QVector<HTextureImage> m_textureImages;
TextureImageManager *m_textureImageManager;
+ QMutex m_flagsMutex;
};
class TextureFunctor : public Qt3DCore::QBackendNodeMapper
diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp
index f44a82649..b732be2d9 100644
--- a/src/render/texture/textureimage.cpp
+++ b/src/render/texture/textureimage.cpp
@@ -106,7 +106,7 @@ void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
// Notify the Texture that we were updated and request it to schedule an update job
Texture *txt = m_textureManager->data(m_textureProvider);
if (txt != nullptr)
- txt->addDirtyFlag(Texture::DirtyGenerators);
+ txt->addDirtyFlag(Texture::DirtyImageGenerators);
}
markDirty(AbstractRenderer::AllDirty);