summaryrefslogtreecommitdiffstats
path: root/src/engine/Qt3DSRenderRuntimeBinding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/Qt3DSRenderRuntimeBinding.cpp')
-rw-r--r--src/engine/Qt3DSRenderRuntimeBinding.cpp1858
1 files changed, 1858 insertions, 0 deletions
diff --git a/src/engine/Qt3DSRenderRuntimeBinding.cpp b/src/engine/Qt3DSRenderRuntimeBinding.cpp
new file mode 100644
index 0000000..4507c74
--- /dev/null
+++ b/src/engine/Qt3DSRenderRuntimeBinding.cpp
@@ -0,0 +1,1858 @@
+/****************************************************************************
+**
+** Copyright (C) 1993-2009 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "EnginePrefix.h"
+#include "Qt3DSRenderRuntimeBindingImpl.h"
+#include "Qt3DSSceneManager.h"
+#include "Qt3DSIScene.h"
+#include "Qt3DSRuntimeView.h"
+#include "Qt3DSQmlEngine.h"
+#include "Qt3DSRenderUIPLoader.h"
+#include "Qt3DSPresentationFrameData.h"
+#include "foundation/AutoDeallocatorAllocator.h"
+#include "Qt3DSRenderSubpresentation.h"
+#include "Qt3DSIScriptBridge.h"
+#include "Qt3DSFileStream.h"
+#include "Qt3DSDMPrefix.h"
+#include "foundation/IOStreams.h"
+#include "Qt3DSDMStringTable.h"
+#include "Qt3DSDMXML.h"
+#include "Qt3DSRenderBufferManager.h"
+#include "foundation/SerializationTypes.h"
+#include "Qt3DSRenderGraphObjectSerializer.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "Qt3DSRenderImageBatchLoader.h"
+#include "Qt3DSPresentation.h"
+
+#include "Qt3DSDLLManager.h"
+#include "Qt3DSBasicPluginDLL.h"
+#include "Qt3DSPluginDLL.h"
+#include "Qt3DSRenderPlugin.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSStateVisualBindingContextCommands.h"
+#include "Qt3DSStateScriptContext.h"
+#include "EventPollingSystem.h"
+#include "EventSystem.h"
+#include "Qt3DSApplication.h"
+#include "Qt3DSMatrix.h"
+#include "Qt3DSWindowSystem.h"
+#if !defined (Q_OS_MACOS)
+#include "Qt3DSEGLInfo.h"
+#endif
+#include "Qt3DSOffscreenRenderKey.h"
+#include "Qt3DSOldNBustedRenderPlugin.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "foundation/Qt3DSPerfTimer.h"
+#include "Qt3DSRenderBufferLoader.h"
+#include "Qt3DSRenderRenderList.h"
+#include "Qt3DSRenderPrefilterTexture.h"
+#include "foundation/PoolingAllocator.h"
+#include "q3dsqmlrender.h"
+
+#ifdef EA_PLATFORM_WINDOWS
+#pragma warning(disable : 4355)
+#endif
+
+using namespace qt3ds::render;
+using eastl::make_pair;
+using eastl::pair;
+using qt3ds::runtime::IApplication;
+
+#ifndef _WIN32
+#define stricmp strcasecmp
+#endif
+namespace qt3ds {
+namespace render {
+ qt3ds::foundation::MallocAllocator g_BaseAllocator;
+}
+}
+namespace {
+struct Qt3DSRenderScene;
+
+struct Qt3DSRenderSceneSubPresRenderer : public CSubPresentationRenderer
+{
+ Qt3DSRenderScene &m_Scene;
+ Qt3DSRenderSceneSubPresRenderer(Qt3DSRenderScene &inScene, IQt3DSRenderContext &inRenderContext,
+ SPresentation &inPresentation)
+ : CSubPresentationRenderer(inRenderContext, inPresentation)
+ , m_Scene(inScene)
+ {
+ }
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_RenderContext.GetAllocator())
+ SOffscreenRenderFlags NeedsRender(const SOffscreenRendererEnvironment &inEnvironment,
+ QT3DSVec2 inPresScale,
+ const SRenderInstanceId instanceId) override;
+ void Render(const SOffscreenRendererEnvironment &inEnvironment,
+ NVRenderContext &inRenderContext, QT3DSVec2 inPresScale,
+ SScene::RenderClearCommand inClearBuffer,
+ const SRenderInstanceId instanceId) override;
+ void RenderWithClear(const SOffscreenRendererEnvironment &inEnvironment,
+ NVRenderContext &inRenderContext, QT3DSVec2 inPresScale,
+ SScene::RenderClearCommand inClearBuffer, QT3DSVec4 inClearColor,
+ const SRenderInstanceId instanceId) override;
+};
+
+struct SSceneLoadData
+{
+ NVAllocatorCallback &m_Allocator;
+ NVScopedRefCounted<ILoadedBuffer> m_Data;
+ SPresentation *m_Presentation;
+ NVDataRef<QT3DSU8> m_TranslatorData;
+ NVDataRef<QT3DSU8> m_SceneGraphData;
+ eastl::vector<Qt3DSTranslator *> m_Translators;
+ SPoolingAllocator m_AutoAllocator;
+ Q3DStudio::IPresentation *m_RuntimePresentation;
+ QT3DSI32 mRefCount;
+
+ SSceneLoadData(NVAllocatorCallback &alloc)
+ : m_Allocator(alloc)
+ , m_Presentation(nullptr)
+ , m_AutoAllocator(alloc)
+ , m_RuntimePresentation(nullptr)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Allocator)
+};
+
+struct Qt3DSRenderScene : public Q3DStudio::IScene
+{
+ SBindingCore &m_BindingCore;
+ NVScopedRefCounted<IQt3DSRenderContext> m_Context;
+ NVScopedRefCounted<SSceneLoadData> m_LoadData;
+ // The scene graph gets allocated kind of on its own
+ // So do the smaller translation objects that translate TElement properties
+ // into the graph.
+ SPresentation *m_Presentation;
+ Q3DStudio::IPresentation *m_RuntimePresentation;
+ void *m_UserData;
+ TTranslatorDirytSet m_DirtySet;
+ CRegisteredString m_OffscreenRendererId;
+ IOffscreenRenderer *m_OffscreenRenderer;
+ CRegisteredString m_SubPresentationType;
+ nvvector<SGraphObject *> m_GraphObjectList;
+ bool m_LoggedPickLastFrame;
+ NVRenderRect m_LastRenderViewport;
+ CRegisteredString m_PathSubPathType;
+
+ Qt3DSRenderScene(SBindingCore &inBindingCore, IQt3DSRenderContext &inContext,
+ SSceneLoadData &inLoadData)
+ : m_BindingCore(inBindingCore)
+ , m_Context(inContext)
+ , m_LoadData(inLoadData)
+ , m_Presentation(inLoadData.m_Presentation)
+ , m_RuntimePresentation(inLoadData.m_RuntimePresentation)
+ , m_UserData(nullptr)
+ , m_DirtySet(inContext.GetAllocator(), "Qt3DSRenderScene::m_DirtySet")
+ , m_OffscreenRenderer(nullptr)
+ , m_SubPresentationType(
+ inContext.GetStringTable().RegisterStr(CSubPresentationRenderer::GetRendererName()))
+ , m_GraphObjectList(inContext.GetAllocator(), "Qt3DSDSRenderScene::m_GraphObjectList")
+ , m_LoggedPickLastFrame(false)
+ {
+ for (QT3DSU32 idx = 0, end = inLoadData.m_Translators.size(); idx < end; ++idx) {
+ m_DirtySet.insert(*inLoadData.m_Translators[idx]);
+ }
+ m_PathSubPathType = inContext.GetStringTable().RegisterStr("PathAnchorPoint");
+ }
+
+ virtual ~Qt3DSRenderScene() override
+ {
+ if (m_OffscreenRenderer)
+ m_Context->GetOffscreenRenderManager().ReleaseOffscreenRenderer(m_OffscreenRendererId);
+ 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)) {
+ m_Context->GetRenderer().ReleaseLayerRenderResources(*theLayer, nullptr);
+ }
+ }
+ }
+
+ qt3ds::NVAllocatorCallback &allocator() override { return m_LoadData->m_AutoAllocator; }
+ Q3DStudio::IPresentation &GetPresentation() override { return *m_RuntimePresentation; }
+
+ bool preferKtx() const override
+ {
+ return m_Presentation->m_preferKTX;
+ }
+
+ // Update really just adds objects to the dirty set
+ bool Update()
+ {
+ Q3DStudio::TElementList &theDirtyList =
+ m_RuntimePresentation->GetFrameData().GetDirtyList();
+ for (int idx = 0, end = theDirtyList.GetCount(); idx < end; ++idx) {
+ Q3DStudio::TElement &theElement = *theDirtyList[idx];
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(theElement.GetAssociation());
+ if (!theTranslator && theElement.GetType() == m_PathSubPathType) {
+ Q3DStudio::TElement *theParent = theElement.GetParent();
+ if (theParent) {
+ theTranslator = reinterpret_cast<Qt3DSTranslator *>(theParent->GetAssociation());
+ // The path translator responds to anchor point changes as well as its own data
+ // changes.
+ if (theTranslator
+ && theTranslator->RenderObject().m_Type != GraphObjectTypes::PathSubPath)
+ theTranslator = nullptr;
+ }
+ }
+ if (theTranslator)
+ m_DirtySet.insert(*theTranslator);
+ }
+ return m_DirtySet.size() > 0;
+ }
+
+ void TransferDirtyProperties()
+ {
+ if (m_Presentation) {
+ for (QT3DSU32 idx = 0, end = m_DirtySet.size(); idx < end; ++idx) {
+ QT3DS_ASSERT(m_DirtySet.size() == end);
+ m_DirtySet[idx]->OnElementChanged(*m_Presentation, *m_Context,
+ *m_RuntimePresentation);
+ }
+ m_DirtySet.clear();
+ }
+ }
+
+ bool PrepareForRender()
+ {
+ TransferDirtyProperties();
+ m_LastRenderViewport = m_Context->GetRenderList().GetViewport();
+ if (m_Presentation && m_Presentation->m_Scene) {
+ NVRenderRect theViewportSize(m_LastRenderViewport);
+ return m_Presentation->m_Scene->PrepareForRender(
+ QT3DSVec2(QT3DSF32(theViewportSize.m_Width), QT3DSF32(theViewportSize.m_Height)),
+ *m_Context);
+ }
+ return false;
+ }
+
+ void Render()
+ {
+ if (m_Presentation && m_Presentation->m_Scene) {
+ NVRenderRect theViewportSize(m_LastRenderViewport);
+ m_Presentation->m_Scene->Render(
+ QT3DSVec2(QT3DSF32(theViewportSize.m_Width), QT3DSF32(theViewportSize.m_Height)),
+ *m_Context, SScene::DoNotClear);
+ }
+ }
+
+ // Note that we do not need to call WindowToPresentation on the mouse coordinates because they
+ // are specifically
+ // supposed to be the return values from getMousePosition which applies that transformation. We
+ // do, however need
+ // to reverse part of this transformation; whatever part happens after
+ // m_Context->GetMousePickMouseCoords
+ Q3DStudio::TElement *UserPick(float mouseX, float mouseY)
+ {
+ // Note that the pick code below only calls GetMousePickMouseCoords
+ // while windowToPresentation subtracts the window positional offset from
+ // the mouse position.
+ // Thus we have to add it back.
+ QT3DSVec2 mousePos(mouseX + m_LastRenderViewport.m_X, mouseY + m_LastRenderViewport.m_Y);
+
+ Qt3DSRenderPickResult thePickResult = m_Context->GetRenderer().Pick(
+ *m_Presentation->m_Scene->m_FirstChild, m_Context->GetMousePickViewport()
+ // GetMousePickMouseCoords is called by the renderer to setup the pick frame.
+ // This is so that the presentation's lastMouseX and lastMouseY variables are correctly
+ // setup.
+ ,
+ mousePos, true, true);
+
+ if (thePickResult.m_HitObject != nullptr) {
+ SModel *theHitModel =
+ static_cast<SModel *>(const_cast<SGraphObject *>(thePickResult.m_HitObject));
+ return &Qt3DSTranslator::GetTranslatorFromGraphNode(*theHitModel)->Element();
+ }
+ return nullptr;
+ }
+
+ virtual Option<QT3DSVec2> FacePosition(Q3DStudio::TElement &inElement, float mouseX, float mouseY,
+ NVDataRef<Q3DStudio::TElement *> inMapperElements,
+ Q3DStudio::FacePositionPlanes::Enum inPlane)
+ {
+ if (inElement.GetBelongedPresentation() != this->m_RuntimePresentation
+ && inMapperElements.size() == 0) {
+ return Empty();
+ }
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement.GetAssociation());
+ if (theTranslator == nullptr)
+ return Empty();
+ bool isValidPickObject =
+ GraphObjectTypes::IsNodeType(theTranslator->m_RenderObject->m_Type);
+ if (isValidPickObject == false)
+ return Empty();
+ SNode &theNode = static_cast<SNode &>(*theTranslator->m_RenderObject);
+ NVBounds3 theBounds = GetNodeLocalBoundingBox(&inElement, false);
+ // See commens in UserPick
+ QT3DSVec2 mousePos(mouseX + m_LastRenderViewport.m_X, mouseY + m_LastRenderViewport.m_Y);
+ eastl::vector<SGraphObject *> theMapperObjects(inMapperElements.size());
+ for (QT3DSU32 idx = 0, end = inMapperElements.size(); idx < end; ++idx) {
+ Qt3DSTranslator *theMapperTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inMapperElements[idx]->GetAssociation());
+ SGraphObject *theMapperObject = nullptr;
+ if (theMapperTranslator) {
+ theMapperObject = theMapperTranslator->m_RenderObject;
+ }
+ if (theMapperObject == nullptr) {
+ QT3DS_ASSERT(false);
+ } else {
+ theMapperObjects[idx] = theMapperObject;
+ }
+ }
+ qt3ds::render::SBasisPlanes::Enum thePlane(qt3ds::render::SBasisPlanes::XY);
+ switch (inPlane) {
+ case Q3DStudio::FacePositionPlanes::XY:
+ thePlane = qt3ds::render::SBasisPlanes::XY;
+ break;
+ case Q3DStudio::FacePositionPlanes::YZ:
+ thePlane = qt3ds::render::SBasisPlanes::YZ;
+ break;
+ case Q3DStudio::FacePositionPlanes::XZ:
+ thePlane = qt3ds::render::SBasisPlanes::XZ;
+ break;
+ }
+ if (theBounds.isEmpty() == false) {
+ return m_Context->GetRenderer().FacePosition(
+ theNode, theBounds, theNode.m_GlobalTransform, m_Context->GetMousePickViewport(),
+ mousePos, NVDataRef<SGraphObject *>(theMapperObjects.data(),
+ QT3DSU32(theMapperObjects.size())), thePlane);
+ }
+ return Empty();
+ }
+
+ void Pick(Q3DStudio::SPickFrame &ioPickFrame)
+ {
+ // Presentation's m_Hide can disable rendering
+ bool wasPickLoggedLastFrame = m_LoggedPickLastFrame;
+ m_LoggedPickLastFrame = false;
+ if (ioPickFrame.m_InputFrame.m_PickValid) {
+ // If we have not already found a valid pick on a previous layer
+ if (!ioPickFrame.m_ResultValid && m_Presentation && m_Presentation->m_Scene
+ && m_Presentation->m_Scene->m_FirstChild) {
+ Qt3DSRenderPickResult thePickResult = m_Context->GetRenderer().Pick(
+ *m_Presentation->m_Scene->m_FirstChild, m_Context->GetMousePickViewport()
+ // GetMousePickMouseCoords is called by the renderer to setup the pick frame.
+ // This is so that the presentation's lastMouseX and lastMouseY variables are
+ // correctly setup.
+ ,
+ m_Context->GetMousePickMouseCoords(
+ QT3DSVec2(ioPickFrame.m_InputFrame.m_PickX, ioPickFrame.m_InputFrame.m_PickY)),
+ true);
+ if (thePickResult.m_HitObject != nullptr) {
+ SModel *theHitModel = static_cast<SModel *>(
+ const_cast<SGraphObject *>(thePickResult.m_HitObject));
+ ioPickFrame.m_Model =
+ &Qt3DSTranslator::GetTranslatorFromGraphNode(*theHitModel)->Element();
+ // I don't think local hit is used any more, but not sure. If they are used,
+ // then the code below is probably wrong.
+ ioPickFrame.m_LocalHit[0] = thePickResult.m_LocalUVCoords.x;
+ ioPickFrame.m_LocalHit[1] = thePickResult.m_LocalUVCoords.y;
+ ioPickFrame.m_SquaredDistance = thePickResult.m_CameraDistanceSq;
+ ioPickFrame.m_ResultValid = true;
+ if (wasPickLoggedLastFrame == false) {
+ m_LoggedPickLastFrame = true;
+ Q3DStudio::IPresentation *thePresentation =
+ ioPickFrame.m_Model->GetBelongedPresentation();
+ IApplication &theRuntime = thePresentation->GetApplication();
+ // We are picking against the previous frame of information.
+ qCInfo(TRACE_INFO, "Model Picked: %s on frame %d",
+ theHitModel->m_Id.c_str(),
+ theRuntime.GetFrameCount() - 1);
+ }
+ } else {
+ // The scene is always picked if it is pickable; nothing else really makes
+ // sense.
+ Qt3DSTranslator *theTranslator =
+ Qt3DSTranslator::GetTranslatorFromGraphNode(*m_Presentation->m_Scene);
+
+ if (theTranslator) {
+ ioPickFrame.m_Model = &theTranslator->Element();
+ // I don't think local hit is used any more, but not sure. If they are
+ // used, then the code below is probably wrong.
+ ioPickFrame.m_LocalHit[0] = ioPickFrame.m_InputFrame.m_PickX
+ / m_Presentation->m_PresentationDimensions.x;
+ ioPickFrame.m_LocalHit[1] = 1.0f
+ - ioPickFrame.m_InputFrame.m_PickY
+ / m_Presentation->m_PresentationDimensions.y;
+ ioPickFrame.m_SquaredDistance = 0;
+ ioPickFrame.m_ResultValid = true;
+ }
+ }
+ }
+ }
+ }
+
+ void SetUserData(void *inUserData) override { m_UserData = inUserData; }
+ void *GetUserData() override { return m_UserData; }
+
+ // Unfortunately, you should expect the node to be dirty at this point so we may need to force
+ // an update
+ void CalculateGlobalTransform(Q3DStudio::TElement *inElement,
+ Q3DStudio::RuntimeMatrix &outTransform) override
+ {
+ if (inElement == nullptr) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation());
+ if (theTranslator && GraphObjectTypes::IsNodeType(theTranslator->GetUIPType())) {
+ Update();
+ TransferDirtyProperties();
+ SNode *theNode = static_cast<SNode *>(&theTranslator->RenderObject());
+ // Ensure the node stays dirty
+ bool wasDirty = theNode->m_Flags.IsDirty();
+ theNode->CalculateGlobalVariables();
+ theNode->m_Flags.SetDirty(wasDirty);
+ memCopy(outTransform.m_Data, theNode->m_GlobalTransform.front(), sizeof(QT3DSMat44));
+ } else {
+ qCCritical(INVALID_OPERATION, "Calculate global transform called on invalide object");
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ void SetLocalTransformMatrix(Q3DStudio::TElement *inElement,
+ const Q3DStudio::RuntimeMatrix &inTransform) override
+ {
+ if (inElement == nullptr) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation());
+ if (theTranslator && GraphObjectTypes::IsNodeType(theTranslator->GetUIPType())) {
+ SNode *theNode = static_cast<SNode *>(&theTranslator->RenderObject());
+ QT3DSMat44 transform;
+ memCopy(transform.front(), inTransform.m_Data, sizeof(QT3DSMat44));
+ theNode->SetLocalTransformFromMatrix(transform);
+ theNode->MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ }
+ }
+
+ void EnsureNodeIsUpToDate(SNode &inNode, bool inIncludeChildren)
+ {
+ bool wasDirty = inNode.m_Flags.IsDirty();
+ if (wasDirty) {
+ inNode.CalculateGlobalVariables();
+ inNode.m_Flags.SetDirty(wasDirty);
+ if (inIncludeChildren) {
+ for (SNode *theChild = inNode.m_FirstChild; theChild;
+ theChild = theChild->m_NextSibling)
+ EnsureNodeIsUpToDate(*theChild, inIncludeChildren);
+ }
+ }
+ }
+
+ NVBounds3 GetNodeLocalBoundingBox(Q3DStudio::TElement *inElement, bool inSelfOnly)
+ {
+ NVBounds3 retval(NVBounds3::empty());
+ if (inElement == nullptr) {
+ QT3DS_ASSERT(false);
+ return retval;
+ }
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation());
+ if (theTranslator && GraphObjectTypes::IsNodeType(theTranslator->GetUIPType())) {
+ Update();
+ TransferDirtyProperties();
+ SNode *theNode = static_cast<SNode *>(&theTranslator->RenderObject());
+ bool theIncludeChildren = !inSelfOnly;
+ EnsureNodeIsUpToDate(*theNode, theIncludeChildren);
+ IBufferManager &theBufferManager(m_Context->GetBufferManager());
+ return theNode->GetBounds(theBufferManager, m_Context->GetPathManager(),
+ theIncludeChildren);
+ } else {
+ qCCritical(INVALID_OPERATION, "GetBoundingBox called on invalid object");
+ QT3DS_ASSERT(false);
+ }
+ return retval;
+ }
+
+ static void Assign(Q3DStudio::CBoundingBox &lhs, NVBounds3 &rhs)
+ {
+ lhs.m_Min.m_X = rhs.minimum.x;
+ lhs.m_Min.m_Y = rhs.minimum.y;
+ lhs.m_Min.m_Z = rhs.minimum.z;
+
+ lhs.m_Max.m_X = rhs.maximum.x;
+ lhs.m_Max.m_Y = rhs.maximum.y;
+ lhs.m_Max.m_Z = rhs.maximum.z;
+ }
+
+ Q3DStudio::CBoundingBox GetBoundingBox(Q3DStudio::TElement *inElement, bool inSelfOnly) override
+ {
+ Q3DStudio::CBoundingBox retval;
+ retval.SetEmpty();
+ NVBounds3 theLocalBox = GetNodeLocalBoundingBox(inElement, inSelfOnly);
+ if (theLocalBox.isEmpty() == false) {
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation());
+ if (theTranslator && GraphObjectTypes::IsNodeType(theTranslator->GetUIPType())) {
+ SNode *theNode = static_cast<SNode *>(&theTranslator->RenderObject());
+ theLocalBox.transform(theNode->m_GlobalTransform);
+ Assign(retval, theLocalBox);
+ // Left handed nodes need to return values in their space, not in the global space
+ // This is a hack fix due to a bug.
+ if (theNode->m_Flags.IsLeftHanded()) {
+ eastl::swap(retval.m_Min.m_Z, retval.m_Max.m_Z);
+ retval.m_Min.m_Z *= -1;
+ retval.m_Max.m_Z *= -1;
+ }
+ }
+ }
+ return retval;
+ }
+
+ Q3DStudio::CBoundingBox GetLocalBoundingBox(Q3DStudio::TElement *inElement,
+ bool inSelfOnly) override
+ {
+ Q3DStudio::CBoundingBox retval;
+ retval.SetEmpty();
+ if (inElement == nullptr) {
+ QT3DS_ASSERT(false);
+ return retval;
+ }
+ NVBounds3 theLocalBounds = GetNodeLocalBoundingBox(inElement, inSelfOnly);
+ if (theLocalBounds.isEmpty() == false)
+ Assign(retval, theLocalBounds);
+
+ return retval;
+ }
+
+ Q3DStudio::SCameraRect GetCameraBounds(Q3DStudio::TElement &inElem) override
+ {
+ Qt3DSTranslator *theTranslator = reinterpret_cast<Qt3DSTranslator *>(inElem.GetAssociation());
+ if (theTranslator && theTranslator->m_RenderObject) {
+ Option<qt3ds::render::SCuboidRect> theRectOpt =
+ m_Context->GetRenderer().GetCameraBounds(*theTranslator->m_RenderObject);
+ if (theRectOpt.hasValue()) {
+ qt3ds::render::SCuboidRect theRect(*theRectOpt);
+ return Q3DStudio::SCameraRect(theRect.m_Left, theRect.m_Top, theRect.m_Right,
+ theRect.m_Bottom);
+ }
+ }
+ return Q3DStudio::SCameraRect();
+ }
+
+ void PositionToScreen(Q3DStudio::TElement &inElement, QT3DSVec3 &inPos, QT3DSVec3 &outScreen) override
+ {
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement.GetAssociation());
+ if (theTranslator && theTranslator->m_RenderObject) {
+ SNode *theNode = reinterpret_cast<SNode *>(theTranslator->m_RenderObject);
+ QT3DSVec3 thePos = theNode->m_GlobalTransform.transform(inPos);
+ outScreen = m_Context->GetRenderer().ProjectPosition(*theNode, thePos);
+ }
+ }
+
+ void ScreenToPosition(Q3DStudio::TElement &inElement, QT3DSVec3 &inScreen, QT3DSVec3 &outPos) override
+ {
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement.GetAssociation());
+ if (theTranslator && theTranslator->m_RenderObject) {
+ SNode *theNode = reinterpret_cast<SNode *>(theTranslator->m_RenderObject);
+ QT3DSVec3 objPos = theNode->GetGlobalPos();
+ outPos = m_Context->GetRenderer().UnprojectWithDepth(*(theNode), objPos, inScreen);
+ }
+ }
+
+ static void GenerateBsdfMipmaps(SImage *theImage, const unsigned char *inBuffer,
+ Q3DStudio::INT32 inBufferLength, Q3DStudio::INT32 inWidth,
+ Q3DStudio::INT32 inHeight,
+ qt3ds::render::NVRenderTextureFormats::Enum inFormat,
+ IQt3DSRenderContext *theContext)
+ {
+ NVRenderTextureFormats::Enum destFormat = qt3ds::render::NVRenderTextureFormats::RGBA16F;
+
+ Qt3DSRenderPrefilterTexture *theBSDFMipMap = theImage->m_TextureData.m_BSDFMipMap;
+ if (theBSDFMipMap == nullptr) {
+ theBSDFMipMap = Qt3DSRenderPrefilterTexture::Create(
+ &theContext->GetRenderContext(), inWidth, inHeight,
+ *theImage->m_TextureData.m_Texture, destFormat, theContext->GetFoundation());
+ theImage->m_TextureData.m_BSDFMipMap = theBSDFMipMap;
+ }
+
+ if (theBSDFMipMap)
+ theBSDFMipMap->Build((void *)(inBuffer), inBufferLength, inFormat);
+ }
+
+ // This could cause some significant drama.
+ void SetTextureData(Q3DStudio::TElement *inElement, const unsigned char *inBuffer,
+ Q3DStudio::INT32 inBufferLength, Q3DStudio::INT32 inWidth,
+ Q3DStudio::INT32 inHeight,
+ qt3ds::render::NVRenderTextureFormats::Enum inFormat,
+ Q3DStudio::INT32 inHasTransparency) override
+ {
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation());
+ if (theTranslator && theTranslator->GetUIPType() == GraphObjectTypes::Image) {
+ SImage *theImage = static_cast<SImage *>(&theTranslator->RenderObject());
+ // Attempt to resolve the image's path
+ if (!theImage->m_TextureData.m_Texture) {
+ if (theImage->m_ImagePath.IsValid())
+ theImage->m_TextureData = m_Context->GetBufferManager().LoadRenderImage(
+ theImage->m_ImagePath, false,
+ theImage->m_MappingMode == ImageMappingModes::LightProbe);
+ }
+ // Here we go, updating the texture.
+ if (theImage->m_TextureData.m_Texture) {
+
+ if (theImage->m_MappingMode == ImageMappingModes::LightProbe) {
+ // theImage->m_TextureData.m_Texture->GenerateMipmaps();
+ GenerateBsdfMipmaps(theImage, inBuffer, inBufferLength, inWidth, inHeight,
+ inFormat, m_Context);
+ } else
+ theImage->m_TextureData.m_Texture->SetTextureData(
+ NVDataRef<QT3DSU8>((QT3DSU8 *)inBuffer, (QT3DSU32)inBufferLength), 0, inWidth,
+ inHeight, inFormat);
+
+ if (inHasTransparency >= 0) {
+ bool hasTransparency = inHasTransparency ? true : false;
+ theImage->m_TextureData.m_TextureFlags.SetHasTransparency(hasTransparency);
+ m_Context->GetBufferManager().SetImageHasTransparency(theImage->m_ImagePath,
+ hasTransparency);
+ }
+ theImage->m_Flags.SetDirty(true);
+ }
+ } else {
+ qCCritical(INVALID_OPERATION, "SetTextureData called on object that is not an image");
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ bool CreateOrSetMeshData(const char *inPathStr, unsigned char *vertData,
+ unsigned int numVerts, unsigned int vertStride,
+ unsigned int *indexData, unsigned int numIndices,
+ qt3ds::NVBounds3 &objBounds) override
+ {
+ SRenderMesh *theMesh = nullptr;
+
+ if (inPathStr && vertData && indexData) {
+ theMesh = m_Context->GetBufferManager().CreateMesh(
+ inPathStr, vertData, numVerts, vertStride, indexData, numIndices, objBounds);
+ } else {
+ qCCritical(INVALID_OPERATION,
+ "CreateOrSetMeshData was not supplied necessary buffers or object path");
+ }
+
+ return (theMesh != nullptr);
+ }
+
+ Q3DStudio::STextSizes MeasureText(Q3DStudio::TElement *inElement, const char *inTextStr) override
+ {
+ Qt3DSTranslator *theTranslator =
+ reinterpret_cast<Qt3DSTranslator *>(inElement->GetAssociation());
+ Q3DStudio::STextSizes retval;
+ if (theTranslator && theTranslator->GetUIPType() == GraphObjectTypes::Text) {
+ if (inElement->IsDirty()) {
+ theTranslator->OnElementChanged(*m_Presentation, *m_Context,
+ *m_RuntimePresentation);
+ }
+ SText *theText = static_cast<SText *>(&theTranslator->RenderObject());
+ if (theText) {
+
+ STextDimensions theDimensions =
+ m_Context->GetTextRenderer()->MeasureText(*theText, 1.0f, inTextStr);
+
+ retval = Q3DStudio::STextSizes(Q3DStudio::INT32(theDimensions.m_TextWidth),
+ Q3DStudio::INT32(theDimensions.m_TextHeight));
+ }
+ } else {
+ qCCritical(INVALID_OPERATION, "MeasureText called on object that is not text");
+ QT3DS_ASSERT(false);
+
+ }
+ return retval;
+ }
+
+ Q3DStudio::STextSizes GetPresentationDesignDimensions() override
+ {
+ if (m_Presentation) {
+ return Q3DStudio::STextSizes(
+ static_cast<Q3DStudio::INT32>(m_Presentation->m_PresentationDimensions.x),
+ static_cast<Q3DStudio::INT32>(m_Presentation->m_PresentationDimensions.y));
+ }
+ QT3DS_ASSERT(false);
+ return Q3DStudio::STextSizes();
+ }
+
+ virtual Q3DStudio::SMousePosition
+ WindowToPresentation(const Q3DStudio::SMousePosition &inWindowCoords) override
+ {
+ // If there aren't any rotations, then account for the difference in width/height of the
+ // presentation and the window
+ QT3DSVec2 theCoords = m_Context->GetMousePickMouseCoords(
+ QT3DSVec2(QT3DSF32(inWindowCoords.m_X), QT3DSF32(inWindowCoords.m_Y)));
+ theCoords.x -= m_LastRenderViewport.m_X;
+ // Note that the mouse Y is reversed. Thus a positive offset of the viewport will reduce
+ // the mouse value.
+ theCoords.y -= m_LastRenderViewport.m_Y;
+ return Q3DStudio::SMousePosition(theCoords.x, theCoords.y);
+ }
+
+ qt3ds::foundation::CRegisteredString RegisterStr(const char *inStr) override
+ {
+ return m_Context->GetStringTable().RegisterStr(inStr);
+ }
+
+ void RegisterOffscreenRenderer(const char *inKey) override
+ {
+ m_OffscreenRenderer = QT3DS_NEW(m_Context->GetAllocator(), Qt3DSRenderSceneSubPresRenderer)(
+ *this, *m_Context, *m_Presentation);
+ m_OffscreenRendererId = m_Context->GetStringTable().RegisterStr(inKey);
+ m_Context->GetOffscreenRenderManager().RegisterOffscreenRenderer(m_OffscreenRendererId,
+ *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() && qt3ds::runtime::isImagePath(
+ image->m_ImagePath.c_str())) {
+ const bool ibl = image->m_MappingMode == ImageMappingModes::LightProbe;
+ image->m_LoadedTextureData = mgr.CreateReloadableImage(image->m_ImagePath,
+ false, ibl);
+ image->m_LoadedTextureData->m_callbacks.push_back(image);
+ }
+ });
+ }
+
+ void Release() override { NVDelete(m_Context->GetAllocator(), this); }
+};
+
+SOffscreenRenderFlags
+Qt3DSRenderSceneSubPresRenderer::NeedsRender(const SOffscreenRendererEnvironment &inEnvironment,
+ QT3DSVec2 inPresScale,
+ const SRenderInstanceId instanceId)
+{
+ m_Scene.TransferDirtyProperties();
+ return CSubPresentationRenderer::NeedsRender(inEnvironment, inPresScale, instanceId);
+}
+
+void Qt3DSRenderSceneSubPresRenderer::Render(const SOffscreenRendererEnvironment &inEnvironment,
+ NVRenderContext &inRenderContext,
+ QT3DSVec2 inPresScale,
+ SScene::RenderClearCommand inClearBuffer,
+ const SRenderInstanceId instanceId)
+{
+ CSubPresentationRenderer::Render(inEnvironment, inRenderContext, inPresScale, inClearBuffer,
+ instanceId);
+}
+
+void Qt3DSRenderSceneSubPresRenderer::RenderWithClear(
+ const SOffscreenRendererEnvironment &inEnvironment,
+ NVRenderContext &inRenderContext, QT3DSVec2 inPresScale,
+ SScene::RenderClearCommand inClearBuffer, QT3DSVec4 inClearColor,
+ const SRenderInstanceId id)
+{
+ CSubPresentationRenderer::RenderWithClear(inEnvironment, inRenderContext,
+ inPresScale, inClearBuffer,
+ inClearColor, id);
+}
+
+//////////////////////////////////////////////////////////////////
+// Scene Manager
+//////////////////////////////////////////////////////////////////
+
+struct Qt3DSRenderSceneManager : public Q3DStudio::ISceneManager,
+ public Q3DStudio::ISceneBinaryLoader
+{
+ typedef nvhash_map<CRegisteredString, bool> TStrBoolMap;
+
+ NVScopedRefCounted<SBindingCore> m_Context;
+ nvvector<pair<Q3DStudio::IPresentation *, Qt3DSRenderScene *>> m_Scenes;
+ nvvector<pair<qt3ds::foundation::CRegisteredString, long>> m_RenderPlugins;
+ Q3DStudio::INT32 m_ViewWidth;
+ Q3DStudio::INT32 m_ViewHeight;
+ Q3DStudio::SPickFrame m_PickFrame;
+ NVDataRef<QT3DSU8> m_StrTableData;
+ // The boolean is to mark transparent images and ibl images
+ nvvector<eastl::pair<CRegisteredString, eastl::pair<bool, bool>>> m_SourcePaths;
+ eastl::hash_set<CRegisteredString> m_SourcePathSet;
+
+ Qt3DSRenderScene *m_LastRenderedScene;
+ Q3DStudio::IWindowSystem &m_WindowSystem;
+ Mutex m_LoadingScenesMutex;
+ eastl::vector<NVScopedRefCounted<SSceneLoadData>> m_LoadingScenes;
+ CRegisteredString m_ProjectDir;
+ CRegisteredString m_BinaryDir;
+ bool m_ProjectInitialized;
+ QT3DSI32 mRefCount;
+
+ Qt3DSRenderSceneManager(SBindingCore &ctx, Q3DStudio::IWindowSystem &inWindowSystem)
+ : m_Context(ctx)
+ , m_Scenes(ctx.GetAllocator(), "Qt3DSRenderSceneManager::m_Scenes")
+ , m_RenderPlugins(ctx.GetAllocator(), "Qt3DSRenderSceneManager::m_RenderPlugins")
+ , m_ViewWidth(0)
+ , m_ViewHeight(0)
+ , m_SourcePaths(ctx.GetAllocator(), "Qt3DSRenderSceneManager::m_SourcePaths")
+ , m_LastRenderedScene(nullptr)
+ , m_WindowSystem(inWindowSystem)
+ , m_LoadingScenesMutex(ctx.GetAllocator())
+ , m_ProjectInitialized(false)
+ , mRefCount(0)
+ {
+ memZero(&m_PickFrame, sizeof(m_PickFrame));
+ }
+ virtual ~Qt3DSRenderSceneManager() override
+ {
+ for (QT3DSU32 idx = 0, end = m_Scenes.size(); idx < end; ++idx)
+ m_Scenes[idx].second->Release();
+ m_Scenes.clear();
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Context->GetAllocator())
+
+ static QT3DSU32 GetFileTag()
+ {
+ const char *fileTag = "Qt3DSS";
+ const QT3DSU32 *theTagPtr = reinterpret_cast<const QT3DSU32 *>(fileTag);
+ return *theTagPtr;
+ }
+
+ void FinalizeScene(Q3DStudio::IPresentation &inPresentation, Qt3DSRenderScene &inScene)
+ {
+ inPresentation.SetScene(&inScene);
+ if (m_ProjectInitialized == false) {
+ m_ProjectInitialized = true;
+ // For QT3DS-3353 assume project fonts are in a subdirectory relative to presentation.
+ QString projectFontDir = inPresentation.getProjectPath() + QStringLiteral("/fonts");
+ if (m_Context->m_Context->GetTextRenderer()) {
+ m_Context->m_Context->GetTextRenderer()->AddProjectFontDirectory(
+ projectFontDir.toUtf8().data());
+ }
+ if (m_Context->m_Context->getDistanceFieldRenderer()) {
+ m_Context->m_Context->getDistanceFieldRenderer()->AddProjectFontDirectory(
+ projectFontDir.toUtf8().data());
+ }
+ eastl::string theBinaryPath(inPresentation.GetFilePath().toLatin1().constData());
+ qt3ds::foundation::CFileTools::AppendDirectoryInPathToFile(theBinaryPath, "binary");
+ eastl::string theBinaryDir(theBinaryPath);
+ qt3ds::foundation::CFileTools::GetDirectory(theBinaryDir);
+ if (m_Context->m_WriteOutShaderCache)
+ qt3ds::foundation::CFileTools::CreateDir(theBinaryDir.c_str());
+ }
+ inScene.m_RuntimePresentation = &inPresentation;
+ m_Scenes.push_back(make_pair(&inPresentation, &inScene));
+ Qt3DSTranslator::AssignUserData(inPresentation, *inScene.m_Presentation);
+ }
+
+ static const char *GetBinaryExtension() { return "uibsg"; }
+
+ struct SPluginInstanceTableProvider : public Q3DStudio::IScriptTableProvider
+ {
+ IRenderPluginInstance &m_Instance;
+ SPluginInstanceTableProvider(IRenderPluginInstance &ins)
+ : m_Instance(ins)
+ {
+ }
+ void CreateTable(script_State *inState) override { m_Instance.CreateScriptProxy(inState); }
+ };
+
+ void InitializeTranslator(Qt3DSTranslator &inTranslator, Q3DStudio::IScriptBridge &inBridge)
+ {
+ if (inTranslator.m_RenderObject->m_Type == GraphObjectTypes::RenderPlugin) {
+ SRenderPlugin &theRenderPlugin =
+ static_cast<SRenderPlugin &>(*inTranslator.m_RenderObject);
+ IRenderPluginInstance *thePluginInstance =
+ m_Context->m_Context->GetRenderPluginManager().GetOrCreateRenderPluginInstance(
+ theRenderPlugin.m_PluginPath, &theRenderPlugin);
+ if (thePluginInstance) {
+ SPluginInstanceTableProvider theProvider(*thePluginInstance);
+ inBridge.SetTableForElement(*inTranslator.m_Element, theProvider);
+ }
+ }
+ }
+
+ struct SResolver : public qt3ds::render::IUIPReferenceResolver
+ {
+ IStringTable &m_StringTable;
+ Q3DStudio::IUIPParser &m_Parser;
+ SResolver(IStringTable &strt, Q3DStudio::IUIPParser &p)
+ : m_StringTable(strt)
+ , m_Parser(p)
+ {
+ }
+
+ CRegisteredString ResolveReference(CRegisteredString inStart,
+ const char *inReference) override
+ {
+ eastl::string theResolvedId = m_Parser.ResolveReference(inStart, inReference);
+ if (theResolvedId.size())
+ return m_StringTable.RegisterStr(theResolvedId.c_str());
+ return CRegisteredString();
+ }
+ };
+
+ Q3DStudio::IScene *LoadScene(Q3DStudio::IPresentation *inPresentation,
+ 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 = nullptr;
+ if (inParser) {
+ QString thePath(inPresentation->GetFilePath());
+ QFileInfo fileInfo(thePath);
+ TIdObjectMap theObjMap(m_Context->GetAllocator(), "LoadScene::theObjMap");
+ SResolver theResolver(m_Context->m_CoreContext->GetStringTable(), *inParser);
+
+ theScene->m_Presentation = IUIPLoader::LoadUIPFile(
+ inParser->GetDOMReader(),
+ fileInfo.absoluteFilePath().toLatin1().constData(),
+ inParser->GetMetaData(),
+ m_Context->m_CoreContext->GetStringTable(),
+ m_Context->m_RenderContext->GetFoundation(),
+ theScene->m_AutoAllocator, theObjMap,
+ m_Context->m_Context->GetBufferManager(),
+ m_Context->m_Context->GetEffectSystem(),
+ fileInfo.path().toLatin1().constData(),
+ m_Context->m_Context->GetRenderPluginManager(),
+ m_Context->m_Context->GetCustomMaterialSystem(),
+ m_Context->m_Context->GetDynamicObjectSystem(),
+ m_Context->m_Context->GetPathManager(), &theResolver,
+ variantConfig, false);
+ if (!theScene->m_Presentation) {
+ QT3DS_ASSERT(false);
+ 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;
+ eastl::vector<CRegisteredString> iblList;
+ for (QT3DSU32 idx = 0, end = theSourcePathData.size(); idx < end; ++idx) {
+ const eastl::string &theValue = theSourcePathData[idx];
+ CRegisteredString theSourcePath =
+ m_Context->m_CoreContext->GetStringTable().RegisterStr(theValue.c_str());
+ size_t theValueSize = theValue.size();
+ if (theValueSize > 3) {
+ CRegisteredString theObjectPath = theSourcePath;
+ if (qt3ds::runtime::isImagePath(theValue.c_str())) {
+ // load only images not on any slide
+ if (!theManager.isReloadableResourcesEnabled() ||
+ !slideSourcePaths.contains(QString::fromLatin1(theValue.c_str()))) {
+ theManager.SetImageTransparencyToFalseIfNotSet(theObjectPath);
+ bool ibl = inParser->isIblImage(theObjectPath.c_str());
+ bool transparent = theManager.GetImageHasTransparency(theObjectPath);
+ if (m_SourcePathSet.insert(theSourcePath).second) {
+
+ m_SourcePaths.push_back(eastl::make_pair(theSourcePath,
+ eastl::make_pair(transparent, ibl)));
+ }
+ if (ibl)
+ iblList.push_back(theObjectPath);
+ else
+ theSourcePathList.push_back(theObjectPath);
+
+ }
+ } else if (theValue.find(".mesh") != eastl::string::npos) {
+ theManager.LoadMesh(theObjectPath);
+ }
+ }
+ }
+
+ // Fire off parallel loading of the source paths
+ QT3DSU64 imageBatchId = m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ toConstDataRef(theSourcePathList.data(), theSourcePathList.size()),
+ CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
+ .GetRenderContextType(),
+ theScene->m_Presentation->m_preferKTX, false);
+ QT3DSU64 iblImageBatchId = m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ toConstDataRef(iblList.data(), iblList.size()),
+ CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
+ .GetRenderContextType(),
+ theScene->m_Presentation->m_preferKTX, true);
+ m_Context->m_Context->GetImageBatchLoader().BlockUntilLoaded(
+ static_cast<TImageBatchId>(imageBatchId));
+ m_Context->m_Context->GetImageBatchLoader().BlockUntilLoaded(
+ static_cast<TImageBatchId>(iblImageBatchId));
+
+ theIScene = QT3DS_NEW(m_Context->GetAllocator(),
+ Qt3DSRenderScene)(*m_Context, *m_Context->m_Context, *theScene);
+ // Now we need to associate the presentation with everything else.
+ NVAllocatorCallback &translatorAllocator = theScene->m_AutoAllocator;
+ for (TIdObjectMap::iterator iter = theObjMap.begin(), end = theObjMap.end();
+ iter != end; ++iter) {
+ theIScene->m_GraphObjectList.push_back(iter->second);
+ Q3DStudio::SElementAndType theElement =
+ inParser->GetElementForID(iter->first.c_str());
+ if (theElement.m_Element
+ && theElement.m_Type != Q3DStudio::UIPElementTypes::Unknown) {
+ Qt3DSTranslator *theTranslator = Qt3DSTranslator::CreateTranslatorForElement(
+ *theElement.m_Element, *iter->second, translatorAllocator);
+ if (theTranslator) {
+ theIScene->m_DirtySet.insert(*theTranslator);
+ InitializeTranslator(*theTranslator, inBridge);
+ }
+ }
+ }
+ theIScene->PostLoadStep();
+ } else {
+ // Binary load path is quite different than normal load path and
+ // nothing else will load here.
+ QT3DS_ASSERT(false);
+ }
+ if (inPresentation && theIScene)
+ FinalizeScene(*inPresentation, *theIScene);
+ return theIScene;
+ }
+
+ // threadsafe
+ // Can be called from any thread
+ bool GetBinaryLoadFileName(eastl::string &inPresentationFilename,
+ eastl::string &outResult) override
+ {
+ eastl::string theBinaryPath(inPresentationFilename.c_str());
+ qt3ds::foundation::CFileTools::AppendDirectoryInPathToFile(theBinaryPath, "binary");
+ qt3ds::foundation::CFileTools::SetExtension(
+ theBinaryPath, GetBinaryExtension()); // uibb: short for ui binary binding
+ outResult = theBinaryPath;
+ return true;
+ }
+
+ // threadsafe
+ // returns a handle to the loaded object. Return value of zero means error.
+ qt3ds::QT3DSU32 LoadSceneStage1(CRegisteredString inPresentationDirectory,
+ qt3ds::render::ILoadedBuffer &inData) override
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load Scene Graph Stage 1");
+ NVDataRef<QT3DSU8> theLoadedData(inData.Data());
+ SDataReader theReader(theLoadedData.begin(), theLoadedData.end());
+
+ QT3DSU32 theFileSig = theReader.LoadRef<QT3DSU32>();
+ QT3DSU32 theBinaryVersion = theReader.LoadRef<QT3DSU32>();
+ QT3DSU32 theDataSectionSize = QT3DSU32(theReader.m_EndPtr - theReader.m_CurrentPtr);
+
+ if (theFileSig != GetFileTag()
+ || theBinaryVersion != SGraphObject::GetSceneGraphBinaryVersion()) {
+ QT3DS_ASSERT(false);
+ return 0;
+ }
+ QT3DSU32 theLoadingSceneIndex = 0;
+ SSceneLoadData *theScene;
+ {
+ Mutex::ScopedLock __locker(m_LoadingScenesMutex);
+ theLoadingSceneIndex = QT3DSU32(m_LoadingScenes.size()) + 1;
+ m_LoadingScenes.push_back(
+ QT3DS_NEW(m_Context->GetAllocator(), SSceneLoadData)(m_Context->GetAllocator()));
+ theScene = m_LoadingScenes.back();
+ }
+ // preserve the data buffer because we run directly from it; there isn't a memcopy.
+ theScene->m_Data = inData;
+
+ QT3DSU32 theTranslatorOffset = theReader.LoadRef<QT3DSU32>();
+
+ NVDataRef<QT3DSU8> theSGData = NVDataRef<QT3DSU8>(theReader.m_CurrentPtr, theTranslatorOffset);
+ NVDataRef<QT3DSU8> theTranslatorData = NVDataRef<QT3DSU8>(
+ theReader.m_CurrentPtr + theTranslatorOffset, theDataSectionSize - theTranslatorOffset);
+
+ CStrTableOrDataRef theStrTableData(m_Context->m_CoreContext->GetStringTable());
+ if (m_StrTableData.size())
+ theStrTableData = CStrTableOrDataRef(m_StrTableData);
+
+ theScene->m_Presentation = SGraphObjectSerializer::Load(
+ theSGData, m_StrTableData, m_Context->m_CoreContext->GetDynamicObjectSystemCore(),
+ m_Context->m_CoreContext->GetPathManagerCore(), m_Context->GetAllocator(),
+ inPresentationDirectory);
+ if (theScene->m_Presentation)
+ theScene->m_Presentation->m_PresentationDirectory = inPresentationDirectory;
+
+ theScene->m_TranslatorData = theTranslatorData;
+ theScene->m_SceneGraphData = theSGData;
+
+ {
+ Mutex::ScopedLock __locker(m_LoadingScenesMutex);
+ m_LoadingScenes[theLoadingSceneIndex - 1] = theScene;
+ }
+ return theLoadingSceneIndex;
+ }
+
+ // threadsafe
+ // still does not require openGL context but has dependency on a few other things.
+ void LoadSceneStage2(qt3ds::QT3DSU32 inSceneHandle, Q3DStudio::IPresentation &inPresentation,
+ size_t inElementMemoryOffset, Q3DStudio::IScriptBridge &inBridge) override
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load Scene Graph Stage 2");
+ QT3DSU32 theSceneIndex = QT3DS_MAX_U32;
+ SSceneLoadData *theScene;
+ {
+ Mutex::ScopedLock __locker(m_LoadingScenesMutex);
+ QT3DSU32 numLoadingScenes = QT3DSU32(m_LoadingScenes.size());
+ if (inSceneHandle && inSceneHandle <= numLoadingScenes) {
+ theSceneIndex = inSceneHandle - 1;
+ theScene = m_LoadingScenes[theSceneIndex];
+ } else {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ }
+ SDataReader theReader(theScene->m_TranslatorData.begin(), theScene->m_TranslatorData.end());
+ QT3DSU32 theNumTranslators = theReader.LoadRef<QT3DSU32>();
+ theScene->m_Translators.resize(theNumTranslators);
+ theScene->m_RuntimePresentation = &inPresentation;
+ for (QT3DSU32 idx = 0, end = theNumTranslators; idx < end; ++idx) {
+ Qt3DSTranslator *theTranslator = Qt3DSTranslator::LoadTranslator(
+ theReader, inElementMemoryOffset, theScene->m_SceneGraphData,
+ theScene->m_AutoAllocator);
+ if (theTranslator) {
+ InitializeTranslator(*theTranslator, inBridge);
+ }
+ theScene->m_Translators[idx] = theTranslator;
+ }
+ }
+
+ void OnGraphicsInitialized()
+ {
+ QT3DS_ASSERT(m_Context->m_Context.mPtr);
+ // this means graphics have been initialized
+ eastl::string theSourcePathStr;
+ IBufferManager &theManager(m_Context->m_Context->GetBufferManager());
+ nvvector<CRegisteredString> imagePathList(m_Context->GetAllocator(),
+ "imagePathList");
+ nvvector<CRegisteredString> iblImagePathList(m_Context->GetAllocator(),
+ "iblImagePathList");
+ for (QT3DSU32 idx = 0, end = m_SourcePaths.size(); idx < end; ++idx) {
+ theSourcePathStr.assign(m_SourcePaths[idx].first);
+ bool hasTransparency = m_SourcePaths[idx].second.first;
+ bool isIbl = m_SourcePaths[idx].second.second;
+ if (theSourcePathStr.size() > 4) {
+ CRegisteredString theObjectPath = m_SourcePaths[idx].first;
+ if (qt3ds::runtime::isImagePath(theSourcePathStr.c_str())) {
+ theManager.SetImageHasTransparency(theObjectPath, hasTransparency);
+ if (isIbl)
+ iblImagePathList.push_back(theObjectPath);
+ else
+ imagePathList.push_back(theObjectPath);
+ } else {
+ if (theSourcePathStr.find(".mesh") != eastl::string::npos)
+ theManager.LoadMesh(theObjectPath);
+ }
+ }
+ }
+
+ bool pktx = false;
+ for (unsigned int i = 0; i < m_Scenes.size(); ++i) {
+ if (m_Scenes[i].second->m_Presentation->m_preferKTX) {
+ pktx = true;
+ break;
+ }
+ }
+
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Initial Batch Image Load");
+
+ m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ toConstDataRef(imagePathList.data(), imagePathList.size()),
+ CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
+ .GetRenderContextType(), pktx, false);
+ m_Context->m_Context->GetImageBatchLoader().LoadImageBatch(
+ toConstDataRef(iblImagePathList.data(), iblImagePathList.size()),
+ CRegisteredString(), nullptr, m_Context->m_Context->GetRenderContext()
+ .GetRenderContextType(), pktx, true);
+ }
+
+ {
+
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Initialize Scenes");
+ for (QT3DSU32 idx = 0, end = m_LoadingScenes.size(); idx < end; ++idx) {
+ SSceneLoadData &theScene = *m_LoadingScenes[idx];
+ // m_Context->m_Foundation->error( QT3DS_WARN, "Finalizing scene %d", (int)idx+1 );
+ if (theScene.m_RuntimePresentation) {
+ 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));
+ }
+ }
+ }
+ }
+
+ void LoadRenderPlugin(const char *inAssetIDString, const char *inPath,
+ const char *inArgs) override
+ {
+ Q3DStudio::CDLLManager &theDLLManager = Q3DStudio::CDLLManager::GetDLLManager();
+ long theHandle = theDLLManager.LoadLibrary(inPath, EDLLTYPE_RENDERABLE_PLUGIN);
+ if (theHandle >= 0) {
+ qt3ds::render::IOffscreenRenderer *theOffscreenRenderer =
+ QT3DS_NEW(m_Context->GetAllocator(),
+ qt3ds::render::COldNBustedPluginRenderer)(*m_Context->m_Context, theHandle);
+ qt3ds::foundation::CRegisteredString theAssetString =
+ m_Context->m_CoreContext->GetStringTable().RegisterStr(inAssetIDString);
+
+ m_Context->m_Context->GetOffscreenRenderManager().RegisterOffscreenRenderer(
+ theAssetString, *theOffscreenRenderer);
+
+ PROC_Initialize theInitializeProc =
+ reinterpret_cast<PROC_Initialize>(theDLLManager.GetProc("Initialize", theHandle));
+ Q3DStudio_ASSERT(theInitializeProc);
+#if !defined (Q_OS_MACOS)
+ PROC_SetEGLInfo theSetEGLInfoProc =
+ reinterpret_cast<PROC_SetEGLInfo>(theDLLManager.GetProc("SetEGLInfo", theHandle));
+ // Set EGL parameters used for optional context creation
+ if (theSetEGLInfoProc) {
+ Q3DStudio::SEGLInfo *theInfo = m_WindowSystem.GetEGLInfo();
+ if (theInfo)
+ theSetEGLInfoProc(theInfo->display, theInfo->context, theInfo->surface,
+ theInfo->config);
+ }
+#endif
+ if (theInitializeProc && theInitializeProc(inArgs) == EDLLSTATUS_OK)
+ m_RenderPlugins.push_back(make_pair(theAssetString, theHandle));
+ else
+ qCWarning(qt3ds::INVALID_OPERATION) << "Unable to load plugin " << inAssetIDString;
+ } else
+ qCWarning(qt3ds::INVALID_OPERATION) << "Unable to load plugin " << inAssetIDString;
+
+ return;
+ }
+
+ void LoadQmlStreamerPlugin(const char *inAssetIDString) override
+ {
+ qt3ds::render::IOffscreenRenderer *theOffscreenRenderer =
+ QT3DS_NEW(m_Context->GetAllocator(),
+ Q3DSQmlRender)(*m_Context->m_Context, inAssetIDString);
+ if (theOffscreenRenderer) {
+ qt3ds::foundation::CRegisteredString theAssetString =
+ m_Context->m_CoreContext->GetStringTable().RegisterStr(inAssetIDString);
+ m_Context->m_Context->GetOffscreenRenderManager().RegisterOffscreenRenderer(
+ SOffscreenRendererKey(theAssetString), *theOffscreenRenderer);
+
+ m_RenderPlugins.push_back(make_pair(theAssetString, 0));
+ }
+ }
+
+ void BinarySave(Q3DStudio::IScene &inScene) override
+ {
+ Qt3DSRenderScene &theScene = static_cast<Qt3DSRenderScene &>(inScene);
+ qt3ds::render::SWriteBuffer theWriteBuffer(m_Context->GetAllocator(), "BinarySaveBuffer");
+ qt3ds::render::SPtrOffsetMap theSGOffsetMap(m_Context->GetAllocator(), "PointerOffsetMap");
+ // Start with some versioning and sanity checks.
+ theWriteBuffer.write(GetFileTag());
+ theWriteBuffer.write(SGraphObject::GetSceneGraphBinaryVersion());
+ QT3DSU32 theTranslatorOffsetAddress = theWriteBuffer.size();
+ // Now the data section starts. Offsets should be relative to here, not the first
+ // 8 bytes.
+ theWriteBuffer.writeZeros(4); // offset where the translator data starts;
+ QT3DSU32 theDataSectionStart = theWriteBuffer.size();
+
+ // These offsets are after we have read in the data section
+ SGraphObjectSerializer::Save(
+ m_Context->m_RenderContext->GetFoundation(), *theScene.m_Presentation, theWriteBuffer,
+ m_Context->m_Context->GetDynamicObjectSystem(),
+ m_Context->m_Context->GetPathManager(), theSGOffsetMap,
+ m_Context->m_CoreContext->GetStringTable(), theScene.m_GraphObjectList);
+
+ theWriteBuffer.align(sizeof(void *));
+ QT3DSU32 theTranslatorCountAddress = theWriteBuffer.size();
+ QT3DSU32 theTranslatorOffset = theTranslatorCountAddress - theDataSectionStart;
+
+ theWriteBuffer.writeZeros(4);
+ // Now write out the translators verbatim. We get an adjustment parameter on save that
+ // allows a translation
+ // from old element ptr->new element ptr.
+ QT3DSU32 theTranslatorCount = 0;
+ for (QT3DSU32 idx = 0, end = theScene.m_GraphObjectList.size(); idx < end; ++idx) {
+ Qt3DSTranslator *theTranslator =
+ Qt3DSTranslator::GetTranslatorFromGraphNode(*theScene.m_GraphObjectList[idx]);
+ // Presentation nodes don't have translator
+ if (theTranslator) {
+ qt3ds::render::SPtrOffsetMap::iterator theIter =
+ theSGOffsetMap.find(theScene.m_GraphObjectList[idx]);
+ if (theIter != theSGOffsetMap.end()) {
+ QT3DSU32 theOffset = theIter->second;
+ theTranslator->Save(theWriteBuffer, theOffset);
+ ++theTranslatorCount;
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+ QT3DSU32 *theTranslatorCountPtr =
+ reinterpret_cast<QT3DSU32 *>(theWriteBuffer.begin() + theTranslatorCountAddress);
+ *theTranslatorCountPtr = theTranslatorCount;
+ QT3DSU32 *theTranslatorOffsetPtr =
+ reinterpret_cast<QT3DSU32 *>(theWriteBuffer.begin() + theTranslatorOffsetAddress);
+ *theTranslatorOffsetPtr = theTranslatorOffset;
+
+ Q3DStudio::IPresentation &thePresentation = *theScene.m_RuntimePresentation;
+ eastl::string theBinaryPath(thePresentation.GetFilePath().toLatin1().constData());
+ qt3ds::foundation::CFileTools::AppendDirectoryInPathToFile(theBinaryPath, "binary");
+ eastl::string theBinaryDir(theBinaryPath);
+ qt3ds::foundation::CFileTools::GetDirectory(theBinaryDir);
+ qt3ds::foundation::CFileTools::SetExtension(
+ theBinaryPath, GetBinaryExtension()); // uibb: short for ui binary binding
+
+ Q3DStudio::CFileStream theStream(theBinaryPath.c_str(), "wb");
+ if (theStream.IsOpen() == false) {
+ QT3DS_ASSERT(false);
+ }
+
+ theStream.WriteRaw(theWriteBuffer.begin(), theWriteBuffer.size());
+ theStream.Close();
+ }
+
+ // We save in the reverse order that we load because the effect system may add strings
+ // to the string table when it is writing its data out, this the string table needs to come
+ // last.
+ // Loading, obviously, the string table needs to be the first object loaded.
+ void BinarySaveManagerData(qt3ds::foundation::IOutStream &inStream,
+ const char *inBinaryDir) override
+ {
+ qt3ds::render::SWriteBuffer theWriteBuffer(m_Context->GetAllocator(), "BinarySaveBuffer");
+ IStringTable &theStrTable = m_Context->m_CoreContext->GetStringTable();
+ eastl::string theProjectDir(inBinaryDir);
+ qt3ds::foundation::CFileTools::GetDirectory(theProjectDir);
+
+ // We save everything before the string table because often times saving something creates
+ // new strings.
+ theWriteBuffer.writeZeros(4); // Total data size
+ // Dynamic object system
+ theWriteBuffer.writeZeros(4); // Effect system offset
+ // effect system
+ theWriteBuffer.writeZeros(4); // Material system offset
+ // material system
+ theWriteBuffer.writeZeros(4); // Binary path offset
+ // binary path data
+ theWriteBuffer.writeZeros(4); // Plugin manager offset
+ // plugin manager
+ theWriteBuffer.writeZeros(4); // String system offset
+ // string system last.
+ QT3DSU32 theOffsetStart = theWriteBuffer.size();
+ m_Context->m_Context->GetDynamicObjectSystem().Save(
+ theWriteBuffer, theStrTable.GetRemapMap(), theProjectDir.c_str());
+ theWriteBuffer.align(sizeof(void *));
+ QT3DSU32 theEffectSystemOffset = theWriteBuffer.size() - theOffsetStart;
+ m_Context->m_Context->GetEffectSystem().Save(theWriteBuffer, theStrTable.GetRemapMap(),
+ theProjectDir.c_str());
+ theWriteBuffer.align(sizeof(void *));
+ QT3DSU32 theMaterialSystemOffset = theWriteBuffer.size() - theOffsetStart;
+ m_Context->m_Context->GetCustomMaterialSystem().Save(
+ theWriteBuffer, theStrTable.GetRemapMap(), theProjectDir.c_str());
+ QT3DSU32 theBinaryPathOffset = theWriteBuffer.size() - theOffsetStart;
+
+ theWriteBuffer.write(QT3DSU32(m_SourcePaths.size()));
+ for (nvvector<pair<CRegisteredString, eastl::pair<bool, bool>>>::iterator iter
+ = m_SourcePaths.begin(), end = m_SourcePaths.end();
+ iter != end; ++iter) {
+ CRegisteredString theStr(iter->first);
+ theStr.Remap(theStrTable.GetRemapMap());
+ theWriteBuffer.write(size_t(theStr.c_str()));
+ QT3DSU32 theSourcePathFlags = iter->second.first ? 1 : 0;
+ theSourcePathFlags |= iter->second.second ? 2 : 0;
+ theWriteBuffer.write(theSourcePathFlags);
+ }
+
+ QT3DSU32 thePluginManagerOffset = theWriteBuffer.size() - theOffsetStart;
+
+ m_Context->m_Context->GetRenderPluginManager().Save(
+ theWriteBuffer, theStrTable.GetRemapMap(), theProjectDir.c_str());
+
+ QT3DSU32 theStringTableOffset = theWriteBuffer.size() - theOffsetStart;
+
+ theStrTable.Save(theWriteBuffer);
+
+ QT3DSU32 *theSizePtr = reinterpret_cast<QT3DSU32 *>(theWriteBuffer.begin());
+
+ theSizePtr[0] = theWriteBuffer.size() - 4; // overall size
+ theSizePtr[1] = theEffectSystemOffset;
+ theSizePtr[2] = theMaterialSystemOffset;
+ theSizePtr[3] = theBinaryPathOffset; // thePathOffset
+ theSizePtr[4] = thePluginManagerOffset;
+ theSizePtr[5] = theStringTableOffset;
+
+ inStream.Write(theWriteBuffer.begin(), theWriteBuffer.size());
+ }
+
+ NVDataRef<qt3ds::QT3DSU8> BinaryLoadManagerData(qt3ds::foundation::IInStream &inStream,
+ const char *inBinaryDir) override
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - String Table + Render Objects");
+ QT3DS_ASSERT(m_Context->m_FlowData == nullptr);
+ QT3DSU32 dataSize = 0;
+ inStream.Read(dataSize);
+ m_Context->m_FlowData = (QT3DSU8 *)m_Context->m_CoreContext->GetAllocator().allocate(
+ dataSize, "SceneManager::BinaryFlowData", __FILE__, __LINE__);
+
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - Initial Data Load");
+ inStream.Read(m_Context->m_FlowData, dataSize);
+ }
+ SDataReader theReader(m_Context->m_FlowData, m_Context->m_FlowData + dataSize);
+ QT3DSU32 theEffectSystemOffset = theReader.LoadRef<QT3DSU32>();
+ QT3DSU32 theMaterialSystemOffset = theReader.LoadRef<QT3DSU32>();
+ QT3DSU32 theBinaryPathOffset = theReader.LoadRef<QT3DSU32>();
+ QT3DSU32 thePluginManagerOffset = theReader.LoadRef<QT3DSU32>();
+ QT3DSU32 theStringTableOffset = theReader.LoadRef<QT3DSU32>();
+ QT3DSU8 *theStartOffset = theReader.m_CurrentPtr;
+ IStringTable &theStrTable = m_Context->m_CoreContext->GetStringTable();
+
+ // Load string table.
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - Load String Table");
+ m_StrTableData = toDataRef(theReader.m_CurrentPtr + theStringTableOffset,
+ dataSize - theStringTableOffset);
+ theStrTable.Load(m_StrTableData);
+ }
+
+ // Load source paths to preload heavy data
+ theReader.m_CurrentPtr = theStartOffset + theBinaryPathOffset;
+ QT3DSU32 theNumSourcePaths = theReader.LoadRef<QT3DSU32>();
+ eastl::string theSourcePathStr;
+ eastl::string theProjectDir(inBinaryDir);
+ eastl::string theShaderCacheDir(inBinaryDir);
+
+ // Up one moves to the project directory.
+ qt3ds::foundation::CFileTools::GetDirectory(theProjectDir);
+ const char8_t *theBasePath(theProjectDir.c_str());
+
+ m_ProjectDir = theStrTable.RegisterStr(theProjectDir.c_str());
+ m_BinaryDir = theStrTable.RegisterStr(theShaderCacheDir.c_str());
+
+ // Preload the heavy buffers
+ m_SourcePaths.resize(theNumSourcePaths);
+ for (QT3DSU32 idx = 0, end = theNumSourcePaths; idx < end; ++idx) {
+ CRegisteredString thePath = theReader.LoadRef<CRegisteredString>();
+ QT3DSU32 theFlags = theReader.LoadRef<QT3DSU32>();
+ thePath.Remap(m_StrTableData);
+ bool theBoolFlagValue = theFlags ? true : false;
+ m_SourcePaths[idx] = eastl::make_pair(thePath, theBoolFlagValue);
+ }
+
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - Base Dynamic System");
+ // Load effect system.
+ NVDataRef<QT3DSU8> theDynamicSystemData(theStartOffset, theEffectSystemOffset);
+ m_Context->m_CoreContext->GetDynamicObjectSystemCore().Load(
+ theDynamicSystemData, m_StrTableData, theBasePath);
+ }
+
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - Effect System");
+ NVDataRef<QT3DSU8> theEffectSystemData(theStartOffset + theEffectSystemOffset,
+ theMaterialSystemOffset - theEffectSystemOffset);
+ m_Context->m_CoreContext->GetEffectSystemCore().Load(theEffectSystemData,
+ m_StrTableData, theBasePath);
+ }
+
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - Material System");
+ NVDataRef<QT3DSU8> theMaterialSystemData(theStartOffset + theMaterialSystemOffset,
+ thePluginManagerOffset - theMaterialSystemOffset);
+ m_Context->m_CoreContext->GetMaterialSystemCore().Load(theMaterialSystemData,
+ m_StrTableData, theBasePath);
+ }
+
+ {
+ SStackPerfTimer __perfTimer(m_Context->m_CoreContext->GetPerfTimer(),
+ "Load UIAB - Plugin Manager Data");
+ NVDataRef<QT3DSU8> thePluginManagerData(theStartOffset + thePluginManagerOffset,
+ theStringTableOffset - thePluginManagerOffset);
+ m_Context->m_CoreContext->GetRenderPluginCore().Load(thePluginManagerData,
+ m_StrTableData, theBasePath);
+ }
+
+ return m_StrTableData;
+ }
+
+ virtual void DeleteScene(Q3DStudio::IPresentation *inPresentation)
+ {
+ QT3DSU32 idx;
+ QT3DSU32 end;
+ for (idx = 0, end = m_Scenes.size(); idx < end; ++idx) {
+ if (m_Scenes[idx].first == inPresentation)
+ break;
+ }
+ if (idx < m_Scenes.size()) {
+ m_Scenes[idx].second->Release();
+ m_Scenes.erase(m_Scenes.begin() + idx);
+ }
+ }
+
+ Q3DStudio::BOOL Update() override
+ {
+ bool theResult = false;
+ long theSceneCount = m_Scenes.size();
+ for (size_t theSceneIndex = 0; theSceneIndex < theSceneCount; ++theSceneIndex) {
+ Qt3DSRenderScene *theScene = m_Scenes[theSceneIndex].second;
+ theResult |= theScene->Update();
+ }
+ return theResult;
+ }
+
+ Q3DStudio::BOOL RenderPresentation(Q3DStudio::IPresentation *inPresentation,
+ bool firstFrame) override
+ {
+ 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 && theFirstScene->m_Presentation) {
+ m_LastRenderedScene = theFirstScene;
+ if (theFirstScene->m_Presentation->m_Scene
+ && theFirstScene->m_Presentation->m_Scene->m_UseClearColor) {
+ m_Context->m_Context->SetSceneColor(
+ theFirstScene->m_Presentation->m_Scene->m_ClearColor);
+ } else
+ m_Context->m_Context->SetSceneColor(QT3DSVec4(0.0f, 0.0f, 0.0f, 0.0f));
+
+ // Setup the render rotation *before* rendering so that the magic can happen on begin
+ // render.
+ if (m_Context->m_RenderRotationsEnabled)
+ m_Context->m_Context->SetRenderRotation(
+ theFirstScene->m_Presentation->m_PresentationRotation);
+ else
+ m_Context->m_Context->SetRenderRotation(RenderRotationValues::NoRotation);
+
+ m_Context->m_Context->SetPresentationDimensions(QSize(
+ int(theFirstScene->m_Presentation->m_PresentationDimensions.x),
+ int(theFirstScene->m_Presentation->m_PresentationDimensions.y)));
+ }
+
+ m_Context->m_Context->BeginFrame(firstFrame);
+ m_Context->m_RenderContext->ResetBlendState();
+
+ // How exactly does this work, I have no idea.
+ // Should we only render the first scene and not every scene, perhaps?
+ bool wasDirty = false;
+ if (theFirstScene)
+ wasDirty = theFirstScene->PrepareForRender();
+ else {
+ m_Context->m_RenderContext->SetClearColor(QT3DSVec4(0, 0, 0, 0));
+ m_Context->m_RenderContext->Clear(qt3ds::render::NVRenderClearFlags(
+ NVRenderClearValues::Color | NVRenderClearValues::Depth));
+ }
+ m_Context->m_Context->RunRenderTasks();
+ if (theFirstScene)
+ theFirstScene->Render();
+
+ m_Context->m_Context->EndFrame();
+
+ return wasDirty;
+ }
+ // I think render::check resize is called so this isn't necessary
+ void OnViewResize(Q3DStudio::INT32 inViewWidth, Q3DStudio::INT32 inViewHeight) override
+ {
+ m_ViewWidth = inViewWidth;
+ m_ViewHeight = inViewHeight;
+ }
+ void GetViewSize(Q3DStudio::INT32 &outWidth, Q3DStudio::INT32 &outHeight) override
+ {
+ outWidth = m_ViewWidth;
+ outHeight = m_ViewHeight;
+ }
+
+ Q3DStudio::STextSizes GetDisplayDimensions(Q3DStudio::IPresentation *inPresentation) override
+ {
+ 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) {
+ m_Context->m_Context->SetPresentationDimensions(QSize(
+ int(theFirstScene->m_Presentation->m_PresentationDimensions.x),
+ int(theFirstScene->m_Presentation->m_PresentationDimensions.y)));
+ render::NVRenderRectF theDisplayViewport =
+ m_Context->m_Context->GetDisplayViewport();
+ return Q3DStudio::STextSizes(
+ static_cast<Q3DStudio::INT32>(theDisplayViewport.m_Width),
+ static_cast<Q3DStudio::INT32>(theDisplayViewport.m_Height));
+ }
+ return Q3DStudio::STextSizes(static_cast<Q3DStudio::INT32>(0),
+ static_cast<Q3DStudio::INT32>(0));
+ }
+
+ Q3DStudio::TElement *UserPick(float mouseX, float mouseY) override
+ {
+ if (m_LastRenderedScene) {
+ return m_LastRenderedScene->UserPick(mouseX, mouseY);
+ }
+ return nullptr;
+ }
+
+ Option<QT3DSVec2> FacePosition(Q3DStudio::TElement &inElement, float mouseX, float mouseY,
+ NVDataRef<Q3DStudio::TElement *> inElements,
+ Q3DStudio::FacePositionPlanes::Enum inPlane) override
+ {
+ if (m_LastRenderedScene) {
+
+ return m_LastRenderedScene->FacePosition(inElement, mouseX, mouseY, inElements,
+ inPlane);
+ }
+ return Empty();
+ }
+
+ Q3DStudio::SPickFrame AdvancePickFrame(const Q3DStudio::SInputFrame &inInputFrame) override
+ {
+ // 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 = nullptr;
+ m_PickFrame.m_ResultValid = false;
+ if (m_LastRenderedScene) {
+ if (m_PickFrame.m_InputFrame.m_PickValid)
+ m_LastRenderedScene->Pick(m_PickFrame);
+ }
+ return m_PickFrame;
+ }
+
+ void Release() override
+ {
+ long theRenderPluginSize = m_RenderPlugins.size();
+ Q3DStudio::CDLLManager &theDLLManager = Q3DStudio::CDLLManager::GetDLLManager();
+ for (int theRenderPluginIndex = 0; theRenderPluginIndex < theRenderPluginSize;
+ ++theRenderPluginIndex) {
+ long theDLLHandle = m_RenderPlugins[theRenderPluginIndex].second;
+ PROC_Uninitialize theUninitializeProc = reinterpret_cast<PROC_Uninitialize>(
+ theDLLManager.GetProc("Uninitialize", theDLLHandle));
+ Q3DStudio_ASSERT(theUninitializeProc);
+ theUninitializeProc &&theUninitializeProc();
+
+ theDLLManager.UnloadLibrary(theDLLHandle);
+ }
+
+ // Ensure the binding core doesn't get released until after we get released.
+ NVScopedRefCounted<SBindingCore> theContext(m_Context);
+ NVDelete(m_Context->GetAllocator(), this);
+ }
+};
+
+struct SRenderFactory;
+
+struct SRenderFactory : public IQt3DSRenderFactoryCore, public IQt3DSRenderFactory
+{
+ NVScopedRefCounted<SBindingCore> m_Context;
+
+ NVScopedRefCounted<Q3DStudio::CQmlEngine> m_ScriptBridgeQml;
+ NVScopedRefCounted<Qt3DSRenderSceneManager> m_SceneManager;
+ NVScopedRefCounted<qt3ds::evt::IEventSystem> m_EventSystem;
+ qt3ds::runtime::IApplication *m_Application;
+ QT3DSI32 m_RefCount;
+
+ SRenderFactory(SBindingCore &inCore)
+ : m_Context(inCore)
+ , m_ScriptBridgeQml(nullptr)
+ , m_SceneManager(nullptr)
+ , m_Application(nullptr)
+ , m_RefCount(0)
+ {
+ }
+
+ ~SRenderFactory()
+ {
+ using namespace Q3DStudio;
+ // Release the event system, it must be released before script engine
+ m_EventSystem = nullptr;
+ m_ScriptBridgeQml->Shutdown(*m_Context->m_Foundation);
+ }
+
+ void addRef() override { atomicIncrement(&m_RefCount); }
+
+ void release() override
+ {
+ atomicDecrement(&m_RefCount);
+ if (m_RefCount <= 0) {
+ NVScopedRefCounted<SBindingCore> theContext(m_Context);
+ NVDelete(m_Context->GetAllocator(), this);
+ }
+ }
+
+ qt3ds::render::IQt3DSRenderContextCore &GetRenderContextCore() override
+ {
+ return *m_Context->m_CoreContext;
+ }
+
+ qt3ds::runtime::IApplication *GetApplicationCore() override { return m_Application; }
+ void SetApplicationCore(qt3ds::runtime::IApplication *app) override
+ {
+ m_Application = app;
+ }
+
+ Q3DStudio::ISceneBinaryLoader &GetSceneLoader() override
+ {
+ if (m_SceneManager == nullptr)
+ m_SceneManager = QT3DS_NEW(m_Context->GetAllocator(),
+ Qt3DSRenderSceneManager)(*m_Context, m_Context->m_WindowSystem);
+ return *m_SceneManager;
+ }
+
+ Q3DStudio::ITegraApplicationRenderEngine &CreateRenderEngine() override
+ {
+ return m_Context->CreateRenderer();
+ }
+ Q3DStudio::ISceneManager &GetSceneManager() override
+ {
+ 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 == nullptr) {
+ m_ScriptBridgeQml =
+ Q3DStudio::CQmlEngine::Create(*m_Context->m_Foundation, m_Context->m_TimeProvider);
+ }
+
+ return *m_ScriptBridgeQml;
+ }
+ qt3ds::render::IInputStreamFactory &GetInputStreamFactory() override
+ {
+ return m_Context->m_CoreContext->GetInputStreamFactory();
+ }
+
+ qt3ds::render::IQt3DSRenderContext &GetQt3DSRenderContext() override
+ {
+ return *m_Context->m_Context;
+ }
+
+ qt3ds::evt::IEventSystem &GetEventSystem() override
+ {
+ if (!m_EventSystem) {
+ m_EventSystem = qt3ds::evt::IEventSystem::Create(*m_Context->m_Foundation);
+ }
+ return *m_EventSystem;
+ }
+ Q3DStudio::ITimeProvider &GetTimeProvider() override { return m_Context->m_TimeProvider; }
+ qt3ds::foundation::IStringTable &GetStringTable() override
+ {
+ return m_Context->m_CoreContext->GetStringTable();
+ }
+ qt3ds::NVFoundationBase &GetFoundation() override { return *m_Context->m_Foundation.mPtr; }
+ qt3ds::foundation::IPerfTimer &GetPerfTimer() override
+ {
+ return m_Context->m_CoreContext->GetPerfTimer();
+ }
+ qt3ds::runtime::IApplication *GetApplication() override { return m_Application; }
+ void SetApplication(qt3ds::runtime::IApplication *app) override
+ {
+ m_Application = app;
+ if (app) {
+ // QML engine
+ GetScriptEngineQml();
+ m_ScriptBridgeQml->SetApplication(*app);
+ m_ScriptBridgeQml->Initialize();
+ }
+ }
+ void SetDllDir(const char *dllDir) override
+ {
+ m_Context->m_CoreContext->GetRenderPluginCore().SetDllDir(dllDir);
+ }
+
+ void AddSearchPath(const char8_t *inFile) override
+ {
+ m_Context->m_CoreContext->GetInputStreamFactory().AddSearchDirectory(inFile);
+ }
+ virtual void Release() { NVDelete(m_Context->GetAllocator(), this); }
+
+ struct SContextTypeRenderFactory : public IRuntimeFactoryRenderFactory
+ {
+ QSurfaceFormat format;
+ SContextTypeRenderFactory(const QSurfaceFormat &fmt)
+ : format(fmt)
+ {
+ }
+
+ qt3ds::render::NVRenderContext *CreateRenderContext(qt3ds::NVFoundationBase &foundat,
+ IStringTable &strt) override
+ {
+#ifndef Qt3DS_NO_RENDER_SYMBOLS
+ qt3ds::render::NVRenderContext &retval = NVRenderContext::CreateGL(foundat, strt, format);
+ return &retval;
+#else
+ qt3ds::render::NVRenderContext &retval = NVRenderContext::Createnullptr(foundat, strt);
+ return &retval;
+#endif
+ }
+ };
+
+ IQt3DSRenderFactory &CreateRenderFactory(const QSurfaceFormat& format,
+ bool delayedLoading) override
+ {
+
+ SContextTypeRenderFactory theContextFactory(format);
+ m_Context->CreateRenderContext(theContextFactory, delayedLoading);
+
+ GetSceneLoader();
+ {
+ SStackPerfTimer __loadTimer(GetPerfTimer(), "SceneManager OnGraphicsInitialized");
+ m_SceneManager->OnGraphicsInitialized();
+ }
+ return *this;
+ }
+};
+
+}
+
+IQt3DSRenderFactoryCore &IQt3DSRenderFactoryCore::CreateRenderFactoryCore(
+ const char8_t *inApplicationDirectory,
+ Q3DStudio::IWindowSystem &inWindowSystem,
+ Q3DStudio::ITimeProvider &inTimeProvider)
+{
+ SBindingCore *theCore = reinterpret_cast<SBindingCore *>(malloc(sizeof(SBindingCore)));
+ new (theCore) SBindingCore(inApplicationDirectory, inWindowSystem, inTimeProvider);
+ return *QT3DS_NEW(theCore->GetAllocator(), SRenderFactory)(*theCore);
+}