summaryrefslogtreecommitdiffstats
path: root/src/uipparser
diff options
context:
space:
mode:
authorPasi Keränen <pasi.keranen@qt.io>2019-06-06 16:22:02 +0300
committerPasi Keränen <pasi.keranen@qt.io>2019-06-07 13:52:44 +0300
commitb4954701093739e7a4e54a0669f306922d0d4605 (patch)
tree73d71319a921234f6b507c9098fdc842f7fe06dc /src/uipparser
parent8548a5f5579e3eee7e5ae6b1f6901dcc8bfee19e (diff)
Long live the slayer!
Initial commit of OpenGL Runtime to repository. Based on SHA1 61823aaccc6510699a54b34a2fe3f7523dab3b4e of qt3dstudio repository. Task-number: QT3DS-3600 Change-Id: Iaeb80237399f0e5656a19ebec9d1ab3a681d8832 Reviewed-by: Pasi Keränen <pasi.keranen@qt.io>
Diffstat (limited to 'src/uipparser')
-rw-r--r--src/uipparser/Qt3DSIPresentation.h158
-rw-r--r--src/uipparser/Qt3DSUIPParser.h155
-rw-r--r--src/uipparser/Qt3DSUIPParserActionHelper.cpp738
-rw-r--r--src/uipparser/Qt3DSUIPParserActionHelper.h172
-rw-r--r--src/uipparser/Qt3DSUIPParserImpl.cpp2623
-rw-r--r--src/uipparser/Qt3DSUIPParserImpl.h679
-rw-r--r--src/uipparser/Qt3DSUIPParserObjectRefHelper.cpp1011
-rw-r--r--src/uipparser/Qt3DSUIPParserObjectRefHelper.h159
8 files changed, 5695 insertions, 0 deletions
diff --git a/src/uipparser/Qt3DSIPresentation.h b/src/uipparser/Qt3DSIPresentation.h
new file mode 100644
index 0000000..a9d3644
--- /dev/null
+++ b/src/uipparser/Qt3DSIPresentation.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#pragma once
+
+#include "Qt3DSEventCallbacks.h"
+
+namespace qt3ds {
+namespace runtime {
+ class IApplication;
+ class IActivityZone;
+ class IAnimationSystem;
+ class ISlideSystem;
+ class ILogicSystem;
+ class IParametersSystem;
+}
+}
+
+namespace qt3ds {
+namespace foundation {
+ class IStringTable;
+}
+}
+
+namespace Q3DStudio {
+
+class IComponentManager;
+class IEventManager;
+class IScene;
+class IScriptBridge;
+class CPresentationFrameData;
+class CTimePolicy;
+using qt3ds::runtime::ISlideSystem;
+using qt3ds::runtime::IAnimationSystem;
+using qt3ds::runtime::ILogicSystem;
+using qt3ds::runtime::IParametersSystem;
+
+// Method used to translate from presentation size to window size
+enum EScaleMode {
+ SCALEMODE_FREE, // Free scaling mode
+ SCALEMODE_EXACT, // Fixed presentation size
+ SCALEMODE_ASPECT, // Maintain aspect ratio
+ SCALEMODE_UNKNOWN, // ERROR! - Uninitialized scale mode
+};
+
+struct SPresentationSize
+{
+ SPresentationSize()
+ : m_Width(0)
+ , m_Height(0)
+ , m_ScaleMode(0)
+ {
+ }
+ UINT16 m_Width; // Native width of the presentation
+ UINT16 m_Height; // Native height of the presentation
+ UINT8 m_ScaleMode; // Presentation to window scale method
+ UINT8 m_Padding[3];
+};
+
+/**
+ * @interface IPresentation
+ * Base interface of the presentation.
+ */
+class IPresentation
+{
+public: // Construction
+ IPresentation() {}
+ virtual ~IPresentation() {}
+
+public: // Execution
+ virtual void ClearDirtyList() = 0;
+ virtual void PreUpdate(const TTimeUnit inGlobalTime) = 0;
+ virtual void BeginUpdate() = 0;
+ virtual void EndUpdate() = 0;
+ virtual void PostUpdate(const TTimeUnit inGlobalTime) = 0;
+
+public: // Bridge Control
+ virtual void SetScene(IScene *inScene) = 0;
+ virtual IScene *GetScene() const = 0;
+ virtual IScriptBridge *GetScriptBridgeQml() = 0;
+
+public: // Commands and Events
+ virtual void FireEvent(const TEventCommandHash inEventType, TElement *inTarget,
+ const UVariant *inArg1 = nullptr, const UVariant *inArg2 = nullptr,
+ const EAttributeType inType1 = ATTRIBUTETYPE_NONE,
+ const EAttributeType inType2 = ATTRIBUTETYPE_NONE) = 0;
+ virtual void FireCommand(const TEventCommandHash inEventType, TElement *inTarget,
+ const UVariant *inArg1 = nullptr, const UVariant *inArg2 = nullptr,
+ const EAttributeType inType1 = ATTRIBUTETYPE_NONE,
+ const EAttributeType inType2 = ATTRIBUTETYPE_NONE) = 0;
+ virtual void FlushEventCommandQueue(void) = 0;
+ virtual void ProcessEvent(SEventCommand &) = 0;
+
+public: // Manager Access
+ virtual IComponentManager &GetComponentManager() = 0;
+ virtual ISlideSystem &GetSlideSystem() = 0;
+ virtual IAnimationSystem &GetAnimationSystem() = 0;
+ virtual ILogicSystem &GetLogicSystem() = 0;
+ virtual IParametersSystem &GetParametersSystem() = 0;
+
+ virtual qt3ds::foundation::IStringTable &GetStringTable() = 0;
+ virtual qt3ds::runtime::IApplication &GetApplication() = 0;
+ virtual qt3ds::runtime::IActivityZone *GetActivityZone() = 0;
+
+public: // Hooks and callbacks
+ virtual void OnPresentationLoaded() = 0;
+
+public: // Full file path
+ virtual void SetFilePath(const CHAR *inPath) = 0;
+ virtual QString GetFilePath() const = 0;
+ virtual QString getProjectPath() const = 0;
+ virtual TElement *GetRoot() = 0;
+ virtual void SetRoot(TElement &inRoot) = 0;
+
+public: // Configuration access
+ virtual SPresentationSize GetSize() const = 0;
+ virtual void SetSize(const SPresentationSize &inSize) = 0;
+ virtual void SetElementPath(TElement &inElement, const char8_t *inPath) = 0;
+ virtual qt3ds::foundation::CRegisteredString GetElementPath(TElement &inElement) = 0;
+
+public: // Event Callbacks
+ virtual void RegisterEventCallback(TElement *inElement, const TEventCommandHash inEventHash,
+ const TEventCallback inCallback, void *inContextData) = 0;
+ virtual BOOL UnregisterEventCallback(TElement *inElement, const TEventCommandHash inEventHash,
+ const TEventCallback inCallback, void *inContextData) = 0;
+
+public: // FrameData access
+ virtual CPresentationFrameData &GetFrameData() = 0;
+};
+
+} // namespace Q3DStudio
diff --git a/src/uipparser/Qt3DSUIPParser.h b/src/uipparser/Qt3DSUIPParser.h
new file mode 100644
index 0000000..2b75f25
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParser.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "foundation/StringTable.h"
+#include <EASTL/string.h>
+
+namespace qt3ds {
+namespace state {
+ struct SSetAttribute;
+ namespace debugger {
+ class ISceneGraphRuntimeDebugger;
+ }
+}
+}
+
+namespace qt3ds {
+namespace render {
+ class IInputStreamFactory;
+}
+}
+
+//==============================================================================
+// Forwards
+//==============================================================================
+namespace qt3dsdm {
+class IDOMReader;
+class IStringTable;
+}
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+using namespace qt3ds::foundation;
+//==============================================================================
+// Forwards
+//==============================================================================
+class IRuntimeMetaData;
+class IPresentation;
+
+struct UIPElementTypes
+{
+ enum Enum {
+ Unknown = 0,
+ Scene = 1,
+ Node,
+ Layer,
+ Component,
+ Group,
+ Behavior,
+ Model,
+ Light,
+ Camera,
+ Image,
+ Material,
+ Text,
+ Effect,
+ RenderPlugin,
+ CustomMaterial,
+ ReferencedMaterial,
+ Path,
+ PathAnchorPoint,
+ PathSubPath,
+ };
+};
+
+struct SElementAndType
+{
+ UIPElementTypes::Enum m_Type;
+ TElement *m_Element;
+ SElementAndType(UIPElementTypes::Enum inType, TElement *elem)
+ : m_Type(inType)
+ , m_Element(elem)
+ {
+ }
+};
+
+// Ensure these elements exist and if the attribute isn't empty ensure the attribute is referenced.
+struct SElementAttributeReference
+{
+ eastl::string m_Path;
+ eastl::string m_Attribute;
+ SElementAttributeReference(const eastl::string &p, const eastl::string &a)
+ : m_Path(p)
+ , m_Attribute(a)
+ {
+ }
+};
+//==============================================================================
+/**
+ * @class CUIPParser
+ * @brief Class for parsing UIP file
+ */
+
+class IUIPParser : public NVReleasable
+{
+protected:
+ virtual ~IUIPParser() {}
+public: // Parse UIP file
+ virtual BOOL Load(IPresentation &inPresentation,
+ NVConstDataRef<SElementAttributeReference> inStateReferences) = 0;
+ virtual qt3dsdm::IDOMReader &GetDOMReader() = 0;
+ virtual IRuntimeMetaData &GetMetaData() = 0;
+ // Mapping back from file id to element id, needed to hook elements up to their respective
+ // parsed
+ // counterparts.
+ virtual SElementAndType GetElementForID(const char *inStringId) = 0;
+ virtual eastl::string ResolveReference(const char *inStringId, const char *inReferance) = 0;
+ // The rendering system needs to know every sourcepath found during parse of the UIP file
+ // so that it can do things like register images as opaque/transparent as well as preload
+ // mesh files (and possibly font files).
+ virtual NVConstDataRef<eastl::string> GetSourcePaths() const = 0;
+ virtual bool isIblImage(const eastl::string &sourcepath) const = 0;
+
+ virtual QVector<QString> GetSlideSourcePaths() const = 0;
+
+ // Creation function
+ static IUIPParser &Create(const QString &inFileName, IRuntimeMetaData &inMetaData,
+ qt3ds::render::IInputStreamFactory &inStreamFactory,
+ qt3ds::foundation::IStringTable &inStrTable);
+};
+
+} // namespace Q3DStudio
diff --git a/src/uipparser/Qt3DSUIPParserActionHelper.cpp b/src/uipparser/Qt3DSUIPParserActionHelper.cpp
new file mode 100644
index 0000000..ab6d751
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParserActionHelper.cpp
@@ -0,0 +1,738 @@
+/****************************************************************************
+**
+** 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 "Qt3DSUIPParserActionHelper.h"
+#include "Qt3DSUIPParserObjectRefHelper.h"
+#include "Qt3DSIPresentation.h"
+#include "Qt3DSCommandEventTypes.h"
+
+#include "Qt3DSDMPrefix.h"
+#include "Qt3DSDMXML.h"
+#include "Qt3DSDMWStrOpsImpl.h"
+#include "Qt3DSMetadata.h"
+#include "Qt3DSEulerAngles.h"
+#include "Qt3DSLogicSystem.h"
+#include "Qt3DSParametersSystem.h"
+
+using namespace qt3dsdm;
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CUIPParserActionHelper::CUIPParserActionHelper(CUIPParserImpl *inUIPParser,
+ CUIPParserObjectRefHelper *inObjRefHelper,
+ IRuntimeMetaData &inMetaData)
+ : m_UIPParser(inUIPParser)
+ , m_ObjRefHelper(inObjRefHelper)
+ , m_MetaData(inMetaData)
+{
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CUIPParserActionHelper::~CUIPParserActionHelper()
+{
+}
+
+void CUIPParserActionHelper::CacheAction(qt3dsdm::IDOMReader &inReader,
+ const char8_t *inActionOwnerId)
+{
+ if (IsTrivial(inActionOwnerId))
+ return;
+
+ IDOMReader::Scope __childScope(inReader);
+
+ const char *theRef;
+ if (inReader.Att("ref", theRef)) {
+ // Ignore "ref" because we are only interested in new actions
+ return;
+ }
+
+ // Parse the action
+ SActionInfo theAction;
+ inReader.Att("id", theAction.m_Id);
+ theAction.m_Owner = inActionOwnerId;
+
+ const char *tempStr;
+ if (inReader.Att("triggerObject", tempStr))
+ theAction.m_TriggerObject = m_UIPParser->ParseObjectRefId(tempStr, inActionOwnerId);
+ inReader.Att("event", theAction.m_Event);
+ if (inReader.Att("targetObject", tempStr))
+ theAction.m_TargetObject = m_UIPParser->ParseObjectRefId(tempStr, inActionOwnerId);
+ if (inReader.Att("handler", tempStr)) {
+ theAction.m_Handler = tempStr;
+ CacheHandlerArguments(inReader, theAction);
+ }
+
+ // Only proceeds if we can find the elements
+ if (theAction.m_TargetObject.empty() || theAction.m_TriggerObject.empty()
+ || theAction.m_Owner.empty()) {
+ qCWarning(qt3ds::INVALID_OPERATION) << "Action invalid, id: " << theAction.m_Id.c_str();
+ return;
+ }
+
+ m_ActionMap[theAction.m_Id] = theAction;
+
+ // Build up logic tables to be processed by BuildAction later
+ // There are 2 tables involved:
+ // 1. The Listener-To-Events tables - multimap of each listener to all events it is listening to
+ // 2. The Listener-Event-To-Actions table - multimap of each listener-event pair to all actions
+ // it triggers
+ // note: The struct for Action is a pair of EventAction node and its owner
+ AddListenerEventPair(theAction.m_TriggerObject, theAction.m_Event);
+
+ SListenerEventNamePair theListenerEventPair(theAction.m_TriggerObject, theAction.m_Event);
+ TEventActionOwnerPair theLogicOwnerPair(theAction.m_Id, theAction.m_Owner);
+ m_ListenerEventActionsMap.insert(eastl::make_pair(theListenerEventPair, theLogicOwnerPair));
+}
+
+void CUIPParserActionHelper::AddListenerEventPair(eastl::string inListener,
+ const eastl::string &inEventName)
+{
+ // Check for dupes
+ TListenerEventsNameMap::iterator theStartItr = m_ListenerEventsNameMap.lower_bound(inListener);
+ TListenerEventsNameMap::iterator theEndItr = m_ListenerEventsNameMap.upper_bound(inListener);
+ for (; theStartItr != theEndItr; ++theStartItr) {
+ if (theStartItr->second == inEventName)
+ return;
+ }
+
+ m_ListenerEventsNameMap.insert(eastl::make_pair(inListener, inEventName));
+}
+
+void CUIPParserActionHelper::CacheHandlerArguments(qt3dsdm::IDOMReader &inReader,
+ SActionInfo &inAction)
+{
+ IDOMReader::Scope __handlerArgScope(inReader);
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ SHandlerArgumentInfo theArg;
+ inReader.Att("name", theArg.m_Name);
+ inReader.Att("value", theArg.m_Value);
+ inAction.m_HandlerArgs.push_back(theArg);
+ }
+ if (inAction.m_Handler == "Set Property") {
+ SHandlerArgumentInfo theHandlerArg1 = inAction.m_HandlerArgs[0];
+ SElementData *targetData = m_UIPParser->GetElementData(inAction.m_TargetObject.c_str());
+ if (targetData && !theHandlerArg1.m_Value.empty()) {
+ m_UIPParser->m_ParseElementManager.MarkAttributeAsReferenced(
+ *targetData, theHandlerArg1.m_Value.c_str());
+ }
+ }
+}
+
+SElement *CUIPParserActionHelper::GetElement(const eastl::string &inElementName)
+{
+ return m_UIPParser->GetElement(inElementName.c_str());
+}
+
+void CUIPParserActionHelper::GetActionSectionCount(
+ CUIPParserImpl::SActionSectionCount &outActionCount)
+{
+ // There are 2 tables involved:
+ // 1. The Listener-To-Events tables - multimap of each listener to all events it is listening to
+ // 2. The Listener-Event-To-Actions table - multimap of each listener-event pair to all actions
+ // it triggers
+ // note: The struct for Action is a pair of EventAction node and its owner
+
+ // Get the count to reserve
+ // Iterate through each listener
+ for (TListenerEventsNameMap::iterator theListenerItr = m_ListenerEventsNameMap.begin();
+ theListenerItr != m_ListenerEventsNameMap.end();) {
+ ++outActionCount.m_TriggerElementCount;
+
+ INT32 theEventCount =
+ static_cast<INT32>(m_ListenerEventsNameMap.count(theListenerItr->first));
+ for (INT32 theEventCounter = 0; theEventCounter < theEventCount;
+ ++theEventCounter, ++theListenerItr) {
+ ++outActionCount.m_TriggerEventCount;
+
+ // iterate through each listener-event pair
+ SListenerEventNamePair thePair(theListenerItr->first, theListenerItr->second);
+ TListenerEventActionsMap::iterator theActionsItr =
+ m_ListenerEventActionsMap.lower_bound(thePair);
+ INT32 theActionCount = static_cast<INT32>(m_ListenerEventActionsMap.count(thePair));
+ for (INT32 theActionCounter = 0; theActionCounter < theActionCount;
+ ++theActionCounter) {
+ eastl::string theActionId = theActionsItr->second.first;
+ outActionCount.m_ActionCount +=
+ GetActionCount(theActionId, outActionCount.m_StringAttrCount,
+ outActionCount.m_CustomParamCount);
+ ++theActionsItr;
+ }
+ }
+ }
+}
+
+void CUIPParserActionHelper::BuildActions(IPresentation &inPresentation)
+{
+ // Now we start building
+ // Iterate through each listener
+ for (TListenerEventsNameMap::iterator theListenerItr = m_ListenerEventsNameMap.begin();
+ theListenerItr != m_ListenerEventsNameMap.end();) {
+ TElement *theElement = GetElement(theListenerItr->first);
+
+ INT32 theEventCount =
+ static_cast<INT32>(m_ListenerEventsNameMap.count(theListenerItr->first));
+ for (INT32 theEventCounter = 0; theEventCounter < theEventCount;
+ ++theEventCounter, ++theListenerItr) {
+ UINT32 theEventName =
+ CHash::HashEventCommand(theListenerItr->second.c_str()); // UINT32: HashedName
+
+ // iterate through each listener-event pair
+ SListenerEventNamePair thePair(theListenerItr->first, theListenerItr->second);
+ TListenerEventActionsMap::iterator theActionsItr =
+ m_ListenerEventActionsMap.lower_bound(thePair);
+ INT32 theActionCount = static_cast<INT32>(m_ListenerEventActionsMap.count(thePair));
+ for (INT32 theActionCounter = 0; theActionCounter < theActionCount;
+ ++theActionCounter) {
+ eastl::string theActionId = theActionsItr->second.first;
+ if (theElement)
+ BuildAction(*theElement, theEventName, inPresentation, theActionId);
+ ++theActionsItr;
+ }
+ }
+ }
+}
+
+union UTypeConverter {
+ SAttributeKey m_Key;
+ INT32 m_IntData;
+};
+
+struct SActionAdder
+{
+ ILogicSystem &m_LogicSystem;
+ TElement &m_EventElement;
+ UINT32 m_EventName;
+ TElement *m_Owner;
+ TElement *m_Target;
+
+ SActionAdder(ILogicSystem &inLogicSystem, TElement &inEventElement, UINT32 inEventName,
+ TElement *inOwner, TElement *inTarget)
+ : m_LogicSystem(inLogicSystem)
+ , m_EventElement(inEventElement)
+ , m_EventName(inEventName)
+ , m_Owner(inOwner)
+ , m_Target(inTarget)
+ {
+ }
+
+ INT32 AddAction(TEventCommandHash inCommand, UINT32 inArg1 = 0, UINT32 inArg2 = 0)
+ {
+ UVariant arg1Var;
+ UVariant arg2Var;
+ arg1Var.m_INT32 = (INT32)inArg1;
+ arg2Var.m_INT32 = (INT32)inArg2;
+ return m_LogicSystem.AddAction(m_EventElement, m_EventName, m_Target, m_Owner, inCommand,
+ arg1Var, arg2Var, true);
+ }
+};
+
+void CUIPParserActionHelper::BuildAction(TElement &inElement, UINT32 inEventName,
+ IPresentation &inPresentation,
+ const eastl::string &inActionId)
+{
+ ILogicSystem &theLogicBuilder = inPresentation.GetLogicSystem();
+ IParametersSystem &theParamSystem = inPresentation.GetParametersSystem();
+ TActionMap::iterator theIter = m_ActionMap.find(inActionId);
+ if (theIter == m_ActionMap.end()) {
+ Q3DStudio_ASSERT(false);
+ qCWarning(qt3ds::INVALID_OPERATION) << "Can't find action, id: " << inActionId.c_str();
+ return;
+ }
+
+ SActionInfo theAction = theIter->second;
+ INT32 theAddActionIndex = -1; // the index of newly added action. If there are more than 1
+ // actions, the index points to the firstly added action.
+ SActionAdder theAdder(theLogicBuilder, inElement, inEventName, GetElement(theAction.m_Owner),
+ GetElement(theAction.m_TargetObject));
+
+ // The list of applicable handler is loaded from metadata xml file (if it is non-custom handler)
+ bool theIsCustomHandler = IsCustomHandler(theAction);
+
+ if (theIsCustomHandler) {
+ // Argument 1 - param table start index
+ INT32 paramGroup = theParamSystem.CreateParameterGroup();
+
+ // First param is the handler name we want to invoke for the custom action.
+ ExportCustomActionParameters(inPresentation, theParamSystem, paramGroup,
+ theAction.m_Handler.c_str(), ERuntimeDataModelDataTypeString,
+ ERuntimeAdditionalMetaDataTypeNone);
+
+ int theHandlerArgumentCount = theAction.m_HandlerArgs.size();
+ ERuntimeDataModelDataType theType;
+ ERuntimeAdditionalMetaDataType theAdditionalType;
+ // Actual handler parameters to pass in.
+ for (int theIndex = 0; theIndex < theHandlerArgumentCount; ++theIndex) {
+ GetHandlerArgumentType(theAction, theIndex, theType, theAdditionalType);
+ ExportCustomActionParameters(inPresentation, theParamSystem, paramGroup,
+ theAction.m_HandlerArgs[theIndex].m_Value.c_str(), theType,
+ theAdditionalType);
+ }
+ theAddActionIndex = theAdder.AddAction(COMMAND_CUSTOMACTION, (UINT32)paramGroup);
+ } else if (theAction.m_Handler == "Set Property") // Plain set action
+ {
+ // ArgumentOne - HashPropertyName
+ // ArgumentTwo - Value
+ SHandlerArgumentInfo theHandlerArg1 = theAction.m_HandlerArgs[0];
+ SHandlerArgumentInfo theHandlerArg2 = theAction.m_HandlerArgs[1];
+
+ eastl::string thePropertyName = theHandlerArg1.m_Value;
+ SElementData *theTargetObject =
+ m_UIPParser->GetElementData(theAction.m_TargetObject.c_str());
+ if (theTargetObject) {
+ SElementPropertyInfo *theProperty = m_UIPParser->m_ParseElementManager.FindProperty(
+ *theTargetObject, thePropertyName.c_str());
+ if (theProperty) {
+ TPropertyDescAndValueList theProperties;
+ ERuntimeDataModelDataType theType = theProperty->m_DataType;
+ ERuntimeAdditionalMetaDataType theAdditionalType = theProperty->m_AdditionalType;
+
+ m_UIPParser->GetAttributeList(inPresentation, theProperties, theType,
+ theAdditionalType, thePropertyName.c_str(),
+ theHandlerArg2.m_Value.c_str(),
+ theProperty->m_PropertyNames);
+
+ UINT32 theActionCount = theProperties.size();
+ Q3DStudio_ASSERT(theActionCount > 0);
+ for (UINT32 theActionIndex = 0; theActionIndex < theActionCount; ++theActionIndex) {
+ INT32 actionId = theAdder.AddAction(
+ COMMAND_SETPROPERTY, theProperties[theActionIndex].first.GetNameHash(),
+ theProperties[theActionIndex].second.m_INT32);
+ if (theActionIndex == 0)
+ theAddActionIndex = actionId;
+ }
+ }
+ }
+ } else if (theAction.m_Handler == "Fire Event") // Fire the selected event on the element
+ {
+ theAddActionIndex = theAdder.AddAction(
+ COMMAND_FIREEVENT, CHash::HashEventCommand(theAction.m_HandlerArgs[0].m_Value.c_str()));
+ } else if (theAction.m_Handler == "Go to Slide") // Switch slides
+ {
+ theAddActionIndex = theAdder.AddAction(
+ COMMAND_GOTOSLIDENAME, CHash::HashString(theAction.m_HandlerArgs[0].m_Value.c_str()));
+ } else if (theAction.m_Handler == "Next Slide") // Switch slides
+ {
+ theAddActionIndex = theAdder.AddAction(COMMAND_GOTONEXTSLIDE);
+ } else if (theAction.m_Handler == "Previous Slide") // Switch slides
+ {
+ theAddActionIndex = theAdder.AddAction(COMMAND_GOTOPREVIOUSSLIDE);
+ } else if (theAction.m_Handler == "Preceding Slide") // Switch slides
+ {
+ theAddActionIndex = theAdder.AddAction(COMMAND_BACKSLIDE);
+ } else if (theAction.m_Handler == "Play") // Play
+ {
+ theAddActionIndex = theAdder.AddAction(COMMAND_PLAY);
+ } else if (theAction.m_Handler == "Pause") // Pause
+ {
+ theAddActionIndex = theAdder.AddAction(COMMAND_PAUSE);
+ } else if (theAction.m_Handler == "Go to Time") // Goto Time
+ {
+ float theTime = 0;
+ const char *theValue = theAction.m_HandlerArgs[0].m_Value.c_str();
+ if (!IsTrivial(theValue))
+ WStrOps<float>().StrTo(theValue, theTime);
+
+ theAddActionIndex =
+ theAdder.AddAction(COMMAND_GOTOTIME, static_cast<UINT32>(theTime * 1000.0f));
+
+ bool thePause = false;
+ theValue = theAction.m_HandlerArgs[1].m_Value.c_str();
+ if (!IsTrivial(theValue))
+ WStrOps<bool>().StrTo(theValue, thePause);
+ theAdder.AddAction(thePause ? COMMAND_PAUSE : COMMAND_PLAY);
+ } else if (theAction.m_Handler == "Emit Signal") // Emit a signal
+ {
+ qt3ds::foundation::CStringHandle theStringHandle;
+ if (!theAction.m_HandlerArgs[0].m_Value.empty()) {
+ const char *theValue = theAction.m_HandlerArgs[0].m_Value.c_str();
+ theStringHandle = inPresentation.GetStringTable().GetHandle(theValue);
+ }
+ theAddActionIndex = theAdder.AddAction(COMMAND_EMITSIGNAL, theStringHandle.handle());
+ } else {
+ Q3DStudio_ASSERT(false); // what sort of crazy action is this?
+ }
+
+ if (theAddActionIndex > -1)
+ m_ActionIdentifierMap[theAction.m_Id] = theAddActionIndex;
+}
+
+INT32 CUIPParserActionHelper::GetActionCount(const eastl::string &inActionId)
+{
+ INT32 theStringAttrCount = 0;
+ INT32 theCustomParamCount = 0;
+ return GetActionCount(inActionId, theStringAttrCount, theCustomParamCount);
+}
+
+INT32 CUIPParserActionHelper::GetActionCount(const eastl::string &inActionId,
+ INT32 &outStringAttrCount, INT32 &outCustomParamCount)
+{
+ INT32 theActionCount = 0;
+
+ TActionMap::iterator theIter = m_ActionMap.find(inActionId);
+ if (theIter == m_ActionMap.end()) {
+ Q3DStudio_ASSERT(false);
+ qCWarning(qt3ds::INVALID_OPERATION) << "Can't find action, id: " << inActionId.c_str();
+ return theActionCount;
+ }
+
+ SActionInfo theAction = theIter->second;
+
+ // The list of applicable handler is loaded from metadata xml file (if it is non-custom handler)
+ bool theIsCustomHandler = IsCustomHandler(theAction);
+
+ if (theIsCustomHandler) {
+ theActionCount = 1;
+
+ // First param is the handler name we want to invoke for the custom action.
+ ++outStringAttrCount;
+ ++outCustomParamCount;
+
+ int theHandlerArgumentCount = theAction.m_HandlerArgs.size();
+ ERuntimeDataModelDataType theType;
+ ERuntimeAdditionalMetaDataType theAdditionalType;
+ // Actual handler parameters to pass in.
+ for (int theIndex = 0; theIndex < theHandlerArgumentCount; ++theIndex) {
+ GetHandlerArgumentType(theAction, theIndex, theType, theAdditionalType);
+ GetCustomActionParametersCount(theType, theAdditionalType, outStringAttrCount,
+ outCustomParamCount);
+ }
+ }
+
+ else if (theAction.m_Handler == "Set Property") // Plain set action
+ {
+ SHandlerArgumentInfo theHandlerArg1 = theAction.m_HandlerArgs[0];
+
+ eastl::string thePropertyName = theHandlerArg1.m_Value;
+ SElementData *theData = m_UIPParser->GetElementData(theAction.m_TargetObject.c_str());
+ if (theData) {
+ SElementPropertyInfo *thePropertyInfo =
+ m_UIPParser->m_ParseElementManager.GetOrCreateProperty(*theData,
+ thePropertyName.c_str());
+ if (thePropertyInfo) {
+ theActionCount = thePropertyInfo->m_Arity;
+ if (m_UIPParser->IsStringType(thePropertyInfo->m_DataType))
+ ++outStringAttrCount;
+ }
+ }
+ }
+
+ else if (theAction.m_Handler == "Fire Event" // Fire the selected event on the element
+ || theAction.m_Handler == "Go to Slide" // Switch slides
+ || theAction.m_Handler == "Next Slide" // Switch slides
+ || theAction.m_Handler == "Previous Slide" // Switch slides
+ || theAction.m_Handler == "Preceding Slide" // Switch slides
+ || theAction.m_Handler == "Play" // Play
+ || theAction.m_Handler == "Pause" // Pause
+ ) {
+ theActionCount = 1;
+ }
+
+ else if (theAction.m_Handler == "Go to Time") // Goto Time
+ {
+ theActionCount = 2;
+ } else if (theAction.m_Handler == "Play Sound") // Play Sound
+ {
+ theActionCount = 1;
+ ++outStringAttrCount;
+ } else if (theAction.m_Handler == "Emit Signal") // Emit Signal
+ {
+ theActionCount = 1;
+ ++outStringAttrCount;
+ } else {
+ Q3DStudio_ASSERT(false); // what sort of crazy action is this?
+ }
+
+ return theActionCount;
+}
+
+INT32 CUIPParserActionHelper::GetActionIndex(const eastl::string &inActionId)
+{
+ TActionIdentifierMap::iterator theFind = m_ActionIdentifierMap.find(inActionId);
+ if (theFind != m_ActionIdentifierMap.end())
+ return theFind->second;
+ Q3DStudio_ASSERT(false);
+ return -1;
+}
+
+bool CUIPParserActionHelper::IsCustomHandler(const SActionInfo &inAction)
+{
+ const char *theClass = m_ObjRefHelper->GetClass(inAction.m_TargetObject);
+ if (!IsTrivial(theClass))
+ return m_MetaData.IsCustomHandler(theClass, inAction.m_Handler.c_str());
+ return false;
+}
+
+void CUIPParserActionHelper::GetHandlerArgumentType(
+ const SActionInfo &inAction, int inArgumentIndex, ERuntimeDataModelDataType &outType,
+ ERuntimeAdditionalMetaDataType &outAdditionalType)
+{
+ const char *theClass = m_ObjRefHelper->GetClass(inAction.m_TargetObject);
+ return m_MetaData.GetHandlerArgumentType(theClass, inAction.m_Handler.c_str(),
+ inAction.m_HandlerArgs[inArgumentIndex].m_Name.c_str(),
+ outType, outAdditionalType);
+}
+
+void CUIPParserActionHelper::GetCustomActionParametersCount(
+ ERuntimeDataModelDataType inDataType, ERuntimeAdditionalMetaDataType inAdditionalType,
+ INT32 &outStringAttrCount, INT32 &outCustomParamCount)
+{
+ // This function should match ExportCustomActionParameters
+ switch (inDataType) {
+ case ERuntimeDataModelDataTypeFloat:
+ case ERuntimeDataModelDataTypeLong:
+ case ERuntimeDataModelDataTypeBool: {
+ outCustomParamCount += 1;
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat2: {
+ outCustomParamCount += 2;
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat3: {
+ if (inAdditionalType == ERuntimeAdditionalMetaDataTypeColor) {
+ // Append rgba
+ outCustomParamCount += 4;
+ } else {
+ // Append xyz
+ outCustomParamCount += 3;
+ }
+ break;
+ }
+ // default to string
+ default: {
+ outCustomParamCount += 1;
+ outStringAttrCount += 1;
+ }
+ }
+}
+
+namespace {
+
+ using qt3ds::foundation::IStringTable;
+
+ struct SCustomParameterParseInfoFloat
+ {
+ typedef float TParseType;
+ static const char8_t *Name() { return "float"; }
+ static TParseType Default() { return 0; }
+ static Q3DStudio::UVariant ToVariant(const TParseType &inParseType)
+ {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = inParseType;
+ return retval;
+ }
+ };
+
+ struct SCustomParameterParseInfoLong
+ {
+ typedef QT3DSI32 TParseType;
+ static const char8_t *Name() { return "long"; }
+ static TParseType Default() { return 0; }
+ static Q3DStudio::UVariant ToVariant(const TParseType &inParseType)
+ {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = static_cast<float>(inParseType);
+ return retval;
+ }
+ };
+
+ struct SCustomParameterParseInfoBool
+ {
+ typedef bool TParseType;
+ static const char8_t *Name() { return "bool"; }
+ static TParseType Default() { return false; }
+ static Q3DStudio::UVariant ToVariant(const TParseType &inParseType)
+ {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = static_cast<float>(inParseType);
+ return retval;
+ }
+ };
+
+ struct SCustomParameterParseInfoFloat2
+ {
+ typedef SFloat2 TParseType;
+ static const char8_t *Name() { return "float2"; }
+ static TParseType Default() { return SFloat2(0, 0); }
+ static QT3DSU32 NumParameters() { return 2; }
+ static Q3DStudio::UVariant ToVariant(QT3DSU32 inIdx, const TParseType &inParseType)
+ {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = static_cast<float>(inParseType[inIdx]);
+ return retval;
+ }
+ };
+
+ struct SCustomParameterParseInfoFloat3
+ {
+ typedef SFloat3 TParseType;
+ static const char8_t *Name() { return "float3"; }
+ static const char8_t **Extensions()
+ {
+ static const char8_t *retval[] = { ".x", ".y", ".z", NULL };
+ return retval;
+ }
+ static TParseType Default() { return SFloat3(0, 0, 0); }
+ static QT3DSU32 NumParameters() { return 3; }
+ static Q3DStudio::UVariant ToVariant(QT3DSU32 inIdx, const TParseType &inParseType)
+ {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = static_cast<float>(inParseType[inIdx]);
+ return retval;
+ }
+ };
+
+ struct SCustomParameterParseInfoColor
+ {
+ typedef SFloat3 TParseType;
+ static const char8_t *Name() { return "color4"; }
+ static TParseType Default() { return SFloat3(0, 0, 0); }
+ static QT3DSU32 NumParameters() { return 4; }
+ static Q3DStudio::UVariant ToVariant(QT3DSU32 inIdx, const TParseType &inParseType)
+ {
+ if (inIdx < 3) {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = static_cast<float>(inParseType[inIdx]) * 255.0f;
+ return retval;
+ } else {
+ Q3DStudio::UVariant retval;
+ retval.m_FLOAT = 255.0f;
+ return retval;
+ }
+ }
+ };
+
+ template <typename TParseInfo>
+ struct ParseParameter
+ {
+ void operator()(WCharTReader &inReader, const char *inValue, IParametersSystem &inSystem,
+ QT3DSI32 inGroupId)
+ {
+ typename TParseInfo::TParseType theValue = TParseInfo::Default();
+ if (!IsTrivial(inValue))
+ inReader.Read(theValue);
+ Q3DStudio::UVariant theVarValue = TParseInfo::ToVariant(theValue);
+ inSystem.AddParameter(inGroupId, CHash::HashString(TParseInfo::Name()), theVarValue);
+ }
+ };
+
+ template <typename TParseInfo>
+ struct ParseAggregateParameter
+ {
+ void operator()(WCharTReader &inReader, const char *inValue, IParametersSystem &inSystem,
+ QT3DSI32 inGroupId)
+ {
+ typename TParseInfo::TParseType theValue = TParseInfo::Default();
+ if (!IsTrivial(inValue))
+ inReader.ReadRef(NVDataRef<float>(&theValue[0], TParseInfo::NumParameters()));
+
+ for (QT3DSU32 idx = 0, end = TParseInfo::NumParameters(); idx < end; ++idx) {
+ Q3DStudio::UVariant theVarValue = TParseInfo::ToVariant(idx, theValue);
+ inSystem.AddParameter(inGroupId, CHash::HashString(TParseInfo::Name()),
+ theVarValue);
+ }
+ }
+ };
+}
+
+void CUIPParserActionHelper::ExportCustomActionParameters(
+ IPresentation &inPresentation, IParametersSystem &inParamSystem, QT3DSI32 inParamGroupId,
+ const char *inValue, ERuntimeDataModelDataType inDataType,
+ ERuntimeAdditionalMetaDataType inAdditionalType)
+{
+ // Create a destructible value
+ m_UIPParser->m_ValueBuffer.clear();
+ m_UIPParser->m_ValueBuffer.write(inValue, (QT3DSU32)strlen(inValue) + 1);
+ // Clear the destination buffer
+ m_UIPParser->m_TempBuffer.clear();
+ WCharTReader theReader((char8_t *)m_UIPParser->m_ValueBuffer.begin(), m_UIPParser->m_TempBuffer,
+ *m_UIPParser->GetDOMReader().GetStringTable());
+
+ // The function should match CUIPParserActionHelper::GetCustomActionParametersCount
+ switch (inDataType) {
+ case ERuntimeDataModelDataTypeFloat: {
+ ParseParameter<SCustomParameterParseInfoFloat>()(theReader, inValue, inParamSystem,
+ inParamGroupId);
+ break;
+ }
+ case ERuntimeDataModelDataTypeLong: {
+ ParseParameter<SCustomParameterParseInfoLong>()(theReader, inValue, inParamSystem,
+ inParamGroupId);
+ break;
+ }
+ case ERuntimeDataModelDataTypeBool: {
+ ParseParameter<SCustomParameterParseInfoBool>()(theReader, inValue, inParamSystem,
+ inParamGroupId);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat2: {
+ ParseAggregateParameter<SCustomParameterParseInfoFloat2>()(theReader, inValue,
+ inParamSystem, inParamGroupId);
+ break;
+ }
+ case ERuntimeDataModelDataTypeFloat3: {
+ if (inAdditionalType == ERuntimeAdditionalMetaDataTypeColor) {
+ ParseAggregateParameter<SCustomParameterParseInfoColor>()(
+ theReader, inValue, inParamSystem, inParamGroupId);
+ } else {
+ ParseAggregateParameter<SCustomParameterParseInfoFloat3>()(
+ theReader, inValue, inParamSystem, inParamGroupId);
+ }
+ break;
+ }
+ // default to string
+ default: {
+ UVariant theValue;
+ theValue.m_StringHandle = inPresentation.GetStringTable().GetHandle(inValue);
+ inParamSystem.AddParameter(inParamGroupId, CHash::HashString("string"), theValue);
+ break;
+ }
+ }
+}
+}
diff --git a/src/uipparser/Qt3DSUIPParserActionHelper.h b/src/uipparser/Qt3DSUIPParserActionHelper.h
new file mode 100644
index 0000000..3d9d44c
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParserActionHelper.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Qt3DSUIPParserImpl.h"
+
+namespace qt3ds {
+namespace runtime {
+ class IParametersSystem;
+}
+}
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+using qt3ds::runtime::IParametersSystem;
+//==============================================================================
+// Forwards
+//==============================================================================
+
+//==============================================================================
+/**
+ * @class CUIPParserActionHelper
+ * @brief Class for parsing UIP file - Action
+ */
+class CUIPParserActionHelper
+{
+ //==============================================================================
+ // Fields
+ //==============================================================================
+protected:
+ CUIPParserImpl *m_UIPParser;
+ CUIPParserObjectRefHelper *m_ObjRefHelper;
+ IRuntimeMetaData &m_MetaData; ///< Reference to Metadata
+
+ typedef eastl::map<eastl::string, INT32> TActionIdentifierMap; ///< Mapping of the string that
+ ///uniquely identify the action
+ ///to the index created
+ TActionIdentifierMap m_ActionIdentifierMap;
+
+ struct SHandlerArgumentInfo
+ {
+ eastl::string m_Name;
+ eastl::string m_Value;
+
+ SHandlerArgumentInfo() {}
+ };
+ typedef eastl::vector<SHandlerArgumentInfo> THandlerArguments; ///< List of handler arguments
+ struct SActionInfo
+ {
+ eastl::string m_Id;
+
+ // Where the action is added to
+ eastl::string m_Owner; // Absolute path of owner object
+
+ // Trigger object
+ eastl::string m_TriggerObject; // Absolute path of trigger object
+ eastl::string m_Event;
+
+ // Target object
+ eastl::string m_TargetObject; // Absolute path of target object
+ eastl::string m_Handler;
+ THandlerArguments m_HandlerArgs;
+
+ SActionInfo() {}
+ };
+ typedef eastl::map<eastl::string, SActionInfo> TActionMap; ///< Map of action id and action info
+
+ TActionMap m_ActionMap;
+
+ // There are 2 tables involved:
+ // 1. The Listener-To-Events tables - multimap of each listener to all events it is listening to
+ // 2. The Listener-Event-To-Actions table - multimap of each listener-event pair to all actions
+ // it triggers
+ // note: The struct for Action is a pair of EventAction node and its owner
+ struct SListenerEventNamePair
+ {
+ eastl::string m_Listener;
+ eastl::string m_Event;
+
+ SListenerEventNamePair(eastl::string inListener, const eastl::string &inEvent)
+ : m_Listener(inListener)
+ , m_Event(inEvent)
+ {
+ }
+
+ bool operator<(const SListenerEventNamePair &inListenerEventPair) const
+ {
+ if (m_Listener == inListenerEventPair.m_Listener)
+ return m_Event < inListenerEventPair.m_Event;
+ return m_Listener < inListenerEventPair.m_Listener;
+ }
+ };
+
+ typedef eastl::pair<eastl::string, eastl::string>
+ TEventActionOwnerPair; ///< One listener(source) can listen to multiple events
+ typedef eastl::multimap<eastl::string, eastl::string>
+ TListenerEventsNameMap; ///< One listener(source)-event pair can trigger multiple actions
+ typedef eastl::multimap<SListenerEventNamePair, TEventActionOwnerPair> TListenerEventActionsMap;
+
+ TListenerEventsNameMap m_ListenerEventsNameMap;
+ TListenerEventActionsMap m_ListenerEventActionsMap;
+
+ //==============================================================================
+ // Methods
+ //==============================================================================
+public: // Construction
+ CUIPParserActionHelper(CUIPParserImpl *inUIPParser, CUIPParserObjectRefHelper *inObjRefHelper,
+ IRuntimeMetaData &inMetaData);
+ virtual ~CUIPParserActionHelper();
+
+public:
+ void CacheAction(qt3dsdm::IDOMReader &inReader, const char8_t *inOwnerId);
+ void BuildActions(IPresentation &inPresentation);
+ void GetActionSectionCount(CUIPParserImpl::SActionSectionCount &outActionCount);
+ INT32 GetActionCount(const eastl::string &inActionId);
+ INT32 GetActionIndex(const eastl::string &inActionId);
+
+protected: // Action helper
+ void AddListenerEventPair(eastl::string inListener, const eastl::string &inEventName);
+ void CacheHandlerArguments(qt3dsdm::IDOMReader &inReader, SActionInfo &inAction);
+ void BuildAction(TElement &inElement, UINT32 inEventName, IPresentation &inPresentation,
+ const eastl::string &inActionId);
+ INT32 GetActionCount(const eastl::string &inActionId, INT32 &outStringAttrCount,
+ INT32 &outCustomParamCount);
+ bool IsCustomHandler(const SActionInfo &inAction);
+ void GetHandlerArgumentType(const SActionInfo &inAction, int inArgumentIndex,
+ ERuntimeDataModelDataType &outType,
+ ERuntimeAdditionalMetaDataType &outAdditionalType);
+ void GetCustomActionParametersCount(ERuntimeDataModelDataType inDataType,
+ ERuntimeAdditionalMetaDataType inAdditionalType,
+ INT32 &outStringAttrCount, INT32 &outCustomParamCount);
+ void ExportCustomActionParameters(IPresentation &inPresentation,
+ IParametersSystem &inParamSystem, QT3DSI32 inParamGroup,
+ const char *inDataValue, ERuntimeDataModelDataType inDataType,
+ ERuntimeAdditionalMetaDataType inAdditionalType);
+
+ inline SElement *GetElement(const eastl::string &inElementName);
+};
+
+} // namespace Q3DStudio
diff --git a/src/uipparser/Qt3DSUIPParserImpl.cpp b/src/uipparser/Qt3DSUIPParserImpl.cpp
new file mode 100644
index 0000000..79876ba
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParserImpl.cpp
@@ -0,0 +1,2623 @@
+/****************************************************************************
+**
+** 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, false);
+}
+
+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)) {
+ const char8_t *mapping;
+ bool ibl = false;
+ if (inReader.UnregisteredAtt("mappingmode", mapping)) {
+ if (QString::fromUtf8(mapping) == QLatin1String("Light Probe"))
+ ibl = true;
+ }
+ AddSourcePath(theSourcePath, ibl);
+ }
+
+ 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)) {
+ const char8_t *mapping;
+ bool ibl = false;
+ if (inReader.UnregisteredAtt("mappingmode", mapping)) {
+ if (QString::fromUtf8(mapping) == QLatin1String("Light Probe"))
+ ibl = true;
+ }
+ AddSourcePath(sourcepath, ibl);
+ 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;
+}
+}
diff --git a/src/uipparser/Qt3DSUIPParserImpl.h b/src/uipparser/Qt3DSUIPParserImpl.h
new file mode 100644
index 0000000..bca984b
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParserImpl.h
@@ -0,0 +1,679 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#pragma once
+/*
+This is the main file responsible for conversion from the uip format into the runtime's data format.
+The runtime works in a sort of global space so any object, be it an animation, action or element,
+once
+activated stays activated. Furthermore it is important that the runtime declare and set the fewest
+number
+of properties possible to still get the right answer. In order to achieve this the runtime relies
+on the
+rendering system to have the initial state of the entire scene graph, including state that is only
+"Add"
+commands declared in slides.
+
+Given that you understand master slide/ slide distinction, an accurate description would be to do
+this:
+1. Move all parse objects (actions, animations, elements) to be master objects and deactivate them.
+2. Running through the list of nonmaster slides, activate the objects on those slides that would be
+activated.
+3. Now remove properties that are both unreferenced and applied 1 or fewer times.
+
+
+The parsing system does this in reverse order so the passes look like:
+1. Load meta data information (scripts, effects) to have a complete meta data model.
+1. Build element graph. This is used during attribute lookup
+2. Figure out which attributes will be on the elements in the graph by resolving behavior
+references, action references and
+ Animations, and Set command attribute applications.
+
+ During this pass we also build the set of actions and animations which will appear on each
+slide. This involves both promoting
+ actions/animations that appear on the master slide to child slides and pulling
+animations/actions declared on all child slides
+ onto the master slide.
+
+3. Count the objects that we will need. The runtime currently requires fixed object counts that
+can't be exceeded
+ thus we have to effectively preallocate all runtime objects.
+
+4. Run through the file again and build the actual runtime datastructures. Actions and animations
+are built from
+ an intermediate memory representation but the set commands and element activations are built
+via running through
+ the file.
+
+
+Care needs to be taken so the runtime can survive poorly formed or just meaningless uip files.
+Studio is only *one*
+system for producing UIP files, clients are free to use code generates (like ruby scripts and such)
+to build their final
+uip files so we need to be careful that we are as robust as possible and can tolerate gracefully
+some level of incorrect
+uip file data.
+*/
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Qt3DSUIPParser.h"
+#include "Qt3DSTypes.h"
+#include "Qt3DSMetadata.h"
+#include "Qt3DSRenderInputStreamFactory.h"
+#include "Qt3DSSlideSystem.h"
+#include "Qt3DSDMDataTypes.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+#include <EASTL/map.h>
+#include <EASTL/set.h>
+#include <EASTL/hash_map.h>
+#include "Qt3DSElementSystem.h"
+#include "Qt3DSSlideSystem.h"
+
+namespace qt3ds {
+namespace render {
+ class IRefCountedInputStream;
+}
+}
+
+namespace qt3dsdm {
+class IDOMReader;
+class IDOMWriter;
+}
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class IPresentation;
+class SElementBuilder;
+class CContractBuilder;
+class CAnimationBuilder;
+class CLogicBuilder;
+class CSlideBuilder;
+class IRuntimeMetaData;
+class CUIPParserActionHelper;
+class CUIPParserObjectRefHelper;
+
+typedef eastl::vector<qt3ds::runtime::element::TPropertyDescAndValue> TPropertyDescAndValueList;
+
+using qt3ds::render::IInputStreamFactory;
+using qt3ds::render::IRefCountedInputStream;
+typedef NVScopedRefCounted<IRefCountedInputStream> TInputStreamPtr;
+typedef qt3ds::foundation::CRegisteredString TStrType;
+using qt3ds::runtime::element::SElement;
+
+struct SElementPropertyInfo
+{
+ enum Enum {
+ MaxArity = 4,
+ };
+ TStrType m_PropertyName;
+ ERuntimeDataModelDataType m_DataType;
+ ERuntimeAdditionalMetaDataType m_AdditionalType;
+ // Number of sub components of the property, 1-4
+ qt3ds::QT3DSU32 m_Arity;
+ qt3ds::QT3DSU32 m_PropertyHashes[MaxArity];
+ CRegisteredString m_PropertyNames[MaxArity];
+ bool m_ElementFlag; // True if this property exists on the element. Some properties do not.
+ bool m_SlideFlag; // True if this property exists on the slides at all.
+ // starttime,endtime are forced to be on the slides whether they are in the UIP or not.
+ bool m_SlideForceFlag; // True if this property is *forced* on the slides whether it needs to be
+ // there or not
+
+ SElementPropertyInfo(TStrType inPropName)
+ : m_PropertyName(inPropName)
+ , m_DataType(ERuntimeDataModelDataTypeNone)
+ , m_Arity(0)
+ , m_ElementFlag(false)
+ , m_SlideFlag(false)
+ , m_SlideForceFlag(false)
+ {
+ memZero(m_PropertyHashes, sizeof(m_PropertyHashes));
+ }
+ bool operator<(const SElementPropertyInfo &inOther) const
+ {
+ return m_PropertyName < inOther.m_PropertyName;
+ }
+};
+
+typedef eastl::hash_map<TStrType, SElementPropertyInfo> TAttrMap;
+
+struct SElementData
+{
+ SElement *m_Element;
+ TStrType m_Id;
+ TStrType m_Type;
+ TStrType m_Class;
+ TAttrMap m_PropertyMap;
+
+ SElementData(TStrType inId)
+ : m_Element(NULL)
+ , m_Id(inId)
+ {
+ }
+ void SetElement(SElement *inElement, TStrType inType, TStrType inClass)
+ {
+ m_Element = inElement;
+ m_Type = inType;
+ m_Class = inClass;
+ }
+};
+
+typedef eastl::hash_map<TStrType, SElementData> TIdElementMap;
+
+struct SParseElementManager
+{
+ IRuntimeMetaData &m_MetaData;
+ TIdElementMap m_ElementMap;
+ // Temporary variables for various algorithms
+ eastl::string m_Workspace;
+ eastl::vector<eastl::string> m_PropertyList;
+ qt3ds::foundation::IStringTable &m_StringTable;
+
+ SParseElementManager(IRuntimeMetaData &inMetaData, qt3ds::foundation::IStringTable &inStrTable)
+ : m_MetaData(inMetaData)
+ , m_StringTable(inStrTable)
+ {
+ }
+ TStrType RegisterStr(const char8_t *inStr);
+ SElementData &GetOrCreateElementData(const char8_t *inElemIdOrRef, const char8_t *inElemType,
+ const char8_t *inElemClassId);
+ SElementData *FindElementData(const char8_t *inIdOrRef);
+ // We don't allow creation of properties that don't exist in the meta data in the first place.
+ SElementPropertyInfo *GetOrCreateProperty(SElementData &inData, const char8_t *inPropertyName);
+ SElementPropertyInfo *GetOrCreateProperty(const char8_t *inIdOrRef, const char8_t *inElemType,
+ const char8_t *inElemClassId,
+ const char8_t *inPropertyName);
+ SElementPropertyInfo *FindProperty(SElementData &inElement, const char8_t *inPropertyName);
+ SElementPropertyInfo *FindProperty(const char8_t *inIdOrRef, const char8_t *inPropertyName);
+ eastl::pair<SElementPropertyInfo *, qt3ds::QT3DSU32>
+ FindPropertyWithSubIndex(SElementData &inElement, const char8_t *inPropertyName);
+ // Attribute marking stage; mark which attributes will be kept on elements at all.
+ void MarkAttributeAsReferenced(SElementData &inElement, const char8_t *inPropertyName);
+ void MarkAttributeAsReferenced(const char8_t *inElement, const char8_t *inPropertyName);
+ void MarkAllAttributesAsReferenced(SElementData &inElement, bool searchParent = false);
+};
+
+struct SParseSlideActionEntry
+{
+ TStrType m_SlideId;
+ TStrType m_ActionId;
+ qt3ds::QT3DSI32 m_ActionCount;
+ bool m_Active;
+ qt3ds::runtime::SSlideAnimAction *m_Actions[SElementPropertyInfo::MaxArity];
+
+ SParseSlideActionEntry(TStrType inSlideId, TStrType inActionId, qt3ds::QT3DSI32 inActionCount,
+ bool inActive)
+ : m_SlideId(inSlideId)
+ , m_ActionId(inActionId)
+ , m_ActionCount(inActionCount)
+ , m_Active(inActive)
+ {
+ memZero(m_Actions, sizeof(m_Actions));
+ }
+ SParseSlideActionEntry()
+ : m_ActionCount(0)
+ , m_Active(false)
+ {
+ }
+ // Partial equals, used for finding object in vector.
+ bool operator==(const SParseSlideActionEntry &inOther) const
+ {
+ return m_SlideId == inOther.m_SlideId && m_ActionId == inOther.m_ActionId;
+ }
+};
+
+typedef eastl::vector<SParseSlideActionEntry> TActionList;
+
+struct SParseSlideAnimationTypes
+{
+ enum Enum {
+ NoAnimation = 0,
+ Linear,
+ EaseInOut,
+ Bezier,
+ };
+};
+
+struct SParseSlideAnimationEntry
+{
+ TStrType m_SlideId;
+ TStrType m_InstanceId;
+ TStrType m_PropertyName;
+ qt3ds::QT3DSU32 m_PropertyHash;
+ qt3ds::QT3DSI32 m_AnimationIndex;
+ eastl::vector<float> m_KeyframeData;
+ SParseSlideAnimationTypes::Enum m_AnimationType;
+ bool m_IsDynamic;
+
+ SParseSlideAnimationEntry()
+ : m_AnimationIndex(-1)
+ , m_KeyframeData("")
+ , m_AnimationType(SParseSlideAnimationTypes::NoAnimation)
+ , m_IsDynamic(false)
+ {
+ }
+ SParseSlideAnimationEntry(TStrType inSlideId, TStrType inInstanceId, TStrType inPropertyName,
+ qt3ds::QT3DSU32 inPropHash, SParseSlideAnimationTypes::Enum inAnimType,
+ const float *inKeyframeData, qt3ds::QT3DSU32 inNumFloats, bool inIsDynamic)
+ : m_SlideId(inSlideId)
+ , m_InstanceId(inInstanceId)
+ , m_PropertyName(inPropertyName)
+ , m_PropertyHash(inPropHash)
+ , m_AnimationType(inAnimType)
+ , m_IsDynamic(inIsDynamic)
+ {
+ m_KeyframeData.insert(m_KeyframeData.begin(), inKeyframeData, inKeyframeData + inNumFloats);
+ }
+};
+
+struct SParseAnimationRef
+{
+ TStrType m_SlideId;
+ TStrType m_InstanceId;
+ TStrType m_PropertyName;
+ bool m_Active;
+ const SParseSlideAnimationEntry *m_Animation;
+
+ SParseAnimationRef(TStrType inSlideId, TStrType inInstanceId, TStrType inPropName,
+ const SParseSlideAnimationEntry *inAnimation, bool inActive)
+ : m_SlideId(inSlideId)
+ , m_InstanceId(inInstanceId)
+ , m_PropertyName(inPropName)
+ , m_Active(inActive)
+ , m_Animation(inAnimation)
+ {
+ }
+ SParseAnimationRef()
+ : m_Active(false)
+ , m_Animation(NULL)
+ {
+ }
+ // Partial equals, used for finding object in vector.
+ bool operator==(const SParseAnimationRef &inOther) const
+ {
+ return m_SlideId == inOther.m_SlideId && m_InstanceId == inOther.m_InstanceId
+ && m_PropertyName == inOther.m_PropertyName;
+ }
+};
+
+typedef eastl::vector<SParseAnimationRef> TAnimationList;
+
+typedef eastl::hash_map<TStrType, TAnimationList> TInstanceIdAnimationMap;
+
+struct SParseSlide
+{
+ TStrType m_SlideId;
+ qt3ds::QT3DSI32 m_SlideIndex;
+ TActionList m_ActionList;
+ TInstanceIdAnimationMap m_Animations;
+
+ SParseSlide(TStrType inId, qt3ds::QT3DSI32 inSlideIndex)
+ : m_SlideId(inId)
+ , m_SlideIndex(inSlideIndex)
+ {
+ }
+ SParseSlide() {}
+};
+
+typedef eastl::hash_map<TStrType, SParseSlide> TSlideIdToParseSlideMap;
+
+struct SParseSlideManager
+{
+ IRuntimeMetaData &m_MetaData;
+ SParseElementManager &m_ElementManager;
+ TSlideIdToParseSlideMap m_SlideMap;
+ eastl::vector<SParseSlideAnimationEntry *> m_Animations;
+ qt3ds::QT3DSI32 m_SlideAnimationCount;
+ qt3ds::QT3DSI32 m_AnimationKeyframeCount;
+ qt3ds::QT3DSI32 m_ActionCount;
+ eastl::vector<qt3ds::QT3DSF32> m_KeyframeParseFloatBuffer;
+ eastl::string m_KeyframeParseBuffer;
+
+ SParseSlideManager(IRuntimeMetaData &inMD, SParseElementManager &inElemMgr)
+ : m_MetaData(inMD)
+ , m_ElementManager(inElemMgr)
+ , m_SlideAnimationCount(0)
+ , m_AnimationKeyframeCount(0)
+ , m_ActionCount(0)
+ {
+ }
+ ~SParseSlideManager();
+ TStrType RegisterId(const char8_t *inStr);
+ TStrType RegisterStr(const char8_t *inStr) { return m_ElementManager.RegisterStr(inStr); }
+ SParseSlide &GetOrCreateSlide(const char8_t *inSlideId, qt3ds::QT3DSI32 inSlideIndex);
+ SParseSlide *FindSlide(const char8_t *inSlideId);
+ // Create an animation and reference that animation
+ void SetAnimationData(SParseSlide &inSlide, const char8_t *inInstanceId,
+ const char8_t *inPropertyName, const char8_t *inKeyframeData,
+ SParseSlideAnimationTypes::Enum inType, bool inIsDynamic,
+ bool inIsActive);
+ // Reference an animation.
+ void ReferenceAnimation(SParseSlide &inSlide, const SParseSlideAnimationEntry &inSource,
+ bool inIsActive);
+ TAnimationList *GetAnimationsForInstance(SParseSlide &inSlide, const char8_t *inInstanceId);
+ SParseSlideActionEntry &GetOrCreateAction(SParseSlide &inSlide, const char8_t *inActionId,
+ qt3ds::QT3DSI32 inActionCount, bool inEyeball);
+ SParseSlideActionEntry *FindAction(SParseSlide &inSlide, const char8_t *inActionId);
+};
+
+//==============================================================================
+/**
+ * @class CUIPParserImpl
+ * @brief Class for parsing UIP file
+ */
+class CUIPParserImpl : public IUIPParser
+{
+
+ typedef eastl::basic_string<char8_t> TNarrowStr;
+
+ //==============================================================================
+ // Fields
+ //==============================================================================
+protected:
+ std::shared_ptr<qt3dsdm::IDOMReader> m_DOMReader;
+ std::shared_ptr<qt3dsdm::IDOMWriter> m_DOMWriter;
+ IRuntimeMetaData &m_MetaData; ///< Reference to Metadata
+ IInputStreamFactory &m_InputStreamFactory;
+ SParseElementManager m_ParseElementManager; ///< Map of id, SElement*
+ SParseSlideManager m_ParseSlideManager;
+
+ CUIPParserActionHelper *m_ActionHelper; ///< Action Helper
+ CUIPParserObjectRefHelper *m_ObjectRefHelper; ///< Object Reference Helper
+
+ typedef eastl::set<SElement *> TAddedSlideElements;
+ TAddedSlideElements m_SlideElements; ///< Caching of slide elements added, so that we don't need
+ ///to pass this around
+
+ typedef eastl::map<eastl::string, eastl::string> TIdSourcePathMap;
+ TIdSourcePathMap m_IdScriptMap; ///< Map of the class id and script sourcepath
+
+ typedef eastl::map<eastl::string, eastl::string> TIdClassMap;
+ TIdClassMap m_IdClassMap; ///< Map of id and class reference
+
+ typedef eastl::set<eastl::string> TStringSet;
+ typedef eastl::vector<eastl::string> TStringVector;
+
+ TStringSet m_SourcePathSet;
+ TStringVector m_SourcePathList;
+ TStringSet m_iblSources;
+ QVector<QString> m_slideSourcePaths;
+
+ struct SElementRefCache
+ {
+ SElementData *m_Element;
+ eastl::string m_Name;
+ eastl::string m_Value;
+ };
+ eastl::vector<SElementRefCache> m_ElementRefCache; ///< Cache those element refs in the scene
+ ///graph that needs to be patch later
+
+ struct SEaseInEaseOutKeyframe
+ {
+ float m_Time;
+ float m_Value;
+ float m_EaseIn;
+ float m_EaseOut;
+ };
+
+ struct SGraphSectionCount
+ {
+ INT32 m_ElementCount;
+ INT32 m_ComponentCount;
+ INT32 m_AttributeCount;
+ INT32 m_StringAttrCount;
+
+ SGraphSectionCount()
+ : m_ElementCount(0)
+ , m_ComponentCount(0)
+ , m_AttributeCount(0)
+ , m_StringAttrCount(0)
+ {
+ }
+ };
+
+ struct SLogicSectionCount
+ {
+ INT32 m_SlideCount;
+ INT32 m_SlideElementCount;
+ INT32 m_SlideAttributeCount;
+ INT32 m_StringAttrCount;
+ INT32 m_PaddingCount;
+
+ SLogicSectionCount()
+ : m_SlideCount(0)
+ , m_SlideElementCount(0)
+ , m_SlideAttributeCount(0)
+ , m_StringAttrCount(0)
+ , m_PaddingCount(0)
+ {
+ }
+ };
+
+ struct SActionSectionCount
+ {
+ INT32 m_TriggerElementCount;
+ INT32 m_TriggerEventCount;
+ INT32 m_ActionCount;
+ INT32 m_StringAttrCount;
+ INT32 m_CustomParamCount;
+
+ SActionSectionCount()
+ : m_TriggerElementCount(0)
+ , m_TriggerEventCount(0)
+ , m_ActionCount(0)
+ , m_StringAttrCount(0)
+ , m_CustomParamCount(0)
+ {
+ }
+ };
+
+ long m_NumGraphElements; /// eclee testing only, must remove
+ long m_NumGraphComponents; /// eclee testing only, must remove
+ long m_NumGraphAttributes; /// eclee testing only, must remove
+ long m_NumSlides; /// eclee testing only, must remove
+ long m_NumSlideElements; /// eclee testing only, must remove
+ long m_NumSlideAttributes; /// eclee testing only, must remove
+ long m_NumAnimationTracks; /// eclee testing only, must remove
+ long m_NumAnimationKeys; /// eclee testing only, must remove
+ long m_NumSlideAnimations; /// eclee testing only, must remove
+ long m_NumSlideActions; /// klarinda testing only, must remove
+
+ // temporarily this is here
+ qt3ds::foundation::MemoryBuffer<RawAllocator> m_TempBuffer;
+ qt3ds::foundation::MemoryBuffer<RawAllocator> m_ValueBuffer;
+
+ IPresentation *m_CurrentPresentation;
+
+ //==============================================================================
+ // Methods
+ //==============================================================================
+public: // Construction
+ CUIPParserImpl(const QString &inFileName, IRuntimeMetaData &inMetaData,
+ IInputStreamFactory &inFactory, qt3ds::foundation::IStringTable &inStringTable);
+ virtual ~CUIPParserImpl();
+
+public: // Parse UIP file
+ BOOL Load(IPresentation &inPresentation,
+ NVConstDataRef<SElementAttributeReference> inStateReferences) override;
+ qt3dsdm::IDOMReader &GetDOMReader() override;
+ IRuntimeMetaData &GetMetaData() override;
+ SElementAndType GetElementForID(const char *inStringId) override;
+ eastl::string ResolveReference(const char *inStringId, const char *inReferance) override;
+ NVConstDataRef<eastl::string> GetSourcePaths() const override
+ {
+ return NVConstDataRef<eastl::string>(m_SourcePathList.data(), m_SourcePathList.size());
+ }
+ QVector<QString> GetSlideSourcePaths() const override
+ {
+ return m_slideSourcePaths;
+ }
+
+ bool isIblImage(const eastl::string &sourcepath) const override
+ {
+ return m_iblSources.find(sourcepath) != m_iblSources.end();
+ }
+
+protected: // Operation
+ BOOL LoadProjectSettings(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+ BOOL LoadClasses(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+ BOOL LoadGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+ BOOL LoadSceneGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader,
+ qt3ds::runtime::element::SElement *inNewStyleParent = NULL);
+ BOOL LoadLogic(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+ BOOL LoadStateGraph(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+
+protected: // Memory Counter
+ void ComputeAndReserveMemory(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader);
+ void DoGraphSectionCount(qt3dsdm::IDOMReader &inReader, SGraphSectionCount &outGraphCounter);
+ void DoLogicSectionCount(qt3dsdm::IDOMReader &inReader, SLogicSectionCount &outLogicCounter);
+ void DoStateSectionCount(qt3dsdm::IDOMReader &inReader, INT32 inSlideIndex,
+ SLogicSectionCount &outLogicCounter);
+ void DoRefSectionCount(qt3dsdm::IDOMReader &inReader, INT32 inNumSlideMultiplier,
+ INT32 inSlideIndex, SLogicSectionCount &outLogicCounter);
+
+protected: // Scene graph heler
+ void CacheGraphRequiredAttributes(qt3dsdm::IDOMReader &inReader);
+ BOOL CacheLogicRequiredAttributes(qt3dsdm::IDOMReader &inReader, qt3ds::QT3DSI32 inSlideIndex = 0,
+ SParseSlide *inParentSlide = NULL);
+ void CacheClassRequiredAttributes(qt3dsdm::IDOMReader &inReader);
+ void CacheClassSceneAttributes(qt3dsdm::IDOMReader &inReader);
+ void CacheClassStateAttributes(qt3dsdm::IDOMReader &inReader);
+ void AddElementRefToPatch(TPropertyDescAndValueList &outDescList, SElementData &inElement,
+ const char *inName, const char *inValue);
+ void PatchSceneElementRef();
+
+protected: // Slide helper
+ BOOL LoadState(IPresentation &inPresentation, SElement *inComponent, INT32 inSlideIndex,
+ qt3dsdm::IDOMReader &inReader);
+ qt3ds::runtime::SSlidePlayInformation GetPlayMode(qt3dsdm::IDOMReader &inReader);
+ INT32 GetPlayThroughTo(INT32 inCurrentSlideIndex, qt3dsdm::IDOMReader &inReader);
+ eastl::string GetSlideName(qt3dsdm::IDOMReader &inReader);
+ eastl::string GetSlideId(qt3dsdm::IDOMReader &inReader);
+ BOOL LoadSlideElements(IPresentation &inPresentation, qt3dsdm::IDOMReader &inReader,
+ bool inMaster, SElement *inComponent, INT32 *outMaxTime = NULL);
+ SElementData *AddSlideElement(IPresentation &inPresentation, bool inMaster,
+ qt3dsdm::IDOMReader &inReader, INT32 *outMaxTime = NULL);
+ BOOL LoadSlideElementAttrs(IPresentation &inPresentation, bool inMaster,
+ SElementData &inElementData, qt3dsdm::IDOMReader &inReader,
+ SElement *inComponent);
+ BOOL ProcessStateRef(IPresentation &inPresentation, SElement *inComponent, bool inMaster,
+ qt3dsdm::IDOMReader &inReader);
+
+protected: // Animation helper
+ void LoadAnimationTrack(IPresentation &inPresentation, SElementData &inElementData,
+ SParseSlideAnimationEntry &inAnimation);
+ void LoadAnimationKeys(IPresentation &inPresentation,
+ const SParseSlideAnimationEntry &inAnimation, bool inIsRotation);
+ BOOL LoadBezierKeys(IPresentation &inPresentation, NVConstDataRef<float> &inValues,
+ bool inIsRotation);
+ BOOL LoadLinearKeys(IPresentation &inPresentation, NVConstDataRef<float> &inValues,
+ bool inIsRotation);
+ BOOL LoadEaseInOutKeys(IPresentation &inPresentation, NVConstDataRef<float> &inValues,
+ bool inIsRotation);
+ SEaseInEaseOutKeyframe ParseEaseInOutKey(const float *&inFloatIter);
+ BOOL ProcessSlideAnimAction(IPresentation &inPresentation, eastl::string &inSlideId,
+ bool inMaster, qt3dsdm::IDOMReader &inReader);
+ BOOL AddSlideAction(IPresentation &inPresentation, eastl::string &inSlideId, bool inActive,
+ qt3dsdm::IDOMReader &inReader);
+ void CreateBezierKeyframeFromEaseInEaseOutKeyframe(float *inPreviousValue,
+ SEaseInEaseOutKeyframe &inCurrent,
+ float *inNextValue, float *&outBezierValues);
+
+protected: // Helper methods
+ bool IsStringType(ERuntimeDataModelDataType inDataType);
+ void GetAttributeList(IPresentation &inPresentation, TPropertyDescAndValueList &outDescList,
+ TStrType inType, TStrType inName, TStrType inClassId, const char *inValue,
+ CRegisteredString *inPropNameStrs);
+ void GetAttributeList(IPresentation &inPresentation, TPropertyDescAndValueList &outDescList,
+ ERuntimeDataModelDataType inDataType,
+ ERuntimeAdditionalMetaDataType inAdditionalType, const char *inName,
+ const char *inValue, CRegisteredString *inPropNameStrs);
+
+ SElementData *GetElementData(TStrType inElementName);
+ SElementData *GetElementData(const char8_t *inElementName);
+ SElement *GetElement(const char8_t *inElementName);
+ // Returns the data type and a boolean indicating if this attribute is actually used on a
+ // particular slide.
+ eastl::pair<ERuntimeDataModelDataType, bool>
+ GetAttributeType(const char8_t *inElementName, const char8_t *inPropertyName,
+ const SElementData &inElementData);
+ SElementData *ParseObjectRef(const eastl::string &inObjectPath, const char8_t *inOwnerId);
+ TStrType ParseObjectRefId(const eastl::string &inObjectPath, const char8_t *inOwnerId);
+
+ void GetMetaAttribute(IPresentation &inPresentation, TPropertyDescAndValueList &outDescList,
+ TStrType inType, TStrType inName, TStrType inClassId,
+ CRegisteredString *inAttStrNames);
+
+protected:
+ void AddFloatAttribute(TPropertyDescAndValueList &outDescList, CRegisteredString inAttStrName,
+ float &inValue);
+ void AddLongAttribute(TPropertyDescAndValueList &outDescList, CRegisteredString inAttStrName,
+ qt3ds::QT3DSI32 &inValue);
+ void AddBoolAttribute(TPropertyDescAndValueList &outDescList, CRegisteredString inAttStrName,
+ bool &inValue);
+ void AddFloat2Attribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString *inAttStrNames, qt3dsdm::SFloat2 &inValue);
+ void AddFloat3Attribute(TPropertyDescAndValueList &outDescList,
+ ERuntimeAdditionalMetaDataType inAdditionalType,
+ CRegisteredString *inAttStrNames, qt3dsdm::SFloat3 &inValue);
+ void AddFloat4Attribute(TPropertyDescAndValueList &outDescList,
+ ERuntimeAdditionalMetaDataType inAdditionalType,
+ CRegisteredString *inAttStrNames, qt3dsdm::SFloat4 &inValue);
+ void AddStringAttribute(IPresentation &inPresentation, TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, const char *inValue);
+ void AddElementRefAttribute(TPropertyDescAndValueList &outDescList,
+ CRegisteredString inAttStrName, SElement *inElement);
+
+ void AddSourcePath(const char *inValue, bool ibl)
+ {
+ if (m_SourcePathSet.find(inValue) == m_SourcePathSet.end()) {
+ m_SourcePathSet.insert(inValue);
+ m_SourcePathList.push_back(eastl::string(inValue));
+ }
+ if (ibl && m_iblSources.find(inValue) == m_iblSources.end())
+ m_iblSources.insert(inValue);
+ }
+
+public: //
+ void release() override { delete this; }
+
+ //==============================================================================
+ // Friends
+ //==============================================================================
+ friend class CUIPParserActionHelper;
+};
+
+} // namespace Q3DStudio
diff --git a/src/uipparser/Qt3DSUIPParserObjectRefHelper.cpp b/src/uipparser/Qt3DSUIPParserObjectRefHelper.cpp
new file mode 100644
index 0000000..4861a5d
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParserObjectRefHelper.cpp
@@ -0,0 +1,1011 @@
+/****************************************************************************
+**
+** 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 : 4100) // std::variant
+#pragma warning(disable : 4396) // specializer warning nonsense
+#endif
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Qt3DSUIPParserObjectRefHelper.h"
+
+#include "Qt3DSDMPrefix.h"
+#include "Qt3DSDMXML.h"
+#include "Qt3DSMetadata.h"
+using namespace qt3dsdm;
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+// Constants
+//==============================================================================
+static const char PATH_DELIMITER = '.'; // can only be single char!
+static const char PATH_LINE_END = '\n';
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CUIPParserObjectRefHelper::CUIPParserObjectRefHelper(IRuntimeMetaData &inMetaData)
+ : m_MetaData(inMetaData)
+ , m_MaterialStr(m_MetaData.Register("Material"))
+{
+ BuildImageNamePropertyList();
+
+ if (m_LayerImageIdToNameMap.empty()) {
+ {
+ TLightProbeAndNamePair theNamePair =
+ eastl::make_pair<eastl::string, eastl::string>("Layer_lightprobe", "lightprobe");
+ m_LayerImageIdToNameMap.insert(theNamePair);
+ }
+ {
+ TLightProbeAndNamePair theNamePair =
+ eastl::make_pair<eastl::string, eastl::string>("Layer_lightprobe2", "lightprobe2");
+ m_LayerImageIdToNameMap.insert(theNamePair);
+ }
+ }
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CUIPParserObjectRefHelper::~CUIPParserObjectRefHelper()
+{
+ // Delete SGraphNode
+ for (TGraphNodeMap::iterator theIter = m_GraphNodeMap.begin(); theIter != m_GraphNodeMap.end();
+ ++theIter)
+ delete theIter->second;
+ m_GraphNodeMap.clear();
+ m_RootNode = NULL;
+}
+
+namespace {
+ void StoreTopLevelAliasAttributes(
+ IDOMReader &inReader,
+ eastl::vector<eastl::pair<eastl::string, eastl::string>> &copiedAttributes)
+ {
+ for (eastl::pair<const char8_t *, const char8_t *> att = inReader.GetNarrowFirstAttribute();
+ !isTrivial(att.first); att = inReader.GetNarrowNextAttribute()) {
+ if (!AreEqual(att.first, "scale") && !AreEqual(att.first, "position")
+ && !AreEqual(att.first, "rotation") && !AreEqual(att.first, "pivot")
+ && !AreEqual(att.first, "endtime") && !AreEqual(att.first, "eyeball")
+ && !AreEqual(att.first, "ref") && !AreEqual(att.first, "id")
+ && !AreEqual(att.first, "name") && !AreEqual(att.first, "orientation")
+ && !AreEqual(att.first, "rotationorder")) // note that sourcepath does come through.
+ {
+ copiedAttributes.push_back(eastl::make_pair(att.first, att.second));
+ }
+ }
+ }
+}
+
+void CUIPParserObjectRefHelper::CacheGraph(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inWriter)
+{
+ {
+ // First, we parse Graph section to build the scene graph
+ IDOMReader::Scope __graphScope(inReader);
+ inReader.MoveToFirstChild("Graph");
+ CacheSceneGraph(inReader);
+ }
+ void *logicScopeItem = NULL;
+ {
+ // Next, we parse Logic section to update the node name and image information
+ IDOMReader::Scope __logicScope(inReader);
+ inReader.MoveToFirstChild("Logic");
+ logicScopeItem = inReader.GetScope();
+ CacheStateGraph(inReader);
+ }
+ if (m_SceneGraphAliasList.empty() == false) {
+ IDOMReader::Scope __aliasScope(inReader);
+ // Now we expand aliases
+ eastl::hash_map<TStrType, TStrType> oldToNewIdMap;
+ std::shared_ptr<qt3dsdm::IDOMFactory> theFactory = inWriter.GetFactory();
+ std::shared_ptr<qt3dsdm::IStringTable> theStrTable = inReader.GetStringTable();
+ qt3dsdm::SDOMElement *theSlidesRoot = theFactory->NextElement("AliasSlides");
+ eastl::pair<std::shared_ptr<qt3dsdm::IDOMWriter>, std::shared_ptr<qt3dsdm::IDOMReader>>
+ slideWriterReaderPair =
+ qt3dsdm::IDOMWriter::CreateDOMWriter(theFactory, *theSlidesRoot, theStrTable);
+ std::shared_ptr<qt3dsdm::IDOMWriter> slideWriter = slideWriterReaderPair.first;
+
+ {
+ IDOMReader::Scope __loopScope(inReader);
+ for (QT3DSU32 idx = 0, end = m_SceneGraphAliasList.size(); idx < end; ++idx) {
+ inReader.SetScope(m_SceneGraphAliasList[idx]);
+ const char8_t *reference;
+ SGraphNode *referencedNode = NULL;
+ const char8_t *theIdStr;
+ inReader.Att("id", theIdStr);
+ SGraphNode *aliasNode = NULL;
+ TGraphNodeMap::iterator iter = m_GraphNodeMap.find(m_MetaData.Register(theIdStr));
+ if (iter != m_GraphNodeMap.end())
+ aliasNode = iter->second;
+
+ if (inReader.UnregisteredAtt("referencednode", reference)) {
+ TStrType theSourceElemId = ParseObjectRefId(reference, theIdStr);
+ iter = m_GraphNodeMap.find(theSourceElemId);
+ if (iter != m_GraphNodeMap.end())
+ referencedNode = iter->second;
+ }
+ if (referencedNode == NULL || aliasNode == NULL) {
+ QT3DS_ASSERT(false);
+ continue;
+ }
+ inReader.SetScope(referencedNode->m_ReaderContext);
+ oldToNewIdMap.clear();
+ std::shared_ptr<qt3dsdm::IDOMFactory> theFactory = inWriter.GetFactory();
+ std::shared_ptr<qt3dsdm::IStringTable> theStrTable = inReader.GetStringTable();
+ qt3dsdm::SDOMElement *theRoot = theFactory->NextElement(inReader.GetElementName());
+ std::shared_ptr<qt3dsdm::IDOMWriter> copyWriter =
+ qt3dsdm::IDOMWriter::CreateDOMWriter(theFactory, *theRoot, theStrTable).first;
+
+ // Step one is just to copy the scene graph generating ids.
+ SGraphNode *theParent = aliasNode->m_Parent;
+ aliasNode->m_Class = referencedNode->m_Class;
+ aliasNode->m_Type = referencedNode->m_Type;
+ // Copy the alias id
+ copyWriter->Att("id", theIdStr);
+ eastl::vector<eastl::pair<eastl::string, eastl::string>> copiedAttributes;
+ StoreTopLevelAliasAttributes(inReader, copiedAttributes);
+ for (QT3DSU32 idx = 0, end = copiedAttributes.size(); idx < end; ++idx) {
+ copyWriter->Att(copiedAttributes[idx].first.c_str(),
+ copiedAttributes[idx].second.c_str());
+ }
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "Alias"))
+ continue;
+ qt3dsdm::IDOMReader::Scope __loopScoper(inReader);
+ qt3dsdm::IDOMWriter::Scope writerScope(*copyWriter,
+ inReader.GetNarrowElementName());
+ CopySceneGraph(inReader, *copyWriter, *slideWriter, oldToNewIdMap,
+ aliasNode->m_Name.c_str(), theIdStr, *aliasNode);
+ }
+ if (referencedNode->m_MasterSlide) {
+ inReader.SetScope(referencedNode->m_MasterSlide);
+ CopyStates(inReader, *slideWriter, oldToNewIdMap, aliasNode->m_Name.c_str(),
+ theIdStr);
+ }
+ // Set the scope to point at the alias node.
+ inReader.SetScope(aliasNode->m_ReaderContext);
+ inWriter.ReplaceCurrent(*theRoot);
+ // Now find the owning component.
+ SGraphNode *theComponent = theParent;
+ while (theComponent && theComponent->m_MasterSlide == NULL)
+ theComponent = theComponent->m_Parent;
+
+ if (theComponent && theComponent->m_MasterSlide) {
+ inReader.SetScope(theComponent->m_MasterSlide);
+ // Copy any state commands that have entries in the old to new map.
+ CopyStateCommands(inReader, inWriter, oldToNewIdMap, aliasNode->m_Name.c_str(),
+ referencedNode->m_Id, theIdStr);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ } // End of loop scope.
+
+ {
+ // Next, we parse Logic section to update the node name and image information
+ {
+ IDOMReader::Scope __logicScope(inReader);
+ inReader.SetScope(theSlidesRoot);
+ // Cache the new items and their names and such.
+ CacheStateGraph(inReader);
+ }
+
+ inReader.MoveToFirstChild("Logic");
+ inWriter.AppendChildren(*theSlidesRoot);
+ }
+
+ /*
+#if defined _DEBUG && defined _WIN32
+ {
+ qt3dsdm::SDOMElement* theElem = inWriter.GetTopElement();
+ {
+ qt3ds::foundation::CFileSeekableIOStream theWriter( "c:\\temp.xml",
+FileWriteFlags() );
+ qt3dsdm::CDOMSerializer::Write( *theElem, theWriter );
+ }
+ }
+#endif
+ */
+ }
+
+}
+
+void CUIPParserObjectRefHelper::CacheSceneGraph(IDOMReader &inReader, SGraphNode *inParent)
+{
+ IDOMReader::Scope __childScope(inReader);
+
+ // build out the graph.
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "Alias")) {
+ CacheSceneGraphNode(inReader, inParent);
+ m_SceneGraphAliasList.push_back(inReader.GetScope());
+ } else {
+ SGraphNode &theNode(CacheSceneGraphNode(inReader, inParent));
+ CacheSceneGraph(inReader, &theNode);
+ }
+ }
+}
+
+CUIPParserObjectRefHelper::SGraphNode &
+CUIPParserObjectRefHelper::CacheSceneGraphNode(qt3dsdm::IDOMReader &inReader, SGraphNode *inParent)
+{
+ SGraphNode *theNode = new SGraphNode();
+ const char8_t *theIdStr;
+ inReader.Att("id", theIdStr);
+ theNode->m_Id = m_MetaData.Register(theIdStr);
+ theNode->m_Type = m_MetaData.Register(inReader.GetNarrowElementName());
+ const char8_t *theClassStr;
+ inReader.Att("class", theClassStr);
+ theNode->m_Class = m_MetaData.Register(theClassStr);
+ const char *theNameStr;
+ theNode->m_ReaderContext = inReader.GetScope();
+
+ if (inParent && inParent->m_Type == m_MetaData.Register("Layer")
+ && theNode->m_Type == m_MetaData.Register("Image")) {
+ TLightProbeIdToNameMap::iterator theFind = m_LayerImageIdToNameMap.find(theIdStr);
+ if (theFind != m_LayerImageIdToNameMap.end())
+ theNode->m_Name = m_MetaData.Register(theFind->second.c_str());
+ } else if (!inReader.Att("name", theNameStr)) {
+ Option<eastl::string> theNameStrOpt = m_MetaData.GetPropertyValueString(
+ theNode->m_Type, m_MetaData.Register("name"), theNode->m_Class);
+ if (theNameStrOpt.hasValue())
+ theNode->m_Name = m_MetaData.Register(theNameStrOpt->c_str());
+ } else
+ theNode->m_Name = m_MetaData.Register(theNameStr);
+
+ if (inParent) {
+ theNode->m_Parent = inParent;
+ inParent->m_Children.push_back(theNode);
+ } else {
+ m_RootNode = theNode;
+ }
+
+ m_GraphNodeMap[theNode->m_Id] = theNode;
+ return *theNode;
+}
+
+void CUIPParserObjectRefHelper::CacheStateGraph(IDOMReader &inReader)
+{
+ IDOMReader::Scope __childScope(inReader);
+ const char8_t *component;
+ if (inReader.UnregisteredAtt("component", component)) {
+ TGraphNodeMap::iterator iter = m_GraphNodeMap.find(m_MetaData.Register(component + 1));
+ if (iter != m_GraphNodeMap.end()) {
+ iter->second->m_MasterSlide = inReader.GetScope();
+ }
+ }
+
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "State"))
+ CacheStateGraph(inReader);
+ else if (AreEqual(inReader.GetNarrowElementName(), "Add")
+ || AreEqual(inReader.GetNarrowElementName(), "Set")) {
+ const char *theRef;
+ const char *theName;
+ if (inReader.Att("ref", theRef)) {
+ theRef++; // remove the '#'
+ SGraphNode *theNode = GetNode(theRef);
+ if (theNode) {
+ // Overwrite the name. This assumes that "name" property is always linked.
+ if (inReader.Att("name", theName)) {
+ // Do not touch the name of an image instance that was renamed in the code
+ // below. i.e. an image that is referred to from a material.
+ if (!(theNode->m_Type == m_MetaData.Register("Image")
+ && m_ImageNamePropertyList.find(theNode->m_Name)
+ != m_ImageNamePropertyList.end())) {
+ theNode->m_Name = m_MetaData.Register(theName);
+ }
+ }
+
+ // Special case for material. Image properties refer to instances.
+ // For example: Scene.Layer.Rectangle.Material.diffusemap.rotationuv ->
+ // diffusemap refers to Image instance
+ // So if we find image instance, overwrite the name of the image with the
+ // property name.
+ // This assumes that user can't rename image property
+ if (theNode->m_Type == m_MaterialStr && !theNode->m_Children.empty()) {
+ for (TImageNamePropertyList::iterator theProp =
+ m_ImageNamePropertyList.begin();
+ theProp != m_ImageNamePropertyList.end(); ++theProp) {
+ const char *theImageInstance;
+ if (inReader.Att(theProp->c_str(), theImageInstance)) {
+ ++theImageInstance; // remove the '#'
+ SGraphNode *theImageNode = GetNode(theImageInstance);
+ QT3DS_ASSERT(theImageNode && theImageNode->m_Parent == theNode);
+ if (theImageNode)
+ theImageNode->m_Name = *theProp;
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+}
+
+void CUIPParserObjectRefHelper::CopySceneGraph(qt3dsdm::IDOMReader &inReader,
+ qt3dsdm::IDOMWriter &inWriter,
+ qt3dsdm::IDOMWriter &inSlideWriter,
+ TStrToStrMap &inMap, const char *inAliasName,
+ const char *inAliasId, SGraphNode &inParent)
+{
+ qt3dsdm::IDOMReader::Scope __graphScope(inReader);
+ // Assume the element itself is already copied.
+ // Run through attributes and duplicate them, but for any id attributes generate a new id.
+ const char8_t *tempItem;
+ if (!inReader.Att("id", tempItem)) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SGraphNode *theParent = &inParent;
+ eastl::string idGenerator(inAliasName);
+ idGenerator.append("-");
+ idGenerator.append(tempItem);
+ while (m_GraphNodeMap.find(m_MetaData.Register(idGenerator.c_str())) != m_GraphNodeMap.end())
+ idGenerator.append("_");
+ inWriter.Att("id", idGenerator.c_str());
+ TStrType srcId = m_MetaData.Register(tempItem);
+ TStrType newId = m_MetaData.Register(idGenerator.c_str());
+ inMap[srcId] = newId;
+ SGraphNode *srcNode = m_GraphNodeMap.find(srcId)->second;
+ SGraphNode *newNode = new SGraphNode();
+ newNode->m_Class = srcNode->m_Class;
+ newNode->m_Id = newId;
+ newNode->m_Name = srcNode->m_Name;
+ newNode->m_Type = srcNode->m_Type;
+ newNode->m_Parent = &inParent;
+ theParent = newNode;
+ m_GraphNodeMap[newId] = newNode;
+ inParent.m_Children.push_back(newNode);
+
+ {
+ qt3dsdm::IDOMReader::Scope __childrenScope(inReader);
+
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "Alias"))
+ continue;
+ qt3dsdm::IDOMWriter::Scope __newNode(inWriter, inReader.GetNarrowElementName());
+ CopySceneGraph(inReader, inWriter, inSlideWriter, inMap, inAliasName, inAliasId,
+ *theParent);
+ }
+ }
+ TGraphNodeMap::iterator iter = m_GraphNodeMap.find(m_MetaData.Register(tempItem));
+ if (iter == m_GraphNodeMap.end()) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SGraphNode *targetNode = iter->second;
+
+ for (eastl::pair<const char8_t *, const char8_t *> att = inReader.GetNarrowFirstAttribute();
+ !isTrivial(att.first); att = inReader.GetNarrowNextAttribute()) {
+ if (AreEqual(att.first, "id"))
+ continue;
+ Q3DStudio::ERuntimeDataModelDataType theDataType = m_MetaData.GetPropertyType(
+ targetNode->m_Type, m_MetaData.Register(att.first), targetNode->m_Class);
+ // Ensure we use new ids for this datatype. This ensures that we go
+ if (theDataType == ERuntimeDataModelDataTypeLong4) {
+ TStrToStrMap::iterator aliasIdName = inMap.find(m_MetaData.Register(att.second));
+ if (aliasIdName != inMap.end())
+ inWriter.Att(att.first, aliasIdName->second.c_str());
+ else {
+ QT3DS_ASSERT(false);
+ }
+ } else
+ inWriter.Att(att.first, att.second);
+ }
+ if (targetNode->m_MasterSlide) {
+ inReader.SetScope(targetNode->m_MasterSlide);
+ CopyStates(inReader, inSlideWriter, inMap, inAliasName, inAliasId);
+ }
+}
+
+void CUIPParserObjectRefHelper::CopyStates(qt3dsdm::IDOMReader &inReader,
+ qt3dsdm::IDOMWriter &inSlideWriter, TStrToStrMap &inMap,
+ const char *inAliasName, const char *inAliasId)
+{
+ qt3dsdm::IDOMReader::Scope __stateScope(inReader);
+ qt3dsdm::IDOMWriter::Scope stateScope(inSlideWriter, "State");
+ CopyAttributes(inReader, inSlideWriter, inMap, inAliasName, inAliasId);
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetNarrowElementName(), "State"))
+ CopyStates(inReader, inSlideWriter, inMap, inAliasName, inAliasId);
+ else {
+ CopyHierarchy(inReader, inSlideWriter, inMap, inAliasName, inAliasId);
+ }
+ }
+}
+
+eastl::pair<const char8_t *, const char8_t *> CUIPParserObjectRefHelper::ProcessAliasAttribute(
+ const char8_t *inObjId, eastl::pair<const char8_t *, const char8_t *> inAttribute,
+ eastl::string &ioStrBuilder, TStrToStrMap &inMap)
+{
+ inObjId = nonNull(inObjId);
+ if (inObjId[0] == '#')
+ ++inObjId;
+ SGraphNode *theNode = GetNode(nonNull(inObjId));
+ if (theNode == NULL)
+ return inAttribute;
+ const char8_t *propName = inAttribute.first;
+ const char8_t *propValue = inAttribute.second;
+ ERuntimeAdditionalMetaDataType thePropertyType = m_MetaData.GetAdditionalType(
+ theNode->m_Type, m_MetaData.Register(propName), theNode->m_Class);
+ if (thePropertyType == ERuntimeAdditionalMetaDataTypeImage
+ || thePropertyType == ERuntimeAdditionalMetaDataTypeObjectRef) {
+ propValue = nonNull(propValue);
+ if (propValue[0] == '#')
+ ++propValue;
+ TStrToStrMap::iterator iter = inMap.find(m_MetaData.Register(propValue));
+ if (iter != inMap.end()) {
+ ioStrBuilder.assign("#");
+ ioStrBuilder.append(iter->second);
+ propValue = ioStrBuilder.c_str();
+ } else
+ propValue = inAttribute.second;
+ }
+ return eastl::make_pair(propName, propValue);
+}
+
+void CUIPParserObjectRefHelper::CopyAttributes(qt3dsdm::IDOMReader &inReader,
+ qt3dsdm::IDOMWriter &inSlideWriter,
+ TStrToStrMap &inMap, const char *inAliasName,
+ const char *inAliasId)
+{
+ eastl::string builder;
+ const char8_t *elemId = "";
+ for (eastl::pair<const char8_t *, const char8_t *> att = inReader.GetNarrowFirstAttribute();
+ !isTrivial(att.first); att = inReader.GetNarrowNextAttribute()) {
+ if (AreEqual(att.first, "component")) {
+ TStrToStrMap::iterator iter = inMap.find(m_MetaData.Register(att.second + 1));
+ builder.assign("#");
+ if (iter != inMap.end()) {
+ builder.append(iter->second);
+ } else {
+ builder.append(inAliasId);
+ }
+ inSlideWriter.Att(att.first, builder.c_str());
+ } else if (AreEqual(att.first, "id")) {
+ builder.assign(inAliasName);
+ builder.append("-");
+ builder.append(att.second);
+ // cannot be
+ while (m_SlideIdSet.find(m_MetaData.Register(builder.c_str())) != m_SlideIdSet.end())
+ builder.append("_");
+ inSlideWriter.Att(att.first, builder.c_str());
+ m_SlideIdSet.insert(m_MetaData.Register(builder.c_str()));
+ inMap[m_MetaData.Register(att.second)] = m_MetaData.Register(builder.c_str());
+ } else if (AreEqual(att.first, "ref")) {
+ const char8_t *refItem = att.second;
+ if (!isTrivial(refItem)) {
+ ++refItem;
+ elemId = refItem;
+ TStrToStrMap::iterator iter = inMap.find(m_MetaData.Register(refItem));
+ if (iter != inMap.end()) {
+ builder.assign("#");
+ builder.append(iter->second.c_str());
+ inSlideWriter.Att("ref", builder.c_str());
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ } else {
+ att = ProcessAliasAttribute(elemId, att, builder, inMap);
+ inSlideWriter.Att(att.first, att.second);
+ }
+ }
+}
+
+void CUIPParserObjectRefHelper::CopyHierarchy(qt3dsdm::IDOMReader &inReader,
+ qt3dsdm::IDOMWriter &inSlideWriter, TStrToStrMap &inMap,
+ const char *inAliasName, const char *inAliasId)
+{
+ qt3dsdm::IDOMReader::Scope __commandScope(inReader);
+ qt3dsdm::IDOMWriter::Scope __writerScope(inSlideWriter, inReader.GetNarrowElementName());
+ CopyAttributes(inReader, inSlideWriter, inMap, inAliasName, inAliasId);
+ const char8_t *childData;
+ if (inReader.Value(childData)) {
+ inSlideWriter.Value(childData);
+ }
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling())
+ CopyHierarchy(inReader, inSlideWriter, inMap, inAliasName, inAliasId);
+}
+
+void CUIPParserObjectRefHelper::CopyStateCommands(qt3dsdm::IDOMReader &inReader,
+ qt3dsdm::IDOMWriter &inWriter,
+ TStrToStrMap &oldToNewIdMap,
+ const char *inAliasName, const char *inOldId,
+ const char *inNewId)
+{
+ qt3dsdm::IDOMReader::Scope __commandScope(inReader);
+ qt3dsdm::SDOMElement *theSlidesRoot = NULL;
+ eastl::pair<std::shared_ptr<qt3dsdm::IDOMWriter>, std::shared_ptr<qt3dsdm::IDOMReader>>
+ slideWriterReaderPair;
+ std::shared_ptr<qt3dsdm::IDOMWriter> commandWriter;
+ {
+ qt3dsdm::IDOMReader::Scope __loopScope(inReader);
+ eastl::vector<eastl::pair<eastl::string, eastl::string>> copiedAttributes;
+ void *destCommand = NULL;
+ eastl::string strBuilder;
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ qt3dsdm::IDOMReader::Scope childScope(inReader);
+ if (AreEqual(inReader.GetNarrowElementName(), "State"))
+ CopyStateCommands(inReader, inWriter, oldToNewIdMap, inAliasName, inOldId, inNewId);
+ else {
+ const char8_t *refItem = "";
+ if (inReader.Att("ref", refItem) && !isTrivial(refItem)) {
+ ++refItem;
+ TStrToStrMap::iterator iter = oldToNewIdMap.find(m_MetaData.Register(refItem));
+ if (iter != oldToNewIdMap.end()) {
+ if (theSlidesRoot == NULL) {
+ std::shared_ptr<qt3dsdm::IDOMFactory> theFactory =
+ inWriter.GetFactory();
+ std::shared_ptr<qt3dsdm::IStringTable> theStrTable =
+ inReader.GetStringTable();
+ theSlidesRoot = theFactory->NextElement("AliasSlides");
+ slideWriterReaderPair = qt3dsdm::IDOMWriter::CreateDOMWriter(
+ theFactory, *theSlidesRoot, theStrTable);
+ commandWriter = slideWriterReaderPair.first;
+ }
+ qt3dsdm::IDOMWriter::Scope elemScope(*commandWriter,
+ inReader.GetNarrowElementName());
+ for (eastl::pair<const char8_t *, const char8_t *> att =
+ inReader.GetNarrowFirstAttribute();
+ !isTrivial(att.first); att = inReader.GetNarrowNextAttribute()) {
+ if (AreEqual(att.first, "ref")) {
+ strBuilder.assign("#");
+ strBuilder.append(iter->second);
+ commandWriter->Att("ref", strBuilder.c_str());
+ } else {
+
+ att =
+ ProcessAliasAttribute(refItem, att, strBuilder, oldToNewIdMap);
+ commandWriter->Att(att.first, att.second);
+ }
+ }
+ for (bool commandChild = inReader.MoveToFirstChild(); commandChild;
+ commandChild = inReader.MoveToNextSibling()) {
+ qt3dsdm::IDOMReader::Scope commandChildScope(inReader);
+ CopyHierarchy(inReader, *commandWriter, oldToNewIdMap, inAliasName, "");
+ }
+ } else if (AreEqual(refItem, inOldId)) {
+ StoreTopLevelAliasAttributes(inReader, copiedAttributes);
+ } else if (AreEqual(refItem, inNewId))
+ destCommand = inReader.GetScope();
+ }
+ }
+ }
+ if (copiedAttributes.size() && destCommand) {
+ inReader.SetScope(destCommand);
+ for (QT3DSU32 idx = 0, end = copiedAttributes.size(); idx < end; ++idx) {
+ eastl::pair<eastl::string, eastl::string> &theItem(copiedAttributes[idx]);
+ inWriter.Att(theItem.first.c_str(), theItem.second.c_str());
+ }
+ }
+ }
+ if (commandWriter)
+ inWriter.AppendChildren(*commandWriter->GetTopElement());
+}
+
+CUIPParserObjectRefHelper::SGraphNode *CUIPParserObjectRefHelper::GetNode(const char *inId)
+{
+ if (IsTrivial(inId))
+ return NULL;
+ if (inId[0] == '#')
+ ++inId;
+ TGraphNodeMap::iterator theIter = m_GraphNodeMap.find(m_MetaData.Register(inId));
+ if (theIter != m_GraphNodeMap.end())
+ return theIter->second;
+ return NULL;
+}
+
+CUIPParserObjectRefHelper::SGraphNode *CUIPParserObjectRefHelper::GetNode(eastl::string inId)
+{
+ return GetNode(inId.c_str());
+}
+
+CUIPParserObjectRefHelper::TStrType CUIPParserObjectRefHelper::GetName(const eastl::string &inId)
+{
+ SGraphNode *theNode = GetNode(inId.c_str());
+ if (theNode)
+ return theNode->m_Name;
+ QT3DS_ASSERT(false);
+ return m_MetaData.Register(inId.c_str());
+}
+
+CUIPParserObjectRefHelper::TStrType CUIPParserObjectRefHelper::GetType(const eastl::string &inId)
+{
+ SGraphNode *theNode = GetNode(inId.c_str());
+ if (theNode)
+ return theNode->m_Type;
+ QT3DS_ASSERT(false);
+ return m_MetaData.Register(inId.c_str());
+}
+
+CUIPParserObjectRefHelper::TStrType CUIPParserObjectRefHelper::GetClass(const eastl::string &inId)
+{
+ SGraphNode *theNode = GetNode(inId.c_str());
+ if (theNode)
+ return theNode->m_Class;
+ QT3DS_ASSERT(false);
+ return m_MetaData.Register(inId.c_str());
+}
+
+CUIPParserObjectRefHelper::TStrType
+CUIPParserObjectRefHelper::ParseObjectRefId(const eastl::string &inObjectPath,
+ const char8_t *inOwnerId)
+{
+ if (inObjectPath.empty()) {
+ QT3DS_ASSERT(false);
+ return TStrType();
+ } else if (inObjectPath[0] == '#') {
+ // Absolute path
+ return m_MetaData.Register(inObjectPath.substr(1).c_str());
+ } else {
+ // Relative path
+ SGraphNode *theNode = GetNode(inOwnerId);
+
+ // Split the string based on PATH_DELIMITER
+ eastl::string theStr = inObjectPath;
+ eastl::string theCurrentPart;
+ eastl::string::size_type thePos;
+ while (theNode) {
+ thePos = theStr.find(PATH_DELIMITER);
+ theCurrentPart = theStr.substr(0, thePos);
+
+ if (theCurrentPart == "parent") {
+ theNode = theNode->m_Parent;
+ } else if (theCurrentPart == "this") {
+ // Do nothing because theNode points to itself
+ } else if (theCurrentPart == "Scene") {
+ theNode = m_RootNode;
+ } else {
+ SGraphNode *theFoundChild = NULL;
+ for (QT3DSU32 childIdx = 0;
+ childIdx < theNode->m_Children.size() && theFoundChild == NULL; ++childIdx) {
+ if (AreEqual(theNode->m_Children[childIdx]->m_Name, theCurrentPart.c_str()))
+ theFoundChild = theNode->m_Children[childIdx];
+ }
+ theNode = theFoundChild;
+ }
+
+ if (thePos == eastl::string::npos)
+ break;
+
+ // Move on to the next token
+ theStr = theStr.substr(thePos + 1);
+ }
+
+ if (theNode)
+ return theNode->m_Id;
+
+ return TStrType();
+ }
+}
+
+eastl::string CUIPParserObjectRefHelper::BuildReferenceString(eastl::string inObjectPath)
+{
+ if (inObjectPath.empty()) {
+ // QT3DS_ASSERT( false );
+ return "";
+ } else if (inObjectPath[0] == '#') {
+ // Absolute path
+ return BuildAbsoluteReferenceString(inObjectPath.substr(1));
+ } else {
+ // Relative path
+ return inObjectPath;
+ }
+}
+
+eastl::string CUIPParserObjectRefHelper::BuildAbsoluteReferenceString(eastl::string inId)
+{
+ return BuildAbsoluteReferenceString(GetNode(inId));
+}
+
+eastl::string CUIPParserObjectRefHelper::BuildAbsoluteReferenceString(SGraphNode *inNode)
+{
+ if (inNode == NULL)
+ return "";
+
+ eastl::string theNameStart;
+ eastl::string theNameEnd(inNode->m_Name);
+
+ SGraphNode *theParent = inNode->m_Parent;
+ if (theParent) {
+ theNameStart.assign(BuildAbsoluteReferenceString(theParent));
+ theNameStart.append(".");
+ }
+ theNameStart += theNameEnd;
+ return theNameStart;
+}
+
+void CUIPParserObjectRefHelper::MarkAllReferencedAttributes(
+ eastl::string inId, const eastl::vector<eastl::string> &inReferences,
+ qt3dsdm::IDOMReader &inReader, SParseElementManager &outIdAttributesMap)
+{
+ IDOMReader::Scope __scope(inReader);
+ eastl::string theReferencesTokenizer;
+ eastl::string theCurrentReference;
+ eastl::string theReferenceTokenizer;
+ eastl::string theCurrentString;
+ eastl::string::size_type startPos = 0;
+ eastl::string::size_type endPos = 0;
+ eastl::string::size_type theReferencesTokenizerPos = 0;
+ eastl::string::size_type theReferenceTokenizerPos = 0;
+ SGraphNode *theBaseInstance = GetNode(inId);
+ SGraphNode *theCurrentInstance = theBaseInstance;
+ eastl::vector<SGraphNode *> theInstanceList;
+
+ for (QT3DSU32 theRefIdx = 0, theRefEnd = inReferences.size(); theRefIdx < theRefEnd; ++theRefIdx) {
+ // Split the string based on PATH_LINE_END
+ theReferencesTokenizer = inReferences[theRefIdx];
+ theReferencesTokenizerPos = 0;
+ while (theReferencesTokenizerPos != eastl::string::npos
+ && !theReferencesTokenizer.empty()) {
+ theCurrentInstance = theBaseInstance;
+ theReferencesTokenizerPos = theReferencesTokenizer.find(PATH_LINE_END);
+ theCurrentReference = theReferencesTokenizer.substr(0, theReferencesTokenizerPos);
+
+ // Move to the next token
+ theReferencesTokenizer = theReferencesTokenizer.substr(theReferencesTokenizerPos + 1);
+
+ // trim whitespace from the beginning and the end of the string
+ startPos = theCurrentReference.find_first_not_of("\n\r\t ");
+ endPos = theCurrentReference.find_last_not_of("\n\r\t ");
+ if (startPos != eastl::string::npos)
+ theCurrentReference = theCurrentReference.substr(startPos, endPos - startPos + 1);
+
+ // Split the string based on PATH_DELIMITER
+ theReferenceTokenizer = theCurrentReference;
+ theReferenceTokenizerPos = 0;
+ theInstanceList.clear();
+ while (theReferenceTokenizerPos != eastl::string::npos
+ && !theReferenceTokenizer.empty()) {
+ theReferenceTokenizerPos = theReferenceTokenizer.find(PATH_DELIMITER);
+ theCurrentString = theReferenceTokenizer.substr(0, theReferenceTokenizerPos);
+
+ // Move to the next token
+ theReferenceTokenizer = theReferenceTokenizer.substr(theReferenceTokenizerPos + 1);
+
+ if (theReferenceTokenizerPos != eastl::string::npos) {
+ theCurrentInstance = GetReferenceNode(theCurrentInstance, theCurrentString,
+ theInstanceList, inReader);
+ } else {
+ if (theInstanceList.size() == 0 && theCurrentInstance)
+ theInstanceList.push_back(theCurrentInstance);
+ if (!MarkAttributeAsReferenced(theBaseInstance, theInstanceList,
+ theCurrentString, inReader,
+ outIdAttributesMap)) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "Unable to parse reference: "
+ << theBaseInstance->m_Id.c_str() << " : "
+ << theCurrentReference.c_str();
+ }
+ }
+ }
+ }
+ }
+}
+
+//==============================================================================
+/**
+ * Helper method to find the VAsset via the name which is the child of inAsset.
+ */
+CUIPParserObjectRefHelper::SGraphNode *
+CUIPParserObjectRefHelper::GetReferenceNode(SGraphNode *inInstance, eastl::string &inAssetName,
+ eastl::vector<SGraphNode *> &outInstanceList,
+ qt3dsdm::IDOMReader &inReader)
+{
+ if (!inInstance)
+ return NULL;
+
+ SGraphNode *theReturnInstance = NULL;
+
+ if (inAssetName == "Scene") {
+ theReturnInstance = m_RootNode;
+ } else if (inAssetName == "parent") {
+ theReturnInstance = inInstance->m_Parent;
+ } else if (inAssetName == "children") {
+ outInstanceList.insert(outInstanceList.end(), inInstance->m_Children.begin(),
+ inInstance->m_Children.end());
+ } else if (inAssetName == "descendants") {
+ for (SGraphNode::TGraphNodeList::iterator theChildren = inInstance->m_Children.begin();
+ theChildren != inInstance->m_Children.end(); ++theChildren) {
+ outInstanceList.push_back(*theChildren);
+ GetReferenceNode(*theChildren, inAssetName, outInstanceList, inReader);
+ }
+ } else if (inAssetName[0] == '[' && inAssetName[inAssetName.length() - 1] == ']') {
+ // For example: [targetElement].position
+ // targetElement should be an Object picker specifying which element to preserve.
+ eastl::string theAssetName = inAssetName.substr(1, inAssetName.length() - 2);
+
+ // Check if the target element property exists and get the property value
+ eastl::string theValue;
+ if (!inReader.Att(theAssetName.c_str(), theValue)) {
+ // Try to find the parent context and get the element name from there.
+ if (AreEqual(inReader.GetElementName(), L"Set")) {
+ IDOMReader::Scope __setScope(inReader);
+ const char8_t *refValue = "";
+ inReader.Att("ref", refValue);
+ inReader.Leave();
+ inReader.Leave();
+ for (bool success = inReader.MoveToFirstChild("Add"); success;
+ success = inReader.MoveToNextSibling("Add")) {
+ const char8_t *newRef;
+ inReader.Att("ref", newRef);
+ if (AreEqual(newRef, refValue)) {
+ inReader.Att(theAssetName.c_str(), theValue);
+ break;
+ }
+ }
+ }
+ if (theValue.empty()) {
+ Option<TRuntimeMetaDataStrType> theRef = m_MetaData.GetPropertyValueObjectRef(
+ inInstance->m_Type, m_MetaData.Register(theAssetName.c_str()),
+ inInstance->m_Class);
+ if (theRef.hasValue())
+ theValue = *theRef;
+ }
+ }
+ if (!IsTrivial(theValue.c_str())) {
+ // Get the target element id
+ eastl::string theTargetElement =
+ ParseObjectRefId(theValue, inInstance->m_Id.c_str()).c_str();
+ if (theTargetElement != "") {
+ // Get the corresponding instance
+ theReturnInstance = GetNode(theTargetElement);
+ }
+ }
+ } else {
+ // Get the child with the specified name.
+ // Note that name is not unique and so this will only return the first child that matches
+ // the name
+ for (SGraphNode::TGraphNodeList::iterator theChildren = inInstance->m_Children.begin();
+ theChildren != inInstance->m_Children.end(); ++theChildren) {
+ if (AreEqual((*theChildren)->m_Name.c_str(), inAssetName.c_str())) {
+ theReturnInstance = *theChildren;
+ break;
+ }
+ }
+ }
+ return theReturnInstance;
+}
+
+bool CUIPParserObjectRefHelper::MarkAttributeAsReferenced(
+ SGraphNode *inBaseInstance, eastl::vector<SGraphNode *> &inInstanceList,
+ eastl::string &inAttributeName, qt3dsdm::IDOMReader &inReader,
+ SParseElementManager &outIdAttributesMap)
+{
+ bool theRet(false);
+ eastl::vector<SGraphNode *>::iterator theIter = inInstanceList.begin();
+ eastl::vector<SGraphNode *>::iterator theEnd = inInstanceList.end();
+ for (; theIter != theEnd; ++theIter) {
+ SGraphNode *theCurrentInstance = *theIter;
+
+ if (inAttributeName == "all") {
+ eastl::vector<TRuntimeMetaDataStrType> theProperties;
+ m_MetaData.GetInstanceProperties(theCurrentInstance->m_Type.c_str(),
+ theCurrentInstance->m_Class.c_str(), theProperties,
+ true);
+
+ if (theProperties.size() > 0) {
+ SElementData *theData =
+ outIdAttributesMap.FindElementData(theCurrentInstance->m_Id.c_str());
+ if (theData) {
+ for (QT3DSU32 theIndex = 0; theIndex < theProperties.size(); ++theIndex)
+ outIdAttributesMap.MarkAttributeAsReferenced(
+ *theData, theProperties[theIndex].c_str());
+ }
+ theRet = true;
+ }
+ } else {
+ eastl::string theAttributeName = inAttributeName;
+ if (inAttributeName[0] == '[' && inAttributeName[inAttributeName.length() - 1] == ']') {
+ // For example: parent.[targetProp]
+ // targetProp should be a string specifying which property to preserve
+ theAttributeName = theAttributeName.substr(1, theAttributeName.length() - 2);
+
+ // Get the targetProp property value from the uip file
+ const char *theValue;
+ if (inReader.Att(theAttributeName.c_str(), theValue)) {
+ theAttributeName = theValue;
+ } else {
+ // Query metadata value of base instance
+ theAttributeName = m_MetaData.GetPropertyValueString(
+ inBaseInstance->m_Type, m_MetaData.Register(theAttributeName.c_str()),
+ inBaseInstance->m_Class);
+ }
+ }
+
+ // Check if the property exists
+ if (m_MetaData.IsPropertyExist(theCurrentInstance->m_Type,
+ m_MetaData.Register(theAttributeName.c_str()),
+ theCurrentInstance->m_Class)) {
+ MarkPreserveFlag(theCurrentInstance, theAttributeName, outIdAttributesMap);
+ theRet = true;
+ } else {
+ // check whether the attribute name has ".", strip those after that and try again
+ eastl::string::size_type theIndex = theAttributeName.rfind('.');
+ if (theIndex != eastl::string::npos) {
+ theAttributeName = theAttributeName.substr(0, theIndex);
+ if (m_MetaData.IsPropertyExist(theCurrentInstance->m_Type,
+ m_MetaData.Register(theAttributeName.c_str()),
+ theCurrentInstance->m_Class)) {
+ MarkPreserveFlag(theCurrentInstance, theAttributeName, outIdAttributesMap);
+ theRet = true;
+ }
+ }
+ }
+ }
+ }
+
+ return theRet;
+}
+
+void CUIPParserObjectRefHelper::MarkPreserveFlag(SGraphNode *inInstance, eastl::string inProperty,
+ SParseElementManager &outIdAttributesMap)
+{
+ outIdAttributesMap.MarkAttributeAsReferenced(inInstance->m_Id.c_str(), inProperty.c_str());
+}
+
+void CUIPParserObjectRefHelper::BuildImageNamePropertyList()
+{
+ // Special case for material
+ // Material's Image properties (such as diffuse map, etc) point to Image instances
+ eastl::vector<TRuntimeMetaDataStrType> theProperties;
+ m_MetaData.GetInstanceProperties("Material", NULL, theProperties, true);
+
+ size_t thePropertyCount = theProperties.size();
+ for (QT3DSU32 thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) {
+ eastl::string theProperty = theProperties[thePropertyIndex];
+ ERuntimeAdditionalMetaDataType theAdditionalMetaDataType =
+ m_MetaData.GetAdditionalType(m_MaterialStr, m_MetaData.Register(theProperty.c_str()));
+
+ if (theAdditionalMetaDataType == ERuntimeAdditionalMetaDataTypeImage) {
+ m_ImageNamePropertyList.insert(m_MetaData.Register(theProperty.c_str()));
+ }
+ }
+}
+}
diff --git a/src/uipparser/Qt3DSUIPParserObjectRefHelper.h b/src/uipparser/Qt3DSUIPParserObjectRefHelper.h
new file mode 100644
index 0000000..fcd1698
--- /dev/null
+++ b/src/uipparser/Qt3DSUIPParserObjectRefHelper.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Qt3DSUIPParser.h"
+#include "Qt3DSUIPParserImpl.h"
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+/**
+ * @class CUIPParserObjectRefHelper
+ * @brief Class for parsing UIP file - Object Reference Helper
+ */
+class CUIPParserObjectRefHelper
+{
+ typedef qt3ds::foundation::CRegisteredString TStrType;
+
+public:
+ typedef eastl::hash_map<TStrType, TStrType> TStrToStrMap;
+
+ /// Tree structure to cache scene graph information. This is used to resolve relative object
+ /// reference
+ struct SGraphNode
+ {
+ typedef eastl::vector<SGraphNode *> TGraphNodeList;
+
+ TStrType m_Id; // node id
+ TStrType m_Name; // name of the node. the name can be default from metadata, specified in
+ // graph section, or specified in logic section.
+ TStrType m_Type; // for example: Layer, Camera, Model
+ TStrType
+ m_Class; // class id. usually used by Behavior or objects that have custom properties.
+ void *m_ReaderContext; // Context to warp back to this node.
+ void *m_MasterSlide;
+ SGraphNode *m_Parent;
+ TGraphNodeList m_Children;
+ SGraphNode()
+ : m_ReaderContext(NULL)
+ , m_MasterSlide(NULL)
+ , m_Parent(NULL)
+ {
+ }
+ };
+ //==============================================================================
+ // Fields
+ //==============================================================================
+private:
+ typedef eastl::hash_set<TStrType> TImageNamePropertyList;
+ IRuntimeMetaData &m_MetaData; ///< Reference to Metadata
+ typedef eastl::hash_map<TStrType, SGraphNode *> TGraphNodeMap;
+ SGraphNode *m_RootNode;
+ TGraphNodeMap m_GraphNodeMap;
+ TImageNamePropertyList m_SlideIdSet;
+
+ // List of Image property names, for example diffusemap, normalmap, etc
+ // This is to handle material and images. Material's Image properties point to instances.
+ TImageNamePropertyList m_ImageNamePropertyList;
+ TStrType m_MaterialStr;
+ eastl::vector<void *> m_SceneGraphAliasList;
+
+ typedef eastl::pair<eastl::string, eastl::string> TLightProbeAndNamePair;
+ typedef eastl::map<eastl::string, eastl::string> TLightProbeIdToNameMap;
+ TLightProbeIdToNameMap m_LayerImageIdToNameMap;
+ //==============================================================================
+ // Methods
+ //==============================================================================
+public: // Construction
+ CUIPParserObjectRefHelper(IRuntimeMetaData &inMetaData);
+ virtual ~CUIPParserObjectRefHelper();
+
+ void CacheGraph(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inWriter);
+ SGraphNode *GetNode(const char *inId);
+ SGraphNode *GetNode(eastl::string inId);
+ TStrType GetName(const eastl::string &inId); // return the node name given the node id
+ TStrType GetType(const eastl::string &inId); // return the node type given the node id
+ TStrType GetClass(const eastl::string &inId); // return the node class given the node id
+
+ TStrType ParseObjectRefId(const eastl::string &inObjectPath, const char8_t *inOwnerId);
+ eastl::string BuildReferenceString(eastl::string inObjectPath);
+ void MarkAllReferencedAttributes(eastl::string inId,
+ const eastl::vector<eastl::string> &inReferences,
+ qt3dsdm::IDOMReader &inReader,
+ SParseElementManager &outIdAttributesMap);
+
+private:
+ void CacheSceneGraph(qt3dsdm::IDOMReader &inReader, SGraphNode *inParent = NULL);
+ SGraphNode &CacheSceneGraphNode(qt3dsdm::IDOMReader &inReader, SGraphNode *inParent = NULL);
+ void CacheStateGraph(qt3dsdm::IDOMReader &inReader);
+
+ void CopySceneGraph(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inWriter,
+ qt3dsdm::IDOMWriter &inSlideWriter, TStrToStrMap &inMap,
+ const char *inAliasName, const char *inAliasId, SGraphNode &inParent);
+ void CopyStates(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inSlideWriter,
+ TStrToStrMap &inMap, const char *inAliasName, const char *inAliasId);
+ void CopyAttributes(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inSlideWriter,
+ TStrToStrMap &inMap, const char *inAliasName, const char *inAliasId);
+ void CopyHierarchy(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inSlideWriter,
+ TStrToStrMap &inMap, const char *inAliasName, const char *inAliasId);
+ void CopyStateCommands(qt3dsdm::IDOMReader &inReader, qt3dsdm::IDOMWriter &inWriter,
+ TStrToStrMap &oldToNewIdMap, const char *inAliasName,
+ const char *inOldId, const char *inNewId);
+ // Helper method for Preseve Attributes
+ SGraphNode *GetReferenceNode(SGraphNode *inInstance, eastl::string &inAssetName,
+ eastl::vector<SGraphNode *> &outInstanceList,
+ qt3dsdm::IDOMReader &inReader);
+ bool MarkAttributeAsReferenced(SGraphNode *inBaseInstance,
+ eastl::vector<SGraphNode *> &inInstanceList,
+ eastl::string &inAttributeName, qt3dsdm::IDOMReader &inReader,
+ SParseElementManager &outIdAttributesMap);
+ void MarkPreserveFlag(SGraphNode *inInstance, eastl::string inProperty,
+ SParseElementManager &outIdAttributesMap);
+ eastl::pair<const char8_t *, const char8_t *>
+ ProcessAliasAttribute(const char8_t *inObjId,
+ eastl::pair<const char8_t *, const char8_t *> inAttribute,
+ eastl::string &ioStrBuilder, TStrToStrMap &inMap);
+
+ eastl::string BuildAbsoluteReferenceString(eastl::string inId);
+ eastl::string BuildAbsoluteReferenceString(SGraphNode *inNode);
+
+ // Special case for material and images. Material's Image properties point to instances.
+ void BuildImageNamePropertyList();
+};
+
+} // namespace Q3DStudio