diff options
author | Jere Tuliniemi <jere.tuliniemi@qt.io> | 2019-09-10 11:00:57 +0300 |
---|---|---|
committer | Jere Tuliniemi <jere.tuliniemi@qt.io> | 2019-09-17 12:35:55 +0300 |
commit | fe29ee5c5b0c1edbfabccf211bd8d73bb61672dc (patch) | |
tree | 21fb79747816ff315ed0f5526321bea2e616b326 | |
parent | ef8b07e32a9ecc8375c1031ba5c7119ac75b81f0 (diff) |
Support QQuickImageProvider in the runtime
With QQuickImageProvider the user can make a callback method returning a
custom QPixmap or QImage to the engine without accessing the filesystem.
Texture sourcepaths are set using an image url scheme. For example
"image://colors/blue" where "image://" tells the runtime to look for an
image provider, "colors" is the image provider id and rest are the image
id the provider uses to create the image.
Task-number: QT3DS-3761
Change-Id: I830649359f9969e957a972a0c08d0ede6e46ee78
Reviewed-by: Antti Määttä <antti.maatta@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-rw-r--r-- | src/api/studio3d/q3dscommandqueue.cpp | 3 | ||||
-rw-r--r-- | src/api/studio3d/q3dscommandqueue_p.h | 1 | ||||
-rw-r--r-- | src/api/studio3d/q3dspresentation.cpp | 18 | ||||
-rw-r--r-- | src/api/studio3d/q3dspresentation.h | 3 | ||||
-rw-r--r-- | src/api/studio3dqml/q3dsrenderer.cpp | 4 | ||||
-rw-r--r-- | src/engine/Qt3DSRuntimeView.cpp | 10 | ||||
-rw-r--r-- | src/engine/Qt3DSRuntimeView.h | 1 | ||||
-rw-r--r-- | src/runtime/Qt3DSIScriptBridge.h | 4 | ||||
-rw-r--r-- | src/runtimerender/graphobjects/Qt3DSRenderDynamicObject.cpp | 3 | ||||
-rw-r--r-- | src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp | 21 | ||||
-rw-r--r-- | src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h | 8 | ||||
-rw-r--r-- | src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp | 3 | ||||
-rw-r--r-- | src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp | 34 | ||||
-rw-r--r-- | src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h | 7 | ||||
-rw-r--r-- | src/viewer/Qt3DSViewerApp.cpp | 8 | ||||
-rw-r--r-- | src/viewer/Qt3DSViewerApp.h | 6 |
16 files changed, 124 insertions, 10 deletions
diff --git a/src/api/studio3d/q3dscommandqueue.cpp b/src/api/studio3d/q3dscommandqueue.cpp index 06bd73f..b2d0937 100644 --- a/src/api/studio3d/q3dscommandqueue.cpp +++ b/src/api/studio3d/q3dscommandqueue.cpp @@ -311,6 +311,9 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue) queueCommand(source.m_elementPath, source.m_commandType, source.m_data); fromQueue.commandAt(i).m_data = nullptr; // This queue takes ownership of data break; + case CommandType_AddImageProvider: + queueCommand(source.m_elementPath, source.m_commandType, source.m_data); + break; case CommandType_RequestSlideInfo: case CommandType_UnloadSlide: case CommandType_PreloadSlide: diff --git a/src/api/studio3d/q3dscommandqueue_p.h b/src/api/studio3d/q3dscommandqueue_p.h index 2f98ed6..0b7b833 100644 --- a/src/api/studio3d/q3dscommandqueue_p.h +++ b/src/api/studio3d/q3dscommandqueue_p.h @@ -77,6 +77,7 @@ enum CommandType { CommandType_DeleteMeshes, CommandType_PreloadSlide, CommandType_UnloadSlide, + CommandType_AddImageProvider, // Requests CommandType_RequestSlideInfo, diff --git a/src/api/studio3d/q3dspresentation.cpp b/src/api/studio3d/q3dspresentation.cpp index e782cfe..0536310 100644 --- a/src/api/studio3d/q3dspresentation.cpp +++ b/src/api/studio3d/q3dspresentation.cpp @@ -941,6 +941,24 @@ void Q3DSPresentation::setAttribute(const QString &elementPath, const QString &a } /*! + Sets the \a provider to use for images requested via the \e + image: url scheme, with host \a providerId. The runtime + takes ownership of \a provider. + + Texture sourcepaths can then be set using the image url scheme. For example + "image://colors/blue" where "image://" tells the runtime to look for an + image provider, "colors" is the image provider id and rest are the image + id the provider uses to create the image. +*/ +void Q3DSPresentation::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->addImageProvider(providerId, provider); + else if (d_ptr->m_commandQueue) + d_ptr->m_commandQueue->queueCommand(providerId, CommandType_AddImageProvider, provider); +} + +/*! Activate or deactivate the presentation identified by \a id depending on the value of \a active. */ diff --git a/src/api/studio3d/q3dspresentation.h b/src/api/studio3d/q3dspresentation.h index af84073..1c53f98 100644 --- a/src/api/studio3d/q3dspresentation.h +++ b/src/api/studio3d/q3dspresentation.h @@ -47,6 +47,7 @@ class Q3DSGeometry; class QMouseEvent; class QWheelEvent; class QKeyEvent; +class QQmlImageProviderBase; class Q_STUDIO3D_EXPORT Q3DSPresentation : public QObject { @@ -123,6 +124,8 @@ public: void deleteMeshes(const QStringList &meshNames); QStringList createdMeshes() const; + void addImageProvider(const QString &providerId, QQmlImageProviderBase *provider); + public Q_SLOTS: void setSource(const QUrl &source); void setVariantList(const QStringList &variantList); diff --git a/src/api/studio3dqml/q3dsrenderer.cpp b/src/api/studio3dqml/q3dsrenderer.cpp index 5a99aad..7d63b30 100644 --- a/src/api/studio3dqml/q3dsrenderer.cpp +++ b/src/api/studio3dqml/q3dsrenderer.cpp @@ -482,6 +482,10 @@ void Q3DSRenderer::processCommands() case CommandType_UnloadSlide: m_runtime->unloadSlide(cmd.m_elementPath); break; + case CommandType_AddImageProvider: + m_runtime->addImageProvider(cmd.m_elementPath, + static_cast<QQmlImageProviderBase *>(cmd.m_data)); + break; case CommandType_RequestSlideInfo: { int current = 0; int previous = 0; diff --git a/src/engine/Qt3DSRuntimeView.cpp b/src/engine/Qt3DSRuntimeView.cpp index 3ab577c..c5448e3 100644 --- a/src/engine/Qt3DSRuntimeView.cpp +++ b/src/engine/Qt3DSRuntimeView.cpp @@ -225,6 +225,7 @@ public: void deleteMaterials(const QStringList &materialNames) override; void createMesh(const QString &name, qt3dsimp::Mesh *mesh) override; void deleteMeshes(const QStringList &meshNames) override; + void addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) override; void SetAttribute(const char *elementPath, const char *attributeName, const char *value) override; bool GetAttribute(const char *elementPath, const char *attributeName, void *value) override; @@ -733,6 +734,15 @@ void CRuntimeView::deleteMeshes(const QStringList &meshNames) } } +void CRuntimeView::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) +{ + if (m_Application) { + IBufferManager &bufferManager + = m_RuntimeFactory->GetQt3DSRenderContext().GetBufferManager(); + bufferManager.addImageProvider(providerId, provider); + } +} + void CRuntimeView::SetAttribute(const char *elementPath, const char *attributeName, const char *value) { diff --git a/src/engine/Qt3DSRuntimeView.h b/src/engine/Qt3DSRuntimeView.h index 1ddc48b..482e69a 100644 --- a/src/engine/Qt3DSRuntimeView.h +++ b/src/engine/Qt3DSRuntimeView.h @@ -226,6 +226,7 @@ public: virtual void deleteMaterials(const QStringList &materialNames) = 0; virtual void createMesh(const QString &name, qt3dsimp::Mesh *mesh) = 0; virtual void deleteMeshes(const QStringList &meshNames) = 0; + virtual void addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) = 0; virtual void SetAttribute(const char *elementPath, const char *attributeName, const char *value) = 0; virtual bool GetAttribute(const char *elementPath, const char *attributeName, void *value) = 0; diff --git a/src/runtime/Qt3DSIScriptBridge.h b/src/runtime/Qt3DSIScriptBridge.h index 16bf299..b9df2b3 100644 --- a/src/runtime/Qt3DSIScriptBridge.h +++ b/src/runtime/Qt3DSIScriptBridge.h @@ -39,6 +39,10 @@ #include <QtCore/qvector.h> #include <QtCore/qstringlist.h> +QT_BEGIN_NAMESPACE +class QQmlImageProviderBase; +QT_END_NAMESPACE + namespace qt3dsimp { struct Mesh; } diff --git a/src/runtimerender/graphobjects/Qt3DSRenderDynamicObject.cpp b/src/runtimerender/graphobjects/Qt3DSRenderDynamicObject.cpp index 2e1e6a0..086453c 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderDynamicObject.cpp +++ b/src/runtimerender/graphobjects/Qt3DSRenderDynamicObject.cpp @@ -133,6 +133,9 @@ void SDynamicObject::SetStrPropertyValueT(dynamic::SPropertyDefinition &inDefini inDefinition.m_ImagePath = inStrTable.RegisterStr(ioWorkspace.c_str()); } else { SetPropertyValueT(inDefinition, inStrTable.RegisterStr(inValue)); + // If the image path is not adjusted here, an invalid textures flashes for one frame + // before the proper texture is set by the custom material render task + inDefinition.m_ImagePath = inStrTable.RegisterStr(inValue); } } else if (inDefinition.m_DataType == NVRenderShaderDataTypes::NVRenderImage2DPtr) { SetPropertyValueT(inDefinition, inStrTable.RegisterStr(inValue)); diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp index b140e85..f3f85f4 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp +++ b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp @@ -119,6 +119,7 @@ struct SBufferManager : public IBufferManager nvvector<qt3ds::render::NVRenderVertexBufferEntry> m_EntryBuffer; bool m_GPUSupportsDXT; bool m_reloadableResources; + QHash<QString, QSharedPointer<QQmlImageProviderBase> > m_imageProviders; QHash<QString, ReloadableTexturePtr> m_reloadableTextures; @@ -377,7 +378,7 @@ struct SBufferManager : public IBufferManager SStackPerfTimer __perfTimer(m_PerfTimer, "Image Decompression"); theLoadedImage = SLoadedTexture::Load( inImagePath.c_str(), m_Context->GetFoundation(), *m_InputStreamFactory, - true, m_Context->GetRenderContextType()); + true, m_Context->GetRenderContextType(), false, this); // Hackish solution to custom materials not finding their textures if they are used // in sub-presentations. if (!theLoadedImage) { @@ -390,7 +391,7 @@ struct SBufferManager : public IBufferManager theLoadedImage = SLoadedTexture::Load( searchPath.toUtf8(), m_Context->GetFoundation(), *m_InputStreamFactory, true, - m_Context->GetRenderContextType()); + m_Context->GetRenderContextType(), false, this); searchPath.prepend(QLatin1String("../")); } } else { @@ -407,7 +408,7 @@ struct SBufferManager : public IBufferManager theLoadedImage = SLoadedTexture::Load( searchPath.toUtf8(), m_Context->GetFoundation(), *m_InputStreamFactory, true, - m_Context->GetRenderContextType()); + m_Context->GetRenderContextType(), false, this); searchPath = splitPath.at(0); for (int i = 0; i < loops; i++) searchPath.append(QLatin1String("../")); @@ -1024,6 +1025,19 @@ struct SBufferManager : public IBufferManager return theMesh.first->second; } + void addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) override + { + QString providerIdLower = providerId.toLower(); + QSharedPointer<QQmlImageProviderBase> sp(provider); + m_imageProviders.insert(std::move(providerIdLower), std::move(sp)); + } + + QQmlImageProviderBase *imageProvider(const QString &providerId) override + { + const QString providerIdLower = providerId.toLower(); + return m_imageProviders.value(providerIdLower).data(); + } + void ReleaseMesh(SRenderMesh &inMesh) { for (QT3DSU32 subsetIdx = 0, subsetEnd = inMesh.m_Subsets.size(); subsetIdx < subsetEnd; @@ -1068,6 +1082,7 @@ struct SBufferManager : public IBufferManager Mutex::ScopedLock __locker(m_LoadedImageSetMutex); m_LoadedImageSet.clear(); } + m_imageProviders.clear(); } void InvalidateBuffer(CRegisteredString inSourcePath) override { diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h index 7930158..b8cd49b 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h +++ b/src/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h @@ -37,6 +37,10 @@ #include "Qt3DSRenderImageTextureData.h" #include "foundation/Qt3DSBounds3.h" +QT_BEGIN_NAMESPACE +class QQmlImageProviderBase; +QT_END_NAMESPACE + namespace qt3dsimp { struct Mesh; } @@ -105,6 +109,10 @@ namespace render { QT3DSU32 inNumVerts, QT3DSU32 inVertStride, QT3DSU32 *inIndexData, QT3DSU32 inIndexCount, qt3ds::NVBounds3 inBounds) = 0; + virtual void addImageProvider(const QString &providerId, + QQmlImageProviderBase *provider) = 0; + virtual QQmlImageProviderBase *imageProvider(const QString &providerId) = 0; + // Remove *all* buffers from the buffer manager; virtual void Clear() = 0; virtual void InvalidateBuffer(CRegisteredString inSourcePath) = 0; diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp index 72495cd..d272911 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp +++ b/src/runtimerender/resourcemanager/Qt3DSRenderImageBatchLoader.cpp @@ -388,7 +388,8 @@ void SLoadingImage::LoadImage(void *inImg) theThis->m_SourcePath.c_str(), theThis->m_Batch->m_Loader.m_Foundation, theThis->m_Batch->m_Loader.m_InputStreamFactory, true, theThis->m_Batch->m_contextType, - theThis->m_Batch->m_preferKTX); + theThis->m_Batch->m_preferKTX, + &theThis->m_Batch->m_Loader.m_BufferManager); // if ( theTexture ) // theTexture->EnsureMultiplerOfFour( theThis->m_Batch->m_Loader.m_Foundation, //theThis->m_SourcePath.c_str() ); diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp index ff221f9..afb6661 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp +++ b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.cpp @@ -37,19 +37,41 @@ #include "foundation/Qt3DSBroadcastingAllocator.h" #include "Qt3DSRenderImageScaler.h" #include "Qt3DSTextRenderer.h" -#include <QImage> +#include "Qt3DSRenderBufferManager.h" +#include <QtQuick/qquickimageprovider.h> +#include <QtGui/qimage.h> using namespace qt3ds::render; SLoadedTexture *SLoadedTexture::LoadQImage(const QString &inPath, QT3DSI32 flipVertical, NVFoundationBase &fnd, - NVRenderContextType renderContextType) + NVRenderContextType renderContextType, + IBufferManager *bufferManager) { Q_UNUSED(flipVertical) Q_UNUSED(renderContextType) SLoadedTexture *retval(NULL); NVAllocatorCallback &alloc(fnd.getAllocator()); - QImage image(inPath); + + QImage image; + const QUrl url(inPath); + if (bufferManager && url.scheme() == QLatin1String("image")) { + QQuickImageProvider *provider = static_cast<QQuickImageProvider *>( + bufferManager->imageProvider(url.host())); + if (!provider) + return nullptr; + QString imageId = url.toString(QUrl::RemoveScheme | QUrl::RemoveAuthority).mid(1); + QSize outSize; + if (provider->imageType() == QQuickImageProvider::Pixmap) + image = provider->requestPixmap(imageId, &outSize, QSize()).toImage(); + else if (provider->imageType() == QQuickImageProvider::Image) + image = provider->requestImage(imageId, &outSize, QSize()); + if (outSize.isEmpty()) + return nullptr; + } else { + image = QImage(inPath); + } + const QImage::Format format = image.format(); switch (format) { case QImage::Format_RGBA64: @@ -682,11 +704,15 @@ void SLoadedTexture::ReleaseDecompressedTexture(STextureData inImage) SLoadedTexture *SLoadedTexture::Load(const QString &inPath, NVFoundationBase &inFoundation, IInputStreamFactory &inFactory, bool inFlipY, - NVRenderContextType renderContextType, bool preferKTX) + NVRenderContextType renderContextType, bool preferKTX, + IBufferManager *bufferManager) { if (inPath.isEmpty()) return nullptr; + if (QUrl(inPath).scheme() == QLatin1String("image")) + return LoadQImage(inPath, inFlipY, inFoundation, renderContextType, bufferManager); + // Check KTX path first QString path = inPath; QString ktxSource = inPath; diff --git a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h index 10200ad..cb0b2b6 100644 --- a/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h +++ b/src/runtimerender/resourcemanager/Qt3DSRenderLoadedTexture.h @@ -155,7 +155,9 @@ namespace render { static SLoadedTexture *Load(const QString &inPath, NVFoundationBase &inAllocator, IInputStreamFactory &inFactory, bool inFlipY = true, NVRenderContextType renderContextType - = NVRenderContextValues::NullContext, bool preferKTX = false); + = NVRenderContextValues::NullContext, + bool preferKTX = false, + IBufferManager *bufferManager = nullptr); static SLoadedTexture *LoadDDS(IInStream &inStream, QT3DSI32 flipVertical, NVFoundationBase &fnd, NVRenderContextType renderContextType); @@ -173,7 +175,8 @@ namespace render { static SLoadedTexture *LoadQImage(const QString &inPath, QT3DSI32 flipVertical, NVFoundationBase &fnd, - NVRenderContextType renderContextType); + NVRenderContextType renderContextType, + IBufferManager *bufferManager = nullptr); private: // Implemented in the bmp loader. diff --git a/src/viewer/Qt3DSViewerApp.cpp b/src/viewer/Qt3DSViewerApp.cpp index 0e73734..5916061 100644 --- a/src/viewer/Qt3DSViewerApp.cpp +++ b/src/viewer/Qt3DSViewerApp.cpp @@ -1043,6 +1043,14 @@ void Q3DSViewerApp::deleteMeshes(const QStringList &meshNames) m_Impl.m_view->deleteMeshes(meshNames); } +void Q3DSViewerApp::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider) +{ + if (!m_Impl.m_view) + return; + + m_Impl.m_view->addImageProvider(providerId, provider); +} + Q3DSViewerApp &Q3DSViewerApp::Create(void *glContext, Q3DStudio::IAudioPlayer *inAudioPlayer, QElapsedTimer *startupTimer) { diff --git a/src/viewer/Qt3DSViewerApp.h b/src/viewer/Qt3DSViewerApp.h index e12057b..d5b02e4 100644 --- a/src/viewer/Qt3DSViewerApp.h +++ b/src/viewer/Qt3DSViewerApp.h @@ -43,6 +43,10 @@ #include <QtCore/qstringlist.h> #include <QtGui/qsurfaceformat.h> +QT_BEGIN_NAMESPACE +class QQmlImageProviderBase; +QT_END_NAMESPACE + namespace Q3DStudio { class IRuntimeView; class IWindowSystem; @@ -489,6 +493,8 @@ public: void createMeshes(const QHash<QString, Q3DSViewer::MeshData> &meshData); void deleteMeshes(const QStringList &meshNames); + void addImageProvider(const QString &providerId, QQmlImageProviderBase *provider); + QString error(); void setPresentationId(const QString &id); |