summaryrefslogtreecommitdiffstats
path: root/src/Runtime/ogl-runtime/src/uipparser/Qt3DSUIPParserImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/ogl-runtime/src/uipparser/Qt3DSUIPParserImpl.cpp')
-rw-r--r--src/Runtime/ogl-runtime/src/uipparser/Qt3DSUIPParserImpl.cpp2610
1 files changed, 2610 insertions, 0 deletions
diff --git a/src/Runtime/ogl-runtime/src/uipparser/Qt3DSUIPParserImpl.cpp b/src/Runtime/ogl-runtime/src/uipparser/Qt3DSUIPParserImpl.cpp
new file mode 100644
index 00000000..9f7641b0
--- /dev/null
+++ b/src/Runtime/ogl-runtime/src/uipparser/Qt3DSUIPParserImpl.cpp
@@ -0,0 +1,2610 @@
+/****************************************************************************
+**
+** 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 "RuntimePrefix.h"
+#ifdef EA_PLATFORM_WINDOWS
+#pragma warning(disable : 4396) // specializer warning nonsense
+#endif
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Qt3DSIPresentation.h"
+#include "Qt3DSIScriptBridge.h"
+#include "Qt3DSAttributeHashes.h"
+#include "Qt3DSCommandEventTypes.h"
+#include "Qt3DSDMPrefix.h"
+#include "Qt3DSDMComposerTypeDefinitions.h"
+#include "Qt3DSDMWStrOpsImpl.h"
+#include "Qt3DSUIPParserActionHelper.h"
+#include "Qt3DSUIPParserObjectRefHelper.h"
+#include "Qt3DSApplication.h"
+#include "Qt3DSRuntimeFactory.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "Qt3DSElementSystem.h"
+#include "Qt3DSAnimationSystem.h"
+#include "Qt3DSSlideSystem.h"
+
+using namespace qt3dsdm;
+
+#ifndef M_PI
+#define M_PI 3.1415926535898
+#endif
+
+#define TODEG(x) x = (float)(x * 180 / M_PI);
+#define TORAD(x) x = (float)(x / 180 * M_PI);
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+TStrType SParseElementManager::RegisterStr(const char8_t *inStr)
+{
+ return m_MetaData.GetStringTable()->GetRenderStringTable().RegisterStr(inStr);
+}
+SElementData &SParseElementManager::GetOrCreateElementData(const char8_t *inIdOrRef,
+ const char8_t *inElemType,
+ const char8_t *inElemClassId)
+{
+ if (inIdOrRef == NULL)
+ inIdOrRef = "";
+ if (inIdOrRef[0] == '#')
+ ++inIdOrRef;
+ if (inElemClassId == NULL)
+ inElemClassId = "";
+ if (inElemClassId[0] == '#')
+ ++inElemClassId;
+ if (inElemType == NULL)
+ inElemType = "";
+ TStrType theStr = RegisterStr(inIdOrRef);
+ eastl::pair<TIdElementMap::iterator, bool> theInserter =
+ m_ElementMap.insert(eastl::make_pair(theStr, SElementData(theStr)));
+ SElementData &retval(theInserter.first->second);
+ if (theInserter.second) {
+ retval.m_Class = RegisterStr(inElemClassId);
+ retval.m_Type = RegisterStr(inElemType);
+ }
+ return retval;
+}
+SElementData *SParseElementManager::FindElementData(const char8_t *inIdOrRef)
+{
+ if (inIdOrRef == NULL)
+ inIdOrRef = "";
+ if (inIdOrRef[0] == '#')
+ ++inIdOrRef;
+ TStrType theStr = RegisterStr(inIdOrRef);
+ TIdElementMap::iterator theIter = m_ElementMap.find(theStr);
+ if (theIter != m_ElementMap.end())
+ return &theIter->second;
+ return NULL;
+}
+static void SetPropertyValueHash(eastl::string &inWorkspace, const char8_t *inExtension,
+ qt3ds::QT3DSU32 *&ioHashes, eastl::string::size_type originalSize,
+ CRegisteredString *&ioPropNames,
+ qt3ds::foundation::IStringTable &ioStringTable)
+{
+ if (inExtension && *inExtension)
+ inWorkspace.append(inExtension);
+ *ioHashes = Q3DStudio::CHash::HashAttribute(inWorkspace.c_str());
+ *ioPropNames = ioStringTable.RegisterStr(inWorkspace.c_str());
+ ++ioHashes;
+ ++ioPropNames;
+ inWorkspace.resize(originalSize);
+}
+static eastl::pair<qt3ds::QT3DSU32, eastl::string::size_type>
+SetupPropertyWorkspace(const char8_t *inPropName, eastl::string &ioWorkspace)
+{
+ qt3ds::QT3DSU32 outSubIndex = 0;
+ ioWorkspace.assign(inPropName ? inPropName : "");
+ eastl::string::size_type thePeriodPos = ioWorkspace.find('.');
+ if (thePeriodPos != eastl::string::npos) {
+ if (thePeriodPos < ioWorkspace.size() - 1) {
+ switch (ioWorkspace[thePeriodPos + 1]) {
+ default:
+ QT3DS_ASSERT(false);
+ case 'r':
+ case 'x':
+ break;
+ case 'g':
+ case 'y':
+ outSubIndex = 1;
+ break;
+ case 'b':
+ case 'z':
+ outSubIndex = 2;
+ break;
+ case 'a':
+ case 'w':
+ outSubIndex = 3;
+ break;
+ }
+ }
+ ioWorkspace.resize(thePeriodPos);
+ }
+ return eastl::make_pair(ioWorkspace.size(), outSubIndex);
+}
+SElementPropertyInfo *SParseElementManager::GetOrCreateProperty(SElementData &inData,
+ const char8_t *inPropertyName)
+{
+ SElementData &theData(inData);
+ SElementPropertyInfo *retvalPtr = FindProperty(inData, inPropertyName);
+ if (retvalPtr)
+ return retvalPtr;
+
+ eastl::string::size_type thePeriodPos =
+ SetupPropertyWorkspace(inPropertyName, m_Workspace).first;
+ TStrType theStr = RegisterStr(m_Workspace.c_str());
+
+ if (m_MetaData.IsPropertyExist(inData.m_Type, theStr, inData.m_Class) == false)
+ return NULL;
+
+ eastl::pair<TAttrMap::iterator, bool> theInserter =
+ theData.m_PropertyMap.insert(eastl::make_pair(theStr, SElementPropertyInfo(theStr)));
+ SElementPropertyInfo &retval(theInserter.first->second);
+ if (theInserter.second) {
+ qt3ds::intrinsics::memZero(retval.m_PropertyHashes, sizeof(retval.m_PropertyHashes));
+ qt3ds::QT3DSU32 *thePropHashes(retval.m_PropertyHashes);
+ CRegisteredString *thePropNames(retval.m_PropertyNames);
+ retval.m_DataType = m_MetaData.GetPropertyType(theData.m_Type, theStr, theData.m_Class);
+ retval.m_AdditionalType =
+ m_MetaData.GetAdditionalType(theData.m_Type, theStr, theData.m_Class);
+ if (retval.m_DataType != ERuntimeDataModelDataTypeNone) {
+ switch (retval.m_DataType) {
+ default:
+ retval.m_Arity = 1;
+ break;
+ case ERuntimeDataModelDataTypeFloat2:
+ retval.m_Arity = 2;
+ break;
+ case ERuntimeDataModelDataTypeFloat3:
+ retval.m_Arity = 3;
+ break;
+ case ERuntimeDataModelDataTypeFloat4:
+ retval.m_Arity = 4;
+ break;
+ }
+ if (retval.m_Arity > 1) {
+ if (retval.m_Arity == 2) {
+ SetPropertyValueHash(m_Workspace, ".x", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".y", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ } else if (retval.m_Arity == 3) {
+ if (m_MetaData.GetAdditionalType(theData.m_Type, theStr, theData.m_Class)
+ == ERuntimeAdditionalMetaDataTypeColor) {
+ SetPropertyValueHash(m_Workspace, ".r", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".g", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".b", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ } else {
+ SetPropertyValueHash(m_Workspace, ".x", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".y", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".z", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ }
+ } else if (retval.m_Arity == 4) {
+ if (m_MetaData.GetAdditionalType(theData.m_Type, theStr, theData.m_Class)
+ == ERuntimeAdditionalMetaDataTypeColor) {
+ SetPropertyValueHash(m_Workspace, ".r", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".g", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".b", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ SetPropertyValueHash(m_Workspace, ".a", thePropHashes, thePeriodPos,
+ thePropNames, m_StringTable);
+ }
+ }
+ } else {
+ retval.m_PropertyHashes[0] = Q3DStudio::CHash::HashAttribute(theStr.c_str());
+ retval.m_PropertyNames[0] = m_StringTable.RegisterStr(m_Workspace.c_str());
+ }
+ }
+ }
+ return &retval;
+}
+
+SElementPropertyInfo *SParseElementManager::GetOrCreateProperty(const char8_t *inIdOrRef,
+ const char8_t *inElemType,
+ const char8_t *inElemClassId,
+ const char8_t *inPropertyName)
+{
+ return GetOrCreateProperty(GetOrCreateElementData(inIdOrRef, inElemType, inElemClassId),
+ inPropertyName);
+}
+
+eastl::pair<SElementPropertyInfo *, qt3ds::QT3DSU32>
+SParseElementManager::FindPropertyWithSubIndex(SElementData &inElement,
+ const char8_t *inPropertyName)
+{
+ qt3ds::QT3DSU32 subIndex = SetupPropertyWorkspace(inPropertyName, m_Workspace).second;
+ TStrType theStr = RegisterStr(m_Workspace.c_str());
+ TAttrMap::iterator theIter = inElement.m_PropertyMap.find(theStr);
+ SElementPropertyInfo *retval = NULL;
+ if (theIter != inElement.m_PropertyMap.end())
+ retval = &theIter->second;
+ return eastl::make_pair(retval, subIndex);
+}
+
+SElementPropertyInfo *SParseElementManager::FindProperty(SElementData &inElement,
+ const char8_t *inPropertyName)
+{
+ return FindPropertyWithSubIndex(inElement, inPropertyName).first;
+}
+SElementPropertyInfo *SParseElementManager::FindProperty(const char8_t *inIdOrRef,
+ const char8_t *inPropertyName)
+{
+ SElementData *theData(FindElementData(inIdOrRef));
+ if (theData)
+ return FindProperty(*theData, inPropertyName);
+ return NULL;
+}
+
+void SParseElementManager::MarkAttributeAsReferenced(SElementData &inElement,
+ const char8_t *inPropertyName)
+{
+ SElementPropertyInfo *theProp = GetOrCreateProperty(inElement, inPropertyName);
+ if (theProp)
+ theProp->m_ElementFlag = true;
+}
+
+void SParseElementManager::MarkAttributeAsReferenced(const char8_t *inElement,
+ const char8_t *inPropertyName)
+{
+ SElementData *theData = FindElementData(inElement);
+ if (theData)
+ MarkAttributeAsReferenced(*theData, inPropertyName);
+}
+
+void SParseElementManager::MarkAllAttributesAsReferenced(SElementData &inElement,
+ bool searchParent)
+{
+ m_PropertyList.clear();
+ m_MetaData.GetInstanceProperties(inElement.m_Type, inElement.m_Class, m_PropertyList,
+ searchParent);
+ for (QT3DSU32 idx = 0, end = m_PropertyList.size(); idx < end; ++idx)
+ MarkAttributeAsReferenced(inElement, m_PropertyList[idx].c_str());
+}
+
+TStrType SParseSlideManager::RegisterId(const char8_t *inStr)
+{
+ if (!inStr)
+ inStr = "";
+ if (*inStr == '#')
+ ++inStr;
+ return RegisterStr(inStr);
+}
+
+SParseSlideManager::~SParseSlideManager()
+{
+ for (QT3DSU32 idx = 0, end = m_Animations.size(); idx < end; ++idx)
+ delete m_Animations[idx];
+ m_Animations.clear();
+}
+
+SParseSlide &SParseSlideManager::GetOrCreateSlide(const char8_t *inSlideId, qt3ds::QT3DSI32 inSlideIndex)
+{
+ TStrType theSlideId(RegisterId(inSlideId));
+ return m_SlideMap.insert(eastl::make_pair(theSlideId, SParseSlide(theSlideId, inSlideIndex)))
+ .first->second;
+}
+
+SParseSlide *SParseSlideManager::FindSlide(const char8_t *inSlideId)
+{
+ TStrType theSlideId(RegisterId(inSlideId));
+ TSlideIdToParseSlideMap::iterator theIter = m_SlideMap.find(theSlideId);
+ if (theIter != m_SlideMap.end())
+ return &theIter->second;
+ return NULL;
+}
+
+void SParseSlideManager::SetAnimationData(SParseSlide &inSlide, const char8_t *inInstanceId,
+ const char8_t *inPropertyName,
+ const char8_t *inKeyframeData,
+ SParseSlideAnimationTypes::Enum inType, bool inIsDynamic,
+ bool inIsActive)
+{
+ TStrType thePropertyName(RegisterStr(inPropertyName));
+ SElementData *theElemData = m_ElementManager.FindElementData(inInstanceId);
+ if (theElemData == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ eastl::pair<SElementPropertyInfo *, qt3ds::QT3DSU32> theProperty =
+ m_ElementManager.FindPropertyWithSubIndex(*theElemData, thePropertyName);
+ if (theProperty.first == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ qt3ds::QT3DSU32 thePropertyHash = theProperty.first->m_PropertyHashes[theProperty.second];
+ // Parse the keyframe data into floating point numbers.
+ if (inKeyframeData == NULL)
+ inKeyframeData = "";
+ m_KeyframeParseBuffer.clear();
+ m_KeyframeParseBuffer.assign(inKeyframeData);
+ m_KeyframeParseFloatBuffer.clear();
+ char8_t *theBufData = const_cast<char8_t *>(m_KeyframeParseBuffer.c_str());
+
+ char8_t *theStartPtr = qt3dsdm::FindNextNonWhitespace(theBufData);
+ while (theStartPtr && *theStartPtr) {
+ char8_t *nextPtr = qt3dsdm::FindNextWhitespace(theStartPtr);
+ if (nextPtr && *nextPtr)
+ *nextPtr = 0;
+ else
+ nextPtr = NULL;
+ QT3DSF32 temp;
+ WStrOps<QT3DSF32>().StrTo(theStartPtr, temp);
+ m_KeyframeParseFloatBuffer.push_back(temp);
+ theStartPtr = nextPtr;
+ if (theStartPtr)
+ theStartPtr = FindNextNonWhitespace(theStartPtr + 1);
+ }
+ // Don't create animations with no keyframes.
+ if (m_KeyframeParseFloatBuffer.empty()) {
+ return;
+ }
+
+ SParseSlideAnimationEntry *theEntry =
+ new SParseSlideAnimationEntry(inSlide.m_SlideId, theElemData->m_Id, thePropertyName,
+ thePropertyHash, inType, NULL, 0, inIsDynamic);
+ theEntry->m_KeyframeData = m_KeyframeParseFloatBuffer;
+ m_Animations.push_back(theEntry);
+ switch (inType) {
+ case SParseSlideAnimationTypes::Linear:
+ m_AnimationKeyframeCount += m_KeyframeParseFloatBuffer.size() / 2;
+ break;
+ case SParseSlideAnimationTypes::Bezier:
+ m_AnimationKeyframeCount += m_KeyframeParseFloatBuffer.size() / 6;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ case SParseSlideAnimationTypes::EaseInOut:
+ m_AnimationKeyframeCount += m_KeyframeParseFloatBuffer.size() / 4;
+ break;
+ }
+
+ ReferenceAnimation(inSlide, *theEntry, inIsActive);
+}
+
+void SParseSlideManager::ReferenceAnimation(SParseSlide &inSlide,
+ const SParseSlideAnimationEntry &inSource,
+ bool inIsActive)
+{
+ TAnimationList &theList =
+ inSlide.m_Animations.insert(eastl::make_pair(inSource.m_InstanceId, TAnimationList()))
+ .first->second;
+ theList.push_back(SParseAnimationRef(inSlide.m_SlideId, inSource.m_InstanceId,
+ inSource.m_PropertyName, &inSource, inIsActive));
+ m_SlideAnimationCount++;
+}
+
+TAnimationList *SParseSlideManager::GetAnimationsForInstance(SParseSlide &inSlide,
+ const char8_t *inInstanceId)
+{
+ SElementData *theElemData = m_ElementManager.FindElementData(inInstanceId);
+ if (theElemData) {
+ TInstanceIdAnimationMap::iterator theAnimations =
+ inSlide.m_Animations.find(theElemData->m_Id);
+ if (theAnimations != inSlide.m_Animations.end())
+ return &theAnimations->second;
+ }
+ return NULL;
+}
+
+SParseSlideActionEntry &SParseSlideManager::GetOrCreateAction(SParseSlide &inSlide,
+ const char8_t *inActionId,
+ qt3ds::QT3DSI32 inActionCount,
+ bool inActive)
+{
+ TStrType theActionId(RegisterId(inActionId));
+ SParseSlideActionEntry theAction(inSlide.m_SlideId, theActionId, inActionCount, inActive);
+ memZero(theAction.m_Actions, sizeof(theAction.m_Actions));
+ TActionList::iterator theIter =
+ eastl::find(inSlide.m_ActionList.begin(), inSlide.m_ActionList.end(), theAction);
+ if (theIter != inSlide.m_ActionList.end())
+ return *theIter;
+ inSlide.m_ActionList.push_back(theAction);
+ m_ActionCount += inActionCount;
+ return inSlide.m_ActionList.back();
+}
+
+SParseSlideActionEntry *SParseSlideManager::FindAction(SParseSlide &inSlide,
+ const char8_t *inActionId)
+{
+ TStrType theActionId(RegisterId(inActionId));
+ SParseSlideActionEntry theAction(inSlide.m_SlideId, theActionId, 0, false);
+ TActionList::iterator theIter =
+ eastl::find(inSlide.m_ActionList.begin(), inSlide.m_ActionList.end(), theAction);
+ if (theIter != inSlide.m_ActionList.end())
+ return &(*theIter);
+ return NULL;
+}
+
+//==============================================================================
+/**
+ * Constructor
+ * @param inFileName name of UIP file
+ */
+CUIPParserImpl::CUIPParserImpl(const QString &inFileName, IRuntimeMetaData &inMetaData,
+ IInputStreamFactory &inFactory,
+ qt3ds::foundation::IStringTable &inStringTable)
+ : m_MetaData(inMetaData)
+ , m_InputStreamFactory(inFactory)
+ , m_ParseElementManager(inMetaData, inStringTable)
+ , m_ParseSlideManager(inMetaData, m_ParseElementManager)
+{
+ // Setup DOMSerializer and DOMReader to read the file
+ std::shared_ptr<qt3dsdm::IStringTable> theStrTable(inMetaData.GetStringTable());
+ shared_ptr<qt3dsdm::IDOMFactory> theFactory(qt3dsdm::IDOMFactory::CreateDOMFactory(theStrTable));
+ TInputStreamPtr theInStream(inFactory.GetStreamForFile(inFileName));
+ qt3dsdm::SDOMElement *topElement = NULL;
+ if (theInStream)
+ topElement = CDOMSerializer::Read(*theFactory, *theInStream);
+ if (!topElement) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Could not open UIP file: " << inFileName.toLatin1().constData();
+ } else {
+ eastl::pair<std::shared_ptr<IDOMWriter>, std::shared_ptr<IDOMReader>> theWriteReader =
+ IDOMWriter::CreateDOMWriter(theFactory, *topElement, theStrTable);
+ m_DOMWriter = theWriteReader.first;
+ m_DOMReader = theWriteReader.second;
+ if (!AreEqual(m_DOMReader->GetNarrowElementName(), "UIP")) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Invalid UIP file: " << inFileName.toLatin1().constData();
+ }
+ }
+
+ // Create Helper class
+ m_ObjectRefHelper = new CUIPParserObjectRefHelper(m_MetaData);
+ m_ActionHelper = new CUIPParserActionHelper(this, m_ObjectRefHelper, m_MetaData);
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CUIPParserImpl::~CUIPParserImpl()
+{
+ // Delete Helper class
+ delete m_ObjectRefHelper;
+ m_ObjectRefHelper = NULL;
+
+ delete m_ActionHelper;
+ m_ActionHelper = NULL;
+}
+
+//==============================================================================
+/**
+ * Load a presentation from a UIP file.
+ * @param inPresentation presentation written to
+ * @return a flag indicating whether or not we successfully loaded the file
+ */
+BOOL CUIPParserImpl::Load(IPresentation &inPresentation,
+ NVConstDataRef<SElementAttributeReference> inStateReferences)
+{
+ m_CurrentPresentation = &inPresentation;
+ if (!m_DOMReader) {
+ qCCritical(qt3ds::INVALID_PARAMETER) << "CUIPParserImpl::Load, No DOM reader";
+ return FALSE;
+ }
+
+ BOOL theLoadResult = m_DOMReader->MoveToFirstChild("Project");
+
+ // Load project settings
+ if (theLoadResult)
+ theLoadResult &= LoadProjectSettings(inPresentation, *m_DOMReader);
+
+ // First, we need to load the classes, because the class information will be stored in metadata
+ if (theLoadResult)
+ theLoadResult &= LoadClasses(inPresentation, *m_DOMReader);
+
+ // Next is to cache the scene graph because we need the id-name information to resolve object
+ // reference
+ m_ObjectRefHelper->CacheGraph(*m_DOMReader, *m_DOMWriter);
+
+ // Next is to cache the required attributes. This will be used to build Element
+ // We also need to cache the actions because we need to know the ActionCount to reserve the
+ // memory
+ {
+ IDOMReader::Scope __graphScope(*m_DOMReader);
+ m_DOMReader->MoveToFirstChild("Graph");
+ CacheGraphRequiredAttributes(*m_DOMReader);
+ }
+
+ {
+ IDOMReader::Scope __logicScope(*m_DOMReader);
+ m_DOMReader->MoveToFirstChild("Logic");
+ {
+
+ IDOMReader::Scope __stateScope(*m_DOMReader);
+ for (BOOL theSuccess = m_DOMReader->MoveToFirstChild("State"); theSuccess;
+ theSuccess = m_DOMReader->MoveToNextSibling("State")) {
+ IDOMReader::Scope __subSlideScope(*m_DOMReader);
+ if (theLoadResult)
+ theLoadResult &= CacheLogicRequiredAttributes(*m_DOMReader);
+ }
+ }
+ }
+
+ // go through all the references and make sure the elements exist and if they do ensure the
+ // attributes are marked as referenced.
+ for (QT3DSU32 idx = 0, end = inStateReferences.size(); idx < end; ++idx) {
+ const SElementAttributeReference &reference = inStateReferences[idx];
+ // All references are absolute, so the start node doesn't really matter.
+ CRegisteredString result = m_ObjectRefHelper->ParseObjectRefId(reference.m_Path, "Scene");
+ if (result.IsValid() == false) {
+ qCCritical(INVALID_OPERATION, "Failed to resolve reference: %s",
+ reference.m_Path.c_str());
+ } else {
+ m_ParseElementManager.MarkAttributeAsReferenced(result.c_str(),
+ reference.m_Attribute.c_str());
+ }
+ }
+
+ if (theLoadResult)
+ CacheClassRequiredAttributes(*m_DOMReader);
+
+ ComputeAndReserveMemory(inPresentation, *m_DOMReader);
+
+ // Now we are ready to load the scene graph
+ if (theLoadResult)
+ theLoadResult &= LoadGraph(inPresentation, *m_DOMReader);
+ if (theLoadResult)
+ theLoadResult &= LoadLogic(inPresentation, *m_DOMReader);
+
+ return theLoadResult;
+}
+
+IDOMReader &CUIPParserImpl::GetDOMReader()
+{
+ return *m_DOMReader.get();
+}
+
+//==============================================================================
+/**
+ * Load Project Settings
+ * @param inPresentation presentation written to
+ * @return a flag indicating whether or not we successfully loaded the file
+ */
+BOOL CUIPParserImpl::LoadProjectSettings(IPresentation &inPresentation, IDOMReader &inReader)
+{
+ IDOMReader::Scope __projectSettingsScope(inReader);
+
+ if (inReader.MoveToFirstChild("ProjectSettings")) {
+ SPresentationSize thePresentationSize;
+ qt3ds::QT3DSI32 theWidth, theHeight;
+
+ if (inReader.Att("presentationWidth", theWidth))
+ thePresentationSize.m_Width = static_cast<UINT16>(theWidth);
+ if (inReader.Att("presentationHeight", theHeight))
+ thePresentationSize.m_Height = static_cast<UINT16>(theHeight);
+ thePresentationSize.m_ScaleMode = SCALEMODE_EXACT; // ScaleMode is always EXACT
+
+ inPresentation.SetSize(thePresentationSize);
+
+ return true;
+ } else
+ return false;
+}
+
+BOOL CUIPParserImpl::LoadClasses(IPresentation & /*inPresentation*/, IDOMReader &inReader)
+{
+ IDOMReader::Scope __classesScope(inReader);
+
+ if (inReader.MoveToFirstChild("Classes")) {
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ const char *theSourcePath;
+ const char *theId;
+ const char *theName;
+ // Read the sourcepath and id
+ if (inReader.Att("sourcepath", theSourcePath) && inReader.Att("id", theId)) {
+ // Read the name
+ if (!inReader.Att("name", theName))
+ theName = theId;
+
+ bool theLoadFlag = false;
+ QString theFullPath(theSourcePath);
+
+ if (theFullPath.endsWith(".qml")) {
+ theLoadFlag = m_MetaData.LoadScriptFile(inReader.GetNarrowElementName(), theId,
+ theName, theFullPath.toUtf8().data());
+ if (theLoadFlag)
+ m_IdScriptMap[theId] = theSourcePath;
+ } else if (theFullPath.endsWith(".effect")) {
+ theLoadFlag = m_MetaData.LoadEffectXMLFile(inReader.GetNarrowElementName(),
+ theId, theName,
+ theFullPath.toUtf8().data());
+ } else if (theFullPath.endsWith(".material") || theFullPath.endsWith(".shader")) {
+ theLoadFlag = m_MetaData.LoadMaterialXMLFile(
+ inReader.GetNarrowElementName(), theId, theName,
+ theFullPath.toUtf8().data());
+ } else if (theFullPath.endsWith(".plugin")) {
+ theLoadFlag = m_MetaData.LoadPluginXMLFile(inReader.GetNarrowElementName(),
+ theId, theName,
+ theFullPath.toUtf8().data());
+ }
+
+ if (!theLoadFlag) {
+ // What file is this?!?
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Could not load sourcepath file: "
+ << theFullPath.toLatin1().constData();
+ }
+ }
+ }
+ }
+
+ // Always return true. Failing to load classes should not block the rest of the system.
+ return true;
+}
+
+BOOL CUIPParserImpl::LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __childScope(inReader);
+
+ m_NumGraphElements = 0;
+ m_NumGraphComponents = 0;
+ m_NumGraphAttributes = 0;
+
+ bool theLoadResult = inReader.MoveToFirstChild("Graph");
+ if (theLoadResult) {
+ theLoadResult &= LoadSceneGraph(inPresentation, inReader);
+ if (theLoadResult)
+ PatchSceneElementRef();
+ }
+
+ return theLoadResult;
+}
+
+using qt3ds::runtime::element::SPropertyDesc;
+using qt3ds::runtime::element::TPropertyDescAndValue;
+
+void CUIPParserImpl::GetMetaAttribute(IPresentation &inPresentation,
+ TPropertyDescAndValueList &outDescList, TStrType inType,
+ TStrType inName, TStrType inClassId,
+ CRegisteredString *inAttStrNames)
+{
+ ERuntimeDataModelDataType thePropertyType =
+ m_MetaData.GetPropertyType(inType, inName, inClassId);
+
+ // TODO: Handle all other types
+ switch (thePropertyType) {
+ case ERuntimeDataModelDataTypeFloat:
+ AddFloatAttribute(outDescList, inAttStrNames[0],
+ m_MetaData.GetPropertyValueFloat(inType, inName, inClassId));
+ break;
+ case ERuntimeDataModelDataTypeFloat2: {
+ QT3DSVec2 vec2 = m_MetaData.GetPropertyValueVector2(inType, inName, inClassId);
+ SFloat2 theValue(vec2.x, vec2.y);
+ AddFloat2Attribute(outDescList, inAttStrNames, theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat3: {
+ QT3DSVec3 vec3 = m_MetaData.GetPropertyValueVector3(inType, inName, inClassId);
+ SFloat3 theValue(vec3.x, vec3.y, vec3.z);
+ ERuntimeAdditionalMetaDataType theAdditionalType =
+ m_MetaData.GetAdditionalType(inType, inName, inClassId);
+ AddFloat3Attribute(outDescList, theAdditionalType, inAttStrNames, theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat4: {
+ QT3DSVec4 vec4 = m_MetaData.GetPropertyValueVector4(inType, inName, inClassId);
+ SFloat4 theValue(vec4.x, vec4.y, vec4.z, vec4.w);
+ ERuntimeAdditionalMetaDataType theAdditionalType =
+ m_MetaData.GetAdditionalType(inType, inName, inClassId);
+ AddFloat4Attribute(outDescList, theAdditionalType, inAttStrNames, theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeLong:
+ AddLongAttribute(outDescList, inAttStrNames[0],
+ m_MetaData.GetPropertyValueLong(inType, inName, inClassId));
+ break;
+ case ERuntimeDataModelDataTypeString: {
+ Option<eastl::string> theRuntimeStr =
+ m_MetaData.GetPropertyValueString(inType, inName, inClassId);
+ if (theRuntimeStr.hasValue())
+ AddStringAttribute(inPresentation, outDescList, inAttStrNames[0],
+ theRuntimeStr->c_str());
+ else
+ AddStringAttribute(inPresentation, outDescList, inAttStrNames[0], "");
+ } break;
+ case ERuntimeDataModelDataTypeBool:
+ AddBoolAttribute(outDescList, inAttStrNames[0],
+ m_MetaData.GetPropertyValueBool(inType, inName, inClassId));
+ break;
+ case ERuntimeDataModelDataTypeLong4:
+ AddElementRefAttribute(outDescList, inAttStrNames[0], NULL);
+ break;
+ case ERuntimeDataModelDataTypeObjectRef: {
+ // Object ref is converted to string path
+ eastl::string theRuntimeStr =
+ m_MetaData.GetPropertyValueObjectRef(inType, inName, inClassId);
+ eastl::string theObjectRef = m_ObjectRefHelper->BuildReferenceString(theRuntimeStr);
+ AddStringAttribute(inPresentation, outDescList, inAttStrNames[0], theObjectRef.c_str());
+ break;
+ }
+ default:
+ QT3DS_ASSERT(false);
+ }
+}
+
+void CUIPParserImpl::AddFloatAttribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, float &inValue)
+{
+ UVariant theValue;
+ theValue.m_FLOAT = inValue;
+ outDescList.push_back(
+ eastl::make_pair(SPropertyDesc(inAttStrName, ATTRIBUTETYPE_FLOAT), theValue));
+}
+
+void CUIPParserImpl::AddLongAttribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, qt3ds::QT3DSI32 &inValue)
+{
+ UVariant theValue;
+ theValue.m_INT32 = inValue;
+ outDescList.push_back(
+ eastl::make_pair(SPropertyDesc(inAttStrName, ATTRIBUTETYPE_INT32), theValue));
+}
+
+void CUIPParserImpl::AddBoolAttribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, bool &inValue)
+{
+ UVariant theValue;
+ theValue.m_INT32 = inValue;
+ outDescList.push_back(
+ eastl::make_pair(SPropertyDesc(inAttStrName, ATTRIBUTETYPE_BOOL), theValue));
+}
+
+void CUIPParserImpl::AddFloat2Attribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString *inAttStrNames, SFloat2 &inValue)
+{
+ for (long theIndex = 0; theIndex < 2; ++theIndex) {
+ UVariant theValue;
+ theValue.m_FLOAT = inValue[theIndex];
+ outDescList.push_back(eastl::make_pair(
+ SPropertyDesc(inAttStrNames[theIndex], ATTRIBUTETYPE_FLOAT), theValue));
+ }
+}
+
+void CUIPParserImpl::AddFloat3Attribute(TPropertyDescAndValueList &outDescList,
+ ERuntimeAdditionalMetaDataType inAdditionalType,
+ CRegisteredString *inAttStrNames, SFloat3 &inValue)
+{
+ for (long theIndex = 0; theIndex < 3; ++theIndex) {
+ float theValue = inValue[theIndex];
+ if (inAdditionalType == ERuntimeAdditionalMetaDataTypeRotation)
+ TORAD(theValue);
+ UVariant theVarValue;
+ theVarValue.m_FLOAT = theValue;
+ outDescList.push_back(eastl::make_pair(
+ SPropertyDesc(inAttStrNames[theIndex], ATTRIBUTETYPE_FLOAT), theVarValue));
+ }
+}
+
+void CUIPParserImpl::AddFloat4Attribute(TPropertyDescAndValueList &outDescList,
+ ERuntimeAdditionalMetaDataType inAdditionalType,
+ CRegisteredString *inAttStrNames, SFloat4 &inValue)
+{
+ for (long i = 0; i < 4; ++i) {
+ UVariant varVal;
+ varVal.m_FLOAT = inValue[i];
+ outDescList.push_back(eastl::make_pair(
+ SPropertyDesc(inAttStrNames[i], ATTRIBUTETYPE_FLOAT), varVal));
+ }
+}
+
+
+void CUIPParserImpl::AddStringAttribute(IPresentation &inPresentation,
+ TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, const char *inValue)
+{
+ qt3ds::foundation::CStringHandle theString = inPresentation.GetStringTable().GetHandle(inValue);
+ UVariant theValue;
+ theValue.m_StringHandle = theString.handle();
+ outDescList.push_back(
+ eastl::make_pair(SPropertyDesc(inAttStrName, ATTRIBUTETYPE_STRING), theValue));
+ if (CHash::HashAttribute(inAttStrName.c_str()) == Q3DStudio::ATTRIBUTE_SOURCEPATH && inValue
+ && *inValue)
+ AddSourcePath(inValue);
+}
+
+void CUIPParserImpl::AddElementRefAttribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, SElement *inElement)
+{
+ UVariant theValue;
+ if (inElement) {
+ theValue.m_ElementHandle = inElement->GetHandle();
+ QT3DS_ASSERT(theValue.m_ElementHandle);
+ } else
+ theValue.m_ElementHandle = 0;
+ outDescList.push_back(
+ eastl::make_pair(SPropertyDesc(inAttStrName, ATTRIBUTETYPE_ELEMENTREF), theValue));
+}
+
+void CUIPParserImpl::GetAttributeList(IPresentation &inPresentation,
+ TPropertyDescAndValueList &outDescList, TStrType inType,
+ TStrType inName, TStrType inClassId, const char *inValue,
+ CRegisteredString *inPropNameStrs)
+{
+ ERuntimeDataModelDataType theDataType = m_MetaData.GetPropertyType(inType, inName, inClassId);
+ ERuntimeAdditionalMetaDataType theAdditionalType =
+ m_MetaData.GetAdditionalType(inType, inName, inClassId);
+
+ GetAttributeList(inPresentation, outDescList, theDataType, theAdditionalType, inName, inValue,
+ inPropNameStrs);
+}
+
+void CUIPParserImpl::GetAttributeList(IPresentation &inPresentation,
+ TPropertyDescAndValueList &outDescList,
+ ERuntimeDataModelDataType inDataType,
+ ERuntimeAdditionalMetaDataType inAdditionalType, const char *,
+ const char *inValue, CRegisteredString *inPropNameStrs)
+{
+ // Create a destructible value
+ m_ValueBuffer.clear();
+ m_TempBuffer.clear();
+ m_ValueBuffer.write(inValue, (QT3DSU32)strlen(inValue) + 1);
+ WCharTReader theReader((char8_t *)m_ValueBuffer.begin(), m_TempBuffer,
+ *m_DOMReader->GetStringTable());
+
+ // TODO: Handle all other types
+ // Note that the default value should be consistent with the SetDefault method of
+ // TDataModelValue
+ switch (inDataType) {
+ case ERuntimeDataModelDataTypeLong: {
+ qt3ds::QT3DSI32 theValue = 0;
+ if (!IsTrivial(inValue))
+ theReader.Read(theValue);
+ AddLongAttribute(outDescList, inPropNameStrs[0], theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat: {
+ float theValue = 0;
+ if (!IsTrivial(inValue))
+ theReader.Read(theValue);
+ AddFloatAttribute(outDescList, inPropNameStrs[0], theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat2: {
+ SFloat2 theValue(0);
+ if (!IsTrivial(inValue))
+ theReader.ReadRef(NVDataRef<QT3DSF32>(&theValue[0], 2));
+ AddFloat2Attribute(outDescList, inPropNameStrs, theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat3: {
+ SFloat3 theValue(0);
+ if (!IsTrivial(inValue))
+ theReader.ReadRef(NVDataRef<QT3DSF32>(&theValue[0], 3));
+ AddFloat3Attribute(outDescList, inAdditionalType, inPropNameStrs, theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat4: {
+ SFloat4 theValue(0);
+ if (!IsTrivial(inValue))
+ theReader.ReadRef(NVDataRef<QT3DSF32>(&theValue[0], 4));
+ AddFloat4Attribute(outDescList, inAdditionalType, inPropNameStrs, theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeBool: {
+ bool theValue = false;
+ if (!IsTrivial(inValue))
+ theReader.Read(theValue);
+ AddBoolAttribute(outDescList, inPropNameStrs[0], theValue);
+ break;
+ }
+ case ERuntimeDataModelDataTypeStringRef:
+ case ERuntimeDataModelDataTypeString: {
+ const char *theDataPtr = "";
+ if (!IsTrivial(inValue))
+ theReader.Read(theDataPtr);
+ AddStringAttribute(inPresentation, outDescList, inPropNameStrs[0], theDataPtr);
+ break;
+ }
+ case ERuntimeDataModelDataTypeLong4: {
+ const char *theDataPtr = NULL;
+ if (!IsTrivial(inValue))
+ theReader.Read(theDataPtr);
+ SElement *theElementData = GetElement(theDataPtr);
+ AddElementRefAttribute(outDescList, inPropNameStrs[0], theElementData);
+ break;
+ }
+ case ERuntimeDataModelDataTypeObjectRef: {
+ // Object ref is converted to string path
+ const char *theDataPtr = NULL;
+ if (!IsTrivial(inValue))
+ theReader.Read(theDataPtr);
+ if (theDataPtr) {
+ eastl::string theObjectRef = m_ObjectRefHelper->BuildReferenceString(theDataPtr);
+ AddStringAttribute(inPresentation, outDescList, inPropNameStrs[0],
+ theObjectRef.c_str());
+ }
+ break;
+ }
+ default:
+ QT3DS_ASSERT(false);
+ }
+}
+
+//==============================================================================
+/**
+ * Looks up the EElementType from the asset type.
+ */
+EElementType GetElementType(const char *inType)
+{
+ if (AreEqual(inType, "Scene") || AreEqual(inType, "Layer") || AreEqual(inType, "Group")
+ || AreEqual(inType, "Model") || AreEqual(inType, "Path"))
+ return ELEMENTTYPE_NODE;
+
+ else if (AreEqual(inType, "Camera"))
+ return ELEMENTTYPE_CAMERA;
+
+ else if (AreEqual(inType, "Light"))
+ return ELEMENTTYPE_LIGHT;
+
+ else if (AreEqual(inType, "Component"))
+ return ELEMENTTYPE_COMPONENT;
+
+ else if (AreEqual(inType, "Material"))
+ return ELEMENTTYPE_MATERIAL;
+
+ else if (AreEqual(inType, "Image"))
+ return ELEMENTTYPE_TEXTURE;
+
+ else if (AreEqual(inType, "Behavior"))
+ return ELEMENTTYPE_BEHAVIOR;
+
+ else if (AreEqual(inType, "Text"))
+ return ELEMENTTYPE_TEXT;
+
+ else if (AreEqual(inType, "PathAnchorPoint"))
+ return ELEMENTTYPE_PATHANCHORPOINT;
+
+ else if (AreEqual(inType, "SubPath"))
+ return ELEMENTTYPE_SUBPATH;
+
+ else
+ return ELEMENTTYPE_UNKNOWN;
+}
+
+//==============================================================================
+/**
+ * Build out the graph.
+ * @param inPresentation presentation written to
+ * @return a flag indicating whether or not we successfully loaded the file
+ */
+BOOL CUIPParserImpl::LoadSceneGraph(IPresentation &inPresentation, IDOMReader &inReader,
+ qt3ds::runtime::element::SElement *inNewStyleParent)
+{
+ IDOMReader::Scope __childScope(inReader);
+ IScriptBridge *theScriptBridgeQml = inPresentation.GetScriptBridgeQml();
+
+ eastl::string theFileString;
+ qt3ds::runtime::IApplication &theApp(inPresentation.GetApplication());
+ qt3ds::runtime::IElementAllocator &theElemAllocator(theApp.GetElementAllocator());
+ TPropertyDescAndValueList theProperties;
+ using qt3ds::runtime::element::SPropertyDesc;
+ qt3ds::foundation::IStringTable &theStringTable(inPresentation.GetStringTable());
+ // build out the graph.
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ theProperties.clear();
+ const char *theId;
+ inReader.Att("id", theId);
+ const char *theClass;
+ inReader.Att("class", theClass);
+ const char *theType(inReader.GetNarrowElementName());
+ eastl::string theName(m_ObjectRefHelper->GetName(theId).c_str());
+ // Get default end time from metadata
+ UINT32 theLoopTime = 0;
+ bool isComponent = false;
+ bool isBehavior = false;
+
+ // Create SElement
+ if (AreEqual(theType, "Scene") || AreEqual(theType, "Component")) {
+ // TDataModelValue theValue;
+ theLoopTime = m_MetaData.GetPropertyValueLong(m_MetaData.Register(theType),
+ m_MetaData.Register("endtime"));
+ Q3DStudio_ASSERT(theLoopTime != 0); // Something is wrong here
+ isComponent = true;
+ } else {
+ if (AreEqual(theType, "Behavior") && !IsTrivial(theClass)) {
+ // Find the sourcepath and load the script
+ ++theClass; // remove the '#'
+ TIdSourcePathMap::iterator theSourcePathIter = m_IdScriptMap.find(theClass);
+ if (theSourcePathIter != m_IdScriptMap.end()) {
+ theFileString.assign(theSourcePathIter->second);
+
+// For non-windows platforms, we need to reverse the slashes
+#ifndef EA_PLATFORM_WINDOWS
+ for (eastl::string::size_type thePos = theFileString.find('\\');
+ thePos != eastl::string::npos;
+ thePos = theFileString.find('\\', thePos + 1)) {
+ theFileString.replace(thePos, 1, 1, '/');
+ }
+#endif
+ isBehavior = true;
+ UVariant theValue;
+ theValue.m_StringHandle =
+ inPresentation.GetStringTable().GetHandle(theFileString.c_str());
+ theProperties.push_back(eastl::make_pair(
+ SPropertyDesc(theStringTable.RegisterStr("behaviorscripts"),
+ ATTRIBUTETYPE_STRING),
+ theValue));
+ } else {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Could not load Behavior script: " << theClass;
+ }
+ }
+ }
+
+ SElementData &theElementData =
+ m_ParseElementManager.GetOrCreateElementData(theId, theType, theClass);
+
+ const char8_t *theSourcePath;
+ if (inReader.UnregisteredAtt("sourcepath", theSourcePath))
+ AddSourcePath(theSourcePath);
+
+ TAttrMap &theList = theElementData.m_PropertyMap;
+
+ const char *theAttribute;
+ for (TAttrMap::iterator theIter = theList.begin(), theMapEnd = theList.end();
+ theIter != theMapEnd; ++theIter) {
+ if (theIter->second.m_ElementFlag) {
+ // Parse the property value from uip, this will overwrite the default value
+ const TStrType &thePropertyName(theIter->first);
+ CRegisteredString *thePropertyNames = theIter->second.m_PropertyNames;
+ size_t theListSize = theProperties.size();
+ if (inReader.Att(thePropertyName.c_str(), theAttribute)) {
+ ERuntimeDataModelDataType theDataType = m_MetaData.GetPropertyType(
+ theElementData.m_Type, thePropertyName, theElementData.m_Class);
+ if (theDataType == ERuntimeDataModelDataTypeLong4) {
+ AddElementRefToPatch(theProperties, theElementData, thePropertyName.c_str(),
+ theAttribute);
+ } else
+ GetAttributeList(inPresentation, theProperties, theElementData.m_Type,
+ thePropertyName, theElementData.m_Class, theAttribute,
+ thePropertyNames);
+ } else {
+ GetMetaAttribute(inPresentation, theProperties, theElementData.m_Type,
+ thePropertyName, theElementData.m_Class, thePropertyNames);
+ }
+ size_t theNumAtts = theProperties.size() - theListSize;
+ QT3DS_ASSERT(theNumAtts == (size_t)theIter->second.m_Arity);
+ (void)theNumAtts;
+ }
+ }
+ qt3ds::runtime::element::SElement &theNewElem = theElemAllocator.CreateElement(
+ theStringTable.RegisterStr(theName.c_str()), theStringTable.RegisterStr(theType),
+ theStringTable.RegisterStr(theElementData.m_Class.c_str()),
+ toConstDataRef(theProperties.data(), (QT3DSU32)theProperties.size()), &inPresentation,
+ inNewStyleParent, isComponent);
+ theElementData.m_Element = &theNewElem;
+
+ if (inPresentation.GetRoot() == NULL)
+ inPresentation.SetRoot(theNewElem);
+
+ eastl::string thePath;
+ // build out the full path to the element for debugging
+ for (CUIPParserObjectRefHelper::SGraphNode *theNode =
+ this->m_ObjectRefHelper->GetNode(theId);
+ theNode; theNode = theNode->m_Parent) {
+ if (thePath.length())
+ thePath.insert(0, ".");
+ thePath.insert(0, theNode->m_Name);
+ }
+ if (thePath.size())
+ theNewElem.m_Path = m_ParseElementManager.m_StringTable.RegisterStr(thePath.c_str());
+
+ if (isBehavior) {
+ if (theFileString.find(".qml") != eastl::string::npos) {
+ theScriptBridgeQml->LoadScript(&inPresentation, &theNewElem,
+ theFileString.c_str());
+ }
+ }
+ LoadSceneGraph(inPresentation, inReader, &theNewElem);
+ }
+
+ return true;
+}
+
+//==============================================================================
+/**
+ * This method will parse through the graph sections to cache those attributes that
+ * should never be optimized
+ */
+void CUIPParserImpl::CacheGraphRequiredAttributes(qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __childScope(inReader);
+
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ const char *theId;
+ inReader.Att("id", theId);
+ const char *theType(inReader.GetNarrowElementName());
+ const char *theClass = "";
+ inReader.Att("class", theClass);
+ SElementData &theData =
+ m_ParseElementManager.GetOrCreateElementData(theId, theType, theClass);
+ // name and sourcepath are never optimized out.
+ m_ParseElementManager.MarkAttributeAsReferenced(theData, "name");
+ // not everything needs to be in the time graph.
+ if (AreEqual(theType, "Scene") == false && AreEqual(theType, "Material") == false
+ && AreEqual(theType, "CustomMaterial") == false && AreEqual(theType, "Image") == false
+ && AreEqual(theType, "RenderPlugin") == false) {
+ SElementPropertyInfo *theProp =
+ m_ParseElementManager.GetOrCreateProperty(theData, "starttime");
+ theProp->m_SlideFlag = true;
+ theProp->m_SlideForceFlag = true;
+ theProp->m_ElementFlag = true;
+ theProp = m_ParseElementManager.GetOrCreateProperty(theData, "endtime");
+ theProp->m_SlideFlag = true;
+ theProp->m_SlideForceFlag = true;
+ theProp->m_ElementFlag = true;
+ }
+
+ // Probably not the most optimal thing to expose this attribute for all elements that
+ // support it, since it is not really needed except during initialization
+ m_ParseElementManager.MarkAttributeAsReferenced(theData, "controlledproperty");
+ m_ParseElementManager.MarkAttributeAsReferenced(theData, "observedproperty");
+
+ // Behaviors need all attributes possible on the object on them all the time.
+ if (AreEqual(theType, "Behavior") || AreEqual(theType, "RenderPlugin")) {
+ m_ParseElementManager.MarkAllAttributesAsReferenced(theData);
+ }
+
+ // Recursive
+ CacheGraphRequiredAttributes(inReader);
+ }
+}
+
+//==============================================================================
+/**
+ * This method will parse through the logic sections to cache those attributes that
+ * will be changed and thus needs to be at the SElement
+ */
+BOOL CUIPParserImpl::CacheLogicRequiredAttributes(qt3dsdm::IDOMReader &inReader,
+ qt3ds::QT3DSI32 inSlideIndex,
+ SParseSlide *inParentSlide)
+{
+ IDOMReader::Scope __stateScope(inReader);
+ eastl::string theSlideId = GetSlideId(inReader);
+ SParseSlide &theSlide = m_ParseSlideManager.GetOrCreateSlide(theSlideId.c_str(), inSlideIndex);
+ eastl::hash_set<TStrType> theCommandInstances;
+ QT3DSU32 slideAnimActions = 0;
+
+ {
+ IDOMReader::Scope __commandLoopScope(inReader);
+ for (BOOL theSuccess = inReader.MoveToFirstChild(); theSuccess;
+ theSuccess = inReader.MoveToNextSibling()) {
+ IDOMReader::Scope __commandScope(inReader);
+ if (AreEqual(inReader.GetNarrowElementName(), "Add")
+ || AreEqual(inReader.GetNarrowElementName(), "Set")) {
+ bool isSet = AreEqual(inReader.GetNarrowElementName(), "Set");
+
+ const char *theRef;
+ if (inReader.Att("ref", theRef)) {
+ theRef++; // remove the '#'
+
+ // Set/Add command applied to an element *not* in the scene graph.
+ SElementData *theData = m_ParseElementManager.FindElementData(theRef);
+ if (theData == NULL) {
+ QT3DS_ASSERT(false);
+ continue;
+ }
+ // If this element has controlledproperty, need to mark all as referenced
+ // in order for datainput initialisation to find attributes that
+ // are controlled
+ // TODO: we could parse out the exact controlled property names and
+ // set only those as referenced. In this case we might have to expand vec3
+ // type attributes to component parts
+ const char *ctrldProp;
+ const char *observedProp;
+ inReader.Att("controlledproperty", ctrldProp);
+ inReader.Att("observedproperty", observedProp);
+ if (ctrldProp || observedProp)
+ m_ParseElementManager.MarkAllAttributesAsReferenced(*theData, true);
+
+ theCommandInstances.insert(theData->m_Id);
+ if (isSet) {
+ for (eastl::pair<const char *, const char *> theAtt =
+ inReader.GetNarrowFirstAttribute();
+ !IsTrivial(theAtt.first); theAtt = inReader.GetNarrowNextAttribute()) {
+ if (AreEqual(theAtt.first, "ref") || AreEqual(theAtt.first, "shy"))
+ continue;
+
+ SElementPropertyInfo *theProperty =
+ m_ParseElementManager.GetOrCreateProperty(*theData, theAtt.first);
+ // This property exists on both the elements and the slides.
+ if (theProperty) {
+ theProperty->m_ElementFlag = true;
+ theProperty->m_SlideFlag = true;
+ }
+ }
+ // Run through parent animations and forward them *if* this set command does
+ // not have this property present.
+ if (inParentSlide) {
+ TAnimationList *theAnimations =
+ m_ParseSlideManager.GetAnimationsForInstance(*inParentSlide,
+ theData->m_Id);
+ if (theAnimations != NULL) {
+ for (QT3DSU32 animIdx = 0, animEnd = theAnimations->size();
+ animIdx < animEnd; ++animIdx) {
+ SParseAnimationRef &theEntry((*theAnimations)[animIdx]);
+ const char8_t *propValue = "";
+ SElementPropertyInfo *thePropInfo =
+ m_ParseElementManager.FindProperty(
+ *theData, theEntry.m_PropertyName.c_str());
+ if (!thePropInfo) {
+ QT3DS_ASSERT(false);
+ continue;
+ }
+ // If the attribute doesn't exist in the command, then we
+ // forward the animation to here
+ if (inReader.Att(thePropInfo->m_PropertyName, propValue)
+ == false) {
+ ++slideAnimActions;
+ m_ParseSlideManager.ReferenceAnimation(
+ theSlide, *theEntry.m_Animation, true);
+ }
+ }
+ }
+ }
+ }
+
+ // find all the animations, regardless of add or set.
+ {
+ IDOMReader::Scope __animationScope(inReader);
+ for (BOOL theAnimScopeSuccess = inReader.MoveToFirstChild("AnimationTrack");
+ theAnimScopeSuccess;
+ theAnimScopeSuccess = inReader.MoveToNextSibling("AnimationTrack")) {
+ const char *theProperty;
+ const char8_t *theValue = "";
+ inReader.Value(theValue);
+ if (theValue != NULL && *theValue
+ && inReader.UnregisteredAtt("property", theProperty)) {
+ m_ParseElementManager.MarkAttributeAsReferenced(*theData,
+ theProperty);
+ // PreParse the animation at this point. This allows us to easily
+ // count animations.
+ bool isDynamic = false;
+ inReader.Att("dynamic", isDynamic);
+ SParseSlideAnimationTypes::Enum theParseType =
+ SParseSlideAnimationTypes::EaseInOut;
+ const char8_t *animType;
+ if (inReader.Att("type", animType)) {
+ if (AreEqual(animType, "EaseInOut")) {
+ } else if (AreEqual(animType, "Bezier"))
+ theParseType = SParseSlideAnimationTypes::Bezier;
+ else if (AreEqual(animType, "Linear"))
+ theParseType = SParseSlideAnimationTypes::Linear;
+ else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ ++slideAnimActions;
+ m_ParseSlideManager.SetAnimationData(
+ theSlide, theData->m_Id, theProperty, theValue, theParseType,
+ isDynamic, inSlideIndex != 0);
+ }
+ }
+ }
+
+ // find all the actions
+ {
+ IDOMReader::Scope __actionScope(inReader);
+ for (BOOL theActionScopeSuccess = inReader.MoveToFirstChild("Action");
+ theActionScopeSuccess;
+ theActionScopeSuccess = inReader.MoveToNextSibling("Action")) {
+ const char8_t *theActionId;
+ // Don't cache reference actions
+ if (inReader.Att("id", theActionId)) {
+ m_ActionHelper->CacheAction(inReader, theData->m_Id);
+ bool active = true;
+ inReader.Att("eyeball", active);
+ ++slideAnimActions;
+ m_ParseSlideManager.GetOrCreateAction(
+ theSlide, theActionId,
+ m_ActionHelper->GetActionCount(theActionId), active);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // Now forward all animations from the parent slide that are for instances that we haven't
+ // covered at all on this slide.
+ if (inParentSlide) {
+ for (TInstanceIdAnimationMap::iterator theIter = inParentSlide->m_Animations.begin(),
+ theEnd = inParentSlide->m_Animations.end();
+ theIter != theEnd; ++theIter) {
+ if (theCommandInstances.find(theIter->first) == theCommandInstances.end()) {
+ TAnimationList &theList(theIter->second);
+ for (QT3DSU32 animIdx = 0, animEnd = theList.size(); animIdx < animEnd; ++animIdx) {
+ SParseAnimationRef &theEntry(theList[animIdx]);
+ m_ParseSlideManager.ReferenceAnimation(theSlide, *theEntry.m_Animation, true);
+ ++slideAnimActions;
+ }
+ }
+ }
+ // Forward action creation onto this slide.
+ for (TActionList::iterator theIter = inParentSlide->m_ActionList.begin(),
+ theEnd = inParentSlide->m_ActionList.end();
+ theIter != theEnd; ++theIter) {
+ SParseSlideActionEntry &theAction(*theIter);
+ m_ParseSlideManager.GetOrCreateAction(theSlide, theAction.m_ActionId,
+ theAction.m_ActionCount, theAction.m_Active);
+ ++slideAnimActions;
+ }
+ }
+
+ eastl::vector<eastl::string> theChildSlideIds;
+
+ for (BOOL theSuccess = inReader.MoveToFirstChild("State"); theSuccess;
+ theSuccess = inReader.MoveToNextSibling("State")) {
+ IDOMReader::Scope __subSlideScope(inReader);
+ ++inSlideIndex;
+ theChildSlideIds.push_back(GetSlideId(inReader));
+ CacheLogicRequiredAttributes(inReader, inSlideIndex, &theSlide);
+ }
+
+ // Pull all child animations up into this slide, but set them to deactivated.
+ for (QT3DSU32 childSlideIdx = 0, childSlideEnd = theChildSlideIds.size();
+ childSlideIdx < childSlideEnd; ++childSlideIdx) {
+ SParseSlide *theChildSlide =
+ m_ParseSlideManager.FindSlide(theChildSlideIds[childSlideIdx].c_str());
+ if (theChildSlide) {
+ // Add animations that did not original in this slide to this slide.
+ for (TInstanceIdAnimationMap::iterator theIter = theChildSlide->m_Animations.begin(),
+ theEnd = theChildSlide->m_Animations.end();
+ theIter != theEnd; ++theIter) {
+ TAnimationList &theList(theIter->second);
+ for (QT3DSU32 animIdx = 0, animEnd = theList.size(); animIdx < animEnd; ++animIdx) {
+ SParseAnimationRef &theEntry(theList[animIdx]);
+ if (theEntry.m_Animation
+ && theEntry.m_Animation->m_SlideId != theSlide.m_SlideId) {
+ m_ParseSlideManager.ReferenceAnimation(theSlide, *theEntry.m_Animation,
+ false);
+ ++slideAnimActions;
+ }
+ }
+ }
+ for (TActionList::iterator theIter = theChildSlide->m_ActionList.begin(),
+ theEnd = theChildSlide->m_ActionList.end();
+ theIter != theEnd; ++theIter) {
+ SParseSlideActionEntry &theEntry(*theIter);
+ // This deactivates actions that may be active on another slide.
+ m_ParseSlideManager.GetOrCreateAction(theSlide, theEntry.m_ActionId,
+ theEntry.m_ActionCount, false);
+ ++slideAnimActions;
+ }
+ }
+ }
+ // qt3ds::NVFoundationBase& fnd(
+ // m_CurrentPresentation->GetApplication().GetRuntimeFactory().GetFoundation() );
+ // fnd.error( QT3DS_TRACE, "Loading slide %s, %d anim actions", theSlideId.c_str(),
+ // slideAnimActions );
+
+ return TRUE;
+}
+
+void CUIPParserImpl::CacheClassRequiredAttributes(qt3dsdm::IDOMReader &inReader)
+{
+ {
+ // First, we parse Graph section to cache custom attributes specified by the class
+ IDOMReader::Scope __graphScope(inReader);
+ inReader.MoveToFirstChild("Graph");
+ CacheClassSceneAttributes(inReader);
+ }
+ if (!m_IdClassMap.empty()) {
+ // Next, we parse Logic section to update the references
+ IDOMReader::Scope __logicScope(inReader);
+ inReader.MoveToFirstChild("Logic");
+ CacheClassStateAttributes(inReader);
+ }
+}
+
+void CUIPParserImpl::CacheClassSceneAttributes(IDOMReader &inReader)
+{
+ IDOMReader::Scope __childScope(inReader);
+ // build out the graph.
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ const char *theId;
+ const char *theClass;
+ if (inReader.Att("class", theClass) && inReader.Att("id", theId)) {
+ // Add to id-class map
+ m_IdClassMap[theId] = theClass;
+ }
+ CacheClassSceneAttributes(inReader);
+ }
+}
+
+void CUIPParserImpl::CacheClassStateAttributes(IDOMReader &inReader)
+{
+ IDOMReader::Scope __childScope(inReader);
+
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "State"))
+ CacheClassStateAttributes(inReader);
+ else if (AreEqual(inReader.GetNarrowElementName(), "Add")
+ || AreEqual(inReader.GetNarrowElementName(), "Set")) {
+ const char *theRef;
+ if (inReader.Att("ref", theRef)) {
+ theRef++; // remove the '#'
+
+ // Find the class, if any
+ TIdClassMap::iterator theIter = m_IdClassMap.find(theRef);
+ if (theIter != m_IdClassMap.end()) {
+ // Get References of the class
+ eastl::vector<eastl::string> theReferences;
+ m_MetaData.GetReferences("", theReferences, theIter->second.c_str());
+ if (!theReferences.empty()) {
+ // Cache the references
+ m_ObjectRefHelper->MarkAllReferencedAttributes(
+ theRef, theReferences, inReader, m_ParseElementManager);
+ }
+ }
+ }
+ }
+ }
+}
+
+//==============================================================================
+/**
+ * For ElementRef type, there could be times where the SElement isn't created yet, thus
+ * this method cache those Long4 type and add an empty attribute into the SElement
+ */
+void CUIPParserImpl::AddElementRefToPatch(TPropertyDescAndValueList &outDescList,
+ SElementData &inElement, const char *inName,
+ const char *inValue)
+{
+ SElementRefCache theElementRefData;
+ theElementRefData.m_Element = &inElement;
+ theElementRefData.m_Name = inName;
+ theElementRefData.m_Value = inValue;
+ m_ElementRefCache.push_back(theElementRefData);
+
+ UVariant theValue;
+ theValue.m_ElementHandle = 0;
+ outDescList.push_back(
+ eastl::make_pair(SPropertyDesc(m_ParseElementManager.m_StringTable.RegisterStr(inName),
+ ATTRIBUTETYPE_ELEMENTREF),
+ theValue));
+}
+
+//==============================================================================
+/**
+ * For those Long4 type that was not loaded correctly, go through all of them and
+ * fix up the ElementRef
+ */
+void CUIPParserImpl::PatchSceneElementRef()
+{
+ for (eastl::vector<SElementRefCache>::iterator theIter = m_ElementRefCache.begin();
+ theIter != m_ElementRefCache.end(); ++theIter) {
+ SElementRefCache &theCache = *theIter;
+
+ SElementData *theElementData = GetElementData(theCache.m_Value.c_str());
+
+ SElement *theElement = theCache.m_Element->m_Element;
+ UVariant *theValue = theElement->FindPropertyValue(
+ m_ParseElementManager.RegisterStr(theCache.m_Value.c_str()));
+ if (theValue) {
+ theValue->m_ElementHandle = 0;
+ if (theElementData->m_Element) {
+ theValue->m_ElementHandle = theElementData->m_Element->GetHandle();
+ QT3DS_ASSERT(theValue->m_ElementHandle);
+ }
+ }
+ }
+}
+
+BOOL CUIPParserImpl::LoadLogic(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __logicScope(inReader);
+
+ m_NumSlides = 0;
+ m_NumSlideElements = 0;
+ m_NumSlideAttributes = 0;
+ m_NumAnimationTracks = 0;
+ m_NumAnimationKeys = 0;
+ m_NumSlideAnimations = 0;
+ m_NumSlideActions = 0;
+
+ bool theStatus = true;
+
+ // Build all of the animation objects that we have tallied up.
+ for (QT3DSU32 animIdx = 0, animEnd = m_ParseSlideManager.m_Animations.size(); animIdx < animEnd;
+ ++animIdx) {
+ SParseSlideAnimationEntry &theEntry = *m_ParseSlideManager.m_Animations[animIdx];
+ SElementData *theData = m_ParseElementManager.FindElementData(theEntry.m_InstanceId);
+ // Generate valid animation indexes while we are at it.
+ LoadAnimationTrack(inPresentation, *theData, theEntry);
+ }
+
+ if (inReader.MoveToFirstChild("Logic")) {
+
+ // Action
+ m_ActionHelper->BuildActions(inPresentation);
+
+ for (BOOL theSuccess = inReader.MoveToFirstChild("State"); theSuccess;
+ theSuccess = inReader.MoveToNextSibling("State")) {
+ theStatus &= LoadStateGraph(inPresentation, inReader);
+ }
+ }
+
+ return theStatus;
+}
+
+//==============================================================================
+/**
+ * Load the State (Slides)
+ * @param inPresentation presentation written to
+ * @return a flag indicating whether or not we successfully loaded the file
+ */
+BOOL CUIPParserImpl::LoadStateGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __slideScope(inReader);
+
+ BOOL theStatus = true;
+
+ SElement *theComponent = NULL;
+ const char8_t *theAttribute;
+ if (inReader.UnregisteredAtt("component", theAttribute))
+ theComponent = GetElement(theAttribute);
+ if (theComponent) {
+ INT32 theSlideIndex = 0;
+ LoadState(inPresentation, theComponent, theSlideIndex, inReader);
+
+ for (BOOL theResult = inReader.MoveToFirstChild("State"); theResult;
+ theResult = inReader.MoveToNextSibling("State")) {
+ if (theStatus)
+ theStatus &= LoadState(inPresentation, theComponent, ++theSlideIndex, inReader);
+ }
+ } else {
+ if (theAttribute) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Slide load failure!! Failed to find component: " << theAttribute;
+ } else {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Slide load failure!! Failed to find component.";
+ }
+ }
+
+ return theStatus;
+}
+
+//==============================================================================
+/**
+ * Load the State (Slides)
+ * @param inPresentation presentation written to
+ * @return a flag indicating whether or not we successfully loaded the file
+ */
+BOOL CUIPParserImpl::LoadState(IPresentation &inPresentation, SElement *inComponent,
+ INT32 inSlideIndex, qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __stateScope(inReader);
+
+ BOOL theResult = true;
+ ISlideSystem &theBuilder = inPresentation.GetSlideSystem();
+
+ eastl::string theSlideName = GetSlideName(inReader);
+
+ qt3ds::runtime::SSlidePlayInformation thePlayMode = GetPlayMode(inReader);
+ thePlayMode.m_PlayThroughTo = (QT3DSU8)GetPlayThroughTo(inSlideIndex, inReader);
+ // Setup with the default value from the metadata
+ INT32 theMinTime = m_MetaData.GetPropertyValueLong(m_MetaData.Register("Asset"),
+ m_MetaData.Register("starttime"));
+ INT32 theMaxTime = m_MetaData.GetPropertyValueLong(m_MetaData.Register("Asset"),
+ m_MetaData.Register("endtime"));
+
+ theBuilder.AddSlide(*inComponent, theSlideName.c_str(), thePlayMode.m_PlayMode,
+ thePlayMode.m_Paused, thePlayMode.m_PlayThroughTo, theMinTime, theMaxTime);
+ m_NumSlides++;
+
+ m_SlideElements.clear();
+ m_SlideElements.insert(inComponent);
+
+ BOOL theActiveFlag = (inSlideIndex != 0);
+ theBuilder.AddSlideElement(*inComponent, theActiveFlag);
+ ProcessStateRef(inPresentation, inComponent, inSlideIndex == 0, inReader);
+
+ m_NumSlideElements++;
+
+ theMaxTime = 0;
+ theResult &=
+ LoadSlideElements(inPresentation, inReader, inSlideIndex == 0, inComponent, &theMaxTime);
+ if (theMaxTime != 0)
+ theBuilder.SetSlideMaxTime((QT3DSU32)theMaxTime);
+
+ return theResult;
+}
+
+//==============================================================================
+/**
+ * Process the state information to add all the animations and actions that might be setup
+ */
+BOOL CUIPParserImpl::ProcessStateRef(IPresentation &inPresentation, SElement *inComponent,
+ bool inMaster, qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __stateScope(inReader);
+ eastl::string theSlideId = GetSlideId(inReader);
+ for (BOOL theResult = inReader.MoveToFirstChild("Set"); theResult;
+ theResult = inReader.MoveToNextSibling("Set")) {
+ const char8_t *theElementRef;
+ if (inReader.UnregisteredAtt("ref", theElementRef)
+ && GetElement(theElementRef) == inComponent)
+ ProcessSlideAnimAction(inPresentation, theSlideId, inMaster, inReader);
+ }
+ return TRUE;
+}
+
+void CUIPParserImpl::ComputeAndReserveMemory(IPresentation & /*inPresentation*/,
+ qt3dsdm::IDOMReader &inReader)
+{
+ SGraphSectionCount theGraphSectionCount;
+ SLogicSectionCount theLogicSectionCount;
+ SActionSectionCount theActionSectionCount;
+
+ {
+ IDOMReader::Scope __graphScope(inReader);
+ if (inReader.MoveToFirstChild("Graph"))
+ DoGraphSectionCount(inReader, theGraphSectionCount);
+ }
+ DoLogicSectionCount(inReader, theLogicSectionCount);
+ m_ActionHelper->GetActionSectionCount(theActionSectionCount);
+}
+
+void CUIPParserImpl::DoGraphSectionCount(qt3dsdm::IDOMReader &inReader,
+ SGraphSectionCount &outGraphCounter)
+{
+ IDOMReader::Scope __graphScope(inReader);
+
+ for (bool theResult = inReader.MoveToFirstChild(); theResult;
+ theResult = inReader.MoveToNextSibling()) {
+ const char *theTypeStr(inReader.GetNarrowElementName());
+ if (AreEqual(theTypeStr, "Scene") || AreEqual(theTypeStr, "Component"))
+ outGraphCounter.m_ComponentCount++;
+ else
+ outGraphCounter.m_ElementCount++;
+
+ const char *theIdStr;
+ inReader.Att("id", theIdStr);
+ const char *theClassStr;
+ inReader.Att("class", theClassStr);
+
+ // For Behavior, we are adding a string attribute ATTRIBUTE_BEHAVIORSCRIPTS
+ if (AreEqual(theTypeStr, "Behavior") && !IsTrivial(theClassStr)) {
+ ++theClassStr; // remove the '#'
+ TIdSourcePathMap::iterator theSourcePathIter = m_IdScriptMap.find(theClassStr);
+ if (theSourcePathIter != m_IdScriptMap.end()) {
+ outGraphCounter.m_AttributeCount++;
+ outGraphCounter.m_StringAttrCount++;
+ }
+ }
+ SElementData *theData = m_ParseElementManager.FindElementData(theIdStr);
+
+ if (theData) {
+ TAttrMap &thePropertyMap = theData->m_PropertyMap;
+
+ // TODO: Maybe we should make m_IdAttributesMap only stores those valid attributes and
+ // also those attributes that already converted to Runtime type (e.g. position to
+ // position.x .y .z )
+ // then we can really stop calling all the IsValidAttribute all over the place
+ // and we can simple just use the size of the vector here.
+ for (TAttrMap::iterator theIter = thePropertyMap.begin(), theEnd = thePropertyMap.end();
+ theIter != theEnd; ++theIter) {
+ if (theIter->second.m_ElementFlag == false)
+ continue;
+ TStrType thePropertyName(theIter->first);
+ outGraphCounter.m_AttributeCount += theIter->second.m_Arity;
+ if (IsStringType(theIter->second.m_DataType))
+ outGraphCounter.m_StringAttrCount += 1;
+ }
+ }
+
+ DoGraphSectionCount(inReader, outGraphCounter);
+ }
+}
+
+void CUIPParserImpl::DoLogicSectionCount(qt3dsdm::IDOMReader &inReader,
+ SLogicSectionCount &outLogicCounter)
+{
+ IDOMReader::Scope __logicCountScope(inReader);
+
+ if (inReader.MoveToFirstChild("Logic")) {
+ for (bool theResult = inReader.MoveToFirstChild("State"); theResult;
+ theResult = inReader.MoveToNextSibling("State")) {
+ DoStateSectionCount(inReader, 0, outLogicCounter);
+ }
+ }
+}
+
+void CUIPParserImpl::DoStateSectionCount(qt3dsdm::IDOMReader &inReader, Q3DStudio::INT32 inStateIndex,
+ SLogicSectionCount &outLogicCounter)
+{
+ IDOMReader::Scope __slideCountScope(inReader);
+
+ outLogicCounter.m_SlideCount++;
+
+ INT32 theChildSlideCount = inReader.CountChildren("State");
+ outLogicCounter.m_SlideElementCount++; // this slide is also an element
+ Q3DStudio::INT32 theChildStateIndex(inStateIndex + 1);
+
+ for (bool theResult = inReader.MoveToFirstChild(); theResult;
+ theResult = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "State")) {
+ DoStateSectionCount(inReader, theChildStateIndex, outLogicCounter);
+ ++theChildStateIndex;
+ } else if (AreEqual(inReader.GetNarrowElementName(), "Add")
+ || AreEqual(inReader.GetNarrowElementName(), "Set")) {
+ // SlideMultipler is used as follows:
+ // For every element, animation or action, the slide is used to turn on/off them
+ // Hence, if it is inside master, it will have an entry in the master and all the child
+ // slides in the SlideManager ( hence, theChildSlideCount + 1 )
+ // if it is local, it will have an entry in the master and it's slide, ( thus 2 )
+ // the assumption made here is that State in uip is definitely 2 level, hence if it has
+ // no child slides, it is definitely master
+ INT32 theSlideMultiplier;
+ if (theChildSlideCount == 0)
+ theSlideMultiplier = 2;
+ else
+ theSlideMultiplier = theChildSlideCount + 1;
+ DoRefSectionCount(inReader, theSlideMultiplier, inStateIndex, outLogicCounter);
+ }
+ }
+}
+
+//==============================================================================
+/**
+ * @ param inNumSlideMultiplier To know how this is used, see comments on the place
+ *where SlideMultipler is calculated
+ */
+void CUIPParserImpl::DoRefSectionCount(qt3dsdm::IDOMReader &inReader, INT32 inNumSlideMultiplier,
+ INT32, SLogicSectionCount &outLogicCounter)
+{
+ IDOMReader::Scope __refCountScope(inReader);
+ const char8_t *theElementRef;
+ inReader.UnregisteredAtt("ref", theElementRef);
+ SElementData *theData(m_ParseElementManager.FindElementData(theElementRef));
+ if (theData == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ if (AreEqual(inReader.GetNarrowElementName(), "Add"))
+ outLogicCounter.m_SlideElementCount += inNumSlideMultiplier;
+
+ // There are cases where some attributes only appear in the local slide element, but not at the
+ // master slide. e.g. endTime.
+ // For these attributes, we must make sure that it is added to the slide element attribute of
+ // the master, so that everything will work correctly.
+ // This is done via the slide force flag on the element property object.
+ for (TAttrMap::iterator theIter = theData->m_PropertyMap.begin(),
+ theEnd = theData->m_PropertyMap.end();
+ theIter != theEnd; ++theIter) {
+ const char8_t *theAttValue = "";
+ bool hasAtt = inReader.UnregisteredAtt(theIter->first.c_str(), theAttValue);
+ if (theIter->second.m_SlideFlag == true
+ && (theIter->second.m_SlideForceFlag == true || hasAtt == true)) {
+ outLogicCounter.m_SlideAttributeCount += theIter->second.m_Arity * inNumSlideMultiplier;
+ }
+ // Strings we may still load regardless
+ if (hasAtt && IsStringType(theIter->second.m_DataType))
+ outLogicCounter.m_StringAttrCount += 1;
+ }
+ // Always add padding for now till I can figure out exactly why padding is needed
+ // and find a minimal way to handle it.
+ outLogicCounter.m_PaddingCount += inNumSlideMultiplier;
+}
+
+qt3ds::runtime::SSlidePlayInformation CUIPParserImpl::GetPlayMode(qt3dsdm::IDOMReader &inReader)
+{
+ using qt3ds::runtime::PlayMode;
+
+ qt3ds::runtime::SSlidePlayInformation thePlayInformation;
+ // Setup with the default value from the metadata
+ eastl::string thePlayMode = m_MetaData.GetPropertyValueString(m_MetaData.Register("Slide"),
+ m_MetaData.Register("playmode"));
+ PlayMode::Enum theMode = PlayMode::StopAtEnd;
+
+ if (thePlayMode == "Looping") {
+ theMode = PlayMode::Looping;
+ } else if (thePlayMode == "PingPong") {
+ theMode = PlayMode::PingPong;
+ } else if (thePlayMode == "Ping") {
+ theMode = PlayMode::Ping;
+ } else if (thePlayMode == "Play Through To...") {
+ theMode = PlayMode::PlayThroughTo;
+ }
+ thePlayInformation.m_PlayMode = theMode;
+
+ eastl::string theInitialPlayState = m_MetaData.GetPropertyValueString(
+ m_MetaData.Register("Slide"), m_MetaData.Register("initialplaystate"));
+ if (theInitialPlayState == "Pause")
+ thePlayInformation.m_Paused = true;
+
+ const char *theAttribute;
+ if (inReader.Att("playmode", theAttribute)) {
+ if (AreEqual(theAttribute, "Play Through To...")) {
+ thePlayInformation.m_PlayMode = PlayMode::PlayThroughTo;
+ } else if (AreEqual(theAttribute, "Stop at end")) {
+ thePlayInformation.m_PlayMode = PlayMode::StopAtEnd;
+ } else if (AreEqual(theAttribute, "Looping")) {
+ thePlayInformation.m_PlayMode = PlayMode::Looping;
+ } else if (AreEqual(theAttribute, "PingPong")) {
+ thePlayInformation.m_PlayMode = PlayMode::PingPong;
+ } else if (AreEqual(theAttribute, "Ping")) {
+ thePlayInformation.m_PlayMode = PlayMode::Ping;
+ }
+ }
+
+ if (inReader.Att("initialplaystate", theAttribute)) {
+ if (AreEqual(theAttribute, "Play"))
+ thePlayInformation.m_Paused = false;
+ else
+ thePlayInformation.m_Paused = true;
+ }
+
+ return thePlayInformation;
+}
+
+INT32 CUIPParserImpl::GetPlayThroughTo(INT32 inCurrentSlideIndex, qt3dsdm::IDOMReader &inReader)
+{
+ // Just hardcode it to Next since we know from the metadata the default is Next.
+ // If we want to query from MetaData, need to write accessor to get back SStringOrInt
+ INT32 thePlayThroughTo = inCurrentSlideIndex + 1;
+
+ const char *theAttribute;
+ if (inReader.Att("playthroughto", theAttribute) && *theAttribute) {
+ if (AreEqual(theAttribute, "Previous"))
+ thePlayThroughTo = inCurrentSlideIndex - 1;
+ else if (AreEqual(theAttribute, "Next"))
+ thePlayThroughTo = inCurrentSlideIndex + 1;
+ else if (theAttribute[0] == '#') {
+ theAttribute++;
+ SParseSlide *theSlide = m_ParseSlideManager.FindSlide(theAttribute);
+ if (theSlide)
+ thePlayThroughTo = theSlide->m_SlideIndex;
+ else
+ Q_ASSERT(!"Slide Not Found");
+ }
+ }
+
+ return thePlayThroughTo;
+}
+
+eastl::string CUIPParserImpl::GetSlideName(qt3dsdm::IDOMReader &inReader)
+{
+ eastl::string theSlideName;
+ if (!inReader.Att("name", theSlideName))
+ inReader.Att("id", theSlideName);
+ return theSlideName;
+}
+
+eastl::string CUIPParserImpl::GetSlideId(qt3dsdm::IDOMReader &inReader)
+{
+ eastl::string theSlideId;
+ if (!inReader.Att("id", theSlideId))
+ inReader.Att("component", theSlideId);
+ return theSlideId;
+}
+
+// In the event we added something to the slide, we return the element data.
+SElementData *CUIPParserImpl::AddSlideElement(IPresentation &inPresentation, bool inMaster,
+ qt3dsdm::IDOMReader &inReader, INT32 *outMaxTime)
+{
+ ISlideSystem &theBuilder = inPresentation.GetSlideSystem();
+
+ SElementData *theElementData = NULL;
+ const char8_t *theElementRef = "";
+ if (inReader.UnregisteredAtt("ref", theElementRef))
+ theElementData = m_ParseElementManager.FindElementData(theElementRef);
+
+ SElement *theElement = theElementData ? theElementData->m_Element : NULL;
+ if (theElement) {
+ if (m_SlideElements.find(theElement) == m_SlideElements.end()) {
+ const char *theEyeball;
+ bool theActiveFlag = !(
+ inMaster || (inReader.Att("eyeball", theEyeball) && AreEqual(theEyeball, "False")));
+
+ m_SlideElements.insert(theElement);
+ theBuilder.AddSlideElement(*theElement, theActiveFlag);
+ m_NumSlideElements++;
+ if (outMaxTime) {
+ INT32 theElementMaxTime = 0;
+ SElement *theParent = theElement->GetParent();
+ if (theParent && theParent->IsComponent() && theElement) {
+ // Ignore material durations (in practice this is always a material container)
+ qt3dsdm::ComposerObjectTypes::Enum composerType(
+ qt3dsdm::ComposerObjectTypes::Convert(theElementData->m_Type.c_str()));
+ if (composerType != qt3dsdm::ComposerObjectTypes::Material
+ && inReader.Att("endtime", theElementMaxTime) == false) {
+ theElementMaxTime = m_MetaData.GetPropertyValueLong(
+ theElementData->m_Type, m_MetaData.Register("endtime"),
+ theElementData->m_Class);
+ }
+ *outMaxTime = NVMax(*outMaxTime, theElementMaxTime);
+ }
+ }
+ } else
+ theElementData = NULL;
+ }
+
+ return theElementData;
+}
+
+BOOL CUIPParserImpl::LoadSlideElements(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader,
+ bool inMaster, SElement *inComponent, INT32 *outMaxTime)
+{
+ BOOL theSuccess = true;
+
+ {
+ IDOMReader::Scope __childScope(inReader);
+ eastl::string theSlideId = GetSlideId(inReader);
+ eastl::string theActionIdStr;
+ // Setup the add/set commands for this slide.
+ {
+ IDOMReader::Scope __slideScope(inReader);
+ // Load all the animations for this slide right now:
+
+ SParseSlide *theSlide = m_ParseSlideManager.FindSlide(theSlideId.c_str());
+ // All animations and actions added to the master slide are deactivated.
+ QT3DSU32 animActions = 0;
+ if (theSlide) {
+ bool canActivateFlag = !inMaster;
+ ISlideSystem &theBuilder = inPresentation.GetSlideSystem();
+ for (TInstanceIdAnimationMap::iterator
+ theInstAnimIter = theSlide->m_Animations.begin(),
+ theInstAnimEnd = theSlide->m_Animations.end();
+ theInstAnimIter != theInstAnimEnd; ++theInstAnimIter) {
+ const TAnimationList &theAnimList(theInstAnimIter->second);
+ for (QT3DSU32 theAnimIdx = 0, theAnimEnd = theAnimList.size();
+ theAnimIdx < theAnimEnd; ++theAnimIdx) {
+ theBuilder.AddSlideAnimAction(
+ true, theAnimList[theAnimIdx].m_Animation->m_AnimationIndex,
+ theAnimList[theAnimIdx].m_Active && canActivateFlag);
+ ++animActions;
+ }
+ }
+ // Build the actions for this slide.
+ for (TActionList::iterator theActionIter = theSlide->m_ActionList.begin(),
+ theActionEnd = theSlide->m_ActionList.end();
+ theActionIter != theActionEnd; ++theActionIter) {
+ SParseSlideActionEntry &theActionEntry(*theActionIter);
+ theActionIdStr.assign(theActionEntry.m_ActionId.c_str());
+ qt3ds::QT3DSI32 theActionIndex = m_ActionHelper->GetActionIndex(theActionIdStr);
+ for (qt3ds::QT3DSI32 idx = 0; idx < theActionEntry.m_ActionCount; ++idx) {
+ qt3ds::runtime::SSlideAnimAction *theSlideData =
+ theBuilder.AddSlideAnimAction(false, theActionIndex + idx,
+ theActionEntry.m_Active
+ && canActivateFlag);
+ theActionEntry.m_Actions[idx] = theSlideData;
+ ++animActions;
+ }
+ }
+
+ // qt3ds::NVFoundationBase& fnd(
+ // inPresentation.GetApplication().GetRuntimeFactory().GetFoundation() );
+ // fnd.error( QT3DS_TRACE, "Loading slide %s, %d anim actions", theSlideId.c_str(),
+ // animActions );
+ }
+ for (BOOL theResult = inReader.MoveToFirstChild(); theResult;
+ theResult = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "Add")
+ || AreEqual(inReader.GetNarrowElementName(), "Set")) {
+ SElementData *theAddedElement =
+ AddSlideElement(inPresentation, inMaster, inReader, outMaxTime);
+ if (theAddedElement && theAddedElement->m_Element) {
+ LoadSlideElementAttrs(inPresentation, inMaster, *theAddedElement, inReader,
+ inComponent);
+ // This can define actions or set the active
+ ProcessSlideAnimAction(inPresentation, theSlideId, inMaster, inReader);
+ }
+ }
+ }
+ }
+ // Pull add commands from child slides into master slide with active=false
+ // else things won't get reset when we switch slides.
+ {
+ // All child state adds go into this object with active set to false
+ IDOMReader::Scope __masterScope(inReader);
+ for (BOOL theResult = inReader.MoveToFirstChild("State"); theResult;
+ theResult = inReader.MoveToNextSibling("State")) {
+ IDOMReader::Scope __childScope(inReader);
+ for (BOOL theResult = inReader.MoveToFirstChild("Add"); theResult;
+ theResult = inReader.MoveToNextSibling("Add")) {
+ // Add the slide element, setting the active flag to false.
+ AddSlideElement(inPresentation, inMaster, inReader, outMaxTime);
+ }
+ }
+ }
+ // Pull add commands from master slide for objects in this slide.
+ // We do this after we process the add/set commands for this slide so that objects already
+ // added
+ // get ignored. If we do pull an object forward then we have to set all of the force-set
+ // properties as well
+ // as account for a possible end-time difference.
+ {
+ IDOMReader::Scope __childScope(inReader);
+ inReader.Leave();
+ if (AreEqual(inReader.GetNarrowElementName(), "State")) {
+ TPropertyDescAndValueList theProperties;
+ for (BOOL theResult = inReader.MoveToFirstChild("Add"); theResult;
+ theResult = inReader.MoveToNextSibling("Add")) {
+ theProperties.clear();
+ SElementData *theData =
+ AddSlideElement(inPresentation, inMaster, inReader, NULL);
+ if (theData) {
+ // Add all forced attributes to this slide.
+ for (TAttrMap::iterator theIter = theData->m_PropertyMap.begin(),
+ theEnd = theData->m_PropertyMap.end();
+ theIter != theEnd; ++theIter) {
+ if (theIter->second.m_SlideForceFlag) {
+ GetMetaAttribute(inPresentation, theProperties, theData->m_Type,
+ theIter->first, theData->m_Class,
+ theIter->second.m_PropertyNames);
+ }
+ }
+ ISlideSystem &theBuilder = inPresentation.GetSlideSystem();
+ for (TPropertyDescAndValueList::iterator theIter = theProperties.begin();
+ theIter != theProperties.end(); ++theIter) {
+ theBuilder.AddSlideAttribute(theIter->first.GetAttributeKey(),
+ theIter->second);
+ m_NumSlideAttributes++;
+ }
+
+ // Ensure the actual end time is accounted for.
+ if (outMaxTime && theData->m_Element) {
+ SElement *theParent = theData->m_Element->GetParent();
+ if (theParent && theParent->IsComponent()) {
+ // Ignore material durations
+ // (in practice this is always a material container)
+ qt3dsdm::ComposerObjectTypes::Enum composerType(
+ qt3dsdm::ComposerObjectTypes::Convert(theData->m_Type.c_str()));
+ if (composerType != qt3dsdm::ComposerObjectTypes::Material) {
+ long theoutMaxTime = (long)*outMaxTime;
+ long theMaxTime = m_MetaData.GetPropertyValueLong(
+ theData->m_Type, m_MetaData.Register("endtime"),
+ theData->m_Class);
+ *outMaxTime = NVMax(theoutMaxTime, theMaxTime);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return theSuccess;
+}
+
+BOOL CUIPParserImpl::LoadSlideElementAttrs(IPresentation &inPresentation, bool,
+ SElementData &inElementData, qt3dsdm::IDOMReader &inReader,
+ SElement *inComponent)
+{
+ ISlideSystem &theBuilder = inPresentation.GetSlideSystem();
+
+ TPropertyDescAndValueList theAttributeList;
+
+ const char8_t *theRef = "";
+ inReader.Att("ref", theRef);
+ if (theRef && *theRef && theRef[0] == '#')
+ ++theRef;
+ bool isSet = AreEqual(inReader.GetNarrowElementName(), "Set");
+ const char8_t *sourcepath;
+ if (inReader.UnregisteredAtt("sourcepath", sourcepath)) {
+ AddSourcePath(sourcepath);
+ theBuilder.AddSourcePath(sourcepath);
+ m_slideSourcePaths.push_back(QString::fromLatin1(sourcepath));
+ }
+
+ // We don't force set attributes when a given component has a set command within one of its
+ // child states. This happens in the case of actions (but nothing else).
+ bool shouldForce = inElementData.m_Element != inComponent;
+ for (TAttrMap::iterator theIter = inElementData.m_PropertyMap.begin(),
+ theEnd = inElementData.m_PropertyMap.end();
+ theIter != theEnd; ++theIter) {
+ const char8_t *theAttValue = "";
+ bool hasAtt = inReader.UnregisteredAtt(theIter->first, theAttValue);
+ QT3DSU32 previousListSize = theAttributeList.size();
+ if (hasAtt == false) {
+ // StartTime and EndTime in Master Slide are useless, so set it to the value in the
+ // metadata.
+ // if we look at the uip file, if the element doesn't have endTime, it means is 10000ms,
+ // and not really the value in the master slide
+ // this make it special from other attributes
+ if (theIter->second.m_SlideForceFlag && shouldForce)
+ GetMetaAttribute(inPresentation, theAttributeList, inElementData.m_Type,
+ theIter->first, inElementData.m_Class,
+ theIter->second.m_PropertyNames);
+ } else {
+ // Only use the attribute list from set blocks to set values into the slide, not from
+ // add attributes
+ // This isn't completely correct
+ GetAttributeList(inPresentation, theAttributeList, inElementData.m_Type, theIter->first,
+ inElementData.m_Class, theAttValue, theIter->second.m_PropertyNames);
+ }
+ if (isSet == false && theIter->second.m_SlideForceFlag == false) {
+ if (inElementData.m_Element != NULL && theIter->second.m_ElementFlag) {
+ for (QT3DSU32 idx = previousListSize, end = theAttributeList.size(); idx < end;
+ ++idx) {
+ UVariant *theValue = inElementData.m_Element->FindPropertyValue(
+ theAttributeList[idx].first.m_Name);
+ if (theValue) {
+ *theValue = theAttributeList[idx].second;
+ }
+ }
+ }
+ theAttributeList.resize(previousListSize);
+ }
+ }
+ for (TPropertyDescAndValueList::iterator theIter = theAttributeList.begin();
+ theIter != theAttributeList.end(); ++theIter) {
+ theBuilder.AddSlideAttribute(theIter->first.GetAttributeKey(), theIter->second);
+ m_NumSlideAttributes++;
+ }
+
+ return TRUE;
+}
+
+void CUIPParserImpl::LoadAnimationTrack(IPresentation &inPresentation, SElementData &inElementData,
+ SParseSlideAnimationEntry &inAnimation)
+{
+ SElementPropertyInfo *theInfo =
+ m_ParseElementManager.FindProperty(inElementData, inAnimation.m_PropertyName);
+ if (theInfo == NULL)
+ return;
+ UINT32 theHashedKey = inAnimation.m_PropertyHash;
+ bool theIsDynamic = inAnimation.m_IsDynamic;
+ INT32 theIndex = inPresentation.GetAnimationSystem().CreateAnimationTrack(
+ *inElementData.m_Element, theHashedKey, theIsDynamic);
+ inAnimation.m_AnimationIndex = theIndex;
+ m_NumAnimationTracks++;
+ bool isRotation = theInfo->m_AdditionalType == ERuntimeAdditionalMetaDataTypeRotation;
+ LoadAnimationKeys(inPresentation, inAnimation, isRotation);
+}
+
+void CUIPParserImpl::LoadAnimationKeys(IPresentation &inPresentation,
+ const SParseSlideAnimationEntry &inAnimation,
+ bool inIsRotation)
+{
+
+ NVConstDataRef<qt3ds::QT3DSF32> theFloatValues(inAnimation.m_KeyframeData.data(),
+ (qt3ds::QT3DSU32)inAnimation.m_KeyframeData.size());
+ switch (inAnimation.m_AnimationType) {
+ case SParseSlideAnimationTypes::Linear:
+ LoadLinearKeys(inPresentation, theFloatValues, inIsRotation);
+ break;
+ case SParseSlideAnimationTypes::Bezier:
+ LoadBezierKeys(inPresentation, theFloatValues, inIsRotation);
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ case SParseSlideAnimationTypes::EaseInOut:
+ LoadEaseInOutKeys(inPresentation, theFloatValues, inIsRotation);
+ break;
+ }
+}
+
+BOOL CUIPParserImpl::LoadBezierKeys(IPresentation &inPresentation, NVConstDataRef<float> &inValues,
+ bool inIsRotation)
+{
+ QT3DS_ASSERT(inValues.size() % 6 == 0);
+ if (inValues.size() % 6 != 0)
+ return FALSE;
+
+ IAnimationSystem &theBuilder = inPresentation.GetAnimationSystem();
+
+ float theTime;
+ float theValue;
+ float theC1Time;
+ float theC1Value;
+ float theC2Time;
+ float theC2Value;
+
+ const float *theIter = inValues.begin();
+
+ long theNumKeys = inValues.size() / 6;
+ QT3DS_ASSERT(theNumKeys > 0);
+ for (long theIndex = 0; theIndex < theNumKeys; ++theIndex) {
+ theTime = *theIter * 1000.0f;
+ ++theIter;
+ theValue = *theIter;
+ ++theIter;
+ ++theIter; // just increment the iterator, C2Time is set below
+ ++theIter; // just increment the iterator, C2Value is set below
+ theC1Time = *theIter * 1000.0f;
+ ++theIter;
+ theC1Value = *theIter;
+ ++theIter;
+
+ if (theIndex == theNumKeys - 1) {
+ // Last keyframe
+ theC2Time = 0.0f;
+ theC2Value = 0.0f;
+ } else {
+ theC2Time = *(theIter + 2) * 1000.0f; // access the next inTangentTime
+ theC2Value = *(theIter + 3); // access the next inTangentValue
+ }
+
+ if (inIsRotation) {
+ TORAD(theValue);
+ TORAD(theC1Value);
+ TORAD(theC2Value);
+ }
+
+ theBuilder.AddKey(theTime, theValue, theC1Time, theC1Value, theC2Time, theC2Value);
+ m_NumAnimationKeys++;
+ }
+ return TRUE;
+}
+
+BOOL CUIPParserImpl::LoadLinearKeys(IPresentation &inPresentation, NVConstDataRef<float> &inValues,
+ bool inIsRotation)
+{
+ QT3DS_ASSERT(inValues.size() % 2 == 0);
+ if (inValues.size() % 2 != 0)
+ return FALSE;
+
+ const float *theIter = inValues.begin();
+
+ long theNumKeys = inValues.size() / 2;
+ float *theEaseInOutValues = new float[theNumKeys * 4];
+ float *theEaseInOutPtr = theEaseInOutValues;
+ for (long theKeyIndex = 0; theKeyIndex < theNumKeys; ++theKeyIndex) {
+ *theEaseInOutPtr++ = *theIter++;
+ *theEaseInOutPtr++ = *theIter++;
+ *theEaseInOutPtr++ = 0.0f;
+ *theEaseInOutPtr++ = 0.0f;
+ }
+
+ NVConstDataRef<float> theFloatValues =
+ NVConstDataRef<float>(theEaseInOutValues, theNumKeys * 4);
+ BOOL theStatus = LoadEaseInOutKeys(inPresentation, theFloatValues, inIsRotation);
+
+ delete[] theEaseInOutValues;
+
+ return theStatus;
+}
+
+CUIPParserImpl::SEaseInEaseOutKeyframe CUIPParserImpl::ParseEaseInOutKey(const float *&inFloatIter)
+{
+ CUIPParserImpl::SEaseInEaseOutKeyframe theKeyframe;
+ theKeyframe.m_Time = *inFloatIter;
+ ++inFloatIter;
+ theKeyframe.m_Value = *inFloatIter;
+ ++inFloatIter;
+ theKeyframe.m_EaseIn = *inFloatIter;
+ ++inFloatIter;
+ theKeyframe.m_EaseOut = *inFloatIter;
+ ++inFloatIter;
+ return theKeyframe;
+}
+
+BOOL CUIPParserImpl::LoadEaseInOutKeys(IPresentation &inPresentation,
+ NVConstDataRef<float> &inValues, bool inIsRotation)
+{
+ QT3DS_ASSERT(inValues.size() % 4 == 0);
+ if (inValues.size() % 4 != 0)
+ return FALSE;
+
+ long theNumKeys = inValues.size() / 4;
+
+ float *theBezierValues = new float[theNumKeys * 6];
+ float *theBezierPtr = theBezierValues;
+
+ SEaseInEaseOutKeyframe thePreviousKeyframe;
+ thePreviousKeyframe.m_Value = 0.0f;
+ SEaseInEaseOutKeyframe theCurrentKeyframe;
+ theCurrentKeyframe.m_Value = 0.0f;
+ SEaseInEaseOutKeyframe theNextKeyframe;
+ theNextKeyframe.m_Value = 0.0f;
+
+ const float *theIter = inValues.begin();
+
+ if (theNumKeys > 0) {
+ theCurrentKeyframe = ParseEaseInOutKey(theIter);
+ float *theNextValuePtr = NULL;
+ float theNextValue;
+
+ if (theNumKeys > 1) {
+ theNextKeyframe = ParseEaseInOutKey(theIter);
+ theNextValue = theNextKeyframe.m_Value;
+ theNextValuePtr = &theNextValue;
+ }
+ CreateBezierKeyframeFromEaseInEaseOutKeyframe(NULL, theCurrentKeyframe, theNextValuePtr,
+ theBezierPtr);
+ }
+
+ for (long theKeyIndex = 1; theKeyIndex < theNumKeys; ++theKeyIndex) {
+ thePreviousKeyframe = theCurrentKeyframe;
+ theCurrentKeyframe = theNextKeyframe;
+
+ float theLastValue = thePreviousKeyframe.m_Value;
+ float *theNextValuePtr = NULL;
+ float theNextValue;
+ if (theKeyIndex + 1 < theNumKeys) {
+ theNextKeyframe = ParseEaseInOutKey(theIter);
+ theNextValue = theNextKeyframe.m_Value;
+ theNextValuePtr = &theNextValue;
+ }
+ CreateBezierKeyframeFromEaseInEaseOutKeyframe(&theLastValue, theCurrentKeyframe,
+ theNextValuePtr, theBezierPtr);
+ }
+
+ NVConstDataRef<float> theFloatValues = NVConstDataRef<float>(theBezierValues, theNumKeys * 6);
+ BOOL theStatus = LoadBezierKeys(inPresentation, theFloatValues, inIsRotation);
+
+ delete[] theBezierValues;
+ return theStatus;
+}
+
+inline float AnimationClamp(float inLowerBound, float inUpperBound, float inValue)
+{
+ if (inValue < inLowerBound)
+ return inLowerBound;
+ if (inValue > inUpperBound)
+ return inUpperBound;
+ return inValue;
+}
+
+void CUIPParserImpl::CreateBezierKeyframeFromEaseInEaseOutKeyframe(
+ float *inPreviousValue, SEaseInEaseOutKeyframe &inCurrent, float *inNextValue,
+ float *&outBezierValues)
+{
+ float theValue = inCurrent.m_Value;
+ float theSeconds = inCurrent.m_Time;
+ float inSeconds = 0.f;
+ float inValue = 0.f;
+ float outSeconds = 0.f;
+ float outValue = 0.f;
+ const double oneThird = 1.0 / 3.0;
+ if (inPreviousValue) {
+ float thePercent = 1.0f - AnimationClamp(0.0f, 1.0f, inCurrent.m_EaseIn / 100.f);
+ double theAmount = 1.0f - thePercent * oneThird;
+ inValue = *inPreviousValue + (float)(((inCurrent.m_Value - *inPreviousValue) * theAmount));
+ }
+ if (inNextValue) {
+ float thePercent = 1.0f - AnimationClamp(0.0f, 1.0f, inCurrent.m_EaseOut / 100.f);
+ double theAmount = thePercent * oneThird;
+ outValue = (float)(inCurrent.m_Value + ((*inNextValue - inCurrent.m_Value) * theAmount));
+ }
+
+ *outBezierValues++ = theSeconds;
+ *outBezierValues++ = theValue;
+ *outBezierValues++ = inSeconds;
+ *outBezierValues++ = inValue;
+ *outBezierValues++ = outSeconds;
+ *outBezierValues++ = outValue;
+}
+
+BOOL CUIPParserImpl::ProcessSlideAnimAction(IPresentation &inPresentation, eastl::string &inSlideId,
+ bool inMaster, qt3dsdm::IDOMReader &inReader)
+{
+ IDOMReader::Scope __animationScope(inReader);
+
+ BOOL theStatus = true;
+
+ for (BOOL theResult = inReader.MoveToFirstChild("Action"); theResult;
+ theResult = inReader.MoveToNextSibling("Action")) {
+ // Get the active flag
+ const char *theEyeball;
+ bool theActiveFlag =
+ !(inMaster || (inReader.Att("eyeball", theEyeball) && AreEqual(theEyeball, "False")));
+ theStatus &= AddSlideAction(inPresentation, inSlideId, theActiveFlag, inReader);
+ }
+
+ return theStatus;
+}
+
+BOOL CUIPParserImpl::AddSlideAction(IPresentation &, eastl::string &inSlideId, bool inActive,
+ qt3dsdm::IDOMReader &inReader)
+{
+ SParseSlide *theSlide = m_ParseSlideManager.FindSlide(inSlideId.c_str());
+ if (theSlide == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ // Get the Action id
+ const char *theRef;
+ if (inReader.Att("ref", theRef)) {
+ theRef++; // remove the '#'
+ SParseSlideActionEntry *theEntry = m_ParseSlideManager.FindAction(*theSlide, theRef);
+ if (theEntry == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ for (qt3ds::QT3DSI32 actIdx = 0; actIdx < theEntry->m_ActionCount; ++actIdx) {
+ if (theEntry->m_Actions[actIdx])
+ theEntry->m_Actions[actIdx]->m_Active = inActive ? 1 : 0;
+ }
+ } else {
+ const char8_t *theActionId;
+ inReader.Att("id", theActionId);
+ SParseSlideActionEntry *theEntry = m_ParseSlideManager.FindAction(*theSlide, theActionId);
+ QT3DS_ASSERT(theEntry);
+ // Check to ensure this action was created.
+ (void)theEntry;
+ }
+
+ return TRUE;
+}
+
+bool CUIPParserImpl::IsStringType(ERuntimeDataModelDataType inDataType)
+{
+ if (inDataType == ERuntimeDataModelDataTypeStringRef
+ || inDataType == ERuntimeDataModelDataTypeString
+ || inDataType == ERuntimeDataModelDataTypeObjectRef)
+ return true;
+ return false;
+}
+
+SElementData *CUIPParserImpl::GetElementData(TStrType inElementName)
+{
+ return m_ParseElementManager.FindElementData(inElementName);
+}
+
+//==============================================================================
+/**
+ * Helper function to to get the SElement object from the element name
+ */
+SElementData *CUIPParserImpl::GetElementData(const char8_t *inElementName)
+{
+ const char8_t *theElementName(inElementName);
+ if (!IsTrivial(inElementName) && inElementName[0] == '#')
+ ++theElementName;
+ return GetElementData(m_MetaData.Register(theElementName));
+}
+
+SElement *CUIPParserImpl::GetElement(const char8_t *inElementName)
+{
+ SElementData *theData(GetElementData(inElementName));
+ if (theData)
+ return theData->m_Element;
+ return NULL;
+}
+
+SElementData *CUIPParserImpl::ParseObjectRef(const eastl::string &inObjectPath,
+ const char8_t *inOwnerId)
+{
+ TStrType theId(ParseObjectRefId(inObjectPath, inOwnerId));
+ return GetElementData(theId);
+}
+
+TStrType CUIPParserImpl::ParseObjectRefId(const eastl::string &inObjectPath,
+ const char8_t *inOwnerId)
+{
+ return m_ObjectRefHelper->ParseObjectRefId(inObjectPath, inOwnerId);
+}
+
+SElementAndType CUIPParserImpl::GetElementForID(const char *inElementName)
+{
+ SElementData *theData = m_ParseElementManager.FindElementData(inElementName);
+ if (theData == NULL)
+ return SElementAndType(UIPElementTypes::Unknown, NULL);
+
+ qt3dsdm::ComposerObjectTypes::Enum theComposerType(
+ qt3dsdm::ComposerObjectTypes::Convert(theData->m_Type.c_str()));
+ UIPElementTypes::Enum theUIPType(UIPElementTypes::Unknown);
+ switch (theComposerType) {
+ case qt3dsdm::ComposerObjectTypes::Scene:
+ theUIPType = UIPElementTypes::Scene;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Layer:
+ theUIPType = UIPElementTypes::Layer;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Group:
+ theUIPType = UIPElementTypes::Group;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Component:
+ theUIPType = UIPElementTypes::Component;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Camera:
+ theUIPType = UIPElementTypes::Camera;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Light:
+ theUIPType = UIPElementTypes::Light;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Model:
+ theUIPType = UIPElementTypes::Model;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Material:
+ theUIPType = UIPElementTypes::Material;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Image:
+ theUIPType = UIPElementTypes::Image;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Behavior:
+ theUIPType = UIPElementTypes::Behavior;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Text:
+ theUIPType = UIPElementTypes::Text;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Effect:
+ theUIPType = UIPElementTypes::Effect;
+ break;
+ case qt3dsdm::ComposerObjectTypes::CustomMaterial:
+ theUIPType = UIPElementTypes::CustomMaterial;
+ break;
+ case qt3dsdm::ComposerObjectTypes::ReferencedMaterial:
+ theUIPType = UIPElementTypes::ReferencedMaterial;
+ break;
+ case qt3dsdm::ComposerObjectTypes::RenderPlugin:
+ theUIPType = UIPElementTypes::RenderPlugin;
+ break;
+ case qt3dsdm::ComposerObjectTypes::Path:
+ theUIPType = UIPElementTypes::Path;
+ break;
+ case qt3dsdm::ComposerObjectTypes::PathAnchorPoint:
+ theUIPType = UIPElementTypes::PathAnchorPoint;
+ break;
+ case qt3dsdm::ComposerObjectTypes::SubPath:
+ theUIPType = UIPElementTypes::PathSubPath;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ return SElementAndType(theUIPType, theData->m_Element);
+}
+
+eastl::string CUIPParserImpl::ResolveReference(const char *inStringId, const char *inReference)
+{
+ SElementData *theData = ParseObjectRef(inReference, inStringId);
+ if (theData) {
+ return theData->m_Id.c_str();
+ }
+ return eastl::string();
+}
+
+IRuntimeMetaData &CUIPParserImpl::GetMetaData()
+{
+ return m_MetaData;
+}
+
+IUIPParser &IUIPParser::Create(const QString &inFileName, IRuntimeMetaData &inMetaData,
+ IInputStreamFactory &inFactory,
+ qt3ds::foundation::IStringTable &inStrTable)
+{
+ CUIPParserImpl &retval = *new CUIPParserImpl(inFileName, inMetaData, inFactory, inStrTable);
+ return retval;
+}
+}