1481 lines
52 KiB
Diff
1481 lines
52 KiB
Diff
If an entity uses a QBoundingVolume and a QGeometryView, compute
|
|
the bounding volume data in the core aspect. All other cases will
|
|
still happen in the render aspect.
|
|
|
|
Result not currently used (ie it's done again in render aspect).
|
|
|
|
Change-Id: I4b5ed21bac42b79777c3112aa76d876ac5b6f52d
|
|
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
|
|
14 files changed:
|
|
src/core/aspect/qcoreaspect.cpp patch | blob | history
|
|
src/core/aspect/qcoreaspect.h patch | blob | history
|
|
src/core/aspect/qcoreaspect_p.h patch | blob | history
|
|
src/core/core.pro patch | blob | history
|
|
src/core/geometry/bufferutils_p.h [new file with mode: 0644] patch | blob
|
|
src/core/geometry/buffervisitor_p.h [new file with mode: 0644] patch | blob
|
|
src/core/geometry/geometry.pri patch | blob | history
|
|
src/core/geometry/qgeometry_p.h patch | blob | history
|
|
src/core/geometry/qgeometryview.cpp patch | blob | history
|
|
src/core/geometry/qgeometryview_p.h patch | blob | history
|
|
src/core/jobs/calcboundingvolumejob.cpp [new file with mode: 0644] patch | blob
|
|
src/core/jobs/calcboundingvolumejob_p.h [new file with mode: 0644] patch | blob
|
|
src/core/jobs/job_common_p.h [new file with mode: 0644] patch | blob
|
|
src/core/jobs/jobs.pri patch | blob | history
|
|
|
|
diff --git a/src/core/aspect/qcoreaspect.cpp b/src/core/aspect/qcoreaspect.cpp
|
|
index 48f9aaf..dc3566e 100644 (file)
|
|
--- a/src/core/aspect/qcoreaspect.cpp
|
|
+++ b/src/core/aspect/qcoreaspect.cpp
|
|
@@ -39,12 +39,16 @@
|
|
|
|
#include "qcoreaspect.h"
|
|
#include "qcoreaspect_p.h"
|
|
+#include <Qt3DCore/private/qaspectmanager_p.h>
|
|
+#include <Qt3DCore/private/qscene_p.h>
|
|
+#include <Qt3DCore/private/calcboundingvolumejob_p.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
using namespace Qt3DCore;
|
|
|
|
QCoreAspectPrivate::QCoreAspectPrivate()
|
|
+ : Qt3DCore::QAbstractAspectPrivate()
|
|
{
|
|
|
|
}
|
|
@@ -65,7 +69,7 @@ void QCoreAspectPrivate::frameDone()
|
|
}
|
|
|
|
QCoreAspect::QCoreAspect(QObject *parent)
|
|
- : Qt3DCore::QAbstractAspect(parent)
|
|
+ : Qt3DCore::QAbstractAspect(*new QCoreAspectPrivate, parent)
|
|
{
|
|
|
|
}
|
|
@@ -75,10 +79,28 @@ QCoreAspect::~QCoreAspect()
|
|
|
|
}
|
|
|
|
+QAspectJobPtr QCoreAspect::calculateBoundingVolumeJob() const
|
|
+{
|
|
+ Q_D(const QCoreAspect);
|
|
+ return d->m_calculateBoundingVolumeJob;
|
|
+}
|
|
+
|
|
QVector<QAspectJobPtr> QCoreAspect::jobsToExecute(qint64 time)
|
|
{
|
|
+ Q_D(QCoreAspect);
|
|
Q_UNUSED(time)
|
|
- return {};
|
|
+
|
|
+ QVector<QAspectJobPtr> jobs;
|
|
+
|
|
+ auto scene = d->m_aspectManager->scene();
|
|
+ auto dirtyBits = scene->dirtyBits();
|
|
+
|
|
+ if (dirtyBits & QScene::GeometryDirty ||
|
|
+ dirtyBits & QScene::BuffersDirty) {
|
|
+ jobs.push_back(d->m_calculateBoundingVolumeJob);
|
|
+ }
|
|
+
|
|
+ return jobs;
|
|
}
|
|
|
|
QVariant QCoreAspect::executeCommand(const QStringList &args)
|
|
@@ -89,12 +111,25 @@ QVariant QCoreAspect::executeCommand(const QStringList &args)
|
|
|
|
void QCoreAspect::onRegistered()
|
|
{
|
|
+ Q_D(QCoreAspect);
|
|
|
|
+ if (d->m_calculateBoundingVolumeJob.isNull())
|
|
+ d->m_calculateBoundingVolumeJob = CalculateBoundingVolumeJobPtr::create();
|
|
}
|
|
|
|
-void QCoreAspect::onUnregistered()
|
|
+void QCoreAspect::onEngineStartup()
|
|
{
|
|
+ Q_D(QCoreAspect);
|
|
|
|
+ Q_ASSERT(d->m_calculateBoundingVolumeJob);
|
|
+ d->m_calculateBoundingVolumeJob->setRoot(d->m_root);
|
|
+}
|
|
+
|
|
+void QCoreAspect::frameDone()
|
|
+{
|
|
+ Q_D(QCoreAspect);
|
|
+ auto scene = d->m_aspectManager->scene();
|
|
+ scene->clearDirtyBits();
|
|
}
|
|
|
|
QT_END_NAMESPACE
|
|
diff --git a/src/core/aspect/qcoreaspect.h b/src/core/aspect/qcoreaspect.h
|
|
index 27c72f4..071b738 100644 (file)
|
|
--- a/src/core/aspect/qcoreaspect.h
|
|
+++ b/src/core/aspect/qcoreaspect.h
|
|
@@ -55,6 +55,8 @@ public:
|
|
explicit QCoreAspect(QObject *parent = nullptr);
|
|
~QCoreAspect();
|
|
|
|
+ QAspectJobPtr calculateBoundingVolumeJob() const;
|
|
+
|
|
protected:
|
|
Q_DECLARE_PRIVATE(QCoreAspect)
|
|
|
|
@@ -62,7 +64,8 @@ private:
|
|
QVector<Qt3DCore::QAspectJobPtr> jobsToExecute(qint64 time) override;
|
|
QVariant executeCommand(const QStringList &args) override;
|
|
void onRegistered() override;
|
|
- void onUnregistered() override;
|
|
+ void onEngineStartup() override;
|
|
+ void frameDone() override;
|
|
};
|
|
|
|
}
|
|
diff --git a/src/core/aspect/qcoreaspect_p.h b/src/core/aspect/qcoreaspect_p.h
|
|
index ca665fa..cda0a14 100644 (file)
|
|
--- a/src/core/aspect/qcoreaspect_p.h
|
|
+++ b/src/core/aspect/qcoreaspect_p.h
|
|
@@ -55,10 +55,15 @@
|
|
#include <Qt3DCore/private/qabstractaspect_p.h>
|
|
#include <Qt3DCore/private/qt3dcore_global_p.h>
|
|
|
|
+#include <QSharedPointer>
|
|
+
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
namespace Qt3DCore {
|
|
|
|
+class CalculateBoundingVolumeJob;
|
|
+using CalculateBoundingVolumeJobPtr = QSharedPointer<CalculateBoundingVolumeJob>;
|
|
+
|
|
class Q_3DCORE_PRIVATE_EXPORT QCoreAspectPrivate : public Qt3DCore::QAbstractAspectPrivate
|
|
{
|
|
public:
|
|
@@ -71,6 +76,7 @@ public:
|
|
void frameDone() override;
|
|
|
|
bool m_initialized;
|
|
+ CalculateBoundingVolumeJobPtr m_calculateBoundingVolumeJob;
|
|
};
|
|
|
|
}
|
|
diff --git a/src/core/core.pro b/src/core/core.pro
|
|
index b149497..846e9d8 100644 (file)
|
|
--- a/src/core/core.pro
|
|
+++ b/src/core/core.pro
|
|
@@ -1,7 +1,8 @@
|
|
-TARGET = Qt3DCore
|
|
-MODULE = 3dcore
|
|
+TARGET = Qt3DCore
|
|
+MODULE = 3dcore
|
|
|
|
-QT = core-private gui-private network
|
|
+QT = core-private gui-private network
|
|
+QT_FOR_PRIVATE = concurrent
|
|
|
|
gcov {
|
|
QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage
|
|
diff --git a/src/core/geometry/bufferutils_p.h b/src/core/geometry/bufferutils_p.h
|
|
new file mode 100644 (file)
|
|
index 0000000..1b83d99
|
|
--- /dev/null
|
|
+++ b/src/core/geometry/bufferutils_p.h
|
|
@@ -0,0 +1,113 @@
|
|
+/****************************************************************************
|
|
+**
|
|
+** 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 QT3DCORE_BUFFERUTILS_P_H
|
|
+#define QT3DCORE_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 <Qt3DCore/QAttribute>
|
|
+#include <QByteArray>
|
|
+
|
|
+QT_BEGIN_NAMESPACE
|
|
+
|
|
+
|
|
+namespace Qt3DCore {
|
|
+
|
|
+class QGeometryView;
|
|
+class QBuffer;
|
|
+
|
|
+struct BufferInfo
|
|
+{
|
|
+ BufferInfo()
|
|
+ : type(Qt3DCore::QAttribute::VertexBaseType::Float)
|
|
+ , dataSize(0)
|
|
+ , count(0)
|
|
+ , byteStride(0)
|
|
+ , byteOffset(0)
|
|
+ , restartEnabled(false)
|
|
+ , restartIndexValue(-1)
|
|
+ {}
|
|
+
|
|
+ QByteArray data;
|
|
+ Qt3DCore::QAttribute::VertexBaseType type;
|
|
+ uint dataSize;
|
|
+ uint count;
|
|
+ uint byteStride;
|
|
+ uint byteOffset;
|
|
+ bool restartEnabled;
|
|
+ int restartIndexValue;
|
|
+};
|
|
+
|
|
+
|
|
+namespace BufferTypeInfo {
|
|
+
|
|
+ template <Qt3DCore::QAttribute::VertexBaseType> struct EnumToType;
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::Byte> { typedef const char type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::UnsignedByte> { typedef const uchar type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::Short> { typedef const short type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::UnsignedShort> { typedef const ushort type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::Int> { typedef const int type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::UnsignedInt> { typedef const uint type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::Float> { typedef const float type; };
|
|
+ template <> struct EnumToType<Qt3DCore::QAttribute::Double> { typedef const double type; };
|
|
+
|
|
+ template<Qt3DCore::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 Qt3DCore
|
|
+
|
|
+QT_END_NAMESPACE
|
|
+
|
|
+
|
|
+#endif // QT3DCORE_BUFFERUTILS_P_H
|
|
diff --git a/src/core/geometry/buffervisitor_p.h b/src/core/geometry/buffervisitor_p.h
|
|
new file mode 100644 (file)
|
|
index 0000000..69cfb9b
|
|
--- /dev/null
|
|
+++ b/src/core/geometry/buffervisitor_p.h
|
|
@@ -0,0 +1,285 @@
|
|
+/****************************************************************************
|
|
+**
|
|
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
|
+** Contact: https://www.qt.io/licensing/
|
|
+**
|
|
+** This file is part of the Qt3D module of the Qt Toolkit.
|
|
+**
|
|
+** $QT_BEGIN_LICENSE:LGPL$
|
|
+** Commercial License Usage
|
|
+** Licensees holding valid commercial Qt licenses may use this file in
|
|
+** accordance with the commercial license agreement provided with the
|
|
+** Software or, alternatively, in accordance with the terms contained in
|
|
+** a written agreement between you and The Qt Company. For licensing terms
|
|
+** and conditions see https://www.qt.io/terms-conditions. For further
|
|
+** information use the contact form at https://www.qt.io/contact-us.
|
|
+**
|
|
+** GNU Lesser General Public License Usage
|
|
+** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
+** General Public License version 3 as published by the Free Software
|
|
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
+** packaging of this file. Please review the following information to
|
|
+** ensure the GNU Lesser General Public License version 3 requirements
|
|
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
+**
|
|
+** GNU General Public License Usage
|
|
+** Alternatively, this file may be used under the terms of the GNU
|
|
+** General Public License version 2.0 or (at your option) the GNU General
|
|
+** Public license version 3 or any later version approved by the KDE Free
|
|
+** Qt Foundation. The licenses are as published by the Free Software
|
|
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
+** included in the packaging of this file. Please review the following
|
|
+** information to ensure the GNU General Public License requirements will
|
|
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
+** https://www.gnu.org/licenses/gpl-3.0.html.
|
|
+**
|
|
+** $QT_END_LICENSE$
|
|
+**
|
|
+****************************************************************************/
|
|
+
|
|
+#ifndef QT3DCORE_BUFFERVISITOR_P_H
|
|
+#define QT3DCORE_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 <Qt3DCore/qattribute.h>
|
|
+#include <Qt3DCore/qbuffer.h>
|
|
+#include <Qt3DCore/private/bufferutils_p.h>
|
|
+
|
|
+QT_BEGIN_NAMESPACE
|
|
+
|
|
+namespace Qt3DCore {
|
|
+class QEntity;
|
|
+
|
|
+template <typename ValueType, Qt3DCore::QAttribute::VertexBaseType VertexBaseType, uint dataSize>
|
|
+class Q_AUTOTEST_EXPORT BufferVisitor
|
|
+{
|
|
+public:
|
|
+ explicit BufferVisitor() = default;
|
|
+ virtual ~BufferVisitor() = default;
|
|
+
|
|
+ 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(QAttribute *attribute,
|
|
+ QAttribute *indexAttribute,
|
|
+ int drawVertexCount,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+ {
|
|
+ if (attribute->vertexBaseType() != VertexBaseType)
|
|
+ return false;
|
|
+ if (attribute->vertexSize() < dataSize)
|
|
+ return false;
|
|
+
|
|
+ auto data = attribute->buffer()->data();
|
|
+ auto vertexBuffer = BufferTypeInfo::castToType<VertexBaseType>(data, attribute->byteOffset());
|
|
+
|
|
+ if (indexAttribute) {
|
|
+ auto indexData = indexAttribute->buffer()->data();
|
|
+ switch (indexAttribute->vertexBaseType()) {
|
|
+ case Qt3DCore::QAttribute::UnsignedShort: {
|
|
+ auto indexBuffer = BufferTypeInfo::castToType<Qt3DCore::QAttribute::UnsignedShort>(indexData, indexAttribute->byteOffset());
|
|
+ traverseCoordinateIndexed(vertexBuffer, indexBuffer, attribute->byteStride(), drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ }
|
|
+ case Qt3DCore::QAttribute::UnsignedInt: {
|
|
+ auto indexBuffer = BufferTypeInfo::castToType<Qt3DCore::QAttribute::UnsignedInt>(indexData, indexAttribute->byteOffset());
|
|
+ traverseCoordinateIndexed(vertexBuffer, indexBuffer, attribute->byteStride(), drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ }
|
|
+ case Qt3DCore::QAttribute::UnsignedByte: {
|
|
+ auto indexBuffer = BufferTypeInfo::castToType<Qt3DCore::QAttribute::UnsignedByte>(indexData, indexAttribute->byteOffset());
|
|
+ traverseCoordinateIndexed(vertexBuffer, indexBuffer, attribute->byteStride(), drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ }
|
|
+ default: Q_UNREACHABLE();
|
|
+ }
|
|
+ } else {
|
|
+ switch (dataSize) {
|
|
+ case 1: traverseCoordinates1(vertexBuffer, attribute->byteStride(), drawVertexCount); break;
|
|
+ case 2: traverseCoordinates2(vertexBuffer, attribute->byteStride(), drawVertexCount); break;
|
|
+ case 3: traverseCoordinates3(vertexBuffer, attribute->byteStride(), drawVertexCount); break;
|
|
+ case 4: traverseCoordinates4(vertexBuffer, attribute->byteStride(), drawVertexCount); break;
|
|
+ default: Q_UNREACHABLE();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+protected:
|
|
+ template<typename VertexBufferType, typename IndexBufferType>
|
|
+ void traverseCoordinateIndexed(VertexBufferType *vertexBuffer,
|
|
+ IndexBufferType *indexBuffer,
|
|
+ int vertexByteStride,
|
|
+ int drawVertexCount,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+ {
|
|
+ switch (dataSize) {
|
|
+ case 1: traverseCoordinates1Indexed(vertexBuffer, vertexByteStride, indexBuffer, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ case 2: traverseCoordinates2Indexed(vertexBuffer, vertexByteStride, indexBuffer, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ case 3: traverseCoordinates3Indexed(vertexBuffer, vertexByteStride, indexBuffer, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ case 4: traverseCoordinates4Indexed(vertexBuffer, vertexByteStride, indexBuffer, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex);
|
|
+ break;
|
|
+ default: Q_UNREACHABLE();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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, typename IndexElem>
|
|
+ void traverseCoordinates1Indexed(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ IndexElem *indices,
|
|
+ const uint count,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+ {
|
|
+ const uint stride = byteStride / sizeof(Coordinate);
|
|
+ for (uint i = 0; i < count; ++i) {
|
|
+ if (!primitiveRestartEnabled || static_cast<int>(indices[i]) != primitiveRestartIndex) {
|
|
+ const uint n = stride * indices[i];
|
|
+ visit(i, coordinates[n]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ template <typename Coordinate>
|
|
+ void traverseCoordinates2(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ const uint count)
|
|
+ {
|
|
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2;
|
|
+ for (uint ndx = 0; ndx < count; ++ndx) {
|
|
+ visit(ndx, coordinates[0], coordinates[1]);
|
|
+ coordinates += stride;
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ template <typename Coordinate, typename IndexElem>
|
|
+ void traverseCoordinates2Indexed(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ IndexElem *indices,
|
|
+ const uint count,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+ {
|
|
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 2;
|
|
+ for (uint i = 0; i < count; ++i) {
|
|
+ if (!primitiveRestartEnabled || static_cast<int>(indices[i]) != primitiveRestartIndex) {
|
|
+ const uint n = stride * indices[i];
|
|
+ visit(i, coordinates[n], coordinates[n + 1]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ template <typename Coordinate>
|
|
+ void traverseCoordinates3(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ const uint count)
|
|
+ {
|
|
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3;
|
|
+ for (uint ndx = 0; ndx < count; ++ndx) {
|
|
+ visit(ndx, coordinates[0], coordinates[1], coordinates[2]);
|
|
+ coordinates += stride;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ template <typename Coordinate, typename IndexElem>
|
|
+ void traverseCoordinates3Indexed(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ IndexElem *indices,
|
|
+ const uint count,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+ {
|
|
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 3;
|
|
+ for (uint i = 0; i < count; ++i) {
|
|
+ if (!primitiveRestartEnabled || static_cast<int>(indices[i]) != primitiveRestartIndex) {
|
|
+ const uint n = stride * indices[i];
|
|
+ visit(i, coordinates[n], coordinates[n + 1], coordinates[n + 2]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ template <typename Coordinate>
|
|
+ void traverseCoordinates4(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ const uint count)
|
|
+ {
|
|
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4;
|
|
+ for (uint ndx = 0; ndx < count; ++ndx) {
|
|
+ visit(ndx, coordinates[0], coordinates[1], coordinates[2], coordinates[3]);
|
|
+ coordinates += stride;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ template <typename Coordinate, typename IndexElem>
|
|
+ void traverseCoordinates4Indexed(Coordinate *coordinates,
|
|
+ const uint byteStride,
|
|
+ IndexElem *indices,
|
|
+ const uint count,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+ {
|
|
+ const uint stride = byteStride ? byteStride / sizeof(Coordinate) : 4;
|
|
+ for (uint i = 0; i < count; ++i) {
|
|
+ if (!primitiveRestartEnabled || static_cast<int>(indices[i]) != primitiveRestartIndex) {
|
|
+ const uint n = stride * indices[i];
|
|
+ visit(i, coordinates[n], coordinates[n + 1], coordinates[n + 2], coordinates[n + 3]);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+};
|
|
+
|
|
+typedef BufferVisitor<float, Qt3DCore::QAttribute::Float, 3> Buffer3fVisitor;
|
|
+
|
|
+} // namespace Qt3DCore
|
|
+
|
|
+QT_END_NAMESPACE
|
|
+
|
|
+
|
|
+#endif // QT3DCORE_BUFFERVISITOR_P_H
|
|
diff --git a/src/core/geometry/geometry.pri b/src/core/geometry/geometry.pri
|
|
index eadf7ca..70bda07 100644 (file)
|
|
--- a/src/core/geometry/geometry.pri
|
|
+++ b/src/core/geometry/geometry.pri
|
|
@@ -12,7 +12,9 @@ HEADERS += \
|
|
$$PWD/qgeometry.h \
|
|
$$PWD/qgeometryfactory_p.h \
|
|
$$PWD/qgeometryview_p.h \
|
|
- $$PWD/qgeometryview.h
|
|
+ $$PWD/qgeometryview.h \
|
|
+ $$PWD/bufferutils_p.h \
|
|
+ $$PWD/buffervisitor_p.h
|
|
|
|
SOURCES += \
|
|
$$PWD/qabstractfunctor.cpp \
|
|
diff --git a/src/core/geometry/qgeometry_p.h b/src/core/geometry/qgeometry_p.h
|
|
index 2a05b5b..ed13b3f 100644 (file)
|
|
--- a/src/core/geometry/qgeometry_p.h
|
|
+++ b/src/core/geometry/qgeometry_p.h
|
|
@@ -72,7 +72,6 @@ public:
|
|
void setScene(QScene *scene) override;
|
|
void update() override;
|
|
void setExtent(const QVector3D &minExtent, const QVector3D &maxExtent);
|
|
-
|
|
static QGeometryPrivate *get(QGeometry *q);
|
|
|
|
QVector<QAttribute *> m_attributes;
|
|
diff --git a/src/core/geometry/qgeometryview.cpp b/src/core/geometry/qgeometryview.cpp
|
|
index 65e30d9..258448b 100644 (file)
|
|
--- a/src/core/geometry/qgeometryview.cpp
|
|
+++ b/src/core/geometry/qgeometryview.cpp
|
|
@@ -39,11 +39,250 @@
|
|
|
|
#include "qgeometryview.h"
|
|
#include "qgeometryview_p.h"
|
|
+#include "qgeometry_p.h"
|
|
+#include "buffervisitor_p.h"
|
|
+
|
|
+#include <Qt3DCore/QAttribute>
|
|
+#include <Qt3DCore/QBuffer>
|
|
+#include <Qt3DCore/private/vector3d_p.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
using namespace Qt3DCore;
|
|
|
|
+namespace {
|
|
+
|
|
+class FindExtremePoints : public Buffer3fVisitor
|
|
+{
|
|
+public:
|
|
+ FindExtremePoints()
|
|
+ : Buffer3fVisitor()
|
|
+ , 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;
|
|
+ Vector3D 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 = Vector3D(x, y, z);
|
|
+ }
|
|
+ if (x > xMax) {
|
|
+ xMax = x;
|
|
+ xMaxPt = Vector3D(x, y, z);
|
|
+ }
|
|
+ if (y < yMin) {
|
|
+ yMin = y;
|
|
+ yMinPt = Vector3D(x, y, z);
|
|
+ }
|
|
+ if (y > yMax) {
|
|
+ yMax = y;
|
|
+ yMaxPt = Vector3D(x, y, z);
|
|
+ }
|
|
+ if (z < zMin) {
|
|
+ zMin = z;
|
|
+ zMinPt = Vector3D(x, y, z);
|
|
+ }
|
|
+ if (z > zMax) {
|
|
+ zMax = z;
|
|
+ zMaxPt = Vector3D(x, y, z);
|
|
+ }
|
|
+ } else {
|
|
+ xMin = xMax = x;
|
|
+ yMin = yMax = y;
|
|
+ zMin = zMax = z;
|
|
+ xMinPt = xMaxPt = yMinPt = yMaxPt = zMinPt = zMaxPt = Vector3D(x, y, z);
|
|
+ }
|
|
+ }
|
|
+};
|
|
+
|
|
+class FindMaxDistantPoint : public Buffer3fVisitor
|
|
+{
|
|
+public:
|
|
+ FindMaxDistantPoint()
|
|
+ : Buffer3fVisitor()
|
|
+ { }
|
|
+
|
|
+ float maxLengthSquared = 0.0f;
|
|
+ bool setReferencePoint = false;
|
|
+ bool hasNoPoints = true;
|
|
+ Vector3D maxDistPt;
|
|
+ Vector3D referencePt;
|
|
+
|
|
+ void visit(uint ndx, float x, float y, float z) override
|
|
+ {
|
|
+ Q_UNUSED(ndx)
|
|
+ const Vector3D p = Vector3D(x, y, z);
|
|
+
|
|
+ if (hasNoPoints && setReferencePoint) {
|
|
+ maxLengthSquared = 0.0f;
|
|
+ referencePt = p;
|
|
+ }
|
|
+ const float lengthSquared = (p - referencePt).lengthSquared();
|
|
+ if ( lengthSquared >= maxLengthSquared ) {
|
|
+ maxDistPt = p;
|
|
+ maxLengthSquared = lengthSquared;
|
|
+ }
|
|
+ hasNoPoints = false;
|
|
+ }
|
|
+};
|
|
+
|
|
+std::pair<QVector3D, QVector3D> calculateLocalBoundingVolume(QGeometryView *node)
|
|
+{
|
|
+ // The Bounding volume will only be computed if the position Buffer
|
|
+ // isDirty
|
|
+
|
|
+ if (!node->isEnabled())
|
|
+ return {};
|
|
+
|
|
+ if (node->primitiveType() == QGeometryView::Patches)
|
|
+ return {};
|
|
+
|
|
+ QGeometry *geom = node->geometry();
|
|
+ QGeometryPrivate *dgeom = QGeometryPrivate::get(geom);
|
|
+
|
|
+ if (!geom)
|
|
+ return {};
|
|
+
|
|
+ int drawVertexCount = node->vertexCount(); // may be 0, gets changed below if so
|
|
+
|
|
+ QAttribute *positionAttribute = dgeom->m_boundingVolumePositionAttribute;
|
|
+ const QVector<Qt3DCore::QAttribute *> attributes = geom->attributes();
|
|
+
|
|
+ // Use the default position attribute if attribute is null
|
|
+ if (!positionAttribute) {
|
|
+ for (QAttribute *attr : attributes) {
|
|
+ if (attr->name() == QAttribute::defaultPositionAttributeName()) {
|
|
+ positionAttribute = attr;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!positionAttribute
|
|
+ || positionAttribute->attributeType() != QAttribute::VertexAttribute
|
|
+ || positionAttribute->vertexBaseType() != QAttribute::Float
|
|
+ || positionAttribute->vertexSize() < 3) {
|
|
+ qWarning("calculateLocalBoundingVolume: Position attribute not suited for bounding volume computation");
|
|
+ return {};
|
|
+ }
|
|
+
|
|
+ Qt3DCore::QBuffer *buf = positionAttribute->buffer();
|
|
+ // No point in continuing if the positionAttribute doesn't have a suitable buffer
|
|
+ if (!buf) {
|
|
+ qWarning("calculateLocalBoundingVolume: Position attribute not referencing a valid buffer");
|
|
+ return {};
|
|
+ }
|
|
+
|
|
+ // Check if there is an index attribute.
|
|
+ QAttribute *indexAttribute = nullptr;
|
|
+ Qt3DCore::QBuffer *indexBuf = nullptr;
|
|
+
|
|
+ for (const auto attr : attributes) {
|
|
+ if (attr->attributeType() == QAttribute::IndexAttribute) {
|
|
+ indexBuf = attr->buffer();
|
|
+ if (indexBuf) {
|
|
+ indexAttribute = attr;
|
|
+
|
|
+ if (!drawVertexCount)
|
|
+ drawVertexCount = static_cast<int>(indexAttribute->count());
|
|
+
|
|
+ static const QAttribute::VertexBaseType validIndexTypes[] = {
|
|
+ QAttribute::UnsignedShort,
|
|
+ QAttribute::UnsignedInt,
|
|
+ QAttribute::UnsignedByte
|
|
+ };
|
|
+
|
|
+ if (std::find(std::begin(validIndexTypes),
|
|
+ std::end(validIndexTypes),
|
|
+ indexAttribute->vertexBaseType()) == std::end(validIndexTypes)) {
|
|
+ qWarning() << "calculateLocalBoundingVolume: Unsupported index attribute type" << indexAttribute->name() << indexAttribute->vertexBaseType();
|
|
+ return {};
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!indexAttribute && !drawVertexCount)
|
|
+ drawVertexCount = static_cast<int>(positionAttribute->count());
|
|
+
|
|
+ // 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
|
|
+ BoundingVolumeCalculator reader;
|
|
+ if (reader.apply(positionAttribute, indexAttribute, drawVertexCount,
|
|
+ node->primitiveRestartEnabled(), node->restartIndexValue()))
|
|
+ return {reader.min(), reader.max()};
|
|
+
|
|
+ return {};
|
|
+}
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+bool BoundingVolumeCalculator::apply(QAttribute *positionAttribute,
|
|
+ QAttribute *indexAttribute,
|
|
+ int drawVertexCount,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex)
|
|
+{
|
|
+ m_radius = -1.f;
|
|
+
|
|
+ FindExtremePoints findExtremePoints;
|
|
+ if (!findExtremePoints.apply(positionAttribute, indexAttribute, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex)) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ m_min = QVector3D(findExtremePoints.xMin, findExtremePoints.yMin, findExtremePoints.zMin);
|
|
+ m_max = QVector3D(findExtremePoints.xMax, findExtremePoints.yMax, findExtremePoints.zMax);
|
|
+
|
|
+ FindMaxDistantPoint maxDistantPointY;
|
|
+ maxDistantPointY.setReferencePoint = true;
|
|
+ if (!maxDistantPointY.apply(positionAttribute, indexAttribute, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex)) {
|
|
+ return false;
|
|
+ }
|
|
+ if (maxDistantPointY.hasNoPoints)
|
|
+ return false;
|
|
+
|
|
+ //const Vector3D x = maxDistantPointY.referencePt;
|
|
+ const Vector3D y = maxDistantPointY.maxDistPt;
|
|
+
|
|
+ FindMaxDistantPoint maxDistantPointZ;
|
|
+ maxDistantPointZ.setReferencePoint = false;
|
|
+ maxDistantPointZ.referencePt = y;
|
|
+ if (!maxDistantPointZ.apply(positionAttribute, indexAttribute, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex))
|
|
+ return false;
|
|
+ const Vector3D z = maxDistantPointZ.maxDistPt;
|
|
+ const Vector3D center = (y + z) * .5f;
|
|
+
|
|
+ FindMaxDistantPoint maxDistantPointCenter;
|
|
+ maxDistantPointCenter.setReferencePoint = false;
|
|
+ maxDistantPointCenter.referencePt = center;
|
|
+ if (!maxDistantPointCenter.apply(positionAttribute, indexAttribute, drawVertexCount,
|
|
+ primitiveRestartEnabled, primitiveRestartIndex))
|
|
+ return false;
|
|
+
|
|
+ const float radius = (center - maxDistantPointCenter.maxDistPt).length();
|
|
+
|
|
+ if (center == Vector3D{} || radius < 0.f)
|
|
+ return false;
|
|
+
|
|
+ m_radius = radius;
|
|
+ m_center = QVector3D{ center.x(), center.y(), center.z() };
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
QGeometryViewPrivate::QGeometryViewPrivate()
|
|
: QNodePrivate()
|
|
, m_instanceCount(1)
|
|
@@ -65,6 +304,11 @@ QGeometryViewPrivate::~QGeometryViewPrivate()
|
|
{
|
|
}
|
|
|
|
+QGeometryViewPrivate *QGeometryViewPrivate::get(QGeometryView *q)
|
|
+{
|
|
+ return q->d_func();
|
|
+}
|
|
+
|
|
void QGeometryViewPrivate::update()
|
|
{
|
|
if (!m_blockNotifications)
|
|
diff --git a/src/core/geometry/qgeometryview_p.h b/src/core/geometry/qgeometryview_p.h
|
|
index f806c4d..05dea1d 100644 (file)
|
|
--- a/src/core/geometry/qgeometryview_p.h
|
|
+++ b/src/core/geometry/qgeometryview_p.h
|
|
@@ -55,6 +55,8 @@
|
|
#include <Qt3DCore/qgeometryview.h>
|
|
#include <Qt3DCore/private/qgeometryfactory_p.h>
|
|
#include <Qt3DCore/private/qt3dcore_global_p.h>
|
|
+
|
|
+#include <QtGui/qvector3d.h>
|
|
#include <memory>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
@@ -67,6 +69,8 @@ public:
|
|
QGeometryViewPrivate();
|
|
~QGeometryViewPrivate();
|
|
|
|
+ static QGeometryViewPrivate *get(QGeometryView *q);
|
|
+
|
|
void update() override;
|
|
|
|
Q_DECLARE_PUBLIC(QGeometryView)
|
|
@@ -85,6 +89,30 @@ public:
|
|
bool m_dirty;
|
|
};
|
|
|
|
+class BoundingVolumeCalculator
|
|
+{
|
|
+public:
|
|
+ BoundingVolumeCalculator() = default;
|
|
+
|
|
+ const QVector3D min() const { return m_min; }
|
|
+ const QVector3D max() const { return m_max; }
|
|
+ const QVector3D center() const { return m_center; }
|
|
+ float radius() const { return m_radius; }
|
|
+ bool isValid() const { return m_radius >= 0.f; }
|
|
+
|
|
+ bool apply(QAttribute *positionAttribute,
|
|
+ QAttribute *indexAttribute,
|
|
+ int drawVertexCount,
|
|
+ bool primitiveRestartEnabled,
|
|
+ int primitiveRestartIndex);
|
|
+
|
|
+private:
|
|
+ QVector3D m_min;
|
|
+ QVector3D m_max;
|
|
+ QVector3D m_center;
|
|
+ float m_radius = -1.f;
|
|
+};
|
|
+
|
|
} // namespace Qt3DCore
|
|
|
|
QT_END_NAMESPACE
|
|
diff --git a/src/core/jobs/calcboundingvolumejob.cpp b/src/core/jobs/calcboundingvolumejob.cpp
|
|
new file mode 100644 (file)
|
|
index 0000000..37ee92e
|
|
--- /dev/null
|
|
+++ b/src/core/jobs/calcboundingvolumejob.cpp
|
|
@@ -0,0 +1,317 @@
|
|
+/****************************************************************************
|
|
+**
|
|
+** Copyright (C) 2020 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 "calcboundingvolumejob_p.h"
|
|
+
|
|
+#include <Qt3DCore/qattribute.h>
|
|
+#include <Qt3DCore/qboundingvolume.h>
|
|
+#include <Qt3DCore/qbuffer.h>
|
|
+#include <Qt3DCore/qgeometryview.h>
|
|
+#include <Qt3DCore/private/job_common_p.h>
|
|
+#include <Qt3DCore/private/qaspectjob_p.h>
|
|
+#include <Qt3DCore/private/qaspectmanager_p.h>
|
|
+#include <Qt3DCore/private/qattribute_p.h>
|
|
+#include <Qt3DCore/private/qboundingvolume_p.h>
|
|
+#include <Qt3DCore/private/qbuffer_p.h>
|
|
+#include <Qt3DCore/private/qentity_p.h>
|
|
+#include <Qt3DCore/private/qgeometry_p.h>
|
|
+#include <Qt3DCore/private/qgeometryview_p.h>
|
|
+#include <Qt3DCore/private/qnodevisitor_p.h>
|
|
+
|
|
+#include <QtCore/qmath.h>
|
|
+#if QT_CONFIG(concurrent)
|
|
+#include <QtConcurrent/QtConcurrent>
|
|
+#endif
|
|
+
|
|
+QT_BEGIN_NAMESPACE
|
|
+
|
|
+namespace Qt3DCore {
|
|
+
|
|
+namespace {
|
|
+
|
|
+BoundingVolumeComputeData findBoundingVolumeComputeData(QGeometryView *node)
|
|
+{
|
|
+ if (!node->isEnabled())
|
|
+ return {};
|
|
+
|
|
+ if (node->primitiveType() == QGeometryView::Patches)
|
|
+ return {};
|
|
+
|
|
+ QGeometry *geom = node->geometry();
|
|
+ QGeometryPrivate *dgeom = QGeometryPrivate::get(geom);
|
|
+ if (!geom)
|
|
+ return {};
|
|
+
|
|
+ int drawVertexCount = node->vertexCount(); // may be 0, gets changed below if so
|
|
+
|
|
+ QAttribute *positionAttribute = dgeom->m_boundingVolumePositionAttribute;
|
|
+ const QVector<Qt3DCore::QAttribute *> attributes = geom->attributes();
|
|
+
|
|
+ // Use the default position attribute if attribute is null
|
|
+ if (!positionAttribute) {
|
|
+ for (QAttribute *attr : attributes) {
|
|
+ if (attr->name() == QAttribute::defaultPositionAttributeName()) {
|
|
+ positionAttribute = attr;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!positionAttribute
|
|
+ || positionAttribute->attributeType() != QAttribute::VertexAttribute
|
|
+ || positionAttribute->vertexBaseType() != QAttribute::Float
|
|
+ || positionAttribute->vertexSize() < 3) {
|
|
+ qWarning("findBoundingVolumeComputeData: Position attribute not suited for bounding volume computation");
|
|
+ return {};
|
|
+ }
|
|
+
|
|
+ Qt3DCore::QBuffer *positionBuffer = positionAttribute->buffer();
|
|
+ // No point in continuing if the positionAttribute doesn't have a suitable buffer
|
|
+ if (!positionBuffer) {
|
|
+ qWarning("findBoundingVolumeComputeData: Position attribute not referencing a valid buffer");
|
|
+ return {};
|
|
+ }
|
|
+
|
|
+ // Check if there is an index attribute.
|
|
+ QAttribute *indexAttribute = nullptr;
|
|
+ Qt3DCore::QBuffer *indexBuffer = nullptr;
|
|
+
|
|
+ for (const auto attr : attributes) {
|
|
+ if (attr->attributeType() == QAttribute::IndexAttribute) {
|
|
+ indexBuffer = attr->buffer();
|
|
+ if (indexBuffer) {
|
|
+ indexAttribute = attr;
|
|
+
|
|
+ if (!drawVertexCount)
|
|
+ drawVertexCount = static_cast<int>(indexAttribute->count());
|
|
+
|
|
+ static const QAttribute::VertexBaseType validIndexTypes[] = {
|
|
+ QAttribute::UnsignedShort,
|
|
+ QAttribute::UnsignedInt,
|
|
+ QAttribute::UnsignedByte
|
|
+ };
|
|
+
|
|
+ if (std::find(std::begin(validIndexTypes),
|
|
+ std::end(validIndexTypes),
|
|
+ indexAttribute->vertexBaseType()) == std::end(validIndexTypes)) {
|
|
+ qWarning() << "findBoundingVolumeComputeData: Unsupported index attribute type" << indexAttribute->name() << indexAttribute->vertexBaseType();
|
|
+ return {};
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!indexAttribute && !drawVertexCount)
|
|
+ drawVertexCount = static_cast<int>(positionAttribute->count());
|
|
+
|
|
+ return { nullptr, nullptr, positionAttribute, indexAttribute, drawVertexCount };
|
|
+}
|
|
+
|
|
+BoundingVolumeComputeResult calculateLocalBoundingVolume(const BoundingVolumeComputeData &data) {
|
|
+ BoundingVolumeCalculator calculator;
|
|
+ if (calculator.apply(data.positionAttribute, data.indexAttribute, data.vertexCount,
|
|
+ data.provider->view()->primitiveRestartEnabled(),
|
|
+ data.provider->view()->restartIndexValue()))
|
|
+ return {
|
|
+ data.entity, data.provider, data.positionAttribute, data.indexAttribute,
|
|
+ calculator.min(), calculator.max(),
|
|
+ calculator.center(), calculator.radius()
|
|
+ };
|
|
+ return {};
|
|
+}
|
|
+
|
|
+bool isTreeEnabled(QEntity *entity) {
|
|
+ if (!entity->isEnabled())
|
|
+ return false;
|
|
+
|
|
+ QEntity *parent = entity->parentEntity();
|
|
+ while (parent) {
|
|
+ if (!parent->isEnabled())
|
|
+ return false;
|
|
+ parent = parent->parentEntity();
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+struct UpdateBoundFunctor
|
|
+{
|
|
+ // This define is required to work with QtConcurrent
|
|
+ typedef QVector<BoundingVolumeComputeResult> result_type;
|
|
+ result_type operator ()(const BoundingVolumeComputeData &data)
|
|
+ {
|
|
+ return { calculateLocalBoundingVolume(data) };
|
|
+ }
|
|
+};
|
|
+
|
|
+struct ReduceUpdateBoundFunctor
|
|
+{
|
|
+ void operator ()(QVector<BoundingVolumeComputeResult> &result, const QVector<BoundingVolumeComputeResult> &values)
|
|
+ {
|
|
+ result += values;
|
|
+ }
|
|
+};
|
|
+
|
|
+} // anonymous
|
|
+
|
|
+//class CalculateBoundingVolumeJobPrivate : public Qt3DCore::QAspectJobPrivate
|
|
+//{
|
|
+//public:
|
|
+// CalculateBoundingVolumeJobPrivate() { }
|
|
+// ~CalculateBoundingVolumeJobPrivate() override { }
|
|
+
|
|
+// void postFrame(Qt3DCore::QAspectManager *manager) override
|
|
+// {
|
|
+// Q_UNUSED(manager)
|
|
+//// for (Geometry *backend : qAsConst(m_updatedGeometries)) {
|
|
+//// Qt3DCore::QGeometry *node = qobject_cast<Qt3DCore::QGeometry *>(manager->lookupNode(backend->peerId()));
|
|
+//// if (!node)
|
|
+//// continue;
|
|
+//// Qt3DCore::QGeometryPrivate *dNode = static_cast<Qt3DCore::QGeometryPrivate *>(Qt3DCore::QNodePrivate::get(node));
|
|
+//// dNode->setExtent(backend->min(), backend->max());
|
|
+//// }
|
|
+// }
|
|
+
|
|
+//};
|
|
+
|
|
+CalculateBoundingVolumeJob::CalculateBoundingVolumeJob()
|
|
+ : Qt3DCore::QAspectJob()
|
|
+ , m_root(nullptr)
|
|
+{
|
|
+ SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0)
|
|
+}
|
|
+
|
|
+void CalculateBoundingVolumeJob::run()
|
|
+{
|
|
+ m_results.clear();
|
|
+
|
|
+ QHash<QEntity *, BoundingVolumeComputeData> dirtyEntities;
|
|
+ QNodeVisitor visitor;
|
|
+ visitor.traverse(m_root, [](QNode *) {}, [&dirtyEntities](QEntity *entity) {
|
|
+ if (!isTreeEnabled(entity))
|
|
+ return;
|
|
+
|
|
+ const auto bvProviders = entity->componentsOfType<QBoundingVolume>();
|
|
+ if (bvProviders.isEmpty())
|
|
+ return;
|
|
+
|
|
+ // we go through the list until be find a dirty provider,
|
|
+ // or THE primary provider
|
|
+ bool foundBV = false;
|
|
+ for (auto bv: bvProviders) {
|
|
+ if (!bv->view())
|
|
+ continue;
|
|
+ auto dbv = QBoundingVolumePrivate::get(bv);
|
|
+ if (foundBV && !dbv->m_primaryProvider)
|
|
+ continue;
|
|
+
|
|
+ auto bvdata = findBoundingVolumeComputeData(bv->view());
|
|
+ if (!bvdata.valid())
|
|
+ continue;
|
|
+ bvdata.entity = entity;
|
|
+ bvdata.provider = bv;
|
|
+
|
|
+ bool dirty = QEntityPrivate::get(entity)->m_dirty;
|
|
+ dirty |= QGeometryViewPrivate::get(bv->view())->m_dirty;
|
|
+ dirty |= QGeometryPrivate::get(bv->view()->geometry())->m_dirty;
|
|
+ dirty |= QAttributePrivate::get(bvdata.positionAttribute)->m_dirty;
|
|
+ dirty |= QBufferPrivate::get(bvdata.positionAttribute->buffer())->m_dirty;
|
|
+ if (bvdata.indexAttribute) {
|
|
+ dirty |= QAttributePrivate::get(bvdata.indexAttribute)->m_dirty;
|
|
+ dirty |= QBufferPrivate::get(bvdata.indexAttribute->buffer())->m_dirty;
|
|
+ }
|
|
+
|
|
+ if (dbv->m_primaryProvider) {
|
|
+ if (dirty)
|
|
+ dirtyEntities[entity] = bvdata;
|
|
+ break;
|
|
+ } else if (dirty) {
|
|
+ dirtyEntities[entity] = bvdata;
|
|
+ foundBV = true;
|
|
+ }
|
|
+ }
|
|
+ });
|
|
+
|
|
+#if QT_CONFIG(concurrent)
|
|
+ if (dirtyEntities.size() > 1) {
|
|
+ UpdateBoundFunctor functor;
|
|
+ ReduceUpdateBoundFunctor reduceFunctor;
|
|
+ m_results = QtConcurrent::blockingMappedReduced<decltype(m_results)>(dirtyEntities, functor, reduceFunctor);
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ for (auto it = dirtyEntities.begin(); it != dirtyEntities.end(); ++it) {
|
|
+ auto res = calculateLocalBoundingVolume(it.value());
|
|
+ if (res.valid())
|
|
+ m_results.push_back(res); // How do we push it to the backends????
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (auto result: qAsConst(m_results)) {
|
|
+ // set the results
|
|
+ QBoundingVolumePrivate::get(result.provider)->setImplicitBounds(result.m_min, result.m_max, result.m_center, result.m_radius);
|
|
+ }
|
|
+}
|
|
+
|
|
+void CalculateBoundingVolumeJob::postFrame(QAspectEngine *aspectEngine)
|
|
+{
|
|
+ Q_UNUSED(aspectEngine)
|
|
+
|
|
+ for (auto result: qAsConst(m_results)) {
|
|
+ // reset dirty flags
|
|
+ QEntityPrivate::get(result.entity)->m_dirty = false;
|
|
+ QGeometryViewPrivate::get(result.provider->view())->m_dirty = false;
|
|
+ QGeometryPrivate::get(result.provider->view()->geometry())->m_dirty = false;
|
|
+ QAttributePrivate::get(result.positionAttribute)->m_dirty = false;
|
|
+ QBufferPrivate::get(result.positionAttribute->buffer())->m_dirty = false;
|
|
+ if (result.indexAttribute) {
|
|
+ QAttributePrivate::get(result.indexAttribute)->m_dirty = false;
|
|
+ QBufferPrivate::get(result.indexAttribute->buffer())->m_dirty = false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ m_results.clear();
|
|
+}
|
|
+
|
|
+} // namespace Qt3DCore
|
|
+
|
|
+QT_END_NAMESPACE
|
|
+
|
|
diff --git a/src/core/jobs/calcboundingvolumejob_p.h b/src/core/jobs/calcboundingvolumejob_p.h
|
|
new file mode 100644 (file)
|
|
index 0000000..498fe76
|
|
--- /dev/null
|
|
+++ b/src/core/jobs/calcboundingvolumejob_p.h
|
|
@@ -0,0 +1,113 @@
|
|
+/****************************************************************************
|
|
+**
|
|
+** Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
|
|
+** Contact: https://www.qt.io/licensing/
|
|
+**
|
|
+** This file is part of the Qt3D module of the Qt Toolkit.
|
|
+**
|
|
+** $QT_BEGIN_LICENSE:LGPL$
|
|
+** Commercial License Usage
|
|
+** Licensees holding valid commercial Qt licenses may use this file in
|
|
+** accordance with the commercial license agreement provided with the
|
|
+** Software or, alternatively, in accordance with the terms contained in
|
|
+** a written agreement between you and The Qt Company. For licensing terms
|
|
+** and conditions see https://www.qt.io/terms-conditions. For further
|
|
+** information use the contact form at https://www.qt.io/contact-us.
|
|
+**
|
|
+** GNU Lesser General Public License Usage
|
|
+** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
+** General Public License version 3 as published by the Free Software
|
|
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
+** packaging of this file. Please review the following information to
|
|
+** ensure the GNU Lesser General Public License version 3 requirements
|
|
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
+**
|
|
+** GNU General Public License Usage
|
|
+** Alternatively, this file may be used under the terms of the GNU
|
|
+** General Public License version 2.0 or (at your option) the GNU General
|
|
+** Public license version 3 or any later version approved by the KDE Free
|
|
+** Qt Foundation. The licenses are as published by the Free Software
|
|
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
+** included in the packaging of this file. Please review the following
|
|
+** information to ensure the GNU General Public License requirements will
|
|
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
+** https://www.gnu.org/licenses/gpl-3.0.html.
|
|
+**
|
|
+** $QT_END_LICENSE$
|
|
+**
|
|
+****************************************************************************/
|
|
+
|
|
+#ifndef QT3DCORE_CALCBOUNDINGVOLUMEJOB_H
|
|
+#define QT3DCORE_CALCBOUNDINGVOLUMEJOB_H
|
|
+
|
|
+//
|
|
+// W A R N I N G
|
|
+// -------------
|
|
+//
|
|
+// This file is not part of the Qt API. It exists purely as an
|
|
+// implementation detail. This header file may change from version to
|
|
+// version without notice, or even be removed.
|
|
+//
|
|
+// We mean it.
|
|
+//
|
|
+
|
|
+#include <Qt3DCore/qaspectjob.h>
|
|
+#include <Qt3DCore/private/qt3dcore_global_p.h>
|
|
+
|
|
+#include <QtCore/QSharedPointer>
|
|
+#include <QtGui/qvector3d.h>
|
|
+
|
|
+QT_BEGIN_NAMESPACE
|
|
+
|
|
+namespace Qt3DCore {
|
|
+
|
|
+class CalculateBoundingVolumeJobPrivate;
|
|
+class QEntity;
|
|
+class QAttribute;
|
|
+class QBoundingVolume;
|
|
+
|
|
+struct BoundingVolumeComputeData {
|
|
+ QEntity *entity = nullptr;
|
|
+ QBoundingVolume *provider = nullptr;
|
|
+ QAttribute *positionAttribute = nullptr;
|
|
+ QAttribute *indexAttribute = nullptr;
|
|
+ int vertexCount = 0;
|
|
+
|
|
+ bool valid() const { return positionAttribute != nullptr; }
|
|
+};
|
|
+
|
|
+struct BoundingVolumeComputeResult {
|
|
+ QEntity *entity = nullptr;
|
|
+ QBoundingVolume *provider = nullptr;
|
|
+ QAttribute *positionAttribute = nullptr;
|
|
+ QAttribute *indexAttribute = nullptr;
|
|
+ QVector3D m_min;
|
|
+ QVector3D m_max;
|
|
+ QVector3D m_center;
|
|
+ float m_radius = -1.f;
|
|
+
|
|
+ bool valid() const { return m_radius >= 0.f; }
|
|
+};
|
|
+
|
|
+class Q_3DCORE_PRIVATE_EXPORT CalculateBoundingVolumeJob : public Qt3DCore::QAspectJob
|
|
+{
|
|
+public:
|
|
+ explicit CalculateBoundingVolumeJob();
|
|
+
|
|
+ void setRoot(QEntity *root) { m_root = root; }
|
|
+ void run() override;
|
|
+ void postFrame(QAspectEngine *aspectEngine) override;
|
|
+
|
|
+private:
|
|
+ Q_DECLARE_PRIVATE(CalculateBoundingVolumeJob)
|
|
+ QEntity *m_root;
|
|
+ QVector<BoundingVolumeComputeResult> m_results;
|
|
+};
|
|
+
|
|
+typedef QSharedPointer<CalculateBoundingVolumeJob> CalculateBoundingVolumeJobPtr;
|
|
+
|
|
+} // namespace Qt3DCore
|
|
+
|
|
+QT_END_NAMESPACE
|
|
+
|
|
+#endif // QT3DCORE_CALCBOUNDINGVOLUMEJOB_H
|
|
diff --git a/src/core/jobs/job_common_p.h b/src/core/jobs/job_common_p.h
|
|
new file mode 100644 (file)
|
|
index 0000000..6cbf178
|
|
--- /dev/null
|
|
+++ b/src/core/jobs/job_common_p.h
|
|
@@ -0,0 +1,73 @@
|
|
+/****************************************************************************
|
|
+**
|
|
+** Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
|
|
+** Contact: https://www.qt.io/licensing/
|
|
+**
|
|
+** This file is part of the Qt3D module of the Qt Toolkit.
|
|
+**
|
|
+** $QT_BEGIN_LICENSE:LGPL$
|
|
+** Commercial License Usage
|
|
+** Licensees holding valid commercial Qt licenses may use this file in
|
|
+** accordance with the commercial license agreement provided with the
|
|
+** Software or, alternatively, in accordance with the terms contained in
|
|
+** a written agreement between you and The Qt Company. For licensing terms
|
|
+** and conditions see https://www.qt.io/terms-conditions. For further
|
|
+** information use the contact form at https://www.qt.io/contact-us.
|
|
+**
|
|
+** GNU Lesser General Public License Usage
|
|
+** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
+** General Public License version 3 as published by the Free Software
|
|
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
+** packaging of this file. Please review the following information to
|
|
+** ensure the GNU Lesser General Public License version 3 requirements
|
|
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
+**
|
|
+** GNU General Public License Usage
|
|
+** Alternatively, this file may be used under the terms of the GNU
|
|
+** General Public License version 2.0 or (at your option) the GNU General
|
|
+** Public license version 3 or any later version approved by the KDE Free
|
|
+** Qt Foundation. The licenses are as published by the Free Software
|
|
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
+** included in the packaging of this file. Please review the following
|
|
+** information to ensure the GNU General Public License requirements will
|
|
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
+** https://www.gnu.org/licenses/gpl-3.0.html.
|
|
+**
|
|
+** $QT_END_LICENSE$
|
|
+**
|
|
+****************************************************************************/
|
|
+
|
|
+#ifndef QT3DCORE_JOB_COMMON_P_H
|
|
+#define QT3DCORE_JOB_COMMON_P_H
|
|
+
|
|
+//
|
|
+// W A R N I N G
|
|
+// -------------
|
|
+//
|
|
+// This file is not part of the Qt API. It exists purely as an
|
|
+// implementation detail. This header file may change from version to
|
|
+// version without notice, or even be removed.
|
|
+//
|
|
+// We mean it.
|
|
+//
|
|
+
|
|
+#include <Qt3DCore/private/qaspectjob_p.h>
|
|
+
|
|
+QT_BEGIN_NAMESPACE
|
|
+
|
|
+namespace Qt3DCore {
|
|
+
|
|
+namespace JobTypes {
|
|
+
|
|
+ enum JobType {
|
|
+ LoadBuffer = 4096,
|
|
+ CalcBoundingVolume,
|
|
+ };
|
|
+
|
|
+} // JobTypes
|
|
+
|
|
+} // Qt3DCore
|
|
+
|
|
+QT_END_NAMESPACE
|
|
+
|
|
+#endif // QT3DCORE_JOB_COMMON_P_H
|
|
diff --git a/src/core/jobs/jobs.pri b/src/core/jobs/jobs.pri
|
|
index 5d262f5..a045339 100644 (file)
|
|
--- a/src/core/jobs/jobs.pri
|
|
+++ b/src/core/jobs/jobs.pri
|
|
@@ -4,7 +4,8 @@ SOURCES += \
|
|
$$PWD/qaspectjobmanager.cpp \
|
|
$$PWD/qabstractaspectjobmanager.cpp \
|
|
$$PWD/qthreadpooler.cpp \
|
|
- $$PWD/task.cpp
|
|
+ $$PWD/task.cpp \
|
|
+ $$PWD/calcboundingvolumejob.cpp
|
|
|
|
HEADERS += \
|
|
$$PWD/qaspectjob.h \
|
|
@@ -13,7 +14,9 @@ HEADERS += \
|
|
$$PWD/qaspectjobmanager_p.h \
|
|
$$PWD/qabstractaspectjobmanager_p.h \
|
|
$$PWD/task_p.h \
|
|
- $$PWD/qthreadpooler_p.h
|
|
+ $$PWD/qthreadpooler_p.h \
|
|
+ $$PWD/calcboundingvolumejob_p.h \
|
|
+ $$PWD/job_common_p.h
|
|
|
|
INCLUDEPATH += $$PWD
|