summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/runtimerender/Qt3DSRenderGraphObjectSerializer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/runtimerender/Qt3DSRenderGraphObjectSerializer.cpp')
-rw-r--r--src/Runtime/Source/runtimerender/Qt3DSRenderGraphObjectSerializer.cpp670
1 files changed, 670 insertions, 0 deletions
diff --git a/src/Runtime/Source/runtimerender/Qt3DSRenderGraphObjectSerializer.cpp b/src/Runtime/Source/runtimerender/Qt3DSRenderGraphObjectSerializer.cpp
new file mode 100644
index 00000000..8fc7e5aa
--- /dev/null
+++ b/src/Runtime/Source/runtimerender/Qt3DSRenderGraphObjectSerializer.cpp
@@ -0,0 +1,670 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 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 "Qt3DSRenderGraphObjectSerializer.h"
+#include "Qt3DSRenderPresentation.h"
+#include "Qt3DSRenderNode.h"
+#include "Qt3DSRenderScene.h"
+#include "Qt3DSRenderLayer.h"
+#include "Qt3DSRenderModel.h"
+#include "Qt3DSRenderText.h"
+#include "Qt3DSRenderDefaultMaterial.h"
+#include "Qt3DSRenderImage.h"
+#include "Qt3DSRenderEffect.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderCustomMaterial.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/Qt3DSContainers.h"
+#include "Qt3DSRenderEffectSystem.h"
+#include "foundation/SerializationTypes.h"
+#include "Qt3DSRenderString.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSRenderPluginGraphObject.h"
+#include "Qt3DSRenderReferencedMaterial.h"
+#include "Qt3DSRenderPath.h"
+#include "Qt3DSRenderPathSubPath.h"
+#include "Qt3DSRenderPathManager.h"
+
+using namespace qt3ds::render;
+using namespace qt3ds::render::dynamic;
+
+namespace {
+typedef nvhash_set<void *> TPtrSet;
+
+void Align(MemoryBuffer<> &inBuffer)
+{
+ inBuffer.align(sizeof(void *));
+}
+typedef nvvector<eastl::pair<GraphObjectTypes::Enum, QT3DSU32>> TObjectFileStatList;
+typedef SPtrOffsetMap TPtrOffsetMap;
+
+struct SSerializerWriteContext
+{
+ SPtrOffsetMap &m_OffsetMap;
+ SWriteBuffer &m_MemoryBuffer;
+ const SStrRemapMap &m_StrRemapMap;
+ QT3DSU32 m_DataBlockStart;
+ IDynamicObjectSystem &m_DynamicObjectSystem;
+ IPathManager &m_PathManager;
+ TObjectFileStatList &m_FileSizeStats;
+ CRenderString m_PathMapper;
+ CRenderString m_BasePath;
+ CRenderString m_RelativePath;
+ IStringTable &m_StringTable;
+ SSerializerWriteContext(SPtrOffsetMap &inOffsetMap, SWriteBuffer &inWriteBuffer,
+ const SStrRemapMap &inStrMap, QT3DSU32 inDataBlockStart,
+ IDynamicObjectSystem &inDynamicObjectSystem,
+ IPathManager &inPathManager, TObjectFileStatList &inStats,
+ NVAllocatorCallback &inAllocator, const char8_t *inProjectDirectory,
+ IStringTable &inStringTable)
+ : m_OffsetMap(inOffsetMap)
+ , m_MemoryBuffer(inWriteBuffer)
+ , m_StrRemapMap(inStrMap)
+ , m_DataBlockStart(inDataBlockStart)
+ , m_DynamicObjectSystem(inDynamicObjectSystem)
+ , m_PathManager(inPathManager)
+ , m_FileSizeStats(inStats)
+ , m_StringTable(inStringTable)
+ {
+ Q_UNUSED(inAllocator)
+ m_BasePath.assign(inProjectDirectory);
+ }
+
+ bool HasWrittenObject(const void *inObject) { return m_OffsetMap.contains(inObject); }
+
+ QT3DSU32 &GetStatEntry(GraphObjectTypes::Enum inType) const
+ {
+ for (QT3DSU32 idx = 0, end = m_FileSizeStats.size(); idx < end; ++idx)
+ if (m_FileSizeStats[idx].first == inType)
+ return m_FileSizeStats[idx].second;
+ m_FileSizeStats.push_back(eastl::make_pair(inType, (QT3DSU32)0));
+ return m_FileSizeStats.back().second;
+ }
+
+ template <typename TObjType>
+ void AddPtrOffset(const TObjType *inObject)
+ {
+ QT3DSU32 objOffset = m_MemoryBuffer.size() - m_DataBlockStart;
+ m_OffsetMap.insert(eastl::make_pair(inObject, objOffset));
+// In debug we keep stats on how much each type of object
+// contributes to the file size.
+#ifdef _DEBUG
+ GetStatEntry(inObject->m_Type) += sizeof(TObjType);
+#endif
+ }
+
+ void Remap(CRegisteredString &inStr) { inStr.Remap(m_StrRemapMap); }
+
+ template <typename TObjType>
+ void Remap(TObjType *&inPtr)
+ {
+ if (inPtr) {
+ TPtrOffsetMap::iterator theIter = m_OffsetMap.find(inPtr);
+ if (theIter != m_OffsetMap.end())
+ inPtr = reinterpret_cast<TObjType *>(theIter->second);
+ else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+
+ void RemapMaterial(SGraphObject *&inPtr) { Remap(inPtr); }
+
+ template <typename TObjType>
+ void NullPtr(TObjType *&inPtr)
+ {
+ inPtr = NULL;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////
+// --** Reading the scene graph is heavily threaded when we are loading
+// multiple presentations in one application --**
+///////////////////////////////////////////////////////////////////////
+struct SSerializerReadContext : public SDataReader
+{
+ IPathManagerCore &m_PathManager;
+ IDynamicObjectSystemCore &m_DynamicObjectSystem;
+ NVDataRef<QT3DSU8> m_DataBlock;
+ NVDataRef<QT3DSU8> m_StrTableBlock;
+ CRenderString m_PathMapper;
+ const char8_t *m_ProjectDirectory;
+
+ SSerializerReadContext(IPathManagerCore &inPathManager, IDynamicObjectSystemCore &inDynSystem,
+ NVDataRef<QT3DSU8> inDataBlock, NVDataRef<QT3DSU8> inStrTable,
+ NVAllocatorCallback &inAllocator, const char8_t *inProjectDirectory)
+ : SDataReader(inDataBlock.begin(), inDataBlock.end())
+ , m_PathManager(inPathManager)
+ , m_DynamicObjectSystem(inDynSystem)
+ , m_DataBlock(inDataBlock)
+ , m_StrTableBlock(inStrTable)
+ , m_ProjectDirectory(inProjectDirectory)
+ {
+ Q_UNUSED(inAllocator)
+ }
+ void Remap(CRegisteredString &inStr) { inStr.Remap(m_StrTableBlock); }
+ template <typename TObjType>
+ void Remap(TObjType *&inPtr)
+ {
+ if (inPtr) {
+ TObjType *purePtr = inPtr;
+ size_t ptrValue = reinterpret_cast<size_t>(purePtr);
+ if (ptrValue < m_DataBlock.size())
+ inPtr = reinterpret_cast<TObjType *>(m_DataBlock.begin() + ptrValue);
+ else {
+ QT3DS_ASSERT(false);
+ inPtr = NULL;
+ }
+ }
+ }
+ void RemapMaterial(SGraphObject *&inPtr) { Remap(inPtr); }
+ // Nulling out pointers was done on write, so we don't do it here.
+ template <typename TObjType>
+ void NullPtr(TObjType *&)
+ {
+ }
+};
+
+template <typename TObjType>
+struct SGraphObjectSerializerImpl
+{
+ static TObjType *Write(const TObjType &ioObject, SSerializerWriteContext &outSavedBuffer);
+ static void Remap(TObjType &inObject, SSerializerWriteContext &inRemapContext);
+ static TObjType *Read(SSerializerReadContext &inReadContext);
+};
+
+struct SWriteRemapper
+{
+ SSerializerWriteContext &m_WriteBuffer;
+ SWriteRemapper(SSerializerWriteContext &buf)
+ : m_WriteBuffer(buf)
+ {
+ }
+ // This will happen later
+ void Remap(const CRegisteredString &) {}
+ void RemapPath(const CRegisteredString &) {}
+
+ // We ignore objects that are saved out explicitly below.
+ void Remap(const SScene *) {}
+
+ void Remap(const SLayer *) {}
+ // Nodes are ignored because we save them out *not* in depth first order,
+ // with models, text, lights and camera saved out contiguously for in-memory
+ // traversal.
+ void Remap(const SNode *) {}
+#ifdef _INTEGRITYPLATFORM
+ // explicit specialization of class "<unnamed>::SGraphObjectSerializerImpl<qt3ds::render::SCustomMaterial>"
+ // must precede its first use struct SGraphObjectSerializerImpl<SCustomMaterial>
+ template <typename TObjType>
+ void Remap(const TObjType *inObj);
+#else
+ template <typename TObjType>
+ void Remap(const TObjType *inObj)
+ {
+ if (inObj)
+ SGraphObjectSerializerImpl<TObjType>::Write(*inObj, m_WriteBuffer);
+ }
+#endif
+
+ void RemapMaterial(const SGraphObject *inObj)
+ {
+ if (inObj) {
+ if (inObj->m_Type == GraphObjectTypes::DefaultMaterial)
+ Remap(static_cast<const SDefaultMaterial *>(inObj));
+ else if (inObj->m_Type == GraphObjectTypes::CustomMaterial)
+ Remap(static_cast<const SCustomMaterial *>(inObj));
+ else if (inObj->m_Type == GraphObjectTypes::ReferencedMaterial)
+ Remap(static_cast<const SReferencedMaterial *>(inObj));
+ else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+ template <typename TObjType>
+ void NullPtr(const TObjType *)
+ {
+ }
+};
+
+void PrepareFirstPass(const SNode &inNode, nvvector<const SNode *> &ioLightCameras,
+ nvvector<const SNode *> &ioRenderable)
+{
+ if (GraphObjectTypes::IsRenderableType(inNode.m_Type))
+ ioRenderable.push_back(&inNode);
+ else if (GraphObjectTypes::IsLightCameraType(inNode.m_Type))
+ ioLightCameras.push_back(&inNode);
+
+ for (const SNode *theChild = inNode.m_FirstChild; theChild; theChild = theChild->m_NextSibling)
+ PrepareFirstPass(*theChild, ioLightCameras, ioRenderable);
+}
+
+template <typename TObject>
+TObject *WriteGenericGraphObjectNoRemap(const TObject &ioObject,
+ SSerializerWriteContext &outSavedBuffer)
+{
+ if (outSavedBuffer.HasWrittenObject(&ioObject))
+ return NULL;
+
+ outSavedBuffer.AddPtrOffset(&ioObject);
+ QT3DSU32 theOffset = outSavedBuffer.m_MemoryBuffer.size();
+ outSavedBuffer.m_MemoryBuffer.write(ioObject);
+ // Probably the buffer stays aligned but we want to work to keep it that way.
+ Align(outSavedBuffer.m_MemoryBuffer);
+ return reinterpret_cast<TObject *>(outSavedBuffer.m_MemoryBuffer.begin() + theOffset);
+}
+
+template <typename TObject>
+TObject *WriteGenericGraphObject(const TObject &ioObject, SSerializerWriteContext &outSavedBuffer)
+{
+ TObject *theObject = WriteGenericGraphObjectNoRemap(ioObject, outSavedBuffer);
+ if (theObject) // The object may have already been written.
+ {
+ // Write mappers just follow pointers and ensure all the associated objects
+ // are written out.
+ SWriteRemapper theWriteRemapper(outSavedBuffer);
+ const_cast<TObject &>(ioObject).Remap(theWriteRemapper);
+ }
+ return theObject;
+}
+
+template <typename TObject>
+TObject *ReadGenericGraphObject(SSerializerReadContext &inReadContext)
+{
+ TObject *retval = inReadContext.Load<TObject>();
+ inReadContext.Align();
+ if (retval) {
+ retval->Remap(inReadContext);
+ }
+ return retval;
+}
+
+template <typename TObjType>
+TObjType *SGraphObjectSerializerImpl<TObjType>::Write(const TObjType &ioObject,
+ SSerializerWriteContext &outSavedBuffer)
+{
+ return WriteGenericGraphObject(ioObject, outSavedBuffer);
+}
+template <typename TObjType>
+void SGraphObjectSerializerImpl<TObjType>::Remap(TObjType &ioObject,
+ SSerializerWriteContext &inRemapContext)
+{
+ return ioObject.Remap(inRemapContext);
+}
+
+template <typename TObjType>
+TObjType *SGraphObjectSerializerImpl<TObjType>::Read(SSerializerReadContext &inReadContext)
+{
+ return ReadGenericGraphObject<TObjType>(inReadContext);
+}
+
+void RemapProperties(SDynamicObject &ioObject, SSerializerWriteContext &outSavedBuffer,
+ CRegisteredString inClassName)
+{
+ NVConstDataRef<SPropertyDefinition> theObjectProps =
+ outSavedBuffer.m_DynamicObjectSystem.GetProperties(inClassName);
+ for (QT3DSU32 idx = 0, end = theObjectProps.size(); idx < end; ++idx) {
+ const SPropertyDefinition &theDef(theObjectProps[idx]);
+ if (theDef.m_DataType == qt3ds::render::NVRenderShaderDataTypes::NVRenderTexture2DPtr) {
+ CRegisteredString *theStr = reinterpret_cast<CRegisteredString *>(
+ ioObject.GetDataSectionBegin() + theDef.m_Offset);
+ outSavedBuffer.Remap(*theStr);
+ }
+ }
+}
+
+void RemapProperties(SDynamicObject &ioObject, SSerializerReadContext &inReadContext)
+{
+ // CN - !!Note this call is done on multiple threads simultaneously. I added a mutex just to be
+ // sure even though
+ // this is a read-only call; I am not certain how good the arm memory locking is when it is
+ // completely unprotected.
+ NVConstDataRef<SPropertyDefinition> theProperties =
+ inReadContext.m_DynamicObjectSystem.GetProperties(ioObject.m_ClassName);
+ for (QT3DSU32 idx = 0, end = theProperties.size(); idx < end; ++idx) {
+ const SPropertyDefinition &theDefinition(theProperties[idx]);
+ if (theDefinition.m_DataType == NVRenderShaderDataTypes::NVRenderTexture2DPtr) {
+ CRegisteredString *theString = reinterpret_cast<CRegisteredString *>(
+ ioObject.GetDataSectionBegin() + theDefinition.m_Offset);
+ inReadContext.Remap(*theString);
+ }
+ }
+}
+
+template <>
+struct SGraphObjectSerializerImpl<SEffect>
+{
+ static SGraphObject *Write(const SEffect &ioObject, SSerializerWriteContext &outSavedBuffer)
+ {
+ size_t itemOffset = outSavedBuffer.m_MemoryBuffer.size();
+ SEffect *theNewEffect =
+ static_cast<SEffect *>(WriteGenericGraphObjectNoRemap(ioObject, outSavedBuffer));
+ if (theNewEffect) {
+ theNewEffect->m_Context = NULL;
+ // Writing it out is easy. Reading it back in means we have to have a correctly setup
+ // IEffectManager so we
+ // can remap strings.
+ outSavedBuffer.m_MemoryBuffer.write(ioObject.GetDataSectionBegin(),
+ ioObject.m_DataSectionByteSize);
+ Align(outSavedBuffer.m_MemoryBuffer);
+ SWriteRemapper theWriteRemapper(outSavedBuffer);
+ // Write any connected objects.
+ theNewEffect =
+ reinterpret_cast<SEffect *>(outSavedBuffer.m_MemoryBuffer.begin() + itemOffset);
+ theNewEffect->Remap(theWriteRemapper);
+ }
+ return theNewEffect;
+ }
+
+ static void Remap(SEffect &ioObject, SSerializerWriteContext &outSavedBuffer)
+ {
+ CRegisteredString theClassName = ioObject.m_ClassName;
+ ioObject.Remap(outSavedBuffer);
+ RemapProperties(ioObject, outSavedBuffer, theClassName);
+ }
+
+ static SEffect *Read(SSerializerReadContext &inReadContext)
+ {
+ SEffect *theEffect = ReadGenericGraphObject<SEffect>(inReadContext);
+ if (theEffect) {
+ inReadContext.m_CurrentPtr += theEffect->m_DataSectionByteSize;
+ inReadContext.Align();
+ RemapProperties(*theEffect, inReadContext);
+ }
+ return theEffect;
+ }
+};
+
+template <>
+struct SGraphObjectSerializerImpl<SCustomMaterial>
+{
+ static SGraphObject *Write(const SCustomMaterial &ioObject,
+ SSerializerWriteContext &outSavedBuffer)
+ {
+ size_t itemOffset = outSavedBuffer.m_MemoryBuffer.size();
+ SCustomMaterial *theNewObject = static_cast<SCustomMaterial *>(
+ WriteGenericGraphObjectNoRemap(ioObject, outSavedBuffer));
+ if (theNewObject) {
+ // Writing it out is easy. Reading it back in means we have to have a correctly setup
+ // IEffectManager so we
+ // can remap strings.
+ outSavedBuffer.m_MemoryBuffer.write(ioObject.GetDataSectionBegin(),
+ ioObject.m_DataSectionByteSize);
+ Align(outSavedBuffer.m_MemoryBuffer);
+ theNewObject = reinterpret_cast<SCustomMaterial *>(outSavedBuffer.m_MemoryBuffer.begin()
+ + itemOffset);
+ SWriteRemapper theWriteRemapper(outSavedBuffer);
+ // Write any connected objects.
+ theNewObject->Remap(theWriteRemapper);
+ }
+ return theNewObject;
+ }
+
+ static void Remap(SCustomMaterial &ioObject, SSerializerWriteContext &outSavedBuffer)
+ {
+ CRegisteredString theClassName(ioObject.m_ClassName);
+ ioObject.Remap(outSavedBuffer);
+ RemapProperties(ioObject, outSavedBuffer, theClassName);
+ }
+
+ static SCustomMaterial *Read(SSerializerReadContext &inReadContext)
+ {
+ SCustomMaterial *theMaterial = ReadGenericGraphObject<SCustomMaterial>(inReadContext);
+ if (theMaterial) {
+ inReadContext.m_CurrentPtr += theMaterial->m_DataSectionByteSize;
+ inReadContext.Align();
+ RemapProperties(*theMaterial, inReadContext);
+ }
+ return theMaterial;
+ }
+};
+
+#ifdef _INTEGRITYPLATFORM
+ template <typename TObjType>
+ void SWriteRemapper::Remap(const TObjType *inObj)
+ {
+ if (inObj)
+ SGraphObjectSerializerImpl<TObjType>::Write(*inObj, m_WriteBuffer);
+ }
+#endif
+
+template <>
+struct SGraphObjectSerializerImpl<SPathSubPath>
+{
+ static SGraphObject *Write(const SPathSubPath &ioObject,
+ SSerializerWriteContext &outSavedBuffer)
+ {
+ SPathSubPath *theObject = WriteGenericGraphObjectNoRemap(ioObject, outSavedBuffer);
+ if (theObject) // The object may have already been written.
+ {
+ NVConstDataRef<SPathAnchorPoint> thePoints =
+ outSavedBuffer.m_PathManager.GetPathSubPathBuffer(ioObject);
+ outSavedBuffer.m_MemoryBuffer.write((QT3DSU32)thePoints.size());
+ outSavedBuffer.m_MemoryBuffer.write(thePoints.begin(), thePoints.size());
+ // Write mappers just follow pointers and ensure all the associated objects
+ // are written out.
+ SWriteRemapper theWriteRemapper(outSavedBuffer);
+ const_cast<SPathSubPath &>(ioObject).Remap(theWriteRemapper);
+ }
+ return theObject;
+ }
+
+ static void Remap(SPathSubPath &ioObject, SSerializerWriteContext &outSavedBuffer)
+ {
+ ioObject.Remap(outSavedBuffer);
+ }
+
+ static SPathSubPath *Read(SSerializerReadContext &inReadContext)
+ {
+ SPathSubPath *theSubPath = ReadGenericGraphObject<SPathSubPath>(inReadContext);
+ if (theSubPath) {
+ QT3DSU32 numPoints = *inReadContext.Load<QT3DSU32>();
+ SPathAnchorPoint *theAnchorPointBuffer =
+ reinterpret_cast<qt3ds::render::SPathAnchorPoint *>(inReadContext.m_CurrentPtr);
+ inReadContext.m_CurrentPtr += sizeof(SPathAnchorPoint) * numPoints;
+
+ // CN - !!Note this call is done on multiple threads simultaneously. I added a mutex to
+ // the path manager object
+ // so this exact call is always protected. This absolutely caused crashing when it was
+ // not protected approriately.
+ inReadContext.m_PathManager.SetPathSubPathData(
+ *theSubPath, toConstDataRef(theAnchorPointBuffer, numPoints));
+ }
+ return theSubPath;
+ }
+};
+
+void WriteGraphObject(const SGraphObject &inObject, SSerializerWriteContext &outSavedBuffer)
+{
+ SGraphObject *newObject = NULL;
+ switch (inObject.m_Type) {
+#define QT3DS_RENDER_HANDL_GRAPH_OBJECT_TYPE(type) \
+ case GraphObjectTypes::type: \
+ newObject = SGraphObjectSerializerImpl<S##type>::Write( \
+ static_cast<const S##type &>(inObject), outSavedBuffer); \
+ break;
+ QT3DS_RENDER_ITERATE_GRAPH_OBJECT_TYPES
+#undef QT3DS_RENDER_HANDL_GRAPH_OBJECT_TYPE
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+}
+
+void WriteNodeList(nvvector<const SNode *> &inList, SSerializerWriteContext &outSavedBuffer)
+{
+ for (QT3DSU32 idx = 0, end = inList.size(); idx < end; ++idx)
+ WriteGraphObject(*inList[idx], outSavedBuffer);
+}
+
+// Now write everything you haven't written so far, skip writing renderables or cameras or lights
+void WriteNonRenderableNonCLNode(const SNode &inNode, SSerializerWriteContext &outSavedBuffer)
+{
+ if (GraphObjectTypes::IsLightCameraType(inNode.m_Type) == false
+ && GraphObjectTypes::IsRenderableType(inNode.m_Type) == false) {
+ WriteGraphObject(inNode, outSavedBuffer);
+ }
+ for (const SNode *theChild = inNode.m_FirstChild; theChild; theChild = theChild->m_NextSibling)
+ WriteNonRenderableNonCLNode(*theChild, outSavedBuffer);
+}
+
+SGraphObject *ReadGraphObject(SSerializerReadContext &inContext)
+{
+ if (inContext.m_CurrentPtr + sizeof(SGraphObject) < inContext.m_EndPtr) {
+ SGraphObject *theObject = reinterpret_cast<SGraphObject *>(inContext.m_CurrentPtr);
+ switch (theObject->m_Type) {
+#define QT3DS_RENDER_HANDL_GRAPH_OBJECT_TYPE(type) \
+ case GraphObjectTypes::type: \
+ SGraphObjectSerializerImpl<S##type>::Read(inContext); \
+ break;
+ QT3DS_RENDER_ITERATE_GRAPH_OBJECT_TYPES
+#undef QT3DS_RENDER_HANDL_GRAPH_OBJECT_TYPE
+ default:
+ QT3DS_ASSERT(false);
+ theObject = NULL;
+ break;
+ }
+ return theObject;
+ }
+ return NULL;
+}
+}
+
+void SGraphObjectSerializer::Save(NVFoundationBase &inFoundation,
+ const SPresentation &inPresentation,
+ qt3ds::render::SWriteBuffer &outSavedData,
+ IDynamicObjectSystem &inDynamicObjectSystem,
+ IPathManager &inPathManager, SPtrOffsetMap &outSceneGraphOffsets,
+ IStringTable &inStringTable,
+ NVDataRef<SGraphObject *> inExtraGraphObjects)
+{
+ using namespace qt3ds::foundation;
+ nvvector<const SNode *> theLightCameraList(inFoundation.getAllocator(),
+ "SGraphObjectSerializer::theLightCameraList");
+ nvvector<const SNode *> theRenderableList(inFoundation.getAllocator(),
+ "SGraphObjectSerializer::theRenderableList");
+ TObjectFileStatList theStatList(inFoundation.getAllocator(),
+ "SGraphObjectSerializer::FileSizeStats");
+ // We want to save out the scene graph in the order we are going to traverse it normally.
+ // This is reverse depth first for the lights, cameras, and renderables and depth first for
+ // everything else so we go
+ // in two passes per layer.
+ // We expect the incoming data buffer to be aligned already.
+ QT3DS_ASSERT(outSavedData.size() % 4 == 0);
+ if (inPresentation.m_Scene) {
+ QT3DSU32 theDataSectionStart = outSavedData.size();
+ outSavedData.writeZeros(4);
+ SSerializerWriteContext theWriteContext(
+ outSceneGraphOffsets, outSavedData, inStringTable.GetRemapMap(), theDataSectionStart,
+ inDynamicObjectSystem, inPathManager, theStatList, inFoundation.getAllocator(),
+ inPresentation.m_PresentationDirectory, inStringTable);
+ // First pass, just write out the data.
+ WriteGraphObject(inPresentation, theWriteContext);
+ WriteGraphObject(*inPresentation.m_Scene, theWriteContext);
+ for (const SLayer *theLayer = inPresentation.m_Scene->m_FirstChild; theLayer;
+ theLayer = static_cast<const SLayer *>(theLayer->m_NextSibling)) {
+ theLightCameraList.clear();
+ theRenderableList.clear();
+ PrepareFirstPass(*theLayer, theLightCameraList, theRenderableList);
+ eastl::reverse(theLightCameraList.begin(), theLightCameraList.end());
+ eastl::reverse(theRenderableList.begin(), theRenderableList.end());
+ WriteNodeList(theLightCameraList, theWriteContext);
+ WriteNodeList(theRenderableList, theWriteContext);
+ }
+ // Now just write everything *but* renderable objects and cameras.
+ for (const SLayer *theLayer = inPresentation.m_Scene->m_FirstChild; theLayer;
+ theLayer = static_cast<const SLayer *>(theLayer->m_NextSibling)) {
+ WriteNonRenderableNonCLNode(*theLayer, theWriteContext);
+ }
+ // Write out any extra objects we haven't covered yet.
+ for (QT3DSU32 idx = 0, end = inExtraGraphObjects.size(); idx < end; ++idx)
+ WriteGraphObject(*inExtraGraphObjects[idx], theWriteContext);
+
+ QT3DSU32 theNumObjects = theWriteContext.m_OffsetMap.size();
+ QT3DSU32 *theCountPtr = reinterpret_cast<QT3DSU32 *>(outSavedData.begin() + theDataSectionStart);
+ *theCountPtr = theNumObjects;
+
+ // Second pass, perform remapping on all the objects to change their pointers to offsets
+ for (SPtrOffsetMap::iterator theIter = outSceneGraphOffsets.begin(),
+ theEnd = outSceneGraphOffsets.end();
+ theIter != theEnd; ++theIter) {
+ QT3DSU8 *theDataPtr = outSavedData.begin() + theDataSectionStart + theIter->second;
+ SGraphObject *theGraphObj = reinterpret_cast<SGraphObject *>(theDataPtr);
+ switch (theGraphObj->m_Type) {
+#define QT3DS_RENDER_HANDL_GRAPH_OBJECT_TYPE(type) \
+ case GraphObjectTypes::type: \
+ SGraphObjectSerializerImpl<S##type>::Remap(static_cast<S##type &>(*theGraphObj), \
+ theWriteContext); \
+ break;
+ QT3DS_RENDER_ITERATE_GRAPH_OBJECT_TYPES
+#undef QT3DS_RENDER_HANDL_GRAPH_OBJECT_TYPE
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ }
+#ifdef _DEBUG
+ qCDebug(TRACE_INFO, "--File size stats:");
+ // Tell the users how much space is used in the file based on object type:
+ for (QT3DSU32 idx = 0, end = theStatList.size(); idx < end; ++idx) {
+ const char *theObjType = GraphObjectTypes::GetObjectTypeName(theStatList[idx].first);
+ qCDebug(TRACE_INFO, "%s - %d bytes:", theObjType, theStatList[idx].second);
+ }
+ qCDebug(TRACE_INFO, "--End file size stats:");
+#endif
+};
+
+SPresentation *SGraphObjectSerializer::Load(NVDataRef<QT3DSU8> inData, NVDataRef<QT3DSU8> inStrDataBlock,
+ IDynamicObjectSystemCore &inDynamicObjectSystem,
+ IPathManagerCore &inPathManager,
+ NVAllocatorCallback &inAllocator,
+ const char8_t *inProjectDirectory)
+{
+ SSerializerReadContext theReadContext(inPathManager, inDynamicObjectSystem, inData,
+ inStrDataBlock, inAllocator, inProjectDirectory);
+ SPresentation *retval = NULL;
+ if (inData.size() < 4) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ QT3DSU32 theNumObjects = theReadContext.LoadRef<QT3DSU32>();
+ for (QT3DSU32 idx = 0, end = theNumObjects; idx < end; ++idx) {
+ SGraphObject *theObject = ReadGraphObject(theReadContext);
+ if (theObject) {
+ if (theObject->m_Type == GraphObjectTypes::Presentation)
+ retval = static_cast<SPresentation *>(theObject);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ return retval;
+}