summaryrefslogtreecommitdiffstats
path: root/src/render/geometry
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/geometry')
-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
10 files changed, 288 insertions, 52 deletions
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;
};