diff options
author | Antti Määttä <antti.maatta@qt.io> | 2019-04-12 13:54:35 +0300 |
---|---|---|
committer | Antti Määttä <antti.maatta@qt.io> | 2019-05-03 09:34:00 +0000 |
commit | 73ebd0f9cf6376a762c96d37ab6046fefd8d4789 (patch) | |
tree | e415e2af7e30002563422ba9cbec02f3276b013e | |
parent | ccc70e48e576c0dffc289df4850a909fb6fef83d (diff) |
Implement dynamic loading of slide resources
Implements loading of textures and images during runtime instead of load
time.
- Images which are not part of any slide are loaded at load time
- Master slide images are always loaded at load time
- Images used in a slide are loaded when the slide is entered
- Images are unloaded when slide is exited and any other slide does not
use them
Task-number: QT3DS-3208
Change-Id: I7a827a5e828908efd2b104fe25374c66958319d2
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
39 files changed, 1019 insertions, 274 deletions
diff --git a/src/Authoring/Studio/Render/StudioRenderer.cpp b/src/Authoring/Studio/Render/StudioRenderer.cpp index d6b5b3b2..ee03a614 100644 --- a/src/Authoring/Studio/Render/StudioRenderer.cpp +++ b/src/Authoring/Studio/Render/StudioRenderer.cpp @@ -328,7 +328,7 @@ struct SRendererImpl : public IStudioRenderer, m_Context = theCore->CreateRenderContext( m_RenderContext->GetRenderContext(), m_RenderContext->GetRenderContext().GetStringTable().RegisterStr( - theResourcePath.c_str())); + theResourcePath.c_str()), false); // Allow the artist to interact with the top level objects alone. m_Context->GetRenderer().PickRenderPlugins(false); diff --git a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp index 10496753..8ba76fd1 100644 --- a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp +++ b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp @@ -133,9 +133,9 @@ struct SSceneLoadData SSceneLoadData(NVAllocatorCallback &alloc) : m_Allocator(alloc) - , m_Presentation(NULL) + , m_Presentation(nullptr) , m_AutoAllocator(alloc) - , m_RuntimePresentation(NULL) + , m_RuntimePresentation(nullptr) , mRefCount(0) { } @@ -170,9 +170,9 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene , m_LoadData(inLoadData) , m_Presentation(inLoadData.m_Presentation) , m_RuntimePresentation(inLoadData.m_RuntimePresentation) - , m_UserData(NULL) + , m_UserData(nullptr) , m_DirtySet(inContext.GetAllocator(), "Qt3DSRenderScene::m_DirtySet") - , m_OffscreenRenderer(NULL) + , m_OffscreenRenderer(nullptr) , m_SubPresentationType( inContext.GetStringTable().RegisterStr(CSubPresentationRenderer::GetRendererName())) , m_GraphObjectList(inContext.GetAllocator(), "Qt3DSDSRenderScene::m_GraphObjectList") @@ -188,7 +188,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene { if (m_OffscreenRenderer) m_Context->GetOffscreenRenderManager().ReleaseOffscreenRenderer(m_OffscreenRendererId); - m_OffscreenRenderer = NULL; + m_OffscreenRenderer = nullptr; if (m_Presentation && m_Presentation->m_Scene) { for (SLayer *theLayer = m_Presentation->m_Scene->m_FirstChild; theLayer; theLayer = static_cast<SLayer *>(theLayer->m_NextSibling)) { @@ -216,7 +216,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene // changes. if (theTranslator && theTranslator->RenderObject().m_Type != GraphObjectTypes::PathSubPath) - theTranslator = NULL; + theTranslator = nullptr; } } if (theTranslator) @@ -282,12 +282,12 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene , mousePos, true, true); - if (thePickResult.m_HitObject != NULL) { + if (thePickResult.m_HitObject != nullptr) { SModel *theHitModel = static_cast<SModel *>(const_cast<SGraphObject *>(thePickResult.m_HitObject)); return &Qt3DSTranslator::GetTranslatorFromGraphNode(*theHitModel)->Element(); } - return NULL; + return nullptr; } virtual Option<QT3DSVec2> FacePosition(Q3DStudio::TElement &inElement, float mouseX, float mouseY, @@ -300,7 +300,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene } Qt3DSTranslator *theTranslator = reinterpret_cast<Qt3DSTranslator *>(inElement.GetAssociation()); - if (theTranslator == NULL) + if (theTranslator == nullptr) return Empty(); bool isValidPickObject = GraphObjectTypes::IsNodeType(theTranslator->m_RenderObject->m_Type); @@ -314,11 +314,11 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene for (QT3DSU32 idx = 0, end = inMapperElements.size(); idx < end; ++idx) { Qt3DSTranslator *theMapperTranslator = reinterpret_cast<Qt3DSTranslator *>(inMapperElements[idx]->GetAssociation()); - SGraphObject *theMapperObject = NULL; + SGraphObject *theMapperObject = nullptr; if (theMapperTranslator) { theMapperObject = theMapperTranslator->m_RenderObject; } - if (theMapperObject == NULL) { + if (theMapperObject == nullptr) { QT3DS_ASSERT(false); } else { theMapperObjects[idx] = theMapperObject; @@ -363,7 +363,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene m_Context->GetMousePickMouseCoords( QT3DSVec2(ioPickFrame.m_InputFrame.m_PickX, ioPickFrame.m_InputFrame.m_PickY)), true); - if (thePickResult.m_HitObject != NULL) { + if (thePickResult.m_HitObject != nullptr) { SModel *theHitModel = static_cast<SModel *>( const_cast<SGraphObject *>(thePickResult.m_HitObject)); ioPickFrame.m_Model = @@ -415,7 +415,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene void CalculateGlobalTransform(Q3DStudio::TElement *inElement, Q3DStudio::RuntimeMatrix &outTransform) override { - if (inElement == NULL) { + if (inElement == nullptr) { QT3DS_ASSERT(false); return; } @@ -439,7 +439,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene void SetLocalTransformMatrix(Q3DStudio::TElement *inElement, const Q3DStudio::RuntimeMatrix &inTransform) override { - if (inElement == NULL) { + if (inElement == nullptr) { QT3DS_ASSERT(false); return; } @@ -472,7 +472,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene NVBounds3 GetNodeLocalBoundingBox(Q3DStudio::TElement *inElement, bool inSelfOnly) { NVBounds3 retval(NVBounds3::empty()); - if (inElement == NULL) { + if (inElement == nullptr) { QT3DS_ASSERT(false); return retval; } @@ -534,7 +534,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene { Q3DStudio::CBoundingBox retval; retval.SetEmpty(); - if (inElement == NULL) { + if (inElement == nullptr) { QT3DS_ASSERT(false); return retval; } @@ -609,7 +609,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene NVRenderTextureFormats::Enum destFormat = qt3ds::render::NVRenderTextureFormats::RGBA16F; Qt3DSRenderPrefilterTexture *theBSDFMipMap = theImage->m_TextureData.m_BSDFMipMap; - if (theBSDFMipMap == NULL) { + if (theBSDFMipMap == nullptr) { theBSDFMipMap = Qt3DSRenderPrefilterTexture::Create( &theContext->GetRenderContext(), inWidth, inHeight, *theImage->m_TextureData.m_Texture, destFormat, theContext->GetFoundation()); @@ -669,7 +669,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene unsigned int *indexData, unsigned int numIndices, qt3ds::NVBounds3 &objBounds) override { - SRenderMesh *theMesh = NULL; + SRenderMesh *theMesh = nullptr; if (inPathStr && vertData && indexData) { theMesh = m_Context->GetBufferManager().CreateMesh( @@ -679,7 +679,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene "CreateOrSetMeshData was not supplied necessary buffers or object path"); } - return (theMesh != NULL); + return (theMesh != nullptr); } Q3DStudio::STextSizes MeasureText(Q3DStudio::TElement *inElement, const char *inTextStr) override @@ -720,28 +720,6 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene return Q3DStudio::STextSizes(); } - // This is the best place for now... - void GetImageInfoFromRenderEngine(Q3DStudio::TElement *inElement, - Q3DStudio::INT32 &ioWidth, Q3DStudio::INT32 &ioHeight) override - { - ioWidth = 0; - ioHeight = 0; - Qt3DSTranslator *theTranslator = - reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation()); - if (theTranslator->GetUIPType() == GraphObjectTypes::Image) { - SImage *theImage = static_cast<SImage *>(&theTranslator->RenderObject()); - if (theImage) { - SImageTextureData theTextureData( - m_Context->GetBufferManager().LoadRenderImage(theImage->m_ImagePath)); - if (theTextureData.m_Texture) { - STextureDetails theDetails = theTextureData.m_Texture->GetTextureDetails(); - ioWidth = theDetails.m_Width; - ioHeight = theDetails.m_Height; - } - } - } - } - virtual Q3DStudio::SMousePosition WindowToPresentation(const Q3DStudio::SMousePosition &inWindowCoords) override { @@ -780,6 +758,30 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene *m_OffscreenRenderer); } + template <typename T, typename C> + void forAllObjects(nvvector<SGraphObject *> &vec, GraphObjectTypes::Enum type, C callable) + { + nvvector<SGraphObject *>::iterator it = vec.begin(); + nvvector<SGraphObject *>::iterator end = vec.end(); + while (it != end) { + if ((*it)->m_Type == type) + callable(static_cast<T*>(*it)); + ++it; + } + } + + void PostLoadStep() + { + IBufferManager &mgr = m_Context->GetBufferManager(); + forAllObjects<SImage>(m_GraphObjectList, GraphObjectTypes::Image, [&mgr](SImage *image){ + if (image->m_ImagePath.IsValid()) { + image->m_LoadedTextureData = mgr.CreateReloadableImage(image->m_ImagePath, + false, false); + image->m_LoadedTextureData->m_callbacks.push_back(image); + } + }); + } + void Release() override { NVDelete(m_Context->GetAllocator(), this); } }; @@ -849,7 +851,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, , m_ViewWidth(0) , m_ViewHeight(0) , m_SourcePaths(ctx.GetAllocator(), "Qt3DSRenderSceneManager::m_SourcePaths") - , m_LastRenderedScene(NULL) + , m_LastRenderedScene(nullptr) , m_WindowSystem(inWindowSystem) , m_LoadingScenesMutex(ctx.GetAllocator()) , m_ProjectInitialized(false) @@ -879,7 +881,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, return false; return stricmp(ending, "jpg") == 0 || stricmp(ending, "peg") == 0 || stricmp(ending, "png") == 0 || stricmp(ending, "dds") == 0 - || stricmp(ending, "hdr") == 0; + || stricmp(ending, "hdr") == 0 || stricmp(ending, "ktx") == 0; } static bool IsMesh(const char *ending) { @@ -961,16 +963,16 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, }; Q3DStudio::IScene *LoadScene(Q3DStudio::IPresentation *inPresentation, - Q3DStudio::IUIPParser *inParser, - Q3DStudio::IScriptBridge &inBridge, - const qt3ds::Q3DSVariantConfig &variantConfig) override + Q3DStudio::IUIPParser *inParser, + Q3DStudio::IScriptBridge &inBridge, + const qt3ds::Q3DSVariantConfig &variantConfig) override { // We have to initialize the tags late so that we can load flow data before adding anything // to the string table. Qt3DSTranslator::InitializePointerTags(m_Context->m_RenderContext->GetStringTable()); NVScopedRefCounted<SSceneLoadData> theScene = QT3DS_NEW(m_Context->GetAllocator(), SSceneLoadData)(m_Context->GetAllocator()); - Qt3DSRenderScene *theIScene = NULL; + Qt3DSRenderScene *theIScene = nullptr; if (inParser) { QString thePath(inPresentation->GetFilePath()); QFileInfo fileInfo(thePath); @@ -994,10 +996,11 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, variantConfig, false); if (!theScene->m_Presentation) { QT3DS_ASSERT(false); - return NULL; + return nullptr; } NVConstDataRef<eastl::string> theSourcePathData(inParser->GetSourcePaths()); + const QVector<QString> slideSourcePaths = inParser->GetSlideSourcePaths(); IBufferManager &theManager(m_Context->m_Context->GetBufferManager()); // List of image paths to be loaded in parallel at the end. eastl::vector<CRegisteredString> theSourcePathList; @@ -1010,11 +1013,16 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, const char *ending = theValue.c_str() + theValueSize - 3; CRegisteredString theObjectPath = theSourcePath; if (IsImage(ending)) { - theManager.SetImageTransparencyToFalseIfNotSet(theObjectPath); - if (m_SourcePathSet.insert(theSourcePath).second) - m_SourcePaths.push_back(eastl::make_pair( - theSourcePath, theManager.GetImageHasTransparency(theObjectPath))); - theSourcePathList.push_back(theObjectPath); + // load only images not on any slide + if (!theManager.isReloadableResourcesEnabled() || + !slideSourcePaths.contains(QString::fromLatin1(theValue.c_str()))) { + theManager.SetImageTransparencyToFalseIfNotSet(theObjectPath); + if (m_SourcePathSet.insert(theSourcePath).second) { + m_SourcePaths.push_back(eastl::make_pair(theSourcePath, + theManager.GetImageHasTransparency(theObjectPath))); + } + theSourcePathList.push_back(theObjectPath); + } } else if (theValue.find(".mesh") != eastl::string::npos) { theManager.LoadMesh(theObjectPath); } @@ -1049,6 +1057,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, } } } + theIScene->PostLoadStep(); } else { // Binary load path is quite different than normal load path and // nothing else will load here. @@ -1218,6 +1227,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, Qt3DSRenderScene *theIScene = QT3DS_NEW(m_Context->GetAllocator(), Qt3DSRenderScene)( *m_Context, *m_Context->m_Context, theScene); FinalizeScene(*theScene.m_RuntimePresentation, *theIScene); + theIScene->PostLoadStep(); } else { qCWarning(WARNING, "Failed to finalize scene %d", (int)idx + 1); } @@ -1425,7 +1435,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, { SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(), "Load UIAB - String Table + Render Objects"); - QT3DS_ASSERT(m_Context->m_FlowData == NULL); + QT3DS_ASSERT(m_Context->m_FlowData == nullptr); QT3DSU32 dataSize = 0; inStream.Read(dataSize); m_Context->m_FlowData = (QT3DSU8 *)m_Context->m_CoreContext->GetAllocator().allocate( @@ -1544,8 +1554,8 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, Q3DStudio::BOOL RenderPresentation(Q3DStudio::IPresentation *inPresentation) override { - Qt3DSRenderScene *theFirstScene = NULL; - for (QT3DSU32 idx = 0, end = m_Scenes.size(); idx < end && theFirstScene == NULL; ++idx) + Qt3DSRenderScene *theFirstScene = nullptr; + for (QT3DSU32 idx = 0, end = m_Scenes.size(); idx < end && theFirstScene == nullptr; ++idx) if (m_Scenes[idx].second->m_RuntimePresentation == inPresentation) theFirstScene = m_Scenes[idx].second; @@ -1606,8 +1616,8 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, Q3DStudio::STextSizes GetDisplayDimensions(Q3DStudio::IPresentation *inPresentation) override { - Qt3DSRenderScene *theFirstScene = NULL; - for (QT3DSU32 idx = 0, end = m_Scenes.size(); idx < end && theFirstScene == NULL; ++idx) + Qt3DSRenderScene *theFirstScene = nullptr; + for (QT3DSU32 idx = 0, end = m_Scenes.size(); idx < end && theFirstScene == nullptr; ++idx) if (m_Scenes[idx].second->m_RuntimePresentation == inPresentation) theFirstScene = m_Scenes[idx].second; if (theFirstScene) { @@ -1629,7 +1639,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, if (m_LastRenderedScene) { return m_LastRenderedScene->UserPick(mouseX, mouseY); } - return NULL; + return nullptr; } Option<QT3DSVec2> FacePosition(Q3DStudio::TElement &inElement, float mouseX, float mouseY, @@ -1648,7 +1658,7 @@ struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager, { // We now have a new input frame, and our results are invalid but ready to be filled m_PickFrame.m_InputFrame = inInputFrame; - m_PickFrame.m_Model = NULL; + m_PickFrame.m_Model = nullptr; m_PickFrame.m_ResultValid = false; if (m_LastRenderedScene) { if (m_PickFrame.m_InputFrame.m_PickValid) @@ -1687,16 +1697,14 @@ struct SRenderFactory : public IQt3DSRenderFactoryCore, public IQt3DSRenderFacto NVScopedRefCounted<Q3DStudio::CQmlEngine> m_ScriptBridgeQml; NVScopedRefCounted<Qt3DSRenderSceneManager> m_SceneManager; NVScopedRefCounted<qt3ds::evt::IEventSystem> m_EventSystem; - qt3ds::runtime::IApplicationCore *m_ApplicationCore; qt3ds::runtime::IApplication *m_Application; QT3DSI32 m_RefCount; SRenderFactory(SBindingCore &inCore) : m_Context(inCore) - , m_ScriptBridgeQml(NULL) - , m_SceneManager(NULL) - , m_ApplicationCore(NULL) - , m_Application(NULL) + , m_ScriptBridgeQml(nullptr) + , m_SceneManager(nullptr) + , m_Application(nullptr) , m_RefCount(0) { } @@ -1705,7 +1713,7 @@ struct SRenderFactory : public IQt3DSRenderFactoryCore, public IQt3DSRenderFacto { using namespace Q3DStudio; // Release the event system, it must be released before script engine - m_EventSystem = NULL; + m_EventSystem = nullptr; m_ScriptBridgeQml->Shutdown(*m_Context->m_Foundation); } @@ -1725,15 +1733,15 @@ struct SRenderFactory : public IQt3DSRenderFactoryCore, public IQt3DSRenderFacto return *m_Context->m_CoreContext; } - qt3ds::runtime::IApplicationCore *GetApplicationCore() override { return m_ApplicationCore; } - void SetApplicationCore(qt3ds::runtime::IApplicationCore *app) override + qt3ds::runtime::IApplication *GetApplicationCore() override { return m_Application; } + void SetApplicationCore(qt3ds::runtime::IApplication *app) override { - m_ApplicationCore = app; + m_Application = app; } Q3DStudio::ISceneBinaryLoader &GetSceneLoader() override { - if (m_SceneManager == NULL) + if (m_SceneManager == nullptr) m_SceneManager = QT3DS_NEW(m_Context->GetAllocator(), Qt3DSRenderSceneManager)(*m_Context, m_Context->m_WindowSystem); return *m_SceneManager; @@ -1745,14 +1753,14 @@ struct SRenderFactory : public IQt3DSRenderFactoryCore, public IQt3DSRenderFacto } Q3DStudio::ISceneManager &GetSceneManager() override { - if (m_SceneManager == NULL) + if (m_SceneManager == nullptr) m_SceneManager = QT3DS_NEW(m_Context->GetAllocator(), Qt3DSRenderSceneManager)(*m_Context, m_Context->m_WindowSystem); return *m_SceneManager; } Q3DStudio::IScriptBridge &GetScriptEngineQml() override { - if (m_ScriptBridgeQml == NULL) { + if (m_ScriptBridgeQml == nullptr) { m_ScriptBridgeQml = Q3DStudio::CQmlEngine::Create(*m_Context->m_Foundation, m_Context->m_TimeProvider); } @@ -1823,17 +1831,18 @@ struct SRenderFactory : public IQt3DSRenderFactoryCore, public IQt3DSRenderFacto qt3ds::render::NVRenderContext &retval = NVRenderContext::CreateGL(foundat, strt, format); return &retval; #else - qt3ds::render::NVRenderContext &retval = NVRenderContext::CreateNULL(foundat, strt); + qt3ds::render::NVRenderContext &retval = NVRenderContext::Createnullptr(foundat, strt); return &retval; #endif } }; - IQt3DSRenderFactory &CreateRenderFactory(const QSurfaceFormat& format) override + IQt3DSRenderFactory &CreateRenderFactory(const QSurfaceFormat& format, + bool delayedLoading) override { SContextTypeRenderFactory theContextFactory(format); - m_Context->CreateRenderContext(theContextFactory); + m_Context->CreateRenderContext(theContextFactory, delayedLoading); GetSceneLoader(); { diff --git a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.h b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.h index ea95b943..ad0c4e6b 100644 --- a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.h +++ b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.h @@ -63,7 +63,7 @@ namespace render { { public: virtual IQt3DSRenderFactory & - CreateRenderFactory(const QSurfaceFormat &format) = 0; + CreateRenderFactory(const QSurfaceFormat &format, bool delayedLoading) = 0; static IQt3DSRenderFactoryCore & CreateRenderFactoryCore(const char8_t *inApplicationDirectory, diff --git a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBindingImpl.h b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBindingImpl.h index 1d27f293..c174d4a7 100644 --- a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBindingImpl.h +++ b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBindingImpl.h @@ -136,12 +136,15 @@ namespace render { m_FlowData = NULL; } - void CreateRenderContext(qt3ds::render::IRuntimeFactoryRenderFactory &inContextFactory) + void CreateRenderContext(qt3ds::render::IRuntimeFactoryRenderFactory &inContextFactory, + bool delayedLoading) { m_RenderContext = inContextFactory.CreateRenderContext(*m_Foundation, *m_StringTable); - if (m_RenderContext) + if (m_RenderContext) { m_Context = - m_CoreContext->CreateRenderContext(*m_RenderContext, m_PrimitivePath.c_str()); + m_CoreContext->CreateRenderContext(*m_RenderContext, m_PrimitivePath.c_str(), + delayedLoading); + } } QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(g_BaseAllocator) diff --git a/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp b/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp index f2ce9d67..e4e8453d 100644 --- a/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp +++ b/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp @@ -144,7 +144,7 @@ private: // Pre graphics init objects NVScopedRefCounted<qt3ds::render::IQt3DSRenderFactoryCore> m_RuntimeFactoryCore; ///< Base application before graphics - NVScopedRefCounted<qt3ds::runtime::IApplicationCore> m_ApplicationCore; + NVScopedRefCounted<qt3ds::runtime::IApplication> m_ApplicationCore; // Post graphics init objects NVScopedRefCounted<qt3ds::render::IQt3DSRenderFactory> m_RuntimeFactory; @@ -170,7 +170,7 @@ public: bool BeginLoad(const QString &sourcePath, const QStringList &variantList) override; bool HasOfflineLoadingCompleted() override; - bool InitializeGraphics(const QSurfaceFormat &format) override; + bool InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading) override; void Cleanup() override; @@ -219,6 +219,9 @@ public: bool RegisterScriptCallback(int callbackType, qml_Function func, void *inUserData) override; void FireEvent(const TEventCommandHash inEventType, eastl::string inArgument) override; qt3ds::foundation::Option<SPresentationSize> GetPresentationSize() override; + void preloadSlide(const QString &slide) override; + void unloadSlide(const QString &slide) override; + void setDelayedLoading(bool enable) override; void BootupPreGraphicsInitObjects(); }; @@ -275,12 +278,12 @@ bool CRuntimeView::HasOfflineLoadingCompleted() return true; } -bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format) +bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading) { m_ApplicationCore->EndLoad(); // Next call will initialize the render portion of the scenes. This *must* have a loaded // application to go further as it will bind scene graph data to application data. - m_RuntimeFactory = m_RuntimeFactoryCore->CreateRenderFactory(format); + m_RuntimeFactory = m_RuntimeFactoryCore->CreateRenderFactory(format, delayedLoading); m_Application = m_ApplicationCore->CreateApplication(*m_InputEngine, m_AudioPlayer, *m_RuntimeFactory); @@ -655,6 +658,24 @@ void CRuntimeView::FireEvent(const TEventCommandHash inEventType, eastl::string } } +void CRuntimeView::preloadSlide(const QString &slide) +{ + if (m_Application) + m_Application->preloadSlide(slide); +} + +void CRuntimeView::unloadSlide(const QString &slide) +{ + if (m_Application) + m_Application->unloadSlide(slide); +} + +void CRuntimeView::setDelayedLoading(bool enable) +{ + if (m_Application) + m_Application->setDelayedLoading(enable); +} + qt3ds::foundation::Option<SPresentationSize> CRuntimeView::GetPresentationSize() { if (m_Application) { @@ -678,7 +699,7 @@ void CRuntimeView::BootupPreGraphicsInitObjects() m_RuntimeFactoryCore = qt3ds::render::IQt3DSRenderFactoryCore::CreateRenderFactoryCore( theAppDir.c_str(), m_WindowSystem, m_TimeProvider); m_ApplicationCore = qt3ds::runtime::IApplication::CreateApplicationCore(*m_RuntimeFactoryCore, - theAppDir.c_str()); + theAppDir.c_str()); if (m_ApplicationCore && m_visitor) m_ApplicationCore->setAssetVisitor(m_visitor); @@ -697,10 +718,10 @@ void CRuntimeView::setAssetVisitor(qt3ds::Qt3DSAssetVisitor *v) } IRuntimeView &IRuntimeView::Create(ITimeProvider &inProvider, IWindowSystem &inWindowSystem, - IAudioPlayer *inAudioPlayer) + IAudioPlayer *inAudioPlayer) { return *QT3DS_NEW(qt3ds::render::g_BaseAllocator, CRuntimeView)(inProvider, inWindowSystem, - inAudioPlayer); + inAudioPlayer); } QRuntimeViewSignalProxy *IRuntimeView::signalProxy() diff --git a/src/Runtime/Source/engine/Qt3DSRuntimeView.h b/src/Runtime/Source/engine/Qt3DSRuntimeView.h index 87418c8e..52aa969c 100644 --- a/src/Runtime/Source/engine/Qt3DSRuntimeView.h +++ b/src/Runtime/Source/engine/Qt3DSRuntimeView.h @@ -157,7 +157,7 @@ public: public: // loading virtual bool BeginLoad(const QString &sourcePath, const QStringList &variantList) = 0; virtual bool HasOfflineLoadingCompleted() = 0; - virtual bool InitializeGraphics(const QSurfaceFormat &format) = 0; + virtual bool InitializeGraphics(const QSurfaceFormat &format, bool delayedLoading) = 0; virtual void Cleanup() = 0; @@ -204,8 +204,10 @@ public: virtual bool RegisterScriptCallback(int callbackType, qml_Function func, void *inUserData) = 0; virtual void FireEvent(const TEventCommandHash inEventType, eastl::string inArgument) = 0; virtual qt3ds::foundation::Option<SPresentationSize> GetPresentationSize() = 0; - virtual void setAssetVisitor(qt3ds::Qt3DSAssetVisitor *) = 0; + virtual void preloadSlide(const QString &slide) = 0; + virtual void unloadSlide(const QString &slide) = 0; + virtual void setDelayedLoading(bool enable) = 0; public: static IRuntimeView &Create(ITimeProvider &inProvider, IWindowSystem &inWindowSystem, diff --git a/src/Runtime/Source/runtime/Qt3DSApplication.cpp b/src/Runtime/Source/runtime/Qt3DSApplication.cpp index 5f335fec..a1d5812d 100644 --- a/src/Runtime/Source/runtime/Qt3DSApplication.cpp +++ b/src/Runtime/Source/runtime/Qt3DSApplication.cpp @@ -75,6 +75,10 @@ #include "Qt3DSRenderInputStreamFactory.h" #include "Qt3DSAudioPlayer.h" #include "Qt3DSElementSystem.h" +#include "Qt3DSSlideSystem.h" +#include "Qt3DSQmlElementHelper.h" +#include "Qt3DSRenderBufferManager.h" +#include "Qt3DSRenderRenderList.h" #include <QtCore/qlibraryinfo.h> #include <QtCore/qpair.h> #include <QtCore/qdir.h> @@ -82,6 +86,7 @@ using namespace qt3ds; using namespace qt3ds::runtime; +using namespace qt3ds::render; using namespace Q3DStudio; namespace qt3ds { @@ -201,6 +206,139 @@ struct SHandleElementPairComparator } }; +struct SSlideResourceCounter +{ + QHash<QString, int> counters; + QSet<QString> createSet; + QSet<QString> deleteSet; + + QVector<QString> loadedSlides; + + void increment(const QSet<QString> &set) + { + for (auto &r : set) { + if (counters.value(r, 0) == 0) + createSet.insert(r); + counters[r]++; + } + } + void decrement(const QSet<QString> &set) + { + for (auto &r : set) { + if (counters.contains(r)) { + int count = qMax(counters[r] - 1, 0); + if (count == 0) + deleteSet.insert(r); + counters[r] = count; + } + } + } + void begin() + { + createSet.clear(); + deleteSet.clear(); + } + void reset() + { + loadedSlides.clear(); + counters.clear(); + begin(); + } + bool isImage(const QString &path) + { + int index = path.lastIndexOf("."); + if (index < 0) + return false; + const QString ext = path.right(path.length() - index - 1); + return (ext == QLatin1String("jpg") || ext == QLatin1String("jpeg") + || ext == QLatin1String("png") || ext == QLatin1String("hdr") + || ext == QLatin1String("dds") || ext == QLatin1String("ktx")); + } + QSet<QString> toImageSet(const QVector<QString> &vec) + { + QSet<QString> s; + for (const auto &x : vec) { + if (isImage(x)) + s.insert(x); + } + return s; + } + void handleLoadSlide(const QString &slide, SSlideKey key, ISlideSystem &slideSystem) + { + if (loadedSlides.contains(slide)) + return; + loadedSlides.push_back(slide); + begin(); + increment(toImageSet(slideSystem.GetSourcePaths(key))); + print(); + } + void handleUnloadSlide(const QString &slide, SSlideKey key, ISlideSystem &slideSystem) + { + if (!loadedSlides.contains(slide)) + return; + loadedSlides.removeOne(slide); + begin(); + decrement(toImageSet(slideSystem.GetSourcePaths(key))); + print(); + } + void print() + { + static const bool debugging = qEnvironmentVariableIntValue("QT3DS_DEBUG") >= 1; + if (debugging) { + qDebug() << "SlideResourceCounter resources:"; + const auto keys = counters.keys(); + for (auto &x : keys) + qDebug() << x << ": " << counters[x]; + if (createSet.size()) { + qDebug() << "New resources: "; + for (auto y : qAsConst(createSet)) + qDebug() << y; + } + if (deleteSet.size()) { + qDebug() << "Deleted resources: "; + for (auto y : qAsConst(deleteSet)) + qDebug() << y; + } + } + } +}; + +struct STextureUploadRenderTask : public IRenderTask +{ + IBufferManager &m_bufferManager; + QSet<QString> m_uploadSet; + QSet<QString> m_deleteSet; + QMutex m_updateMutex; + + STextureUploadRenderTask(IBufferManager &mgr) + : m_bufferManager(mgr) + { + + } + void Run() override + { + QMutexLocker loc(&m_updateMutex); + m_bufferManager.loadSet(m_uploadSet); + m_bufferManager.unloadSet(m_deleteSet); + } + void add(const QSet<QString> &set) + { + QMutexLocker loc(&m_updateMutex); + m_uploadSet.unite(set); + m_deleteSet.subtract(set); + } + void remove(const QSet<QString> &set) + { + QMutexLocker loc(&m_updateMutex); + m_uploadSet.subtract(set); + m_deleteSet.unite(set); + } + bool persistent() const override + { + return true; + } +}; + struct SApp; class IAppLoadContext : public NVRefCounted @@ -402,7 +540,6 @@ public: struct SApp : public IApplication { - NVScopedRefCounted<Q3DStudio::IRuntimeFactoryCore> m_CoreFactory; NVScopedRefCounted<Q3DStudio::IRuntimeFactory> m_RuntimeFactory; @@ -425,6 +562,7 @@ struct SApp : public IApplication // the name of the file without extension. eastl::string m_Filename; Q3DSVariantConfig m_variantConfig; + QScopedPointer<STextureUploadRenderTask> m_uploadRenderTask; qt3ds::foundation::NVScopedReleasable<IRuntimeMetaData> m_MetaData; nvvector<eastl::pair<SBehaviorAsset, bool>> m_Behaviors; @@ -461,6 +599,9 @@ struct SApp : public IApplication DataInputMap m_dataInputDefs; + SSlideResourceCounter m_resourceCounter; + QSet<QString> m_createSet; + QT3DSI32 mRefCount; SApp(Q3DStudio::IRuntimeFactoryCore &inFactory, const char8_t *inAppDir) : m_CoreFactory(inFactory) @@ -495,9 +636,9 @@ struct SApp : public IApplication , m_ThisFrameStartTime(0) , m_MillisecondsSinceLastFrame(0) , m_DirtyCountdown(5) + , m_visitor(nullptr) , m_createSuccessful(false) , mRefCount(0) - , m_visitor(nullptr) { m_AudioPlayer.SetApplication(*this); eastl::string tempStr(inAppDir); @@ -563,6 +704,21 @@ struct SApp : public IApplication } return m_PresentationBuffer; } + QVector<CPresentation *> getPresentations() + { + QVector<CPresentation *> presentations; + if (m_PresentationBuffer.empty()) { + for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) { + SAssetValue &theAsset = *m_OrderedAssets[idx].second; + if (theAsset.getType() == AssetValueTypes::Presentation) { + SPresentationAsset &thePresAsset = *theAsset.getDataPtr<SPresentationAsset>(); + if (thePresAsset.m_Presentation) + presentations.push_back(thePresAsset.m_Presentation); + } + } + } + return presentations; + } void addRef() override { atomicIncrement(&mRefCount); } @@ -895,6 +1051,49 @@ struct SApp : public IApplication // Generalized save/load //////////////////////////////////////////////////////////////////////////////// + void loadComponentSlideResources(TElement *component, CPresentation *presentation, int index, + const QString slideName) + { + if (m_RuntimeFactory->GetQt3DSRenderContext().GetBufferManager() + .isReloadableResourcesEnabled()) { + auto &slidesystem = presentation->GetSlideSystem(); + SSlideKey key; + key.m_Component = component; + key.m_Index = index; + slidesystem.setUnloadSlide(key, false); + const QString completeName = presentation->GetName() + QLatin1Char(':') + + QString::fromUtf8(key.m_Component->m_Name) + QLatin1Char(':') + slideName; + qCInfo(PERF_INFO) << "Load component slide resources: " << completeName; + m_resourceCounter.handleLoadSlide(completeName, key, slidesystem); + if (m_uploadRenderTask) + m_uploadRenderTask->add(m_resourceCounter.createSet); + else + m_createSet.unite(m_resourceCounter.createSet); + } + } + + void unloadComponentSlideResources(TElement *component, CPresentation *presentation, int index, + const QString slideName) + { + if (m_RuntimeFactory->GetQt3DSRenderContext().GetBufferManager() + .isReloadableResourcesEnabled()) { + auto &slidesystem = presentation->GetSlideSystem(); + SSlideKey key; + key.m_Component = component; + key.m_Index = index; + slidesystem.setUnloadSlide(key, true); + if (!slidesystem.isActiveSlide(key)) { + const QString completeName = presentation->GetName() + QLatin1Char(':') + + QString::fromUtf8(key.m_Component->m_Name) + QLatin1Char(':') + slideName; + qCInfo(PERF_INFO) << "Unload component slide resources: " << completeName; + m_resourceCounter.handleUnloadSlide(completeName, key, slidesystem); + + if (m_uploadRenderTask) + m_uploadRenderTask->remove(m_resourceCounter.deleteSet); + } + } + } + bool LoadUIP(SPresentationAsset &inAsset, NVConstDataRef<SElementAttributeReference> inExternalReferences) { @@ -939,6 +1138,12 @@ struct SApp : public IApplication if (inAsset.m_Id.IsValid()) newScene->RegisterOffscreenRenderer(inAsset.m_Id); + + QVector<TElement *> components; + thePresentation->GetRoot()->findComponents(components); + for (auto &component : qAsConst(components)) + loadComponentSlideResources(component, thePresentation, 0, "Master"); + return true; } } @@ -1087,7 +1292,7 @@ struct SApp : public IApplication } }; - virtual bool BeginLoad(const QString &sourcePath, const QStringList &variantList) override + bool BeginLoad(const QString &sourcePath, const QStringList &variantList) override { SStackPerfTimer __loadTimer(m_CoreFactory->GetPerfTimer(), "Application: Begin Load"); eastl::string directory; @@ -1198,6 +1403,82 @@ struct SApp : public IApplication return m_createSuccessful; } + bool presentationComponentSlide(const QString &elementPath, + Q3DStudio::CPresentation *&presentation, + TElement *&component, + QString &slideName, + int &index) + { + presentation = GetPrimaryPresentation(); + slideName = elementPath; + QString componentName; + if (elementPath.contains(QLatin1Char(':'))) { + // presentation : component : slide + QStringList splits = elementPath.split(QLatin1Char(':')); + if (splits.size() == 3) { + presentation = GetPresentationById(qPrintable(splits[0])); + componentName = splits[1]; + slideName = splits[2]; + } else { + componentName = splits[0]; + slideName = splits[1]; + } + // else assume main presentation and component:slide + } + component = presentation->GetRoot(); + if (!componentName.isNull() && componentName != component->m_Name) + component = component->FindChild(CHash::HashString(qPrintable(componentName))); + if (!component) { + qCWarning(WARNING) << "Could not find slide: " << elementPath; + return false; + } + ISlideSystem &s = presentation->GetSlideSystem(); + index = s.FindSlide(*component, qPrintable(slideName)); + return true; + } + + void preloadSlide(const QString &slide) override + { + CPresentation *pres = nullptr; + TElement *component = nullptr; + QString slideName; + int index; + if (presentationComponentSlide(slide, pres, component, slideName, index)) + loadComponentSlideResources(component, pres, index, slideName); + } + + void unloadSlide(const QString &slide) override + { + CPresentation *pres = nullptr; + TElement *component = nullptr; + QString slideName; + int index; + if (presentationComponentSlide(slide, pres, component, slideName, index)) + unloadComponentSlideResources(component, pres, index, slideName); + } + + void setDelayedLoading(bool enable) + { + m_RuntimeFactory->GetQt3DSRenderContext().GetBufferManager() + .enableReloadableResources(enable); + } + + void ComponentSlideEntered(Q3DStudio::CPresentation *presentation, + Q3DStudio::TElement *component, + const QString &elementPath, int slideIndex, + const QString &slideName) override + { + loadComponentSlideResources(component, presentation, slideIndex, slideName); + } + + void ComponentSlideExited(Q3DStudio::CPresentation *presentation, + Q3DStudio::TElement *component, + const QString &elementPath, int slideIndex, + const QString &slideName) override + { + unloadComponentSlideResources(component, presentation, slideIndex, slideName); + } + // will force loading to end if endLoad hasn't been called yet. Will fire off loading // of resources that need to be uploaded to opengl. Maintains reference to runtime factory IApplication &CreateApplication(Q3DStudio::CInputEngine &inInputEngine, @@ -1275,6 +1556,12 @@ struct SApp : public IApplication m_AudioPlayer.SetPlayer(inAudioPlayer); + m_uploadRenderTask.reset(new STextureUploadRenderTask( + m_RuntimeFactory->GetQt3DSRenderContext().GetBufferManager())); + m_uploadRenderTask->add(m_createSet); + m_RuntimeFactory->GetQt3DSRenderContext().GetRenderList() + .AddRenderTask(*m_uploadRenderTask); + m_createSet.clear(); return *this; } @@ -1567,7 +1854,7 @@ CAppStr &CAppStr::operator=(const CAppStr &inOther) return *this; } -IApplicationCore &IApplicationCore::CreateApplicationCore(Q3DStudio::IRuntimeFactoryCore &inFactory, +IApplication &IApplication::CreateApplicationCore(Q3DStudio::IRuntimeFactoryCore &inFactory, const char8_t *inApplicationDirectory) { return *QT3DS_NEW(inFactory.GetFoundation().getAllocator(), SApp)(inFactory, @@ -1575,7 +1862,7 @@ IApplicationCore &IApplicationCore::CreateApplicationCore(Q3DStudio::IRuntimeFac } // Checks if the event is one that can cause picking -bool IApplicationCore::isPickingEvent(TEventCommandHash event) +bool IApplication::isPickingEvent(TEventCommandHash event) { return (event == ON_MOUSEDOWN || event == ON_MOUSEUP diff --git a/src/Runtime/Source/runtime/Qt3DSApplication.h b/src/Runtime/Source/runtime/Qt3DSApplication.h index 2e7eabad..972c2ad0 100644 --- a/src/Runtime/Source/runtime/Qt3DSApplication.h +++ b/src/Runtime/Source/runtime/Qt3DSApplication.h @@ -85,61 +85,6 @@ public: virtual void Run() = 0; }; -class QT3DS_AUTOTEST_EXPORT IApplicationCore : public NVRefCounted -{ -public: - // threadsafe call. - virtual void QueueForMainThread(IAppRunnable &inRunnable) = 0; - - // The directory that contains the executable and the root resource path - virtual CRegisteredString GetApplicationDirectory() const = 0; - // Directory that contained the UIA file. - virtual CRegisteredString GetProjectDirectory() const = 0; - // Directory where we will copy shared object files to before we load them. - // This is specifically for android and the case where the place where the project exists - // is not always the place where we can load the project. - virtual CRegisteredString GetDllDir() const = 0; - virtual void SetDllDir(const char *inDllDir) = 0; - virtual Q3DStudio::THashValue HashString(const char *inStr) = 0; - virtual const char *ReverseHash(Q3DStudio::THashValue theValue) = 0; - - virtual Q3DStudio::IRuntimeMetaData &GetMetaData() = 0; - // Element handles are unique across all presentations. - virtual Q3DStudio::TElement *GetElementByHandle(Q3DStudio::UINT32 inHandle) = 0; - // Passing in NULL gets you zero as the return handle. - virtual Q3DStudio::UINT32 GetHandleForElement(Q3DStudio::TElement *inElement) = 0; - - virtual Q3DStudio::IRuntimeFactoryCore &GetRuntimeFactoryCore() = 0; - virtual void HideFPS(bool flag) = 0; - - virtual IActivityZoneManager &GetActivityZoneManager() = 0; - virtual IElementAllocator &GetElementAllocator() = 0; - - // nonblocking call to begin loading, loads uia file alone and returns. - virtual bool BeginLoad(const QString &sourcePath, const QStringList &variantList) = 0; - - // blocking call to end all loading threads and such/wait till finished - virtual void EndLoad() = 0; - // Will EndLoad cause nontrivial blocking. - // Runs any queued runnables. - virtual bool HasCompletedLoading() = 0; - - virtual void setAssetVisitor(qt3ds::Qt3DSAssetVisitor *) = 0; - - // will force loading to end if endLoad hasn't been called yet. Will fire off loading - // of resources that need to be uploaded to opengl. Maintains reference to runtime factory - virtual IApplication &CreateApplication(Q3DStudio::CInputEngine &inInputEngine, - Q3DStudio::IAudioPlayer *inAudioPlayer, - Q3DStudio::IRuntimeFactory &inFactory) = 0; - - // maintains reference to runtime factory core. AppDir is where the executable is located; - // the system will expect res directory - // next to executable. - static IApplicationCore &CreateApplicationCore(Q3DStudio::IRuntimeFactoryCore &inFactory, - const char8_t *inApplicationDirectory); - static bool isPickingEvent(Q3DStudio::TEventCommandHash event); -}; - struct DataInputControlledAttribute { QByteArray elementPath; @@ -176,7 +121,7 @@ struct DataInputDef typedef QMap<QString, DataInputDef> DataInputMap; -class IApplication : public IApplicationCore +class QT3DS_AUTOTEST_EXPORT IApplication : public NVRefCounted { public: virtual Q3DStudio::IRuntimeFactory &GetRuntimeFactory() const = 0; @@ -223,6 +168,69 @@ public: virtual float dataInputMin(const QString &name) const = 0; virtual void setPresentationId(const QString &id) = 0; + + virtual void preloadSlide(const QString &slide) = 0; + virtual void unloadSlide(const QString &slide) = 0; + virtual void setDelayedLoading(bool enable) = 0; + + // threadsafe call. + virtual void QueueForMainThread(IAppRunnable &inRunnable) = 0; + + // The directory that contains the executable and the root resource path + virtual CRegisteredString GetApplicationDirectory() const = 0; + // Directory that contained the UIA file. + virtual CRegisteredString GetProjectDirectory() const = 0; + // Directory where we will copy shared object files to before we load them. + // This is specifically for android and the case where the place where the project exists + // is not always the place where we can load the project. + virtual CRegisteredString GetDllDir() const = 0; + virtual void SetDllDir(const char *inDllDir) = 0; + virtual Q3DStudio::THashValue HashString(const char *inStr) = 0; + virtual const char *ReverseHash(Q3DStudio::THashValue theValue) = 0; + + virtual Q3DStudio::IRuntimeMetaData &GetMetaData() = 0; + // Element handles are unique across all presentations. + virtual Q3DStudio::TElement *GetElementByHandle(Q3DStudio::UINT32 inHandle) = 0; + // Passing in NULL gets you zero as the return handle. + virtual Q3DStudio::UINT32 GetHandleForElement(Q3DStudio::TElement *inElement) = 0; + + virtual Q3DStudio::IRuntimeFactoryCore &GetRuntimeFactoryCore() = 0; + virtual void HideFPS(bool flag) = 0; + + virtual IActivityZoneManager &GetActivityZoneManager() = 0; + virtual IElementAllocator &GetElementAllocator() = 0; + + // nonblocking call to begin loading, loads uia file alone and returns. + virtual bool BeginLoad(const QString &sourcePath, const QStringList &variantList) = 0; + // blocking call to end all loading threads and such/wait till finished + virtual void EndLoad() = 0; + // Will EndLoad cause nontrivial blocking. + // Runs any queued runnables. + virtual bool HasCompletedLoading() = 0; + + virtual void setAssetVisitor(qt3ds::Qt3DSAssetVisitor *) = 0; + + virtual void ComponentSlideEntered(Q3DStudio::CPresentation *presentation, + Q3DStudio::TElement *component, + const QString &elementPath, int slideIndex, + const QString &slideName) = 0; + virtual void ComponentSlideExited(Q3DStudio::CPresentation *presentation, + Q3DStudio::TElement *component, + const QString &elementPath, int slideIndex, + const QString &slideName) = 0; + + // will force loading to end if endLoad hasn't been called yet. Will fire off loading + // of resources that need to be uploaded to opengl. Maintains reference to runtime factory + virtual IApplication &CreateApplication(Q3DStudio::CInputEngine &inInputEngine, + Q3DStudio::IAudioPlayer *inAudioPlayer, + Q3DStudio::IRuntimeFactory &inFactory) = 0; + + // maintains reference to runtime factory core. AppDir is where the executable is located; + // the system will expect res directory + // next to executable. + static IApplication &CreateApplicationCore(Q3DStudio::IRuntimeFactoryCore &inFactory, + const char8_t *inApplicationDirectory); + static bool isPickingEvent(Q3DStudio::TEventCommandHash event); }; } } diff --git a/src/Runtime/Source/runtime/Qt3DSComponentManager.cpp b/src/Runtime/Source/runtime/Qt3DSComponentManager.cpp index 2cfb2311..d7ce0b6a 100644 --- a/src/Runtime/Source/runtime/Qt3DSComponentManager.cpp +++ b/src/Runtime/Source/runtime/Qt3DSComponentManager.cpp @@ -106,6 +106,10 @@ void CComponentManager::GotoSlideIndex(TElement *inComponent, theEvent.m_IsEvent = true; m_Presentation.ProcessEvent(theEvent); + m_Presentation.GetApplication().ComponentSlideExited(&m_Presentation, inComponent, + elementPath, theCurrentSlideIndex, + GetCurrentSlideName(inComponent)); + // Signal previous slide change m_Presentation.signalProxy()->SigSlideExited(elementPath, theCurrentSlideIndex, GetCurrentSlideName(inComponent)); @@ -182,6 +186,9 @@ void CComponentManager::GotoSlideIndex(TElement *inComponent, if (theZone) theZone->OnSlideChange(*inComponent); + m_Presentation.GetApplication().ComponentSlideEntered(&m_Presentation, inComponent, + elementPath, theGotoSlideData.m_Slide, + GetCurrentSlideName(inComponent)); // Signal current slide change m_Presentation.signalProxy()->SigSlideEntered(elementPath, GetCurrentSlide(inComponent), GetCurrentSlideName(inComponent)); diff --git a/src/Runtime/Source/runtime/Qt3DSElementSystem.h b/src/Runtime/Source/runtime/Qt3DSElementSystem.h index b9355c55..12ebebd9 100644 --- a/src/Runtime/Source/runtime/Qt3DSElementSystem.h +++ b/src/Runtime/Source/runtime/Qt3DSElementSystem.h @@ -508,6 +508,16 @@ namespace runtime { return ta && ua && inParentActive; } + void findComponents(QVector<SElement *> &components) + { + if (IsComponent()) + components.push_back(this); + SElement *child = m_Child; + while (child) { + child->findComponents(components); + child = child->m_Sibling; + } + } }; struct SGetElementNodeDirtyIndex diff --git a/src/Runtime/Source/runtime/Qt3DSIScene.h b/src/Runtime/Source/runtime/Qt3DSIScene.h index 8872b93f..3f80f85f 100644 --- a/src/Runtime/Source/runtime/Qt3DSIScene.h +++ b/src/Runtime/Source/runtime/Qt3DSIScene.h @@ -156,10 +156,6 @@ public: // Base Interface virtual void ScreenToPosition(TElement &inElement, qt3ds::QT3DSVec3 &inScreen, qt3ds::QT3DSVec3 &outPos) = 0; - // This is the best place for now... - virtual void GetImageInfoFromRenderEngine(TElement *inElement, INT32 &ioWidth, - INT32 &ioHeight) = 0; - virtual qt3ds::foundation::CRegisteredString RegisterStr(const char *inStr) = 0; virtual Q3DStudio::INT32 diff --git a/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h b/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h index af322319..4be6fe16 100644 --- a/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h +++ b/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h @@ -41,7 +41,6 @@ namespace qt3ds { namespace runtime { class IApplication; - class IApplicationCore; } } namespace qt3ds { @@ -130,7 +129,7 @@ public: // thread virtual void DisableMultithreadedAccess() = 0; public: // Settings - virtual void SetApplicationCore(qt3ds::runtime::IApplicationCore &inApplication) = 0; + virtual void SetApplicationCore(qt3ds::runtime::IApplication &inApplication) = 0; virtual void SetApplication(qt3ds::runtime::IApplication &inApplication) = 0; public: // Scripts diff --git a/src/Runtime/Source/runtime/Qt3DSLogicSystem.cpp b/src/Runtime/Source/runtime/Qt3DSLogicSystem.cpp index 1aec08f1..4a8341b4 100644 --- a/src/Runtime/Source/runtime/Qt3DSLogicSystem.cpp +++ b/src/Runtime/Source/runtime/Qt3DSLogicSystem.cpp @@ -221,7 +221,7 @@ struct SLogicSystem : public ILogicSystem listIter != listEnd; ++listIter) if (listIter->m_Id == inActionIndex) { listIter->m_Active = inActive; - if (IApplicationCore::isPickingEvent(logicIter->first.m_CommandHash)) { + if (IApplication::isPickingEvent(logicIter->first.m_CommandHash)) { SElement *theElement = inElemAllocator.FindElementByHandle( logicIter->first.m_ElementHandle); if (theElement && inActive) diff --git a/src/Runtime/Source/runtime/Qt3DSPresentation.cpp b/src/Runtime/Source/runtime/Qt3DSPresentation.cpp index 68691a99..a4302ad5 100644 --- a/src/Runtime/Source/runtime/Qt3DSPresentation.cpp +++ b/src/Runtime/Source/runtime/Qt3DSPresentation.cpp @@ -125,7 +125,7 @@ void CPresentation::RegisterEventCallback(TElement *inElement, const TEventComma m_EventCallbacks.RegisterCallback(inElement, inEventHash, inCallback, inContextData); inElement->SetFlag(ELEMENTFLAG_REGISTEREDFOREVENTCALLBACK, true); - if (qt3ds::runtime::IApplicationCore::isPickingEvent(inEventHash)) + if (qt3ds::runtime::IApplication::isPickingEvent(inEventHash)) inElement->SetFlag(ELEMENTFLAG_PICKENABLED, true); } @@ -149,7 +149,7 @@ BOOL CPresentation::UnregisterEventCallback(TElement *inElement, if (theLast) inElement->SetFlag(ELEMENTFLAG_REGISTEREDFOREVENTCALLBACK, false); - if (qt3ds::runtime::IApplicationCore::isPickingEvent(inEventHash)) + if (qt3ds::runtime::IApplication::isPickingEvent(inEventHash)) inElement->SetFlag(ELEMENTFLAG_PICKENABLED, false); return theResult; diff --git a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp index 1c8d5c31..0898df70 100644 --- a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp +++ b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp @@ -85,7 +85,6 @@ namespace Q3DStudio { #define Q3DStudio_LOG_EVENT(S) #endif -using qt3ds::runtime::IApplicationCore; using qt3ds::runtime::IApplication; using namespace qt3ds; @@ -362,7 +361,7 @@ class CQmlEngineImpl : public CQmlEngine private: qt3ds::NVFoundationBase &m_Foundation; IApplication *m_Application; - IApplicationCore *m_ApplicationCore; + IApplication *m_ApplicationCore; qt3ds::foundation::Mutex m_PreloadMutex; qt3ds::foundation::Mutex *m_MultithreadedMutex; @@ -385,7 +384,7 @@ public: void EnableMultithreadedAccess() override; void DisableMultithreadedAccess() override; - void SetApplicationCore(qt3ds::runtime::IApplicationCore &inApplication) override; + void SetApplicationCore(qt3ds::runtime::IApplication &inApplication) override; void SetApplication(qt3ds::runtime::IApplication &inApplication) override; qt3ds::runtime::IApplication *GetApplication() override; void Initialize() override; @@ -492,7 +491,7 @@ void CQmlEngineImpl::DisableMultithreadedAccess() m_MultithreadedMutex = NULL; } -void CQmlEngineImpl::SetApplicationCore(qt3ds::runtime::IApplicationCore &inApplication) +void CQmlEngineImpl::SetApplicationCore(runtime::IApplication &inApplication) { QML_ENGINE_MULTITHREAD_PROTECT_METHOD; m_ApplicationCore = &inApplication; diff --git a/src/Runtime/Source/runtime/Qt3DSRuntimeFactory.h b/src/Runtime/Source/runtime/Qt3DSRuntimeFactory.h index 4c6de842..fb46240c 100644 --- a/src/Runtime/Source/runtime/Qt3DSRuntimeFactory.h +++ b/src/Runtime/Source/runtime/Qt3DSRuntimeFactory.h @@ -44,7 +44,6 @@ namespace render { namespace qt3ds { namespace runtime { class IApplication; - class IApplicationCore; } } @@ -90,8 +89,8 @@ public: virtual qt3ds::foundation::IStringTable &GetStringTable() = 0; virtual void AddSearchPath(const char8_t *inFile) = 0; virtual void SetDllDir(const char *inDir) = 0; - virtual qt3ds::runtime::IApplicationCore *GetApplicationCore() = 0; - virtual void SetApplicationCore(qt3ds::runtime::IApplicationCore *app) = 0; + virtual qt3ds::runtime::IApplication *GetApplicationCore() = 0; + virtual void SetApplicationCore(qt3ds::runtime::IApplication *app) = 0; }; class IRuntimeFactory : public IRuntimeFactoryCore diff --git a/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp b/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp index e7cc0983..524422f4 100644 --- a/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp +++ b/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp @@ -72,7 +72,7 @@ struct SSlideAttributeNode SSlideAttributeNode *m_NextNode; SSlideAttributeNode() - : m_NextNode(NULL) + : m_NextNode(nullptr) { } }; @@ -93,8 +93,8 @@ struct SSlideElement : m_ElementHandle(0) , m_AttributeCount(0) , m_Active(false) - , m_NextElement(NULL) - , m_AttributeNodes(NULL) + , m_NextElement(nullptr) + , m_AttributeNodes(nullptr) { } }; @@ -107,7 +107,7 @@ struct SSlideAnimActionNode SSlideAnimAction m_Data[AnimActionCount]; SSlideAnimActionNode *m_NextNode; SSlideAnimActionNode() - : m_NextNode(NULL) + : m_NextNode(nullptr) { } }; @@ -128,17 +128,22 @@ struct SSlide QT3DSU32 m_AnimActionCount; SSlideElement *m_FirstElement; SSlideAnimActionNode *m_FirstAnimActionNode; + QVector<QString> m_sourcePaths; + bool m_activeSlide; + bool m_unloadSlide; SSlide() - : m_NextSlide(NULL) + : m_NextSlide(nullptr) , m_PlayMode(PlayMode::StopAtEnd) , m_PlayThroughTo(0xFF) , m_Paused(false) , m_StartTime(0) , m_EndTime(0) , m_AnimActionCount(0) - , m_FirstElement(NULL) - , m_FirstAnimActionNode(NULL) + , m_FirstElement(nullptr) + , m_FirstAnimActionNode(nullptr) + , m_activeSlide(false) + , m_unloadSlide(false) { } @@ -187,8 +192,8 @@ struct SSlideSystem : public ISlideSystem , m_SlidePool(ForwardingAllocator(inFnd.getAllocator(), "m_SlidePool")) , m_SlideElements(ForwardingAllocator(inFnd.getAllocator(), "m_SlideElements")) , m_Slides(inFnd.getAllocator(), "m_Slides") - , m_CurrentSlide(NULL) - , m_CurrentSlideElement(NULL) + , m_CurrentSlide(nullptr) + , m_CurrentSlideElement(nullptr) , m_RefCount(0) { } @@ -209,14 +214,14 @@ struct SSlideSystem : public ISlideSystem QT3DSU32 inMinTime, QT3DSU32 inMaxTime) override { eastl::pair<TComponentSlideHash::iterator, bool> inserter = - m_Slides.insert(eastl::make_pair(&inComponent, (SSlide *)NULL)); + m_Slides.insert(eastl::make_pair(&inComponent, (SSlide *)nullptr)); SSlide *newSlide = m_SlidePool.construct(__FILE__, __LINE__); QT3DSU32 slideIndex = 0; - if (inserter.first->second == NULL) { + if (inserter.first->second == nullptr) { inserter.first->second = newSlide; } else { - SSlide *theSlide = NULL; - for (theSlide = inserter.first->second; theSlide->m_NextSlide != NULL; + SSlide *theSlide = nullptr; + for (theSlide = inserter.first->second; theSlide->m_NextSlide != nullptr; theSlide = theSlide->m_NextSlide) { ++slideIndex; } @@ -225,7 +230,7 @@ struct SSlideSystem : public ISlideSystem m_CurrentSlide = newSlide; newSlide->Initialize(m_StringTable.RegisterStr(inName), inPlayMode, inPlayThroughTo, inPaused, inMinTime, inMaxTime); - m_CurrentSlideElement = NULL; + m_CurrentSlideElement = nullptr; if (inComponent.IsComponent()) { SComponent &theComponent = static_cast<SComponent &>(inComponent); theComponent.m_SlideCount++; @@ -233,21 +238,35 @@ struct SSlideSystem : public ISlideSystem return slideIndex; } + void AddSourcePath(const char8_t *path) override + { + if (m_CurrentSlide) + m_CurrentSlide->m_sourcePaths.push_back(QString::fromUtf8(path)); + } + + QVector<QString> GetSourcePaths(SSlideKey inKey) override + { + auto slide = FindSlide(inKey); + if (slide) + return slide->m_sourcePaths; + return {}; + } + void SetSlideMaxTime(QT3DSU32 inMaxTime) override { - if (m_CurrentSlide != NULL) + if (m_CurrentSlide != nullptr) m_CurrentSlide->m_EndTime = inMaxTime; } void AddSlideElement(element::SElement &inElement, bool inActive) override { - if (m_CurrentSlide != NULL) { + if (m_CurrentSlide != nullptr) { SSlideElement *lastSlideElement = m_CurrentSlideElement; m_CurrentSlideElement = m_SlideElements.construct(__FILE__, __LINE__); m_CurrentSlideElement->m_Active = inActive; m_CurrentSlideElement->m_ElementHandle = inElement.GetHandle(); - if (lastSlideElement == NULL) { - QT3DS_ASSERT(m_CurrentSlide->m_FirstElement == NULL); + if (lastSlideElement == nullptr) { + QT3DS_ASSERT(m_CurrentSlide->m_FirstElement == nullptr); m_CurrentSlide->m_FirstElement = m_CurrentSlideElement; } else { lastSlideElement->m_NextElement = m_CurrentSlideElement; @@ -259,7 +278,7 @@ struct SSlideSystem : public ISlideSystem } void AddSlideAttribute(Q3DStudio::SAttributeKey inKey, Q3DStudio::UVariant inValue) override { - if (m_CurrentSlideElement != NULL) { + if (m_CurrentSlideElement != nullptr) { SElement *theElement = m_ElementSystem.FindElementByHandle(m_CurrentSlideElement->m_ElementHandle); @@ -278,7 +297,7 @@ struct SSlideSystem : public ISlideSystem SSlideAnimAction *AddSlideAnimAction(bool inAnimation, QT3DSI32 inId, bool inActive) override { - if (m_CurrentSlide != NULL) { + if (m_CurrentSlide != nullptr) { SSlideAnimAction &theAnimAction = TSlideAnimActionNodeList::Create( m_CurrentSlide->m_FirstAnimActionNode, m_CurrentSlide->m_AnimActionCount, m_AnimActionPool); @@ -286,14 +305,29 @@ struct SSlideSystem : public ISlideSystem &theAnimAction; } - return NULL; + return nullptr; } const SSlide *FindSlide(SSlideKey inKey) const { TComponentSlideHash::const_iterator iter = m_Slides.find(inKey.m_Component); if (iter == m_Slides.end()) - return NULL; + return nullptr; + + SSlide *theSlide = iter->second; + for (QT3DSU32 idx = inKey.m_Index; idx; --idx) { + if (theSlide) + theSlide = theSlide->m_NextSlide; + } + + return theSlide; + } + + SSlide *FindSlide(SSlideKey inKey) + { + TComponentSlideHash::const_iterator iter = m_Slides.find(inKey.m_Component); + if (iter == m_Slides.end()) + return nullptr; SSlide *theSlide = iter->second; for (QT3DSU32 idx = inKey.m_Index; idx; --idx) { @@ -417,17 +451,17 @@ struct SSlideSystem : public ISlideSystem void InitializeDynamicKeys(SSlideKey inKey, IAnimationSystem &inAnimationSystem) const override { const SSlide *theSlide = FindSlide(inKey); - if (theSlide != NULL) { + if (theSlide != nullptr) { IterateSlideAnimActions(*theSlide, SDynamicKeyOperator(inAnimationSystem)); } } void ExecuteSlide(SSlideKey inKey, IAnimationSystem &inAnimationSystem, - ILogicSystem &inLogicManager) const override + ILogicSystem &inLogicManager) override { - const SSlide *theSlide = FindSlide(inKey); + SSlide *theSlide = FindSlide(inKey); - if (theSlide == NULL) { + if (theSlide == nullptr) { QT3DS_ASSERT(false); return; } @@ -458,22 +492,23 @@ struct SSlideSystem : public ISlideSystem theComponent.SetPlayThrough(theSlide->m_PlayMode == PlayMode::PlayThroughTo); } - + theSlide->m_activeSlide = true; IterateSlideElementAttributes(*theSlide, SElementOperator(false), m_ElementSystem); IterateSlideAnimActions(*theSlide, SExecuteAnimActionOperator( m_ElementSystem, inAnimationSystem, inLogicManager)); } void RollbackSlide(SSlideKey inKey, IAnimationSystem &inAnimationSystem, - ILogicSystem &inLogicManager) const override + ILogicSystem &inLogicManager) override { - const SSlide *theSlide = FindSlide(inKey); + SSlide *theSlide = FindSlide(inKey); - if (theSlide == NULL) { + if (theSlide == nullptr) { QT3DS_ASSERT(false); return; } + theSlide->m_activeSlide = false; IterateSlideElementAttributes(*theSlide, SElementOperator(true), m_ElementSystem); IterateSlideAnimActions( *theSlide, @@ -531,6 +566,30 @@ struct SSlideSystem : public ISlideSystem QT3DS_ASSERT(false); return 0xFF; } + + bool isActiveSlide(SSlideKey inKey) const override + { + const SSlide *theSlide = FindSlide(inKey); + return theSlide->m_activeSlide; + } + + void setUnloadSlide(SSlideKey inKey, bool unload) override + { + SSlide *theSlide = FindSlide(inKey); + theSlide->m_unloadSlide = unload; + } + + bool isUnloadSlideSet(SSlideKey inKey) const override + { + const SSlide *theSlide = FindSlide(inKey); + return theSlide->m_unloadSlide; + } + + void setIsActiveSlide(SSlideKey inKey, bool active) override + { + SSlide *theSlide = FindSlide(inKey); + theSlide->m_activeSlide = active; + } }; } diff --git a/src/Runtime/Source/runtime/Qt3DSSlideSystem.h b/src/Runtime/Source/runtime/Qt3DSSlideSystem.h index de2ddbbc..becc057f 100644 --- a/src/Runtime/Source/runtime/Qt3DSSlideSystem.h +++ b/src/Runtime/Source/runtime/Qt3DSSlideSystem.h @@ -130,14 +130,20 @@ namespace runtime { Q3DStudio::UVariant inValue) = 0; virtual SSlideAnimAction *AddSlideAnimAction(bool inAnimation, QT3DSI32 inIndex, bool inActive) = 0; + virtual void AddSourcePath(const char8_t *path) = 0; + virtual QVector<QString> GetSourcePaths(SSlideKey inKey) = 0; + virtual void setIsActiveSlide(SSlideKey inKey, bool active) = 0; + virtual bool isActiveSlide(SSlideKey inKey) const = 0; + virtual void setUnloadSlide(SSlideKey inKey, bool unload) = 0; + virtual bool isUnloadSlideSet(SSlideKey inKey) const = 0; // Using the dataset virtual void InitializeDynamicKeys(SSlideKey inKey, IAnimationSystem &inAnimationSystem) const = 0; virtual void ExecuteSlide(SSlideKey inKey, IAnimationSystem &inAnimationSystem, - ILogicSystem &inLogicManager) const = 0; + ILogicSystem &inLogicManager) = 0; virtual void RollbackSlide(SSlideKey inKey, IAnimationSystem &inAnimationSystem, - ILogicSystem &inLogicManager) const = 0; + ILogicSystem &inLogicManager) = 0; virtual QT3DSU8 FindSlide(element::SElement &inComponent, const char8_t *inSlideName) const = 0; virtual QT3DSU8 FindSlide(element::SElement &inComponent, QT3DSU32 inSlideHashName) const = 0; diff --git a/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.cpp b/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.cpp index 3c940805..207059fc 100644 --- a/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.cpp +++ b/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.cpp @@ -126,7 +126,8 @@ struct SRenderContextCore : public IQt3DSRenderContextCore IRenderPluginManagerCore &GetRenderPluginCore() override { return *m_RenderPluginManagerCore; } IPathManagerCore &GetPathManagerCore() override { return *m_PathManagerCore; } IQt3DSRenderContext &CreateRenderContext(NVRenderContext &inContext, - const char8_t *inPrimitivesDirectory) override; + const char8_t *inPrimitivesDirectory, + bool delayedLoading) override; void SetTextRendererCore(ITextRendererCore &inRenderer) override { m_TextRenderer = inRenderer; } ITextRendererCore *GetTextRendererCore() override { return m_TextRenderer.mPtr; } void setDistanceFieldRenderer(ITextRendererCore &inRenderer) override @@ -263,7 +264,7 @@ struct SRenderContext : public IQt3DSRenderContext bool m_AuthoringMode; SRenderContext(NVRenderContext &ctx, IQt3DSRenderContextCore &inCore, - const char8_t *inApplicationDirectory) + const char8_t *inApplicationDirectory, bool delayedLoading) : m_RenderContext(ctx) , m_CoreContext(inCore) , m_StringTable(ctx.GetStringTable()) @@ -288,6 +289,7 @@ struct SRenderContext : public IQt3DSRenderContext , m_FPS(qMakePair(0.0, 0)) , m_AuthoringMode(false) { + m_BufferManager->enableReloadableResources(delayedLoading); m_OffscreenRenderManager = IOffscreenRenderManager::CreateOffscreenRenderManager( ctx.GetAllocator(), *m_StringTable, *m_ResourceManager, *this); m_Renderer = IQt3DSRenderer::CreateRenderer(*this); @@ -827,10 +829,12 @@ struct SRenderContext : public IQt3DSRenderContext }; IQt3DSRenderContext &SRenderContextCore::CreateRenderContext(NVRenderContext &inContext, - const char8_t *inPrimitivesDirectory) + const char8_t *inPrimitivesDirectory, + bool delayedLoading) { return *QT3DS_NEW(m_Foundation.getAllocator(), SRenderContext)(inContext, *this, - inPrimitivesDirectory); + inPrimitivesDirectory, + delayedLoading); } } diff --git a/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.h b/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.h index 012864ba..2fcd1e0b 100644 --- a/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.h +++ b/src/Runtime/Source/runtimerender/Qt3DSRenderContextCore.h @@ -77,7 +77,8 @@ namespace render { virtual ITextRendererCore *GetOnscreenTextRendererCore() = 0; // The render context maintains a reference to this object. virtual IQt3DSRenderContext &CreateRenderContext(NVRenderContext &inContext, - const char8_t *inPrimitivesDirectory) = 0; + const char8_t *inPrimitivesDirectory, + bool delayedLoading) = 0; static IQt3DSRenderContextCore &Create(NVFoundationBase &fnd, IStringTable &strt); }; diff --git a/src/Runtime/Source/runtimerender/Qt3DSRenderImageTextureData.h b/src/Runtime/Source/runtimerender/Qt3DSRenderImageTextureData.h index d3698032..aaa73d7e 100644 --- a/src/Runtime/Source/runtimerender/Qt3DSRenderImageTextureData.h +++ b/src/Runtime/Source/runtimerender/Qt3DSRenderImageTextureData.h @@ -33,6 +33,9 @@ #include "Qt3DSRender.h" #include "foundation/Qt3DSFlags.h" +#include <QtCore/qsharedpointer.h> +#include <QtCore/qvector.h> + namespace qt3ds { namespace render { @@ -85,9 +88,16 @@ namespace render { Qt3DSRenderPrefilterTexture *m_BSDFMipMap; SImageTextureData() - : m_Texture(NULL) - , m_BSDFMipMap(NULL) + : m_Texture(nullptr) + , m_BSDFMipMap(nullptr) + { + } + + SImageTextureData(const SImageTextureData& data) + : m_Texture(data.m_Texture), m_TextureFlags(data.m_TextureFlags) + , m_BSDFMipMap(data.m_BSDFMipMap) { + } bool operator!=(const SImageTextureData &inOther) @@ -96,7 +106,33 @@ namespace render { || m_BSDFMipMap != inOther.m_BSDFMipMap; } }; + + struct IReloadableCallback + { + virtual ~IReloadableCallback() {} + virtual void onLoad() = 0; + virtual void onUnload() = 0; + }; + + struct SImage; + struct SReloadableImageTextureData : public SImageTextureData + { + QString m_path; + bool m_loaded; + bool m_scanTransparency; + bool m_bsdfMipmap; + bool m_initialized; + QVector<SImage *> m_callbacks; + + SReloadableImageTextureData() + : SImageTextureData() + , m_loaded(false), m_scanTransparency(false), m_bsdfMipmap(false), m_initialized(false) + { + } + }; + + typedef QSharedPointer<SReloadableImageTextureData> ReloadableTexturePtr; } } -#endif
\ No newline at end of file +#endif diff --git a/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.cpp b/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.cpp index 118c855d..05a7b2c4 100644 --- a/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.cpp +++ b/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.cpp @@ -45,6 +45,7 @@ struct SRenderList : public IRenderList NVFoundationBase &m_Foundation; TTaskList m_Tasks; + TTaskList m_PersistentTasks; QT3DSU32 m_NextTaskId; QT3DSI32 mRefCount; bool m_ScissorEnabled; @@ -54,6 +55,7 @@ struct SRenderList : public IRenderList SRenderList(NVFoundationBase &fnd) : m_Foundation(fnd) , m_Tasks(fnd.getAllocator(), "m_Tasks") + , m_PersistentTasks(fnd.getAllocator(), "m_PersistentTasks") , m_NextTaskId(1) , mRefCount(0) , m_ScissorEnabled(false) @@ -71,8 +73,14 @@ struct SRenderList : public IRenderList QT3DSU32 AddRenderTask(IRenderTask &inTask) override { QT3DSU32 taskId = m_NextTaskId; - ++m_NextTaskId; - m_Tasks.push_back(eastl::make_pair(taskId, &inTask)); + if (inTask.persistent()) { + m_PersistentTasks.push_back(eastl::make_pair(0, &inTask)); + taskId = 0; + } else { + QT3DSU32 taskId = m_NextTaskId; + ++m_NextTaskId; + m_Tasks.push_back(eastl::make_pair(taskId, &inTask)); + } return taskId; } @@ -89,9 +97,15 @@ struct SRenderList : public IRenderList // before rendering to the main render target. void RunRenderTasks() override { + for (TTaskList::reverse_iterator iter = m_PersistentTasks.rbegin(), + end = m_PersistentTasks.rend(); iter != end; + ++iter) { + iter->second->Run(); + } for (TTaskList::reverse_iterator iter = m_Tasks.rbegin(), end = m_Tasks.rend(); iter != end; - ++iter) + ++iter) { iter->second->Run(); + } BeginFrame(); } diff --git a/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.h b/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.h index c498c7ee..957c3d78 100644 --- a/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.h +++ b/src/Runtime/Source/runtimerender/Qt3DSRenderRenderList.h @@ -42,6 +42,10 @@ namespace render { public: virtual ~IRenderTask() {} virtual void Run() = 0; + virtual bool persistent() const + { + return false; + } }; /** diff --git a/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.cpp b/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.cpp index eaa98c77..1cbd6015 100644 --- a/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.cpp +++ b/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.cpp @@ -38,9 +38,9 @@ using namespace qt3ds::render; SImage::SImage() : SGraphObject(GraphObjectTypes::Image) - , m_RenderPlugin(NULL) - , m_LastFrameOffscreenRenderer(NULL) - , m_Parent(NULL) + , m_RenderPlugin(nullptr) + , m_LastFrameOffscreenRenderer(nullptr) + , m_Parent(nullptr) , m_Scale(1, 1) , m_Pivot(0, 0) , m_Rotation(0) @@ -84,7 +84,7 @@ bool SImage::ClearDirty(IBufferManager &inBufferManager, IOffscreenRenderManager } } - if (newImage.m_Texture == NULL) { + if (newImage.m_Texture == nullptr) { if (m_OffscreenRendererId.IsValid()) { SOffscreenRenderResult theResult = inRenderManager.GetRenderedItem(m_OffscreenRendererId); @@ -92,10 +92,26 @@ bool SImage::ClearDirty(IBufferManager &inBufferManager, IOffscreenRenderManager } } - if (newImage.m_Texture == NULL) { - m_LastFrameOffscreenRenderer = NULL; - newImage = inBufferManager.LoadRenderImage(m_ImagePath, false, forIbl); - replaceTexture = newImage.m_Texture != m_TextureData.m_Texture; + if (newImage.m_Texture == nullptr) { + m_LastFrameOffscreenRenderer = nullptr; + if (m_ImagePath.IsValid()) { + if (!m_LoadedTextureData + || m_LoadedTextureData->m_path != QString::fromUtf8(m_ImagePath.c_str())) { + if (m_LoadedTextureData) + m_LoadedTextureData->m_callbacks.removeOne(this); + m_LoadedTextureData = inBufferManager.CreateReloadableImage(m_ImagePath, false, + forIbl); + m_LoadedTextureData->m_callbacks.push_back(this); + } + if (m_LoadedTextureData) { + if (m_LoadedTextureData->m_loaded) { + newImage.m_Texture = m_LoadedTextureData->m_Texture; + newImage.m_TextureFlags = m_LoadedTextureData->m_TextureFlags; + newImage.m_BSDFMipMap = m_LoadedTextureData->m_BSDFMipMap; + } + replaceTexture = m_TextureData.m_Texture != newImage.m_Texture; + } + } } if (replaceTexture) { diff --git a/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.h b/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.h index 47993e73..9b71d3f1 100644 --- a/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.h +++ b/src/Runtime/Source/runtimerender/graphobjects/Qt3DSRenderImage.h @@ -67,6 +67,7 @@ namespace render { SGraphObject *m_Parent; SImageTextureData m_TextureData; + ReloadableTexturePtr m_LoadedTextureData; NodeFlags m_Flags; // only dirty, transform dirty, and active apply diff --git a/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp index 37ca281f..15cf7323 100644 --- a/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp +++ b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.cpp @@ -45,6 +45,7 @@ #include "foundation/Qt3DSFoundation.h" #include "Qt3DSRenderInputStreamFactory.h" #include "Qt3DSRenderImageScaler.h" +#include "Qt3DSRenderImage.h" #include "Qt3DSTextRenderer.h" #include "foundation/Qt3DSPerfTimer.h" #include "foundation/Qt3DSMutex.h" @@ -76,13 +77,13 @@ struct SImageEntry : public SImageTextureData { bool m_Loaded; SImageEntry() - : m_Loaded(false) + : SImageTextureData(), m_Loaded(false) { } - ~SImageEntry() + SImageEntry(const SImageEntry &entry) + : SImageTextureData(entry), m_Loaded(entry.m_Loaded) { - if (m_BSDFMipMap) - m_BSDFMipMap->release(); + } }; @@ -117,6 +118,10 @@ struct SBufferManager : public IBufferManager SPrimitiveEntry m_PrimitiveNames[5]; nvvector<qt3ds::render::NVRenderVertexBufferEntry> m_EntryBuffer; bool m_GPUSupportsDXT; + bool m_reloadableResources; + + QHash<QString, ReloadableTexturePtr> m_reloadableTextures; + static const char8_t *GetPrimitivesDirectory() { return "res//primitives"; } SBufferManager(NVRenderContext &ctx, IStringTable &strTable, @@ -135,6 +140,7 @@ struct SBufferManager : public IBufferManager , m_MeshMap(ctx.GetAllocator(), "SBufferManager::m_MeshMap") , m_EntryBuffer(ctx.GetAllocator(), "SBufferManager::m_EntryBuffer") , m_GPUSupportsDXT(ctx.AreDXTImagesSupported()) + , m_reloadableResources(false) { } virtual ~SBufferManager() { Clear(); } @@ -210,6 +216,15 @@ struct SBufferManager : public IBufferManager return inSourcePath; } + CRegisteredString getImagePath(const QString &path) + { + TAliasImageMap::iterator theAliasIter + = m_AliasImageMap.find(m_StrTable->RegisterStr(qPrintable(path))); + if (theAliasIter != m_AliasImageMap.end()) + return theAliasIter->second; + return m_StrTable->RegisterStr(qPrintable(path)); + } + static inline int wrapMod(int a, int base) { int ret = a % base; @@ -232,6 +247,177 @@ struct SBufferManager : public IBufferManager sY = wrapMod(sY, height); } + template <typename V, typename C> + void iterateAll(const V &vv, C c) + { + for (const auto x : vv) + c(x); + } + + void loadTextureImage(SReloadableImageTextureData &data) + { + CRegisteredString imagePath = getImagePath(data.m_path); + TImageMap::iterator theIter = m_ImageMap.find(imagePath); + if ((theIter == m_ImageMap.end() || theIter->second.m_Loaded == false) + && imagePath.IsValid()) { + NVScopedReleasable<SLoadedTexture> theLoadedImage; + SImageTextureData textureData; + + doImageLoad(imagePath, theLoadedImage); + + if (theLoadedImage) { + textureData = LoadRenderImage(imagePath, *theLoadedImage, data.m_scanTransparency, + data.m_bsdfMipmap); + data.m_Texture = textureData.m_Texture; + data.m_TextureFlags = textureData.m_TextureFlags; + data.m_BSDFMipMap = textureData.m_BSDFMipMap; + data.m_loaded = true; + iterateAll(data.m_callbacks, [](SImage *img){ img->m_Flags.SetDirty(true); }); + } else { + // We want to make sure that bad path fails once and doesn't fail over and over + // again which could slow down the system quite a bit. + pair<TImageMap::iterator, bool> theImage = + m_ImageMap.insert(make_pair(imagePath, SImageEntry())); + theImage.first->second.m_Loaded = true; + qCWarning(WARNING, "Failed to load image: %s", imagePath.c_str()); + theIter = theImage.first; + } + } else { + SImageEntry textureData = theIter->second; + if (textureData.m_Loaded) { + data.m_Texture = textureData.m_Texture; + data.m_TextureFlags = textureData.m_TextureFlags; + data.m_BSDFMipMap = textureData.m_BSDFMipMap; + data.m_loaded = true; + iterateAll(data.m_callbacks, [](SImage *img){ img->m_Flags.SetDirty(true); }); + } + } + } + + void unloadTextureImage(SReloadableImageTextureData &data) + { + CRegisteredString r = m_StrTable->RegisterStr(qPrintable(data.m_path)); + data.m_loaded = false; + data.m_Texture = nullptr; + data.m_BSDFMipMap = nullptr; + data.m_TextureFlags = {}; + iterateAll(data.m_callbacks, [](SImage *img){ img->m_Flags.SetDirty(true); }); + InvalidateBuffer(r); + } + + void loadSet(const QSet<QString> &imageSet) override + { + for (const auto &x : imageSet) { + if (!m_reloadableTextures.contains(x)) { + auto img = CreateReloadableImage(m_StrTable->RegisterStr(qPrintable(x)), false, + false); + img->m_initialized = false; + loadTextureImage(*m_reloadableTextures[x]); + } else if (!m_reloadableTextures[x]->m_loaded) { + loadTextureImage(*m_reloadableTextures[x]); + } + } + } + + void unloadSet(const QSet<QString> &imageSet) override + { + for (const auto &x : imageSet) { + if (m_reloadableTextures.contains(x)) { + if (m_reloadableTextures[x]->m_loaded) + unloadTextureImage(*m_reloadableTextures[x]); + } + } + } + + virtual ReloadableTexturePtr CreateReloadableImage(CRegisteredString inSourcePath, + bool inForceScanForTransparency, + bool inBsdfMipmaps) override + { + QString path = QString::fromLatin1(inSourcePath.c_str()); + const bool inserted = m_reloadableTextures.contains(path); + if (!inserted || (inserted && m_reloadableTextures[path]->m_initialized == false)) { + if (!inserted) + m_reloadableTextures.insert(path, ReloadableTexturePtr::create()); + m_reloadableTextures[path]->m_path = path; + m_reloadableTextures[path]->m_scanTransparency = inForceScanForTransparency; + m_reloadableTextures[path]->m_bsdfMipmap = inBsdfMipmaps; + m_reloadableTextures[path]->m_initialized = true; + + if (!m_reloadableResources) + loadTextureImage(*m_reloadableTextures[path]); + + CRegisteredString imagePath = getImagePath(path); + TImageMap::iterator theIter = m_ImageMap.find(imagePath); + if (theIter != m_ImageMap.end()) { + SImageEntry textureData = theIter->second; + if (textureData.m_Loaded) { + m_reloadableTextures[path]->m_Texture = textureData.m_Texture; + m_reloadableTextures[path]->m_TextureFlags = textureData.m_TextureFlags; + m_reloadableTextures[path]->m_BSDFMipMap = textureData.m_BSDFMipMap; + m_reloadableTextures[path]->m_loaded = true; + } + } + } + return m_reloadableTextures[path]; + } + + void doImageLoad(CRegisteredString inImagePath, + NVScopedReleasable<SLoadedTexture> &theLoadedImage) + { + SStackPerfTimer __perfTimer(m_PerfTimer, "Image Decompression"); + theLoadedImage = SLoadedTexture::Load( + inImagePath.c_str(), m_Context->GetFoundation(), *m_InputStreamFactory, + true, m_Context->GetRenderContextType()); + // Hackish solution to custom materials not finding their textures if they are used + // in sub-presentations. + if (!theLoadedImage) { + if (QDir(inImagePath.c_str()).isRelative()) { + QString searchPath = inImagePath.c_str(); + if (searchPath.startsWith(QLatin1String("./"))) + searchPath.prepend(QLatin1Char('.')); + int loops = 0; + while (!theLoadedImage && ++loops <= 3) { + theLoadedImage = SLoadedTexture::Load( + searchPath.toUtf8(), m_Context->GetFoundation(), + *m_InputStreamFactory, true, + m_Context->GetRenderContextType()); + searchPath.prepend(QLatin1String("../")); + } + } else { + // Some textures, for example environment maps for custom materials, + // have absolute path at this point. It points to the wrong place with + // the new project structure, so we need to split it up and construct + // the new absolute path here. + QString wholePath = inImagePath.c_str(); + QStringList splitPath = wholePath.split(QLatin1String("../")); + if (splitPath.size() > 1) { + QString searchPath = splitPath.at(0) + splitPath.at(1); + int loops = 0; + while (!theLoadedImage && ++loops <= 3) { + theLoadedImage = SLoadedTexture::Load( + searchPath.toUtf8(), m_Context->GetFoundation(), + *m_InputStreamFactory, true, + m_Context->GetRenderContextType()); + searchPath = splitPath.at(0); + for (int i = 0; i < loops; i++) + searchPath.append(QLatin1String("../")); + searchPath.append(splitPath.at(1)); + } + } + } + } + } + + void enableReloadableResources(bool enable) override + { + m_reloadableResources = enable; + } + + bool isReloadableResourcesEnabled() const override + { + return m_reloadableResources; + } + SImageTextureData LoadRenderImage(CRegisteredString inImagePath, SLoadedTexture &inLoadedImage, bool inForceScanForTransparency, bool inBsdfMipmaps) override @@ -336,51 +522,8 @@ struct SBufferManager : public IBufferManager TImageMap::iterator theIter = m_ImageMap.find(inImagePath); if (theIter == m_ImageMap.end() && inImagePath.IsValid()) { NVScopedReleasable<SLoadedTexture> theLoadedImage; - { - SStackPerfTimer __perfTimer(m_PerfTimer, "Image Decompression"); - theLoadedImage = SLoadedTexture::Load( - inImagePath.c_str(), m_Context->GetFoundation(), *m_InputStreamFactory, - true, m_Context->GetRenderContextType()); - // Hackish solution to custom materials not finding their textures if they are used - // in sub-presentations. Note: Runtime 1 is going to be removed in Qt 3D Studio 2.x, - // so this should be ok. - if (!theLoadedImage) { - if (QDir(inImagePath.c_str()).isRelative()) { - QString searchPath = inImagePath.c_str(); - if (searchPath.startsWith(QLatin1String("./"))) - searchPath.prepend(QLatin1String(".")); - int loops = 0; - while (!theLoadedImage && ++loops <= 3) { - theLoadedImage = SLoadedTexture::Load( - searchPath.toUtf8(), m_Context->GetFoundation(), - *m_InputStreamFactory, true, - m_Context->GetRenderContextType()); - searchPath.prepend(QLatin1String("../")); - } - } else { - // Some textures, for example environment maps for custom materials, - // have absolute path at this point. It points to the wrong place with - // the new project structure, so we need to split it up and construct - // the new absolute path here. - QString wholePath = inImagePath.c_str(); - QStringList splitPath = wholePath.split(QLatin1String("../")); - if (splitPath.size() > 1) { - QString searchPath = splitPath.at(0) + splitPath.at(1); - int loops = 0; - while (!theLoadedImage && ++loops <= 3) { - theLoadedImage = SLoadedTexture::Load( - searchPath.toUtf8(), m_Context->GetFoundation(), - *m_InputStreamFactory, true, - m_Context->GetRenderContextType()); - searchPath = splitPath.at(0); - for (int i = 0; i < loops; i++) - searchPath.append(QLatin1String("../")); - searchPath.append(splitPath.at(1)); - } - } - } - } - } + + doImageLoad(inImagePath, theLoadedImage); if (theLoadedImage) { return LoadRenderImage(inImagePath, *theLoadedImage, inForceScanForTransparency, @@ -862,6 +1005,8 @@ struct SBufferManager : public IBufferManager { if (inEntry.m_Texture) inEntry.m_Texture->release(); + if (inEntry.m_BSDFMipMap) + inEntry.m_BSDFMipMap->release(); } void Clear() override { @@ -916,5 +1061,5 @@ IBufferManager &IBufferManager::Create(NVRenderContext &inRenderContext, IString IInputStreamFactory &inFactory, IPerfTimer &inPerfTimer) { return *QT3DS_NEW(inRenderContext.GetAllocator(), SBufferManager)(inRenderContext, inStrTable, - inFactory, inPerfTimer); + inFactory, inPerfTimer); } diff --git a/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h index cd9e3d33..d595c902 100644 --- a/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h +++ b/src/Runtime/Source/runtimerender/resourcemanager/Qt3DSRenderBufferManager.h @@ -83,6 +83,16 @@ namespace render { virtual SImageTextureData LoadRenderImage(CRegisteredString inSourcePath, bool inForceScanForTransparency = false, bool inBsdfMipmaps = false) = 0; + + virtual ReloadableTexturePtr CreateReloadableImage(CRegisteredString inSourcePath, + bool inForceScanForTransparency = false, + bool inBsdfMipmaps = false) = 0; + virtual void enableReloadableResources(bool enable) = 0; + virtual bool isReloadableResourcesEnabled() const = 0; + + virtual void loadSet(const QSet<QString> &imageSet) = 0; + virtual void unloadSet(const QSet<QString> &imageSet) = 0; + virtual SRenderMesh *LoadMesh(CRegisteredString inSourcePath) = 0; virtual SRenderMesh *CreateMesh(const char *inSourcePath, QT3DSU8 *inVertData, diff --git a/src/Runtime/Source/uipparser/Qt3DSUIPParser.h b/src/Runtime/Source/uipparser/Qt3DSUIPParser.h index 857d403c..c3b4611b 100644 --- a/src/Runtime/Source/uipparser/Qt3DSUIPParser.h +++ b/src/Runtime/Source/uipparser/Qt3DSUIPParser.h @@ -143,6 +143,8 @@ public: // Parse UIP file // mesh files (and possibly font files). virtual NVConstDataRef<eastl::string> GetSourcePaths() const = 0; + virtual QVector<QString> GetSlideSourcePaths() const = 0; + // Creation function static IUIPParser &Create(const QString &inFileName, IRuntimeMetaData &inMetaData, qt3ds::render::IInputStreamFactory &inStreamFactory, diff --git a/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.cpp b/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.cpp index 746d5e58..2ddffe3f 100644 --- a/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.cpp +++ b/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.cpp @@ -2089,8 +2089,11 @@ BOOL CUIPParserImpl::LoadSlideElementAttrs(IPresentation &inPresentation, bool, ++theRef; bool isSet = AreEqual(inReader.GetNarrowElementName(), "Set"); const char8_t *sourcepath; - if (inReader.UnregisteredAtt("sourcepath", sourcepath)) + if (inReader.UnregisteredAtt("sourcepath", sourcepath)) { AddSourcePath(sourcepath); + theBuilder.AddSourcePath(sourcepath); + m_slideSourcePaths.push_back(QString::fromLatin1(sourcepath)); + } // We don't force set attributes when a given component has a set command within one of its // child states. This happens in the case of actions (but nothing else). diff --git a/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.h b/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.h index 9d96b681..fd921161 100644 --- a/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.h +++ b/src/Runtime/Source/uipparser/Qt3DSUIPParserImpl.h @@ -429,6 +429,8 @@ protected: TStringSet m_SourcePathSet; TStringVector m_SourcePathList; + QVector<QString> m_slideSourcePaths; + struct SElementRefCache { SElementData *m_Element; @@ -534,6 +536,10 @@ public: // Parse UIP file { return NVConstDataRef<eastl::string>(m_SourcePathList.data(), m_SourcePathList.size()); } + QVector<QString> GetSlideSourcePaths() const override + { + return m_slideSourcePaths; + } protected: // Operation BOOL LoadProjectSettings(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader); diff --git a/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp b/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp index 24d768e9..ccf0a911 100644 --- a/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp +++ b/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp @@ -301,9 +301,10 @@ void Q3DSViewerApp::setOffscreenId(int offscreenID) } bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFormat &format, - int offscreenID, const QString &source, - const QStringList &variantList, - qt3ds::Qt3DSAssetVisitor *assetVisitor) + int offscreenID, const QString &source, + const QStringList &variantList, + bool delayedLoading, + qt3ds::Qt3DSAssetVisitor *assetVisitor) { bool hasValidPresentationFile = !source.isEmpty(); @@ -339,7 +340,7 @@ bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFor return false; } - bool success = m_Impl.m_view->InitializeGraphics(format); + bool success = m_Impl.m_view->InitializeGraphics(format, delayedLoading); if (!success) { m_Impl.m_error = QObject::tr("Viewer launch failure! Failed to load: '%1'").arg(source); m_Impl.m_error.append("\n"); @@ -458,6 +459,27 @@ QString Q3DSViewerApp::error() return error; } +void Q3DSViewerApp::setDelayedLoading(bool enable) +{ + if (!m_Impl.m_view) + return; + m_Impl.m_view->setDelayedLoading(enable); +} + +void Q3DSViewerApp::preloadSlide(const QString &slide) +{ + if (!m_Impl.m_view) + return; + m_Impl.m_view->preloadSlide(slide); +} + +void Q3DSViewerApp::unloadSlide(const QString &slide) +{ + if (!m_Impl.m_view) + return; + m_Impl.m_view->unloadSlide(slide); +} + void Q3DSViewerApp::Resize(int width, int height) { QSize oldSize = m_Impl.m_WindowSystem->GetWindowDimensions(); diff --git a/src/Runtime/Source/viewer/Qt3DSViewerApp.h b/src/Runtime/Source/viewer/Qt3DSViewerApp.h index 65dcda0a..38447579 100644 --- a/src/Runtime/Source/viewer/Qt3DSViewerApp.h +++ b/src/Runtime/Source/viewer/Qt3DSViewerApp.h @@ -116,6 +116,7 @@ public: bool InitializeApp(int winWidth, int winHeight, const QSurfaceFormat& format, int offscreenID, const QString &source, const QStringList &variantList, + bool delayedLoading, qt3ds::Qt3DSAssetVisitor *assetVisitor = nullptr); bool IsInitialised(void); @@ -359,6 +360,9 @@ public: QString error(); void setPresentationId(const QString &id); + void preloadSlide(const QString &slide); + void unloadSlide(const QString &slide); + void setDelayedLoading(bool enable); private: /* diff --git a/src/Runtime/qt3d-runtime b/src/Runtime/qt3d-runtime -Subproject 228b1c7ce76a134e4d2e67809ef8b86f371a15e +Subproject 5e0bfe934b9930b7e41d457b4f88fce91342a0e diff --git a/src/Viewer/qmlviewer/Qt3DSRenderer.cpp b/src/Viewer/qmlviewer/Qt3DSRenderer.cpp index e62d1267..3fe817a9 100644 --- a/src/Viewer/qmlviewer/Qt3DSRenderer.cpp +++ b/src/Viewer/qmlviewer/Qt3DSRenderer.cpp @@ -95,6 +95,7 @@ void Q3DSRenderer::synchronize(QQuickFramebufferObject *inView) // processCommands, as both are needed for init m_presentation->setVariantList(m_commands.m_variantList); m_presentation->setSource(m_commands.m_source); + m_presentation->setDelayedLoading(m_commands.m_delayedLoading); m_initialized = false; m_initializationFailure = false; m_error.clear(); @@ -183,6 +184,7 @@ bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo) QOpenGLContext::currentContext()->format(), inFbo->handle(), localSource, m_presentation->variantList(), + m_presentation->delayedLoading(), m_visitor)) { m_error = m_runtime->error(); releaseRuntime(); @@ -268,6 +270,8 @@ void Q3DSRenderer::processCommands() m_settings->setMatteColor(m_commands.m_matteColor); if (m_commands.m_showRenderStatsChanged) m_settings->setShowRenderStats(m_commands.m_showRenderStats); + if (m_commands.m_delayedLoadingChanged) + this->m_runtime->setDelayedLoading(m_commands.m_delayedLoading); if (m_commands.m_globalAnimationTimeChanged) m_presentation->setGlobalAnimationTime(m_commands.m_globalAnimationTime); @@ -352,6 +356,12 @@ void Q3DSRenderer::processCommands() Q_EMIT requestResponse(cmd.m_elementPath, cmd.m_commandType, requestData); break; } + case CommandType_PreloadSlide: + m_runtime->preloadSlide(cmd.m_elementPath); + break; + case CommandType_UnloadSlide: + m_runtime->unloadSlide(cmd.m_elementPath); + break; default: qWarning() << __FUNCTION__ << "Unrecognized CommandType in command list!"; } diff --git a/src/Viewer/studio3d/q3dscommandqueue.cpp b/src/Viewer/studio3d/q3dscommandqueue.cpp index eba5a545..2bc540af 100644 --- a/src/Viewer/studio3d/q3dscommandqueue.cpp +++ b/src/Viewer/studio3d/q3dscommandqueue.cpp @@ -50,11 +50,13 @@ CommandQueue::CommandQueue() , m_sourceChanged(false) , m_variantListChanged(false) , m_globalAnimationTimeChanged(false) + , m_delayedLoadingChanged(false) , m_visible(false) , m_scaleMode(Q3DSViewerSettings::ScaleModeCenter) , m_shadeMode(Q3DSViewerSettings::ShadeModeShaded) , m_showRenderStats(false) , m_matteColor(Qt::black) + , m_delayedLoading(false) , m_size(0) { qRegisterMetaType<CommandType>(); @@ -165,6 +167,7 @@ void CommandQueue::copyCommands(const CommandQueue &fromQueue) m_variantListChanged = m_variantListChanged || fromQueue.m_variantListChanged; m_globalAnimationTimeChanged = m_globalAnimationTimeChanged || fromQueue.m_globalAnimationTimeChanged; + m_delayedLoadingChanged = m_delayedLoadingChanged || fromQueue.m_delayedLoadingChanged; if (fromQueue.m_visibleChanged) m_visible = fromQueue.m_visible; @@ -182,6 +185,8 @@ void CommandQueue::copyCommands(const CommandQueue &fromQueue) m_variantList = fromQueue.m_variantList; if (fromQueue.m_globalAnimationTimeChanged) m_globalAnimationTime = fromQueue.m_globalAnimationTime; + if (fromQueue.m_delayedLoadingChanged) + m_delayedLoading = fromQueue.m_delayedLoading; // Pending queue may be synchronized multiple times between queue processing, so let's append // to the existing queue rather than clearing it. @@ -221,6 +226,8 @@ void CommandQueue::copyCommands(const CommandQueue &fromQueue) source.m_intValues[2], source.m_intValues[3]); break; case CommandType_RequestSlideInfo: + case CommandType_UnloadSlide: + case CommandType_PreloadSlide: queueRequest(source.m_elementPath, source.m_commandType); break; case CommandType_RequestDataInputs: @@ -244,6 +251,7 @@ void CommandQueue::clear() m_sourceChanged = false; m_variantListChanged = false; m_globalAnimationTimeChanged = false; + m_delayedLoadingChanged = false; // We do not clear the actual queued commands, those will be reused the next frame // To avoid a lot of unnecessary reallocations. diff --git a/src/Viewer/studio3d/q3dscommandqueue_p.h b/src/Viewer/studio3d/q3dscommandqueue_p.h index 46b77d08..27612bfb 100644 --- a/src/Viewer/studio3d/q3dscommandqueue_p.h +++ b/src/Viewer/studio3d/q3dscommandqueue_p.h @@ -69,7 +69,9 @@ enum CommandType { CommandType_SetGlobalAnimationTime, CommandType_SetDataInputValue, CommandType_RequestSlideInfo, - CommandType_RequestDataInputs + CommandType_RequestDataInputs, + CommandType_PreloadSlide, + CommandType_UnloadSlide }; class Q_STUDIO3D_EXPORT ElementCommand @@ -124,6 +126,7 @@ public: bool m_sourceChanged; bool m_variantListChanged; bool m_globalAnimationTimeChanged; + bool m_delayedLoadingChanged; bool m_visible; Q3DSViewerSettings::ScaleMode m_scaleMode; @@ -133,6 +136,7 @@ public: QUrl m_source; QStringList m_variantList; qint64 m_globalAnimationTime; + bool m_delayedLoading; void clear(); int size() const { return m_size; } diff --git a/src/Viewer/studio3d/q3dspresentation.cpp b/src/Viewer/studio3d/q3dspresentation.cpp index d0d93e4f..f4235456 100644 --- a/src/Viewer/studio3d/q3dspresentation.cpp +++ b/src/Viewer/studio3d/q3dspresentation.cpp @@ -129,6 +129,35 @@ void Q3DSPresentation::setVariantList(const QStringList &variantList) } } +bool Q3DSPresentation::delayedLoading() const +{ + return d_ptr->m_delayedLoading; +} + +void Q3DSPresentation::setDelayedLoading(bool enable) +{ + if (d_ptr->m_delayedLoading != enable) { + d_ptr->setDelayedLoading(enable); + Q_EMIT delayedLoadingChanged(enable); + } +} + +void Q3DSPresentation::preloadSlide(const QString &elementPath) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->preloadSlide(elementPath); + else if (d_ptr->m_commandQueue) + d_ptr->m_commandQueue->queueRequest(elementPath, CommandType_PreloadSlide); +} + +void Q3DSPresentation::unloadSlide(const QString &elementPath) +{ + if (d_ptr->m_viewerApp) + d_ptr->m_viewerApp->unloadSlide(elementPath); + else if (d_ptr->m_commandQueue) + d_ptr->m_commandQueue->queueRequest(elementPath, CommandType_UnloadSlide); +} + void Q3DSPresentation::goToSlide(const QString &elementPath, unsigned int index) { if (d_ptr->m_viewerApp) { @@ -330,6 +359,7 @@ Q3DSPresentationPrivate::Q3DSPresentationPrivate(Q3DSPresentation *q) , m_viewerApp(nullptr) , m_commandQueue(nullptr) , m_streamProxy(nullptr) + , m_delayedLoading(false) { } @@ -410,11 +440,21 @@ void Q3DSPresentationPrivate::setCommandQueue(CommandQueue *queue) di->d_ptr->setCommandQueue(queue); if (m_commandQueue) { - setSource(m_source); + setDelayedLoading(m_delayedLoading); setVariantList(m_variantList); // Queue a request ASAP for datainputs defined in UIA file so that // getDataInputs has up-to-date info at the earliest. m_commandQueue->queueRequest({}, CommandType_RequestDataInputs); + setSource(m_source); + } +} + +void Q3DSPresentationPrivate::setDelayedLoading(bool enable) +{ + m_delayedLoading = enable; + if (m_commandQueue) { + m_commandQueue->m_delayedLoading = enable; + m_commandQueue->m_delayedLoadingChanged = true; } } diff --git a/src/Viewer/studio3d/q3dspresentation.h b/src/Viewer/studio3d/q3dspresentation.h index 38625583..34809613 100644 --- a/src/Viewer/studio3d/q3dspresentation.h +++ b/src/Viewer/studio3d/q3dspresentation.h @@ -49,6 +49,7 @@ class Q_STUDIO3D_EXPORT Q3DSPresentation : public QObject Q_DECLARE_PRIVATE(Q3DSPresentation) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QStringList variantList READ variantList WRITE setVariantList NOTIFY variantListChanged) + Q_PROPERTY(bool delayedLoading READ delayedLoading WRITE setDelayedLoading NOTIFY delayedLoadingChanged) public: explicit Q3DSPresentation(QObject *parent = nullptr); @@ -68,6 +69,12 @@ public: Q_INVOKABLE QVariantList getDataInputs() const; QVector<Q3DSDataInput *> dataInputs() const; + bool delayedLoading() const; + void setDelayedLoading(bool enable); + + Q_INVOKABLE void preloadSlide(const QString &elementPath); + Q_INVOKABLE void unloadSlide(const QString &elementPath); + // Input event handlers void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); @@ -100,6 +107,7 @@ Q_SIGNALS: // and datainputs are available through dataInputs() / getDataInputs(). void dataInputsReady(); void customSignalEmitted(const QString &elementPath, const QString &name); + void delayedLoadingChanged(bool enable); private: Q_DISABLE_COPY(Q3DSPresentation) diff --git a/src/Viewer/studio3d/q3dspresentation_p.h b/src/Viewer/studio3d/q3dspresentation_p.h index 7ae7b945..c82e27a7 100644 --- a/src/Viewer/studio3d/q3dspresentation_p.h +++ b/src/Viewer/studio3d/q3dspresentation_p.h @@ -69,6 +69,7 @@ public: void setVariantList(const QStringList &variantList); void setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool connectApp = true); void setCommandQueue(CommandQueue *queue); + void setDelayedLoading(bool enable); void registerElement(Q3DSElement *element); void unregisterElement(Q3DSElement *element); @@ -101,6 +102,7 @@ private: QUrl m_source; QStringList m_variantList; ViewerQmlStreamProxy *m_streamProxy; + bool m_delayedLoading; }; QT_END_NAMESPACE |