diff options
Diffstat (limited to 'src/render/geometry')
-rw-r--r-- | src/render/geometry/attribute.cpp | 2 | ||||
-rw-r--r-- | src/render/geometry/buffer.cpp | 44 | ||||
-rw-r--r-- | src/render/geometry/buffer_p.h | 6 | ||||
-rw-r--r-- | src/render/geometry/geometryrenderer.cpp | 2 | ||||
-rw-r--r-- | src/render/geometry/qbuffer.cpp | 40 | ||||
-rw-r--r-- | src/render/geometry/qbuffer.h | 12 | ||||
-rw-r--r-- | src/render/geometry/qbuffer_p.h | 2 | ||||
-rw-r--r-- | src/render/geometry/qgeometry.cpp | 16 | ||||
-rw-r--r-- | src/render/geometry/qmesh.cpp | 190 | ||||
-rw-r--r-- | src/render/geometry/qmesh_p.h | 26 |
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; }; |