diff options
author | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-06 16:22:02 +0300 |
---|---|---|
committer | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-07 13:52:44 +0300 |
commit | b4954701093739e7a4e54a0669f306922d0d4605 (patch) | |
tree | 73d71319a921234f6b507c9098fdc842f7fe06dc /src/uipparser | |
parent | 8548a5f5579e3eee7e5ae6b1f6901dcc8bfee19e (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.h | 158 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParser.h | 155 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParserActionHelper.cpp | 738 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParserActionHelper.h | 172 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParserImpl.cpp | 2623 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParserImpl.h | 679 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParserObjectRefHelper.cpp | 1011 | ||||
-rw-r--r-- | src/uipparser/Qt3DSUIPParserObjectRefHelper.h | 159 |
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 |