summaryrefslogtreecommitdiffstats
path: root/src/dm/systems/Qt3DSDMMetaData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dm/systems/Qt3DSDMMetaData.cpp')
-rw-r--r--src/dm/systems/Qt3DSDMMetaData.cpp4170
1 files changed, 4170 insertions, 0 deletions
diff --git a/src/dm/systems/Qt3DSDMMetaData.cpp b/src/dm/systems/Qt3DSDMMetaData.cpp
new file mode 100644
index 0000000..66f56ce
--- /dev/null
+++ b/src/dm/systems/Qt3DSDMMetaData.cpp
@@ -0,0 +1,4170 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 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-EXCEPT$
+** 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 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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 "Qt3DSDMPrefix.h"
+#ifdef _WIN32
+#pragma warning(disable : 4103)
+#endif
+#include "Qt3DSDMMetaData.h"
+#include "Qt3DSDMXML.h"
+#include "foundation/Qt3DSAssert.h"
+#include "StandardExtensions.h"
+#include <unordered_map>
+#include <memory>
+#include <unordered_set>
+#include "Qt3DSDMTransactions.h"
+#include "VectorTransactions.h"
+#include "Qt3DSDMSignals.h"
+// Pull in the fancy str-type implementations
+#include "Qt3DSDMWStrOpsImpl.h"
+#include "Qt3DSDMDataCore.h"
+#include "DataCoreProducer.h"
+#include "Qt3DSDMWindowsCompatibility.h"
+#include "Qt3DSRenderEffectSystem.h"
+#include "Qt3DSRenderDynamicObjectSystemCommands.h"
+#include "foundation/StringConversionImpl.h"
+
+#include <QtCore/qdir.h>
+
+using namespace qt3dsdm;
+using std::shared_ptr;
+using std::make_shared;
+using std::static_pointer_cast;
+using std::unordered_map;
+using std::unordered_set;
+using std::function;
+using std::bind;
+using std::ref;
+using std::get;
+using qt3ds::foundation::Empty;
+
+typedef Qt3DSDMInstanceHandle TInstanceHandle;
+typedef Qt3DSDMPropertyHandle TPropertyHandle;
+typedef Qt3DSDMEventHandle TEventHandle;
+typedef Qt3DSDMHandlerHandle THandlerHandle;
+typedef Qt3DSDMHandlerArgHandle THandlerArgHandle;
+typedef Qt3DSDMMetaDataPropertyHandle TMetaDataPropertyHandle;
+typedef Qt3DSDMCategoryHandle TCategoryHandle;
+
+namespace qt3dsdm {
+#define QT3DS_WCHAR_T_None L"None"
+#define QT3DS_WCHAR_T_StringList L"StringList"
+#define QT3DS_WCHAR_T_Range L"Range"
+#define QT3DS_WCHAR_T_Image L"Image"
+#define QT3DS_WCHAR_T_Color L"Color"
+#define QT3DS_WCHAR_T_Rotation L"Rotation"
+#define QT3DS_WCHAR_T_Font L"Font"
+#define QT3DS_WCHAR_T_FontSize L"FontSize"
+#define QT3DS_WCHAR_T_MultiLine L"MultiLine"
+#define QT3DS_WCHAR_T_ObjectRef L"ObjectRef"
+#define QT3DS_WCHAR_T_Mesh L"Mesh"
+#define QT3DS_WCHAR_T_Import L"Import"
+#define QT3DS_WCHAR_T_Texture L"Texture"
+#define QT3DS_WCHAR_T_Image2D L"Image2D"
+#define QT3DS_WCHAR_T_Buffer L"Buffer"
+#define QT3DS_WCHAR_T_Property L"Property"
+#define QT3DS_WCHAR_T_Dependent L"Dependent"
+#define QT3DS_WCHAR_T_Slide L"Slide"
+#define QT3DS_WCHAR_T_Event L"Event"
+#define QT3DS_WCHAR_T_Object L"Object"
+#define QT3DS_WCHAR_T_Signal L"Signal"
+#define QT3DS_WCHAR_T_Renderable L"Renderable"
+#define QT3DS_WCHAR_T_PathBuffer L"PathBuffer"
+#define QT3DS_WCHAR_T_ShadowMapResolution L"ShadowMapResolution"
+#define QT3DS_WCHAR_T_String L"String"
+
+#define ITERATE_ADDITIONAL_META_DATA_TYPES \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(None) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(StringList) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Range) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Image) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Color) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Rotation) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Font) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(FontSize) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(MultiLine) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(ObjectRef) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Mesh) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Import) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Texture) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(Renderable) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(PathBuffer) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(ShadowMapResolution) \
+ HANDLE_ADDITIONAL_META_DATA_TYPE(String)
+template <>
+struct WStrOps<AdditionalMetaDataType::Value>
+{
+ QT3DSU32 ToStr(AdditionalMetaDataType::Value item, NVDataRef<wchar_t> buffer)
+ {
+ switch (item) {
+#define HANDLE_ADDITIONAL_META_DATA_TYPE(name) \
+ case AdditionalMetaDataType::name: \
+ wcscpy_s(buffer.begin(), buffer.size(), QT3DS_WCHAR_T_##name); \
+ return 1;
+ ITERATE_ADDITIONAL_META_DATA_TYPES
+ #undef HANDLE_ADDITIONAL_META_DATA_TYPE
+ }
+ return 0;
+ }
+ bool StrTo(const wchar_t *buffer, AdditionalMetaDataType::Value &item)
+ {
+#define HANDLE_ADDITIONAL_META_DATA_TYPE(name) \
+ if (AreEqual(buffer, QT3DS_WCHAR_T_##name)) { \
+ item = AdditionalMetaDataType::name; \
+ return true; \
+ }
+ ITERATE_ADDITIONAL_META_DATA_TYPES
+ #undef HANDLE_ADDITIONAL_META_DATA_TYPE
+ return false;
+ }
+};
+
+#undef ITERATE_ADDITIONAL_META_DATA_TYPES
+
+#define ITERATE_HANDLER_ARG_TYPES \
+ HANDLE_HANDLER_ARG_TYPE(None) \
+ HANDLE_HANDLER_ARG_TYPE(Property) \
+ HANDLE_HANDLER_ARG_TYPE(Dependent) \
+ HANDLE_HANDLER_ARG_TYPE(Slide) \
+ HANDLE_HANDLER_ARG_TYPE(Event) \
+ HANDLE_HANDLER_ARG_TYPE(Object) \
+ HANDLE_HANDLER_ARG_TYPE(Signal)
+
+QT3DSU32 WStrOps<HandlerArgumentType::Value>::ToStr(HandlerArgumentType::Value item, NVDataRef<wchar_t> buffer)
+{
+ switch (item) {
+#define HANDLE_HANDLER_ARG_TYPE(name) \
+ case HandlerArgumentType::name: \
+ wcscpy_s(buffer.begin(), buffer.size(), QT3DS_WCHAR_T_##name); \
+ return 1;
+ ITERATE_HANDLER_ARG_TYPES
+ #undef HANDLE_HANDLER_ARG_TYPE
+ }
+ return 0;
+}
+
+bool WStrOps<HandlerArgumentType::Value>::StrTo(const wchar_t *buffer, HandlerArgumentType::Value &item)
+{
+#define HANDLE_HANDLER_ARG_TYPE(name) \
+ if (AreEqual(buffer, QT3DS_WCHAR_T_##name)) { \
+ item = HandlerArgumentType::name; \
+ return true; \
+}
+ ITERATE_HANDLER_ARG_TYPES
+ #undef HANDLE_HANDLER_ARG_TYPE
+ return false;
+}
+
+#define QT3DS_WCHAR_T_FloatRange L"FloatRange"
+#define QT3DS_WCHAR_T_LongRange L"LongRange"
+#define QT3DS_WCHAR_T_Vector L"Vector"
+#define QT3DS_WCHAR_T_MultiLineString L"MultiLineString"
+#define QT3DS_WCHAR_T_Boolean L"Boolean"
+#define QT3DS_WCHAR_T_Guid L"Guid"
+#define QT3DS_WCHAR_T_StringListOrInt L"StringListOrInt"
+#define QT3DS_WCHAR_T_Scale L"Scale"
+
+#define ITERATE_QT3DSDM_COMPLETE_TYPES \
+ HANDLE_QT3DSDM_COMPLETE_NONE_TYPE \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(StringList, StringList, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(FloatRange, Range, DataModelDataType::Float) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(LongRange, Range, DataModelDataType::Long) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Float, None, DataModelDataType::Float) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Long, None, DataModelDataType::Long) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Float2, None, DataModelDataType::Float2) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Vector, None, DataModelDataType::Float3) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Scale, None, DataModelDataType::Float3) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Rotation, Rotation, DataModelDataType::Float3) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Color, Color, DataModelDataType::Float4) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Boolean, None, DataModelDataType::Bool) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Slide, None, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Font, Font, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(FontSize, FontSize, DataModelDataType::Float) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(String, String, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(MultiLineString, MultiLine, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(ObjectRef, ObjectRef, DataModelDataType::ObjectRef) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Image, Image, DataModelDataType::Long4) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Mesh, Mesh, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Import, Import, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Texture, Texture, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Image2D, Texture, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Buffer, Texture, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Guid, None, DataModelDataType::Long4) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(StringListOrInt, StringList, DataModelDataType::StringOrInt) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(Renderable, Renderable, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(PathBuffer, PathBuffer, DataModelDataType::String) \
+ HANDLE_QT3DSDM_COMPLETE_TYPE(ShadowMapResolution, ShadowMapResolution, DataModelDataType::Long)
+
+DataModelDataType::Value CompleteMetaDataType::ToDataType(CompleteMetaDataType::Enum inCompleteType)
+{
+ switch (inCompleteType) {
+#define HANDLE_QT3DSDM_COMPLETE_NONE_TYPE \
+ case Unknown: \
+ return DataModelDataType::None;
+#define HANDLE_QT3DSDM_COMPLETE_TYPE(name, addtype, dtype) \
+ case name: \
+ return dtype;
+ ITERATE_QT3DSDM_COMPLETE_TYPES
+ #undef HANDLE_QT3DSDM_COMPLETE_NONE_TYPE
+ #undef HANDLE_QT3DSDM_COMPLETE_TYPE
+ }
+ QT3DS_ASSERT(false);
+ return DataModelDataType::None;
+}
+
+AdditionalMetaDataType::Value
+CompleteMetaDataType::ToAdditionalType(CompleteMetaDataType::Enum inCompleteType)
+{
+ switch (inCompleteType) {
+#define HANDLE_QT3DSDM_COMPLETE_NONE_TYPE \
+ case Unknown: \
+ return AdditionalMetaDataType::None;
+#define HANDLE_QT3DSDM_COMPLETE_TYPE(name, addtype, dtype) \
+ case name: \
+ return AdditionalMetaDataType::addtype;
+ ITERATE_QT3DSDM_COMPLETE_TYPES
+ #undef HANDLE_QT3DSDM_COMPLETE_NONE_TYPE
+ #undef HANDLE_QT3DSDM_COMPLETE_TYPE
+ }
+ QT3DS_ASSERT(false);
+ return AdditionalMetaDataType::None;
+}
+
+CompleteMetaDataType::Enum
+CompleteMetaDataType::ToCompleteType(DataModelDataType::Value inDataType,
+ AdditionalMetaDataType::Value inAdditionalType)
+{
+#define HANDLE_QT3DSDM_COMPLETE_NONE_TYPE \
+ if (inDataType == DataModelDataType::None) \
+ return CompleteMetaDataType::Unknown;
+#define HANDLE_QT3DSDM_COMPLETE_TYPE(name, addtype, dtype) \
+ if (inDataType == dtype \
+ && inAdditionalType == AdditionalMetaDataType::addtype) \
+ return CompleteMetaDataType::name;
+
+ ITERATE_QT3DSDM_COMPLETE_TYPES
+ #undef HANDLE_QT3DSDM_COMPLETE_NONE_TYPE
+ #undef HANDLE_QT3DSDM_COMPLETE_TYPE
+ QT3DS_ASSERT(false);
+ return CompleteMetaDataType::Unknown;
+}
+
+QT3DSU32 WStrOps<CompleteMetaDataType::Enum>::ToStr(CompleteMetaDataType::Enum item,
+ NVDataRef<wchar_t> buffer)
+{
+ switch (item) {
+#define HANDLE_QT3DSDM_COMPLETE_NONE_TYPE \
+ case CompleteMetaDataType::Unknown: \
+ wcscpy_s(buffer.begin(), buffer.size(), L"None"); \
+ return 1;
+#define HANDLE_QT3DSDM_COMPLETE_TYPE(name, addtype, dtype) \
+ case CompleteMetaDataType::name: \
+ wcscpy_s(buffer.begin(), buffer.size(), QT3DS_WCHAR_T_##name); \
+ return 1;
+
+ ITERATE_QT3DSDM_COMPLETE_TYPES
+ #undef HANDLE_QT3DSDM_COMPLETE_NONE_TYPE
+ #undef HANDLE_QT3DSDM_COMPLETE_TYPE
+ }
+ QT3DS_ASSERT(false);
+ return 0;
+}
+bool WStrOps<CompleteMetaDataType::Enum>::StrTo(const wchar_t *buffer,
+ CompleteMetaDataType::Enum &item)
+{
+
+#define HANDLE_QT3DSDM_COMPLETE_NONE_TYPE \
+ if (AreEqual(buffer, L"None")) { \
+ item = CompleteMetaDataType::Unknown; \
+ return true; \
+}
+#define HANDLE_QT3DSDM_COMPLETE_TYPE(name, addtype, dtype) \
+ if (AreEqual(buffer, QT3DS_WCHAR_T_##name)) { \
+ item = CompleteMetaDataType::name; \
+ return true; \
+}
+
+ ITERATE_QT3DSDM_COMPLETE_TYPES
+ #undef HANDLE_QT3DSDM_COMPLETE_NONE_TYPE
+ #undef HANDLE_QT3DSDM_COMPLETE_TYPE
+ return false;
+}
+}
+
+namespace {
+
+#ifndef QT3DSDM_META_DATA_NO_SIGNALS
+#define CONNECT(x) std::make_shared<qt3dsdm::QtSignalConnection>(QObject::connect(this, x, inCallback))
+#else
+#define CONNECT(x) std::shared_ptr<qt3dsdm::ISignalConnection>()
+
+struct SNullFunc
+{
+ template <typename TArgType>
+ void operator()(TArgType)
+ {
+ }
+ template <typename TA1, typename TA2>
+ void operator()(TA1, TA2)
+ {
+ }
+};
+
+#endif
+
+typedef TCharStr TStrType;
+using std::hash;
+
+struct InstanceHandleVecHash
+{
+ size_t operator()(const vector<TInstanceHandle> &inInstances) const
+ {
+ size_t retval = 0;
+ for (size_t idx = 0, end = inInstances.size(); idx < end; ++idx)
+ retval = retval ^ hash<int>()(inInstances[idx]);
+ return retval;
+ }
+};
+
+struct SEventAndHandlerBase
+{
+ Qt3DSDMInstanceHandle m_Instance;
+ TStrType m_Name;
+ TStrType m_FormalName;
+ TStrType m_Category;
+ TStrType m_Description;
+ SEventAndHandlerBase() {}
+ SEventAndHandlerBase(Qt3DSDMInstanceHandle hdl)
+ : m_Instance(hdl)
+ {
+ }
+};
+
+struct SEvent : public SEventAndHandlerBase
+{
+ SEvent() {}
+ SEvent(Qt3DSDMInstanceHandle hdl)
+ : SEventAndHandlerBase(hdl)
+ {
+ }
+};
+
+struct SHandler : public SEventAndHandlerBase
+{
+ SHandler() {}
+ SHandler(Qt3DSDMInstanceHandle hdl)
+ : SEventAndHandlerBase(hdl)
+ {
+ }
+ vector<SMetaDataHandlerArgumentInfo> m_Arguments;
+};
+
+// Note that this hash item only works for strings that are in the string table.
+// These have the property that pointer comparison also indicates string equality.
+struct SInstanceStrHash
+{
+ size_t operator()(const pair<TInstanceHandle, TCharPtr> &inPair) const
+ {
+ return hash<int>()(inPair.first) ^ hash<const void *>()(inPair.second);
+ }
+};
+
+template <typename TDataType>
+NVConstDataRef<TDataType> VecToCRef(const eastl::vector<TDataType> &inType)
+{
+ return NVConstDataRef<TDataType>(inType.data(), (QT3DSU32)inType.size());
+}
+
+struct SMetaDataDynamicObjectImpl
+{
+private:
+ SMetaDataDynamicObjectImpl &operator=(const SMetaDataDynamicObjectImpl &inOther);
+
+public:
+ TCharStr m_Name;
+ TCharStr m_SourcePath;
+ eastl::vector<SMetaDataShader> m_Shaders;
+ eastl::vector<qt3ds::render::dynamic::SPropertyDefinition> m_Properties;
+ eastl::vector<eastl::vector<qt3ds::foundation::CRegisteredString> *> m_EnumValueNames;
+ ~SMetaDataDynamicObjectImpl() { ClearEnumValueNames(); }
+
+ void ClearEnumValueNames()
+ {
+ for (QT3DSU32 idx = 0, end = m_EnumValueNames.size(); idx < end; ++idx)
+ delete (m_EnumValueNames[idx]);
+ m_EnumValueNames.clear();
+ }
+};
+
+struct SMetaDataEffectImpl : public SMetaDataDynamicObjectImpl
+{
+private:
+ SMetaDataEffectImpl &operator=(const SMetaDataEffectImpl &inOther);
+
+public:
+ eastl::vector<qt3ds::render::dynamic::SCommand *> m_EffectCommands;
+
+ void ClearEffectCommands()
+ {
+ for (QT3DSU32 idx = 0, end = m_EnumValueNames.size(); idx < end; ++idx)
+ free(m_EffectCommands[idx]);
+ m_EffectCommands.clear();
+ }
+ SMetaDataEffect ToEffect() const
+ {
+ return SMetaDataEffect(m_Name, VecToCRef(m_Shaders), VecToCRef(m_Properties),
+ VecToCRef(m_EffectCommands));
+ }
+};
+
+struct SMetaDataCustomMaterialImpl : public SMetaDataDynamicObjectImpl
+{
+private:
+ SMetaDataCustomMaterialImpl &operator=(const SMetaDataCustomMaterialImpl &);
+
+public:
+ eastl::vector<qt3ds::render::dynamic::SCommand *>
+ m_CustomerMaterialCommands; ///< our command stream used for rendering
+ bool m_HasTransparency; ///< this material is transparent
+ bool m_HasRefraction; ///< this material is refractive (e.g glass)
+ bool m_AlwaysDirty;
+ QT3DSU32 m_ShaderKey; ///< What does this shader contain ( e.g. specular, diffuse, ...)
+ QT3DSU32 m_LayerCount; ///< How much layers does this material have
+
+ void ClearEffectCommands()
+ {
+ for (QT3DSU32 idx = 0, end = m_EnumValueNames.size(); idx < end; ++idx) {
+ free(m_CustomerMaterialCommands[idx]);
+ }
+
+ m_CustomerMaterialCommands.clear();
+ }
+
+ SMetaDataCustomMaterial ToMaterial() const
+ {
+ return SMetaDataCustomMaterial(m_Name, VecToCRef(m_Shaders), VecToCRef(m_Properties),
+ VecToCRef(m_CustomerMaterialCommands), m_HasTransparency,
+ m_HasRefraction, m_AlwaysDirty, m_ShaderKey, m_LayerCount);
+ }
+};
+
+#ifndef QT3DSDM_META_DATA_NO_SIGNALS
+class SNewMetaDataImpl : public QObject, public IMetaData
+{
+ Q_OBJECT
+#else
+class SNewMetaDataImpl : public IMetaData
+{
+#endif
+public:
+ typedef unordered_map<TCharPtr, TInstanceHandle> TStrInstanceMap;
+ typedef unordered_map<TInstanceHandle, TCharPtr, hash<int>> TInstanceStrMap;
+ // Caching the derivation chain lookup so we can quickly lookup the entire list of
+ // derived instances (and have it ordered, somewhat).
+ typedef unordered_map<vector<TInstanceHandle>, vector<TInstanceHandle>, InstanceHandleVecHash>
+ TDerivationMap;
+
+ typedef unordered_map<TCategoryHandle, SCategoryInfo, hash<int>> TCategoryMap;
+ typedef unordered_map<TCharPtr, TCategoryHandle> TNameCategoryMap;
+
+ typedef unordered_map<TMetaDataPropertyHandle, SMetaDataPropertyInfo, hash<int>>
+ TMetaDataPropertyMap;
+ typedef unordered_map<TInstanceHandle, vector<TMetaDataPropertyHandle>, hash<int>>
+ TInstancePropertyMap;
+ typedef unordered_map<pair<TInstanceHandle, TCharPtr>, TMetaDataPropertyHandle,
+ SInstanceStrHash>
+ TInstancePropertyNamePropertyMap;
+ typedef unordered_map<TMetaDataPropertyHandle, eastl::vector<SPropertyFilterInfo>, hash<int>>
+ TMetaDataPropertyFilterMap;
+ typedef unordered_map<TInstanceHandle, vector<TCharPtr>, hash<int>> TInstanceGroupMap;
+
+ typedef unordered_map<TEventHandle, SEvent, hash<int>> TEventMap;
+ typedef unordered_map<TInstanceHandle, vector<TEventHandle>, hash<int>> TInstanceEventMap;
+ typedef unordered_map<pair<TInstanceHandle, TCharPtr>, TEventHandle, SInstanceStrHash>
+ TInstanceEventNameEventMap;
+
+ typedef unordered_map<THandlerHandle, SHandler, hash<int>> THandlerMap;
+ typedef unordered_map<TInstanceHandle, vector<THandlerHandle>, hash<int>> TInstanceHandlerMap;
+ typedef unordered_map<pair<TInstanceHandle, TCharPtr>, THandlerHandle, SInstanceStrHash>
+ TInstanceHandlerNameHandlerMap;
+
+ typedef unordered_map<TInstanceHandle, vector<TCharPtr>, hash<int>> TInstanceStringListMap;
+ typedef unordered_map<TCharPtr, SMetaDataEffectImpl> TEffectMap;
+ typedef unordered_map<TCharPtr, SMetaDataCustomMaterialImpl> TCustomMaterialMap;
+
+ std::shared_ptr<IDataCore> m_DataCore;
+ IStringTable &m_StringTable;
+ TTransactionConsumerPtr m_Consumer;
+
+ int m_NextId;
+
+ // Helper objects to speed up queries
+ TStrInstanceMap m_CanonicalTypeToInstances;
+ TInstanceStrMap m_InstancesToCanonicalType;
+ TDerivationMap m_DerivationMap;
+
+ TCategoryMap m_Categories;
+ TNameCategoryMap m_NameToCategories;
+
+ TMetaDataPropertyMap m_Properties;
+ TInstancePropertyMap m_InstanceToProperties;
+ TInstancePropertyNamePropertyMap m_InstanceNameToProperties;
+ TMetaDataPropertyFilterMap m_PropertyFilters;
+ TInstanceGroupMap m_InstanceGroupMap;
+
+ TEventMap m_Events;
+ TInstanceEventMap m_InstanceToEvents;
+ TInstanceEventNameEventMap m_InstanceNameToEvents;
+
+ THandlerMap m_Handlers;
+ TInstanceHandlerMap m_InstanceToHandlers;
+ TInstanceHandlerNameHandlerMap m_InstanceNameToHandlers;
+
+ TInstanceStringListMap m_InstanceToReferences;
+
+ vector<TInstanceHandle> m_Parents;
+ vector<TInstanceHandle> m_NextParents;
+ vector<TInstanceHandle> m_DerivationChain;
+ unordered_set<int> m_UniqueSet;
+ unordered_set<size_t> m_SizeTSet;
+
+ MemoryBuffer<RawAllocator> m_TempBuffer;
+ MemoryBuffer<RawAllocator> m_ReadBuffer;
+
+ eastl::string m_ConvertStr;
+
+ TCharStr m_ObjectName;
+
+ TEffectMap m_EffectMap;
+ TCustomMaterialMap m_CustomMaterials;
+
+#ifndef QT3DSDM_META_DATA_NO_SIGNALS
+Q_SIGNALS:
+ void internalCategoryDestroyed(Qt3DSDMCategoryHandle);
+ void internalMetaDataPropertyDestroyed(Qt3DSDMMetaDataPropertyHandle);
+ void internalEventDestroyed(Qt3DSDMEventHandle);
+ void internalHandlerDestroyed(Qt3DSDMHandlerHandle);
+ void internalHandlerArgDestroyed(Qt3DSDMHandlerHandle, QT3DSU32);
+#else
+ SNullFunc internalCategoryDestroyed;
+ SNullFunc internalMetaDataPropertyDestroyed;
+ SNullFunc internalEventDestroyed;
+ SNullFunc internalHandlerDestroyed;
+ SNullFunc internalHandlerArgDestroyed;
+#endif
+public:
+ TSignalConnectionPtr m_PropertyDeletedConnection;
+ bool m_IgnorePropertyDeleted;
+ TSignalConnectionPtr m_InstanceDeletedConnection;
+
+ SNewMetaDataImpl(std::shared_ptr<IDataCore> inDataCore)
+ : m_DataCore(inDataCore)
+ , m_StringTable(inDataCore->GetStringTable())
+ , m_NextId(1)
+ , m_IgnorePropertyDeleted(false)
+ {
+#ifndef QT3DSDM_META_DATA_NO_SIGNALS
+ CDataCoreProducer *producer = dynamic_cast<CDataCoreProducer *>(inDataCore.get());
+ if (producer) {
+ m_PropertyDeletedConnection = producer->ConnectPropertyRemoved(
+ bind(&SNewMetaDataImpl::OnPropertyRemoved, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_InstanceDeletedConnection = producer->ConnectBeforeInstanceDeleted(
+ bind(&SNewMetaDataImpl::OnInstanceRemoved, this,
+ std::placeholders::_1));
+ }
+#endif
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Helper Functions
+
+ const wchar_t *Intern(TStrType inData) { return m_StringTable.RegisterStr(inData.wide_str()); }
+ const wchar_t *Intern(const char *inData) { return m_StringTable.GetWideStr(inData); }
+
+ inline int GetNextId()
+ {
+ int retval = m_NextId;
+ ++m_NextId;
+ return retval;
+ }
+
+ template <typename TMapType, typename THandleType>
+ static void AddItemToInstanceList(TInstanceHandle inInstance, THandleType inHandle, QT3DSU32 inIdx,
+ TMapType &ioMap)
+ {
+ pair<typename TMapType::iterator, bool> inserter =
+ ioMap.insert(make_pair(inInstance, vector<THandleType>()));
+ inserter.first->second.insert(inserter.first->second.begin() + inIdx, inHandle);
+ }
+
+ template <typename TMapType, typename THandleType>
+ static QT3DSU32 AddItemToInstanceList(TInstanceHandle inInstance, THandleType inHandle,
+ TMapType &ioMap)
+ {
+ pair<typename TMapType::iterator, bool> inserter =
+ ioMap.insert(make_pair(inInstance, vector<THandleType>()));
+ QT3DSU32 offset = (QT3DSU32)inserter.first->second.size();
+ inserter.first->second.push_back(inHandle);
+ return offset;
+ }
+
+ template <typename TItemType>
+ struct VectorEqualPred
+ {
+ TItemType m_Item;
+ VectorEqualPred(const TItemType &inItem)
+ : m_Item(inItem)
+ {
+ }
+
+ bool operator()(const TItemType &inOther) const { return m_Item == inOther; }
+ };
+
+ template <typename THandleType, typename TMapType>
+ static QT3DSU32 DoRemoveItemFromInstanceList(TInstanceHandle inInstance, THandleType inHandle,
+ TMapType &ioMap)
+ {
+ typename TMapType::iterator find = ioMap.find(inInstance);
+ if (find != ioMap.end()) {
+ typename vector<THandleType>::iterator theVecFind =
+ std::find(find->second.begin(), find->second.end(), inHandle);
+ if (theVecFind != find->second.end()) {
+ QT3DSU32 retval = (QT3DSU32)(theVecFind - find->second.begin());
+ find->second.erase(theVecFind);
+ if (find->second.empty())
+ ioMap.erase(find);
+ return retval;
+ }
+ }
+ QT3DS_ASSERT(false);
+ return QT3DS_MAX_U32;
+ }
+
+ template <typename TMapType, typename THandleType>
+ struct InstanceListTransaction : ITransaction
+ {
+ TInstanceHandle m_Instance;
+ THandleType m_Handle;
+ TMapType &m_Map;
+ QT3DSU32 m_Idx;
+ bool m_InsertOnDo;
+
+ InstanceListTransaction(const char *inFile, int inLine, TInstanceHandle inst,
+ THandleType handle, TMapType &map, QT3DSU32 inIdx, bool inInsertOnDo)
+ : ITransaction(inFile, inLine)
+ , m_Instance(inst)
+ , m_Handle(handle)
+ , m_Map(map)
+ , m_Idx(inIdx)
+ , m_InsertOnDo(inInsertOnDo)
+ {
+ }
+
+ void insert()
+ {
+ SNewMetaDataImpl::AddItemToInstanceList(m_Instance, m_Handle, m_Idx, m_Map);
+ }
+ void remove()
+ {
+ SNewMetaDataImpl::DoRemoveItemFromInstanceList(m_Instance, m_Handle, m_Map);
+ }
+
+ void Do() override
+ {
+ if (m_InsertOnDo)
+ insert();
+ else
+ remove();
+ }
+ void Undo() override
+ {
+ if (m_InsertOnDo)
+ remove();
+ else
+ insert();
+ }
+ };
+
+ template <typename THandleType, typename TMapType>
+ void RemoveItemFromInstanceList(const char *inFile, int inLine, TInstanceHandle inInstance,
+ THandleType inHandle, TMapType &ioMap)
+ {
+ typename TMapType::iterator find = ioMap.find(inInstance);
+ if (find != ioMap.end()) {
+ QT3DSU32 idx = DoRemoveItemFromInstanceList(inInstance, inHandle, ioMap);
+ if (m_Consumer != NULL) {
+ m_Consumer->OnTransaction(
+ std::make_shared<InstanceListTransaction<TMapType, THandleType>>(
+ inFile, inLine, inInstance, inHandle, std::ref(ioMap), idx, false));
+ }
+ }
+ }
+
+ template <typename THandleType, typename TValueType, typename TMapType,
+ typename TInstanceListMapType>
+ THandleType CreateItem(const char *inFile, int inLine, Qt3DSDMInstanceHandle inInstance,
+ TMapType &inMap, TInstanceListMapType &inInstanceListMap)
+ {
+ int retval = GetNextId();
+ pair<THandleType, TValueType> thePair(make_pair(retval, TValueType(inInstance)));
+ inMap.insert(thePair);
+ QT3DSU32 idx = AddItemToInstanceList(inInstance, THandleType(retval), inInstanceListMap);
+ if (m_Consumer) {
+ CreateHashMapInsertTransaction(inFile, inLine, m_Consumer, thePair, inMap);
+ m_Consumer->OnTransaction(
+ std::make_shared<InstanceListTransaction<TInstanceListMapType, THandleType>>(
+ inFile, inLine, inInstance, retval, std::ref(inInstanceListMap), idx, true));
+ }
+ return retval;
+ }
+
+ template <typename TKeyType, typename TValueType, typename THashType>
+ TValueType *FindHashItem(TKeyType inHandle,
+ unordered_map<TKeyType, TValueType, THashType> &ioHash)
+ {
+ typename unordered_map<TKeyType, TValueType, THashType>::iterator find =
+ ioHash.find(inHandle);
+ if (find != ioHash.end())
+ return &find->second;
+ return NULL;
+ }
+
+ template <typename THandleType, typename TMapType>
+ static void DoReplaceNamedItem(TInstanceHandle inInst, TCharPtr inOldName, TCharPtr inNewName,
+ THandleType inNewHandle, TMapType &ioMap)
+ {
+ ioMap.erase(make_pair(inInst, inOldName));
+ bool success = ioMap.insert(make_pair(make_pair(inInst, inNewName), inNewHandle)).second;
+ (void)success;
+ QT3DS_ASSERT(success);
+ }
+
+ template <typename TMapType, typename THandleType>
+ struct ReplaceNamedItemTransaction : ITransaction
+ {
+ TInstanceHandle m_Instance;
+ TCharPtr m_OldName;
+ TCharPtr m_NewName;
+ THandleType m_OldHandle;
+ THandleType m_NewHandle;
+ TMapType &m_Map;
+ ReplaceNamedItemTransaction(const char *inFile, int inLine, TInstanceHandle inst,
+ TCharPtr oldNm, TCharPtr newNm, THandleType oldHdl,
+ THandleType newHdl, TMapType &map)
+ : ITransaction(inFile, inLine)
+ , m_Instance(inst)
+ , m_OldName(oldNm)
+ , m_NewName(newNm)
+ , m_OldHandle(oldHdl)
+ , m_NewHandle(newHdl)
+ , m_Map(map)
+ {
+ }
+ void Do() override
+ {
+ SNewMetaDataImpl::DoReplaceNamedItem(m_Instance, m_OldName, m_NewName, m_NewHandle,
+ m_Map);
+ }
+ void Undo() override
+ {
+ SNewMetaDataImpl::DoReplaceNamedItem(m_Instance, m_NewName, m_OldName, m_OldHandle,
+ m_Map);
+ }
+ };
+
+ template <typename THandleType, typename TMapType>
+ void ReplaceNamedItem(const char *inFile, int inLine, TInstanceHandle inInst,
+ TCharPtr inOldName, TCharPtr inNewName, THandleType inNewHandle,
+ TMapType &ioMap)
+ {
+ typename TMapType::iterator find = ioMap.find(std::make_pair(inInst, inOldName));
+ THandleType oldHandle;
+ if (find != ioMap.end())
+ oldHandle = find->second;
+ DoReplaceNamedItem(inInst, inOldName, inNewName, inNewHandle, ioMap);
+ if (m_Consumer) {
+ if (oldHandle.Valid()) {
+ m_Consumer->OnTransaction(
+ std::make_shared<ReplaceNamedItemTransaction<TMapType, THandleType>>(
+ inFile, inLine, inInst, inOldName, inNewName, oldHandle, inNewHandle,
+ std::ref(ioMap)));
+ } else
+ CreateHashMapInsertTransaction(__FILE__, __LINE__, m_Consumer,
+ make_pair(make_pair(inInst, inNewName), inNewHandle),
+ ioMap);
+ }
+ }
+
+ template <typename THandleType, typename TMapType>
+ void DestroyNamedItem(const char *inFile, int inLine, TInstanceHandle inInst, TCharPtr inName,
+ TMapType &ioMap)
+ {
+ typename TMapType::iterator iter = ioMap.find(make_pair(inInst, inName));
+ if (iter != ioMap.end()) {
+ pair<pair<TInstanceHandle, TCharPtr>, THandleType> existing(*iter);
+ ioMap.erase(iter);
+ CreateHashMapEraseTransaction(inFile, inLine, m_Consumer, existing, ioMap);
+ }
+ }
+
+ template <typename THandleType, typename TInfoType, typename TMapType, typename TNamedMapType>
+ void SetItemInfo(const char *inFile, int inLine, THandleType inItem, const TInfoType &oldInfo,
+ const TInfoType &newInfo, TMapType &inMap, TNamedMapType &inNamedMap)
+ {
+ TCharPtr newName = Intern(newInfo.m_Name.wide_str());
+ TCharPtr oldName = Intern(oldInfo.m_Name.wide_str());
+ ReplaceNamedItem(inFile, inLine, newInfo.m_Instance, oldName, newName, inItem, inNamedMap);
+ CreateHashMapSwapTransaction(inFile, inLine, m_Consumer, inItem, oldInfo, newInfo, inMap);
+ }
+
+ bool AddDerivationChainItem(TInstanceHandle inInst)
+ {
+ if (m_UniqueSet.find(inInst) == m_UniqueSet.end()) {
+ m_DerivationChain.push_back(inInst);
+ m_UniqueSet.insert(inInst);
+ return true;
+ }
+ return false;
+ }
+
+ void GetDerivationChain(TInstanceHandle inInst)
+ {
+ m_Parents.clear();
+ m_DerivationChain.clear();
+ m_UniqueSet.clear();
+ m_NextParents.clear();
+ m_DataCore->GetInstanceParents(inInst, m_Parents);
+
+ TDerivationMap::iterator mapIter = m_DerivationMap.find(m_Parents);
+ if (mapIter != m_DerivationMap.end())
+ m_DerivationChain = mapIter->second;
+ else {
+ while (m_Parents.empty() == false) {
+ for (size_t idx = 0, end = m_Parents.size(); idx < end; ++idx) {
+ if (AddDerivationChainItem(m_Parents[idx]))
+ m_DataCore->GetInstanceParents(m_Parents[idx], m_NextParents);
+ }
+ m_Parents = m_NextParents;
+ m_NextParents.clear();
+ }
+ m_NextParents.clear();
+
+ m_DataCore->GetInstanceParents(inInst, m_NextParents);
+ m_DerivationMap.insert(make_pair(m_NextParents, m_DerivationChain));
+ }
+ }
+
+ template <typename THandleType, typename TMapType>
+ THandleType FindItemByName(TInstanceHandle inInst, TCharPtr inName, TMapType &ioMap)
+ {
+ typename TMapType::iterator find(ioMap.find(make_pair(inInst, inName)));
+ if (find != ioMap.end())
+ return find->second;
+
+ GetDerivationChain(inInst);
+ for (size_t idx = 0, end = m_DerivationChain.size(); idx < end; ++idx) {
+ find = ioMap.find(make_pair(m_DerivationChain[idx], inName));
+ if (find != ioMap.end())
+ return find->second;
+ }
+ return 0;
+ }
+
+ template <typename TItemType, typename TVectorType>
+ void AddListMapItems(const std::vector<TItemType> &inMapEntry, TVectorType &outVector)
+ {
+ typedef typename std::vector<TItemType>::const_iterator TIterType;
+ for (TIterType theIter = inMapEntry.begin(), theEnd = inMapEntry.end(); theIter != theEnd;
+ ++theIter)
+ outVector.push_back(*theIter);
+ }
+
+ template <typename TListMapType, typename TSizeTOpType, typename TVectorType>
+ void DoGetHandleList(Qt3DSDMInstanceHandle inInstance, TListMapType &inMap,
+ TVectorType &outHandles, TSizeTOpType inOperator)
+ {
+ typename TListMapType::iterator find;
+ GetDerivationChain(inInstance);
+ for (size_t idx = 0, end = m_DerivationChain.size(); idx < end; ++idx) {
+ // Add base classes to the list first
+ find = inMap.find(m_DerivationChain[end - idx - 1]);
+ if (find != inMap.end())
+ AddListMapItems(find->second, outHandles);
+ }
+ find = inMap.find(inInstance);
+ if (find != inMap.end())
+ AddListMapItems(find->second, outHandles);
+ m_SizeTSet.clear();
+ for (size_t ridx = 0; ridx < outHandles.size(); ++ridx) {
+ size_t idx = outHandles.size() - ridx - 1;
+ // Run through the list backwards, making sure that items further in the list
+ // completely overshadow items earlier in the list.
+
+ // Create unique key from the item that we can check against
+ size_t item = inOperator(outHandles[idx]);
+ if (m_SizeTSet.insert(item).second == false) {
+ outHandles.erase(outHandles.begin() + idx);
+ --ridx;
+ }
+ }
+ }
+
+ template <typename THandleType, typename TMapType>
+ struct NameSizeTOpType
+ {
+ SNewMetaDataImpl &m_Impl;
+ TMapType &m_Map;
+ NameSizeTOpType(SNewMetaDataImpl &inImpl, TMapType &inMap)
+ : m_Impl(inImpl)
+ , m_Map(inMap)
+ {
+ }
+
+ size_t operator()(THandleType inHandle)
+ {
+ return reinterpret_cast<size_t>(m_Impl.Intern(m_Map[inHandle].m_Name));
+ }
+ };
+
+ // Ensure we don't return two items of the same name.
+ template <typename THandleType, typename TListMapType, typename TMapType>
+ void GetHandleList(Qt3DSDMInstanceHandle inInstance, TListMapType &inMap, TMapType &inTypeName,
+ vector<THandleType> &outHandles)
+ {
+ DoGetHandleList(inInstance, inMap, outHandles,
+ NameSizeTOpType<THandleType, TMapType>(*this, inTypeName));
+ }
+
+ template <typename THandleType, typename TMapType, typename TNameMapType,
+ typename TListMapType>
+ bool DestroyItem(const char *inFile, int inLine, THandleType inItem,
+ TMapType &inMap, TNameMapType &inNameMap, TListMapType &inListMap)
+ {
+ typename TMapType::iterator find(inMap.find(inItem));
+ if (find == inMap.end())
+ return false;
+ DestroyNamedItem<THandleType>(inFile, inLine, find->second.m_Instance,
+ Intern(find->second.m_Name.wide_str()), inNameMap);
+ RemoveItemFromInstanceList(inFile, inLine, find->second.m_Instance, inItem, inListMap);
+ CreateHashMapEraseTransaction(inFile, inLine, m_Consumer,
+ make_pair(find->first, find->second), inMap);
+ inMap.erase(find);
+ return true;
+ }
+
+ template <typename THandleType, typename TListMapType>
+ void ForEachItem(Qt3DSDMInstanceHandle inInstance, TListMapType &ioMap,
+ function<void(THandleType)> inOperation)
+ {
+ typename TListMapType::iterator find = ioMap.find(inInstance);
+ if (find != ioMap.end()) {
+ vector<THandleType> itemData(find->second);
+ for (size_t idx = 0, end = itemData.size(); idx < end; ++idx)
+ inOperation(itemData[idx]);
+ }
+ }
+
+ SCategoryInfo *FindCategory(Qt3DSDMCategoryHandle inCategory)
+ {
+ return FindHashItem(inCategory, m_Categories);
+ }
+
+ SMetaDataPropertyInfo *FindProperty(Qt3DSDMMetaDataPropertyHandle inPropertyHandle)
+ {
+ return FindHashItem(inPropertyHandle, m_Properties);
+ }
+
+ SEvent *FindEvent(Qt3DSDMEventHandle inEventHandle)
+ {
+ return FindHashItem(inEventHandle, m_Events);
+ }
+
+ SHandler *FindHandler(Qt3DSDMHandlerHandle inHandle)
+ {
+ return FindHashItem(inHandle, m_Handlers);
+ }
+
+ SMetaDataHandlerArgumentInfo *FindHandlerArg(Qt3DSDMHandlerHandle inHandler, QT3DSU32 inIdx)
+ {
+ SHandler *theHandler(FindHandler(inHandler));
+ if (theHandler && theHandler->m_Arguments.size() > inIdx)
+ return &theHandler->m_Arguments[inIdx];
+ return NULL;
+ }
+
+ void OnPropertyRemoved(Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty)
+ {
+ if (m_IgnorePropertyDeleted)
+ return;
+
+ vector<Qt3DSDMMetaDataPropertyHandle> propertiesToDestroy;
+ for (TMetaDataPropertyMap::iterator iter = m_Properties.begin(), end = m_Properties.end();
+ iter != end; ++iter) {
+ if (iter->second.m_Property == inProperty)
+ propertiesToDestroy.push_back(iter->first);
+ }
+
+ for (size_t idx = 0, end = propertiesToDestroy.size(); idx < end; ++idx)
+ DestroyMetaDataProperty(propertiesToDestroy[idx]);
+ }
+
+ void OnInstanceRemoved(Qt3DSDMInstanceHandle inInstance) { DestroyMetaData(inInstance); }
+ template <typename TEntryType, typename TMapType>
+ void InsertWithTransaction(const char *inFile, int inLine, const TEntryType &inEntry,
+ TMapType &inMap)
+ {
+ inMap.insert(inEntry);
+ CreateHashMapInsertTransaction(inFile, inLine, m_Consumer, inEntry, inMap);
+ }
+
+ template <typename TKeyType, typename TMapType>
+ void EraseWithTransaction(const char *inFile, int inLine, TKeyType inKey, TMapType &inMap)
+ {
+ typename TMapType::iterator find(inMap.find(inKey));
+ if (find != inMap.end()) {
+ CreateHashMapEraseTransaction(inFile, inLine, m_Consumer,
+ std::make_pair(find->first, find->second), inMap);
+ inMap.erase(find);
+ }
+ }
+
+ template <typename TEntryType, typename TMapType>
+ void InsertOrUpdateWithTransaction(const TEntryType &inEntry, TMapType &inMap)
+ {
+ pair<typename TMapType::iterator, bool> inserter = inMap.insert(inEntry);
+ if (inserter.second)
+ CreateHashMapInsertTransaction(__FILE__, __LINE__, m_Consumer, inEntry, inMap);
+ else {
+ typename TMapType::iterator theIter(inserter.first);
+ CreateHashMapSwapTransaction(__FILE__, __LINE__, m_Consumer, theIter->first,
+ theIter->second, inEntry.second, inMap);
+ theIter->second = inEntry.second;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // API Implementation
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Sharing some utility objects
+ IStringTable &GetStringTable() override { return m_DataCore->GetStringTable(); }
+ TStringTablePtr GetStringTablePtr() override { return m_DataCore->GetStringTablePtr(); }
+ TDataCorePtr GetDataCore() override { return m_DataCore; }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Canonical Instances
+ void SetInstanceAsCanonical(Qt3DSDMInstanceHandle inInstance, TStrType inTypename) override
+ {
+ const wchar_t *theTypename(Intern(inTypename));
+ if (g_DataModelDebugLogger)
+ g_DataModelDebugLogger("IMetaData::SetInstanceAsCanonical Enter");
+ if (g_DataModelDebugLogger)
+ g_DataModelDebugLogger(GetStringTable().GetNarrowStr(inTypename.wide_str()));
+ m_CanonicalTypeToInstances.insert(make_pair(theTypename, inInstance));
+ m_InstancesToCanonicalType.insert(make_pair(inInstance, theTypename));
+ CreateHashMapInsertTransaction(__FILE__, __LINE__, m_Consumer,
+ make_pair(theTypename, inInstance),
+ m_CanonicalTypeToInstances);
+ CreateHashMapInsertTransaction(__FILE__, __LINE__, m_Consumer,
+ make_pair(inInstance, theTypename),
+ m_InstancesToCanonicalType);
+ if (g_DataModelDebugLogger)
+ g_DataModelDebugLogger("IMetaData::SetInstanceAsCanonical Leave");
+ }
+
+ Qt3DSDMInstanceHandle GetCanonicalInstanceForType(TStrType inTypename) override
+ {
+ TStrInstanceMap::iterator find = m_CanonicalTypeToInstances.find(Intern(inTypename));
+ if (find != m_CanonicalTypeToInstances.end())
+ return find->second;
+ return 0;
+ }
+
+ Option<TCharStr> GetTypeForCanonicalInstance(Qt3DSDMInstanceHandle inInstance) override
+ {
+ TInstanceStrMap::iterator find = m_InstancesToCanonicalType.find(inInstance);
+ if (find != m_InstancesToCanonicalType.end())
+ return TCharStr(find->second);
+ return Empty();
+ }
+
+ Option<TCharStr> GetTypeForInstance(Qt3DSDMInstanceHandle inInstance) override
+ {
+ Option<TCharStr> theType = GetTypeForCanonicalInstance(inInstance);
+ if (theType.hasValue())
+ return theType;
+ GetDerivationChain(inInstance);
+ for (size_t idx = 0, end = m_DerivationChain.size(); idx < end; ++idx) {
+ theType = GetTypeForCanonicalInstance(m_DerivationChain[idx]);
+ if (theType.hasValue())
+ return theType;
+ }
+ return Empty();
+ }
+
+ QT3DSU32 GetGroupCountForInstance(Qt3DSDMInstanceHandle inInstance) override
+ {
+ std::vector<TCharStr> outNames;
+ QT3DSU32 count = GetGroupNamesForInstance(inInstance, outNames);
+ return (count == 0) ? 1 : count;
+ }
+
+ QT3DSU32 GetGroupNamesForInstance(Qt3DSDMInstanceHandle inInstance,
+ std::vector<TCharStr> &outNames) override
+ {
+ TInstanceStrMap::iterator canonicalFind = m_InstancesToCanonicalType.find(inInstance);
+ if (canonicalFind != m_InstancesToCanonicalType.end()) {
+ TInstanceGroupMap::iterator find = m_InstanceGroupMap.find(inInstance);
+ if (find != m_InstanceGroupMap.end()) {
+ pair<typename TInstanceGroupMap::iterator, bool> inserter =
+ m_InstanceGroupMap.insert(make_pair(inInstance, vector<TCharPtr>()));
+ vector<TCharPtr> &itemList = inserter.first->second;
+ for (size_t i = 0, j = itemList.size(); i < j; ++i) {
+ bool alreadyInList = false;
+ // discard duplicates
+ for (size_t k = 0, l = outNames.size(); k < l; ++k) {
+ TCharStr curListName = itemList[i];
+ if (curListName == outNames[k].wide_str()) {
+ alreadyInList = true;
+ break;
+ }
+ }
+ if (!alreadyInList)
+ outNames.push_back(itemList[i]);
+ }
+ }
+ return (QT3DSU32)outNames.size();
+ }
+
+ GetDerivationChain(inInstance);
+
+ for (int idx = (int)m_DerivationChain.size() - 1, end = 0; idx >= end; --idx) {
+ TInstanceGroupMap::iterator find = m_InstanceGroupMap.find(m_DerivationChain[idx]);
+ if (find != m_InstanceGroupMap.end()) {
+ pair<typename TInstanceGroupMap::iterator, bool> inserter =
+ m_InstanceGroupMap.insert(
+ make_pair(m_DerivationChain[idx], vector<TCharPtr>()));
+ vector<TCharPtr> &itemList = inserter.first->second;
+ for (size_t i = 0, j = itemList.size(); i < j; ++i) {
+ bool alreadyInList = false;
+ // discard duplicates
+ for (size_t k = 0, l = outNames.size(); k < l; ++k) {
+ TCharStr curListName = itemList[i];
+ if (curListName == outNames[k].wide_str()) {
+ alreadyInList = true;
+ break;
+ }
+ }
+ if (!alreadyInList)
+ outNames.push_back(itemList[i]);
+ }
+ }
+ }
+
+ return (QT3DSU32)outNames.size();
+ }
+
+ Option<TCharStr> GetGroupFilterNameForInstance(Qt3DSDMInstanceHandle inInstance,
+ long inIndex) override
+ {
+ std::vector<TCharStr> outNames;
+ QT3DSU32 count = GetGroupNamesForInstance(inInstance, outNames);
+ if (count > (QT3DSU32)inIndex)
+ return outNames[inIndex];
+
+ return Empty();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Categories
+
+ std::pair<Qt3DSDMCategoryHandle, bool> GetOrCreateCategory(TStrType inName) override
+ {
+ TCharPtr theName(Intern(inName));
+ TNameCategoryMap::iterator find = m_NameToCategories.find(theName);
+ if (find != m_NameToCategories.end())
+ return make_pair(find->second, false);
+
+ TCategoryHandle retval(GetNextId());
+ InsertWithTransaction(__FILE__, __LINE__, make_pair(retval, SCategoryInfo(inName)),
+ m_Categories);
+ InsertWithTransaction(__FILE__, __LINE__, make_pair(theName, retval), m_NameToCategories);
+ return make_pair(retval, true);
+ }
+
+ void SetCategoryInfo(Qt3DSDMCategoryHandle inCategory, TStrType inIcon,
+ TStrType inHighlight, TStrType inDescription) override
+ {
+ SCategoryInfo *infoPtr(FindCategory(inCategory));
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SCategoryInfo &newInfo(*infoPtr);
+ SCategoryInfo oldInfo(newInfo);
+
+ newInfo.m_Icon = inIcon;
+ newInfo.m_HighlightIcon = inHighlight;
+ newInfo.m_Description = inDescription;
+ CreateHashMapSwapTransaction(__FILE__, __LINE__, m_Consumer, inCategory, oldInfo, newInfo,
+ m_Categories);
+ }
+
+ void DestroyCategory(Qt3DSDMCategoryHandle inCategory) override
+ {
+ SCategoryInfo *infoPtr(FindCategory(inCategory));
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ EraseWithTransaction(__FILE__, __LINE__, Intern(infoPtr->m_Name), m_NameToCategories);
+ EraseWithTransaction(__FILE__, __LINE__, inCategory, m_Categories);
+ }
+ Option<SCategoryInfo> GetCategoryInfo(Qt3DSDMCategoryHandle inCategory) override
+ {
+ SCategoryInfo *infoPtr(FindCategory(inCategory));
+ if (infoPtr)
+ return *infoPtr;
+ return Empty();
+ }
+ Qt3DSDMCategoryHandle FindCategoryByName(TStrType inName) override
+ {
+ TCharPtr theName(Intern(inName));
+ TNameCategoryMap::iterator find = m_NameToCategories.find(theName);
+ if (find != m_NameToCategories.end())
+ return find->second;
+ return 0;
+ }
+
+ void GetCategories(vector<Qt3DSDMCategoryHandle> &outCategories) override
+ {
+ for (TCategoryMap::iterator iter = m_Categories.begin(), end = m_Categories.end();
+ iter != end; ++iter)
+ outCategories.push_back(iter->first);
+ }
+
+ Option<SCategoryInfo> GetEventCategory(TStrType inName) override
+ {
+ return GetCategoryInfo(FindCategoryByName(inName));
+ }
+
+ Option<SCategoryInfo> GetHandlerCategory(TStrType inName) override
+ {
+ return GetCategoryInfo(FindCategoryByName(inName));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Properties
+
+ Qt3DSDMMetaDataPropertyHandle CreateMetaDataProperty(Qt3DSDMInstanceHandle inInstance) override
+ {
+ return CreateItem<Qt3DSDMMetaDataPropertyHandle, SMetaDataPropertyInfo>(
+ __FILE__, __LINE__, inInstance, m_Properties, m_InstanceToProperties);
+ }
+
+ void EnsureDataCoreProperty(SMetaDataPropertyInfo &newInfo)
+ {
+ m_IgnorePropertyDeleted = true;
+ // If the existing property under the new name doesn't match
+ // the new info, then we also have to delete the property
+ Qt3DSDMPropertyHandle theExistingProperty =
+ m_DataCore->GetAggregateInstancePropertyByName(newInfo.m_Instance, newInfo.m_Name);
+ // Ensure the types match.
+ if (theExistingProperty.Valid()) {
+ Qt3DSDMPropertyDefinition theDefinition(m_DataCore->GetProperty(theExistingProperty));
+ if (theDefinition.m_Name != newInfo.m_Name
+ || theDefinition.m_Type != newInfo.GetDataType()) {
+ m_DataCore->RemoveProperty(theExistingProperty);
+ theExistingProperty = 0;
+ }
+ }
+
+ // Finally, if we don't have a property at this point, create a new property
+ if (theExistingProperty.Valid() == false)
+ theExistingProperty = m_DataCore->AddProperty(
+ newInfo.m_Instance, newInfo.m_Name.wide_str(), newInfo.GetDataType());
+ newInfo.m_Property = theExistingProperty;
+ m_IgnorePropertyDeleted = false;
+ }
+
+ // If the type doesn't match the default, then it has no default.
+ SValue VerifyDefaultPropertyType(DataModelDataType::Value inDataType, const SValue &inValue)
+ {
+ if (inValue.empty() == false) {
+ DataModelDataType::Value theType = GetValueType(inValue);
+ if (theType != inDataType) {
+ return SValue(0.0f);
+ }
+ }
+ return inValue;
+ }
+ // If the datatype doesn't match the value, force the value to match the type.
+ // some types *have* to have values.
+ TMetaDataData VerifyMetaDataDataType(AdditionalMetaDataType::Value inDataType,
+ const TMetaDataData &inValue)
+ {
+ if (inDataType == AdditionalMetaDataType::StringList
+ || inDataType == AdditionalMetaDataType::Range) {
+ if (inValue.empty() == true || inDataType != GetMetaDataValueType(inValue)) {
+ QT3DS_ASSERT(false);
+ if (inDataType == AdditionalMetaDataType::StringList)
+ return TMetaDataStringList();
+ if (inDataType == AdditionalMetaDataType::Range)
+ return SMetaDataRange(0, 1);
+ }
+ }
+ return inValue;
+ }
+
+ void SetPropertyBaseInfo(SMetaPropertyBase &newInfo, TStrType inName, TStrType inFormalName,
+ TStrType inDescription, TStrType inUsage,
+ CompleteMetaDataType::Enum inDataType, const SValue &inDefaultValue,
+ const TMetaDataData &inMetaData)
+ {
+ newInfo.m_Name = inName;
+ newInfo.m_FormalName = inFormalName;
+ newInfo.m_Description = inDescription;
+ newInfo.m_Usage = inUsage;
+ newInfo.m_CompleteType = inDataType;
+ newInfo.m_DefaultValue =
+ VerifyDefaultPropertyType(CompleteMetaDataType::ToDataType(inDataType),
+ inDefaultValue);
+ newInfo.m_MetaDataData =
+ VerifyMetaDataDataType(CompleteMetaDataType::ToAdditionalType(inDataType),
+ inMetaData);
+ }
+
+ // For properties, you set the default values separately
+ // This may delete the underlying data model property rebuild it.
+ void SetMetaDataPropertyInfo(Qt3DSDMMetaDataPropertyHandle inPropertyHandle,
+ TStrType inName, TStrType inFormalName,
+ TStrType inDescription, TStrType inUsage,
+ CompleteMetaDataType::Enum inDataType,
+ const SValue &inDefaultValue,
+ const TMetaDataData &inMetaData, TStrType inGroupName,
+ bool inIsHidden, bool inIsAnimatable,
+ bool inIsControllable) override
+ {
+ SMetaDataPropertyInfo *infoPtr = FindProperty(inPropertyHandle);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SMetaDataPropertyInfo &newInfo(*infoPtr);
+ SMetaDataPropertyInfo oldInfo(newInfo);
+
+ SetPropertyBaseInfo(newInfo, inName, inFormalName, inDescription, inUsage, inDataType,
+ inDefaultValue, inMetaData);
+ newInfo.m_IsHidden = inIsHidden;
+ newInfo.m_Animatable = inIsAnimatable;
+ newInfo.m_Controllable = inIsControllable;
+ newInfo.m_GroupName = inGroupName;
+ EnsureDataCoreProperty(newInfo);
+
+ SetItemInfo(__FILE__, __LINE__, inPropertyHandle, oldInfo, newInfo, m_Properties,
+ m_InstanceNameToProperties);
+
+ SetPropertyDefault(newInfo, CompleteMetaDataType::ToDataType(inDataType));
+ }
+
+ void SetPropertyDefault(SMetaDataPropertyInfo &newInfo, DataModelDataType::Value inDataType)
+ {
+ if (newInfo.m_DefaultValue.empty() == false
+ && GetValueType(newInfo.m_DefaultValue) == inDataType) {
+ m_DataCore->SetInstancePropertyValue(newInfo.m_Instance, newInfo.m_Property,
+ newInfo.m_DefaultValue);
+ }
+ }
+
+ // Destroy just this meta data property
+ void DestroyMetaDataProperty(Qt3DSDMMetaDataPropertyHandle inProperty) override
+ {
+ SMetaDataPropertyInfo *infoPtr = FindProperty(inProperty);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (DestroyItem(__FILE__, __LINE__, inProperty,
+ m_Properties, m_InstanceNameToProperties, m_InstanceToProperties)) {
+ Q_EMIT internalMetaDataPropertyDestroyed(inProperty);
+ }
+
+ RemoveMetaDataPropertyFilters(inProperty);
+ }
+
+ Qt3DSDMMetaDataPropertyHandle GetMetaDataProperty(Qt3DSDMInstanceHandle inInstance,
+ TStrType inPropertyName) override
+ {
+ return FindItemByName<Qt3DSDMMetaDataPropertyHandle>(inInstance, Intern(inPropertyName),
+ m_InstanceNameToProperties);
+ }
+ Qt3DSDMMetaDataPropertyHandle GetMetaDataProperty(Qt3DSDMInstanceHandle inInstance,
+ Qt3DSDMPropertyHandle inProperty) override
+ {
+ Qt3DSDMPropertyDefinition propDef(m_DataCore->GetProperty(inProperty));
+ return GetMetaDataProperty(inInstance, propDef.m_Name);
+ }
+ // Sets the value in the data core
+ virtual Option<SMetaDataPropertyInfo>
+ GetMetaDataPropertyInfo(Qt3DSDMMetaDataPropertyHandle inProperty) override
+ {
+ SMetaDataPropertyInfo *infoPtr = FindProperty(inProperty);
+ if (infoPtr == NULL) {
+ return Empty();
+ }
+ return *infoPtr;
+ }
+
+ void GetMetaDataProperties(Qt3DSDMInstanceHandle inInstance,
+ vector<Qt3DSDMMetaDataPropertyHandle> &outProperties) override
+ {
+ return GetHandleList<Qt3DSDMMetaDataPropertyHandle>(inInstance, m_InstanceToProperties,
+ m_Properties, outProperties);
+ }
+ virtual Qt3DSDMMetaDataPropertyHandle
+ GetSpecificMetaDataProperty(Qt3DSDMInstanceHandle inInstance, TStrType inPropertyName)
+ {
+ TInstancePropertyNamePropertyMap::iterator theFind = m_InstanceNameToProperties.find(
+ make_pair(inInstance, m_StringTable.RegisterStr(inPropertyName.wide_str())));
+ if (theFind != m_InstanceNameToProperties.end())
+ return theFind->second;
+ return 0;
+ }
+ virtual Qt3DSDMMetaDataPropertyHandle
+ GetOrCreateSpecificMetaDataProperty(Qt3DSDMInstanceHandle inInstance,
+ TStrType inPropertyName) override
+ {
+ Qt3DSDMMetaDataPropertyHandle theProp(
+ GetSpecificMetaDataProperty(inInstance, inPropertyName));
+ if (theProp.Valid())
+ return theProp;
+ return CreateMetaDataProperty(inInstance);
+ }
+
+ void GetSpecificMetaDataProperties(Qt3DSDMInstanceHandle inInstance,
+ vector<Qt3DSDMMetaDataPropertyHandle> &outProperties) override
+ {
+ TInstancePropertyMap::iterator find = m_InstanceToProperties.find(inInstance);
+ if (find != m_InstanceToProperties.end())
+ outProperties.insert(outProperties.end(), find->second.begin(), find->second.end());
+ }
+
+ TCharStr GetFormalName(Qt3DSDMInstanceHandle inInstance,
+ Qt3DSDMPropertyHandle inProperty) override
+ {
+ Qt3DSDMMetaDataPropertyHandle propHandle(GetMetaDataProperty(inInstance, inProperty));
+ SMetaDataPropertyInfo *infoPtr = FindProperty(propHandle);
+ if (infoPtr)
+ return infoPtr->m_FormalName;
+ return TCharStr();
+ }
+ AdditionalMetaDataType::Value GetAdditionalMetaDataType(
+ Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty) override
+ {
+ Qt3DSDMMetaDataPropertyHandle propHandle(GetMetaDataProperty(inInstance, inProperty));
+ SMetaDataPropertyInfo *infoPtr = FindProperty(propHandle);
+ if (infoPtr)
+ return infoPtr->GetAdditionalType();
+ return AdditionalMetaDataType::None;
+ }
+ TMetaDataData GetAdditionalMetaDataData(Qt3DSDMInstanceHandle inInstance,
+ Qt3DSDMPropertyHandle inProperty) override
+ {
+ Qt3DSDMMetaDataPropertyHandle propHandle(GetMetaDataProperty(inInstance, inProperty));
+ SMetaDataPropertyInfo *infoPtr = FindProperty(propHandle);
+ if (propHandle.Valid())
+ return infoPtr->m_MetaDataData;
+ return TMetaDataData();
+ }
+
+ bool IsCustomInstance(Qt3DSDMInstanceHandle inInstance)
+ {
+ return m_InstancesToCanonicalType.find(inInstance) == m_InstancesToCanonicalType.end();
+ }
+
+ SValue GetDefaultValue(Qt3DSDMInstanceHandle inInstance,
+ Qt3DSDMPropertyHandle inProperty) override
+ {
+ Qt3DSDMMetaDataPropertyHandle theProperty(GetMetaDataProperty(inInstance, inProperty));
+ if (theProperty.Valid() == false) {
+ QT3DS_ASSERT(false);
+ return SValue();
+ }
+ return FindProperty(theProperty)->m_DefaultValue;
+ }
+
+ bool IsCustomProperty(Qt3DSDMInstanceHandle inInstance,
+ Qt3DSDMPropertyHandle inProperty) override
+ {
+ Qt3DSDMMetaDataPropertyHandle propHandle(GetMetaDataProperty(inInstance, inProperty));
+ SMetaDataPropertyInfo *infoPtr = FindProperty(propHandle);
+ if (infoPtr)
+ return IsCustomInstance(infoPtr->m_Instance);
+
+ return false;
+ }
+
+ bool IsFilterValid(Qt3DSDMMetaDataPropertyHandle inProperty,
+ const SPropertyFilterInfo &inFilter)
+ {
+ SMetaDataPropertyInfo *infoPtr = FindProperty(inProperty);
+ if (m_DataCore->IsProperty(inFilter.m_FilterProperty) == false) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ Qt3DSDMPropertyDefinition theProp(m_DataCore->GetProperty(inFilter.m_FilterProperty));
+ Qt3DSDMPropertyHandle propCheck =
+ m_DataCore->GetAggregateInstancePropertyByName(infoPtr->m_Instance, theProp.m_Name);
+ if (propCheck != inFilter.m_FilterProperty) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ DataModelDataType::Value theType = GetValueType(inFilter.m_Value);
+ if (theType != theProp.m_Type) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ return true;
+ }
+
+ void SetMetaDataPropertyFilters(Qt3DSDMMetaDataPropertyHandle inProperty,
+ NVConstDataRef<SPropertyFilterInfo> inFilters) override
+ {
+ SMetaDataPropertyInfo *infoPtr = FindProperty(inProperty);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ eastl::vector<SPropertyFilterInfo> newFilters;
+ for (QT3DSU32 idx = 0, end = inFilters.size(); idx < end; ++idx) {
+ const SPropertyFilterInfo &theFilter(inFilters[idx]);
+ if (IsFilterValid(inProperty, theFilter))
+ newFilters.push_back(theFilter);
+ }
+
+ InsertOrUpdateWithTransaction(std::make_pair(inProperty, newFilters), m_PropertyFilters);
+ }
+
+ virtual NVConstDataRef<SPropertyFilterInfo>
+ GetMetaDataPropertyFilters(Qt3DSDMMetaDataPropertyHandle inProperty) override
+ {
+ TMetaDataPropertyFilterMap::iterator theIter(m_PropertyFilters.find(inProperty));
+ if (theIter != m_PropertyFilters.end())
+ return qt3ds::foundation::toDataRef(theIter->second.data(), theIter->second.size());
+ return NVConstDataRef<SPropertyFilterInfo>();
+ }
+
+ void RemoveMetaDataPropertyFilters(Qt3DSDMMetaDataPropertyHandle inProperty) override
+ {
+ TMetaDataPropertyFilterMap::iterator theIter(m_PropertyFilters.find(inProperty));
+ if (theIter != m_PropertyFilters.end())
+ EraseWithTransaction(__FILE__, __LINE__, inProperty, m_PropertyFilters);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Properties
+ Qt3DSDMEventHandle CreateMetaDataEvent(TInstanceHandle inInstance) override
+ {
+ return CreateItem<Qt3DSDMEventHandle, SEvent>(__FILE__, __LINE__, inInstance, m_Events,
+ m_InstanceToEvents);
+ }
+
+ void SetEventInfo(Qt3DSDMEventHandle inEventHandle, TStrType inName,
+ TStrType inFormalName, TStrType inCategory, TStrType inDescription) override
+ {
+ SEvent *infoPtr = FindEvent(inEventHandle);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SEvent &newInfo(*infoPtr);
+ SEvent oldInfo(newInfo);
+ newInfo.m_Name = inName;
+ newInfo.m_FormalName = inFormalName;
+ newInfo.m_Category = inCategory;
+ newInfo.m_Description = inDescription;
+ SetItemInfo(__FILE__, __LINE__, inEventHandle, oldInfo, newInfo, m_Events,
+ m_InstanceNameToEvents);
+ }
+
+ void DestroyEvent(Qt3DSDMEventHandle inEventHandle) override
+ {
+ if (DestroyItem(__FILE__, __LINE__, inEventHandle, m_Events,
+ m_InstanceNameToEvents, m_InstanceToEvents)) {
+ Q_EMIT internalEventDestroyed(inEventHandle);
+ }
+ }
+
+ void GetEvents(Qt3DSDMInstanceHandle inInstance, TEventHandleList &outEvents) override
+ {
+ return GetHandleList<Qt3DSDMEventHandle>(inInstance, m_InstanceToEvents, m_Events,
+ outEvents);
+ }
+
+ Qt3DSDMEventHandle FindEvent(Qt3DSDMInstanceHandle inInstance, TStrType inName) override
+ {
+ return FindItemByName<Qt3DSDMEventHandle>(inInstance, Intern(inName),
+ m_InstanceNameToEvents);
+ }
+
+ Option<SEventInfo> GetEventInfo(Qt3DSDMEventHandle inEventHandle) override
+ {
+ SEvent *infoPtr = FindEvent(inEventHandle);
+ if (infoPtr == NULL) {
+ return Empty();
+ }
+ SEventInfo retval;
+ retval.m_Name = infoPtr->m_Name;
+ retval.m_FormalName = infoPtr->m_FormalName;
+ retval.m_Description = infoPtr->m_Description;
+ retval.m_Category = infoPtr->m_Category;
+ return retval;
+ }
+
+ bool IsCustomEvent(Qt3DSDMEventHandle inEventHandle) override
+ {
+ SEvent *infoPtr = FindEvent(inEventHandle);
+ if (infoPtr != NULL)
+ return IsCustomInstance(infoPtr->m_Instance);
+ return false;
+ }
+
+ void GetSpecificEvents(Qt3DSDMInstanceHandle inInstance, TEventHandleList &outEvents) override
+ {
+ TInstanceEventMap::iterator theFind(m_InstanceToEvents.find(inInstance));
+ if (theFind != m_InstanceToEvents.end())
+ outEvents.insert(outEvents.end(), theFind->second.begin(), theFind->second.end());
+ }
+
+ Qt3DSDMEventHandle GetOrCreateSpecificEvent(Qt3DSDMInstanceHandle inInstance,
+ TStrType inName) override
+ {
+ TInstanceEventNameEventMap::iterator theFind(
+ m_InstanceNameToEvents.find(make_pair(inInstance, Intern(inName))));
+ if (theFind != m_InstanceNameToEvents.end())
+ return theFind->second;
+ return CreateMetaDataEvent(inInstance);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Handlers
+
+ Qt3DSDMHandlerHandle CreateHandler(Qt3DSDMInstanceHandle inInstance) override
+ {
+ return CreateItem<Qt3DSDMHandlerHandle, SHandler>(__FILE__, __LINE__, inInstance,
+ m_Handlers, m_InstanceToHandlers);
+ }
+
+ void SetHandlerInfo(Qt3DSDMHandlerHandle inHandle, TStrType inName,
+ TStrType inFormalName, TStrType inCategoryName,
+ TStrType inDescription) override
+ {
+ SHandler *infoPtr = FindHandler(inHandle);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SHandler &newInfo(*infoPtr);
+ SHandler oldInfo(newInfo);
+ newInfo.m_Name = inName;
+ newInfo.m_FormalName = inFormalName;
+ newInfo.m_Description = inDescription;
+ newInfo.m_Category = inCategoryName;
+ SetItemInfo(__FILE__, __LINE__, inHandle, oldInfo, newInfo, m_Handlers,
+ m_InstanceNameToHandlers);
+ }
+
+ void DestroyHandler(Qt3DSDMHandlerHandle inHandlerHandle) override
+ {
+ SHandler *infoPtr(FindHandler(inHandlerHandle));
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ while (infoPtr->m_Arguments.empty() == false)
+ DestroyHandlerArgument(inHandlerHandle, (QT3DSU32)infoPtr->m_Arguments.size() - 1);
+ if (DestroyItem(__FILE__, __LINE__, inHandlerHandle, m_Handlers,
+ m_InstanceNameToHandlers, m_InstanceToHandlers)) {
+ Q_EMIT internalHandlerDestroyed(inHandlerHandle);
+ }
+ }
+
+ Qt3DSDMHandlerHandle FindHandlerByName(Qt3DSDMInstanceHandle inInstance,
+ TStrType inName) override
+ {
+ return FindItemByName<Qt3DSDMHandlerHandle>(inInstance, Intern(inName),
+ m_InstanceNameToHandlers);
+ }
+
+ Option<SHandlerInfo> GetHandlerInfo(Qt3DSDMHandlerHandle inHandlerHandle) override
+ {
+ SHandler *infoPtr = FindHandler(inHandlerHandle);
+ if (infoPtr == NULL)
+ return Empty();
+
+ SHandlerInfo retval;
+ retval.m_Name = infoPtr->m_Name;
+ retval.m_FormalName = infoPtr->m_FormalName;
+ retval.m_Category = infoPtr->m_Category;
+ retval.m_Description = infoPtr->m_Description;
+
+ return retval;
+ }
+
+ void GetHandlers(Qt3DSDMInstanceHandle inInstance, THandlerHandleList &outHandlers) override
+ {
+ return GetHandleList<Qt3DSDMHandlerHandle>(inInstance, m_InstanceToHandlers, m_Handlers,
+ outHandlers);
+ }
+
+ bool IsCustomHandler(Qt3DSDMHandlerHandle inHandle) override
+ {
+ SHandler *infoPtr = FindHandler(inHandle);
+ if (infoPtr != NULL)
+ return IsCustomInstance(infoPtr->m_Instance);
+ return false;
+ }
+
+ void GetSpecificHandlers(Qt3DSDMInstanceHandle inInstance,
+ THandlerHandleList &outHandlers) override
+ {
+ TInstanceHandlerMap::iterator theFind = m_InstanceToHandlers.find(inInstance);
+ if (theFind != m_InstanceToHandlers.end())
+ outHandlers.insert(outHandlers.end(), theFind->second.begin(), theFind->second.end());
+ }
+
+ Qt3DSDMHandlerHandle GetOrCreateSpecificHandler(Qt3DSDMInstanceHandle inInstance,
+ TStrType inName) override
+ {
+ TInstanceHandlerNameHandlerMap::iterator theFind =
+ m_InstanceNameToHandlers.find(make_pair(inInstance, Intern(inName)));
+ if (theFind != m_InstanceNameToHandlers.end())
+ return theFind->second;
+ return CreateHandler(inInstance);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Handler Arguments
+
+ void DoAddHandlerArgument(Qt3DSDMHandlerHandle inHandler,
+ const SMetaDataHandlerArgumentInfo &inArgHandle, QT3DSU32 inIdx)
+ {
+ SHandler *infoPtr = FindHandler(inHandler);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ infoPtr->m_Arguments.insert(infoPtr->m_Arguments.begin() + inIdx, inArgHandle);
+ }
+
+ struct ArgNameEqual
+ {
+ const TCharStr &m_Name;
+ ArgNameEqual(const TCharStr &nm)
+ : m_Name(nm)
+ {
+ }
+ bool operator()(const SMetaDataHandlerArgumentInfo &info) const
+ {
+ return m_Name == info.m_Name;
+ }
+ };
+
+ void DoRemoveHandlerArgument(Qt3DSDMHandlerHandle inHandler,
+ const SMetaDataHandlerArgumentInfo &inArgHandle)
+ {
+ SHandler *infoPtr = FindHandler(inHandler);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ erase_if(infoPtr->m_Arguments, ArgNameEqual(inArgHandle.m_Name));
+ }
+
+ struct HandlerArgumentAddRemoveTransaction : public ITransaction
+ {
+ SNewMetaDataImpl &m_Impl;
+ Qt3DSDMHandlerHandle m_Handler;
+ SMetaDataHandlerArgumentInfo m_Arg;
+ QT3DSU32 m_Idx;
+ bool m_AddOnDo;
+
+ HandlerArgumentAddRemoveTransaction(const char *inFile, int inLine, SNewMetaDataImpl &impl,
+ Qt3DSDMHandlerHandle hdl,
+ const SMetaDataHandlerArgumentInfo &arg, QT3DSU32 inIdx,
+ bool inAddOnDo)
+ : ITransaction(inFile, inLine)
+ , m_Impl(impl)
+ , m_Handler(hdl)
+ , m_Arg(arg)
+ , m_Idx(inIdx)
+ , m_AddOnDo(inAddOnDo)
+ {
+ }
+ void insert() { m_Impl.DoAddHandlerArgument(m_Handler, m_Arg, m_Idx); }
+ void remove() { m_Impl.DoRemoveHandlerArgument(m_Handler, m_Arg); }
+ void Do() override
+ {
+ if (m_AddOnDo)
+ insert();
+ else
+ remove();
+ }
+ void Undo() override
+ {
+ if (m_AddOnDo)
+ remove();
+ else
+ insert();
+ }
+ };
+
+ QT3DSU32 AddHandlerArgument(Qt3DSDMHandlerHandle inHandler) override
+ {
+ SHandler *infoPtr = FindHandler(inHandler);
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return 0;
+ }
+
+ SMetaDataHandlerArgumentInfo theInfo(inHandler);
+ QT3DSU32 idx = (QT3DSU32)infoPtr->m_Arguments.size();
+ DoAddHandlerArgument(inHandler, theInfo, idx);
+ if (m_Consumer)
+ m_Consumer->OnTransaction(make_shared<HandlerArgumentAddRemoveTransaction>(
+ __FILE__, __LINE__, ref(*this), inHandler, theInfo,
+ idx, true));
+
+ return idx;
+ }
+
+ void DoSetHandlerArgument(THandlerHandle inHandler, QT3DSU32 inIdx,
+ const SMetaDataHandlerArgumentInfo &inInfo)
+ {
+ SMetaDataHandlerArgumentInfo *infoPtr(FindHandlerArg(inHandler, inIdx));
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ *infoPtr = inInfo;
+ }
+
+ struct SetHandlerArgumentInfoTrans : public ITransaction
+ {
+ SNewMetaDataImpl &m_Impl;
+ THandlerHandle m_Handler;
+ QT3DSU32 m_Idx;
+ SMetaDataHandlerArgumentInfo m_NewValue;
+ SMetaDataHandlerArgumentInfo m_OldValue;
+ SetHandlerArgumentInfoTrans(const char *inFile, int inLine, SNewMetaDataImpl &impl,
+ THandlerHandle handler, QT3DSU32 inIdx,
+ const SMetaDataHandlerArgumentInfo &inNewVal,
+ const SMetaDataHandlerArgumentInfo &inOldVal)
+ : ITransaction(inFile, inLine)
+ , m_Impl(impl)
+ , m_Handler(handler)
+ , m_Idx(inIdx)
+ , m_NewValue(inNewVal)
+ , m_OldValue(inOldVal)
+ {
+ }
+ void Do() override { m_Impl.DoSetHandlerArgument(m_Handler, m_Idx, m_NewValue); }
+ void Undo() override { m_Impl.DoSetHandlerArgument(m_Handler, m_Idx, m_OldValue); }
+ };
+
+ void SetHandlerArgumentInfo(THandlerHandle inHandler, QT3DSU32 inIdx, TStrType inName,
+ TStrType inFormalName, TStrType inDescription,
+ CompleteMetaDataType::Enum inDataType,
+ const SValue &inDefaultValue,
+ const TMetaDataData &inMetaData,
+ HandlerArgumentType::Value inArgType) override
+ {
+ SMetaDataHandlerArgumentInfo *infoPtr(FindHandlerArg(inHandler, inIdx));
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SMetaDataHandlerArgumentInfo &newInfo(*infoPtr);
+ SMetaDataHandlerArgumentInfo oldInfo(newInfo);
+ SetPropertyBaseInfo(newInfo, inName, inFormalName, inDescription, L"", inDataType,
+ inDefaultValue, inMetaData);
+ newInfo.m_ArgType = inArgType;
+ if (m_Consumer != NULL)
+ m_Consumer->OnTransaction(make_shared<SetHandlerArgumentInfoTrans>(
+ __FILE__, __LINE__, ref(*this), inHandler, inIdx,
+ newInfo, oldInfo));
+ }
+
+ void DestroyHandlerArgument(THandlerHandle inHandler, QT3DSU32 inIdx) override
+ {
+ SHandler *ownerPtr = FindHandler(inHandler);
+ SMetaDataHandlerArgumentInfo *infoPtr(FindHandlerArg(inHandler, inIdx));
+ if (infoPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (ownerPtr == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ Q_EMIT internalHandlerArgDestroyed(inHandler, inIdx);
+
+ if (m_Consumer)
+ m_Consumer->OnTransaction(make_shared<HandlerArgumentAddRemoveTransaction>(
+ __FILE__, __LINE__, ref(*this), infoPtr->m_Handler,
+ *infoPtr, inIdx, false));
+
+ DoRemoveHandlerArgument(infoPtr->m_Handler, *infoPtr);
+ }
+
+ Option<SMetaDataHandlerArgumentInfo> FindHandlerArgumentByName(THandlerHandle inHandler,
+ TStrType inName) override
+ {
+ SHandler *ownerPtr = FindHandler(inHandler);
+ if (ownerPtr == NULL) {
+ return Empty();
+ }
+ for (size_t idx = 0, end = ownerPtr->m_Arguments.size(); idx < end; ++idx) {
+ if (ownerPtr->m_Arguments[idx].m_Name == inName)
+ return ownerPtr->m_Arguments[idx];
+ }
+ return Empty();
+ }
+
+ void GetHandlerArguments(THandlerHandle inHandler,
+ vector<SMetaDataHandlerArgumentInfo> &outArguments) override
+ {
+ SHandler *ownerPtr = FindHandler(inHandler);
+ if (ownerPtr == NULL) {
+ return;
+ }
+ outArguments.insert(outArguments.end(), ownerPtr->m_Arguments.begin(),
+ ownerPtr->m_Arguments.end());
+ }
+
+ virtual Option<SMetaDataHandlerArgumentInfo>
+ GetHandlerArgumentInfo(Qt3DSDMHandlerHandle inHandle, QT3DSU32 inIdx) override
+ {
+ SMetaDataHandlerArgumentInfo *infoPtr(FindHandlerArg(inHandle, inIdx));
+ if (infoPtr == NULL) {
+ return Empty();
+ }
+ return *infoPtr;
+ }
+
+ QT3DSU32 GetNumHandlerArguments(Qt3DSDMHandlerHandle inHandler) override
+ {
+ SHandler *ownerPtr = FindHandler(inHandler);
+ if (ownerPtr == NULL) {
+ return 0;
+ }
+ return (QT3DSU32)ownerPtr->m_Arguments.size();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // References
+ void AddReference(Qt3DSDMInstanceHandle inInstance, TStrType inRefString) override
+ {
+ // trim whitespace from the beginning and the end of the string
+ TCharStr::size_type startPos = inRefString.find_first_not_of(L"\n\r\t ");
+ TCharStr::size_type endPos = inRefString.find_last_not_of(L"\n\r\t ");
+ const wchar_t *theStr = NULL;
+ if (startPos != TCharStr::npos) {
+ TStrType temp = inRefString.substr(startPos, endPos - startPos + 1);
+ theStr = Intern(temp);
+ } else
+ theStr = Intern(inRefString);
+
+ QT3DSU32 idx = AddItemToInstanceList(inInstance, theStr, m_InstanceToReferences);
+ if (m_Consumer) {
+ m_Consumer->OnTransaction(
+ std::make_shared<InstanceListTransaction<TInstanceStringListMap,
+ const wchar_t *>>(
+ __FILE__, __LINE__, inInstance, theStr,
+ std::ref(m_InstanceToReferences), idx,
+ true));
+ }
+ }
+
+ void DestroyReferences(Qt3DSDMInstanceHandle inInstance) override
+ {
+ TInstanceStringListMap::iterator find = m_InstanceToReferences.find(inInstance);
+
+ if (find == m_InstanceToReferences.end())
+ return;
+
+ CreateHashMapEraseTransaction(__FILE__, __LINE__, m_Consumer,
+ make_pair(find->first, find->second), m_InstanceToReferences);
+ m_InstanceToReferences.erase(find);
+ }
+
+ struct InternSizeTOpType
+ {
+ SNewMetaDataImpl &m_Impl;
+ InternSizeTOpType(SNewMetaDataImpl &inImpl)
+ : m_Impl(inImpl)
+ {
+ }
+
+ size_t operator()(const TCharStr &inHandle)
+ {
+ return reinterpret_cast<size_t>(m_Impl.Intern(inHandle));
+ }
+ };
+
+ void GetReferences(Qt3DSDMInstanceHandle inInstance, vector<TCharStr> &outReferences) override
+ {
+ DoGetHandleList(inInstance, m_InstanceToReferences, outReferences,
+ InternSizeTOpType(*this));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Instance-global functions
+ // Destroy all meta data that relates to this instance.
+ // Calling this on a derived instance does nothing, this only works if this specific
+ // instance was mapped to a type.
+ // This function must be completely undoable.
+ void DestroyMetaData(Qt3DSDMInstanceHandle inInstance) override
+ {
+ ForEachItem<TMetaDataPropertyHandle>(
+ inInstance, m_InstanceToProperties,
+ bind(&SNewMetaDataImpl::DestroyMetaDataProperty, this,
+ std::placeholders::_1));
+ ForEachItem<TEventHandle>(inInstance, m_InstanceToEvents,
+ bind(&SNewMetaDataImpl::DestroyEvent, this,
+ std::placeholders::_1));
+ ForEachItem<THandlerHandle>(inInstance, m_InstanceToHandlers,
+ bind(&SNewMetaDataImpl::DestroyHandler, this,
+ std::placeholders::_1));
+ DestroyReferences(inInstance);
+
+ TInstanceStrMap::iterator find = m_InstancesToCanonicalType.find(inInstance);
+ if (find != m_InstancesToCanonicalType.end()) {
+ TCharPtr theName(find->second);
+ m_CanonicalTypeToInstances.erase(theName);
+ m_InstancesToCanonicalType.erase(inInstance);
+ CreateHashMapEraseTransaction(__FILE__, __LINE__, m_Consumer,
+ make_pair(theName, inInstance),
+ m_CanonicalTypeToInstances);
+ CreateHashMapEraseTransaction(__FILE__, __LINE__, m_Consumer,
+ make_pair(inInstance, theName),
+ m_InstancesToCanonicalType);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Serialization
+ // You can either save out in canonical format (and it will only save canonical-instance-related
+ // information *or* you can save out in normal format where we link directly to instance handle
+ // instead of to typename
+ template <typename THashType>
+ void AddInstancesFromHash(THashType &inHash,
+ unordered_set<TInstanceHandle, hash<int>> &outInstances)
+ {
+ for (typename THashType::const_iterator iter = inHash.begin(), end = inHash.end();
+ iter != end; ++iter)
+ outInstances.insert(iter->first);
+ }
+
+ void SerializeMetaDataData(IDOMWriter &inWriter, TMetaDataData &inItem,
+ AdditionalMetaDataType::Value inType)
+ {
+ if (!inItem.empty()) {
+ if (inType == AdditionalMetaDataType::Range) {
+ SMetaDataRange theRange(get<SMetaDataRange>(inItem));
+ inWriter.Att(L"min", theRange.m_min);
+ inWriter.Att(L"max", theRange.m_max);
+ inWriter.Att(L"decimals", theRange.m_decimals);
+ } else if (inType == AdditionalMetaDataType::StringList) {
+ const TMetaDataStringList &theList(get<TMetaDataStringList>(inItem));
+ TCharStr theBuffer;
+ for (uint32_t idx = 0, end = theList.size(); idx < end; ++idx) {
+ if (idx)
+ theBuffer.append(L":");
+ theBuffer.append(theList[idx]);
+ }
+ inWriter.Att(L"list", theBuffer.wide_str());
+ }
+ }
+ }
+
+ void SerializeDataModelValue(IDOMWriter &inWriter, const SValue &inValue,
+ DataModelDataType::Value /*inType*/,
+ const wchar_t *inName = L"default")
+ {
+ if (inValue.empty())
+ return;
+
+ m_TempBuffer.clear();
+ WCharTWriter writer(m_TempBuffer);
+ WStrOps<SValue>().ToBuf(inValue, writer);
+
+ if (m_TempBuffer.size()) {
+ m_TempBuffer.write((QT3DSU16)0);
+ inWriter.Att(inName, (const wchar_t *)m_TempBuffer.begin());
+ }
+ }
+
+ void SerializeDataModelValue(IDOMReader &inReader, SValue &outValue,
+ DataModelDataType::Value inType,
+ const wchar_t *inName = L"default")
+ {
+ const char8_t *theDefaultValue;
+ qt3ds::foundation::ConvertUTF(
+ reinterpret_cast<const qt3ds::foundation::TWCharEASTLConverter::TCharType *>(
+ inName), 0,
+ m_ConvertStr);
+ if (inReader.UnregisteredAtt(m_ConvertStr.c_str(), theDefaultValue)) {
+ m_TempBuffer.clear();
+ // We have to write a temporary value because the parsing of floats,
+ // in order to be efficient, is destructive.
+ if (theDefaultValue && *theDefaultValue)
+ m_TempBuffer.write(theDefaultValue, (QT3DSU32)strlen(theDefaultValue) + 1);
+
+ if (m_TempBuffer.size() == 0) {
+ SetDefault(inType, outValue);
+ return;
+ }
+ m_ReadBuffer.clear();
+
+ char8_t *trashPtr = (char8_t *)m_TempBuffer.begin();
+ WCharTReader theReader(trashPtr, m_ReadBuffer, m_StringTable);
+ outValue = WStrOps<SValue>().BufTo(inType, theReader);
+ } else
+ SetDefault(inType, outValue);
+ }
+
+ void SerializeMetaDataData(IDOMReader &inReader, TMetaDataData &ioItem,
+ CompleteMetaDataType::Enum &ioType)
+ {
+ // Use the meta data extra information to force the type
+ // to something that works correctly.
+ SMetaDataRange theRange;
+ if (inReader.Att("min", theRange.m_min) && inReader.Att("max", theRange.m_max)) {
+ inReader.Att("decimals", theRange.m_decimals);
+ ioItem = theRange;
+ if (ioType == CompleteMetaDataType::Long)
+ ioType = CompleteMetaDataType::LongRange;
+ else
+ ioType = CompleteMetaDataType::FloatRange;
+ } else {
+ TMetaDataStringList theList;
+ TCharStr theItems;
+ if (inReader.Att(L"list", theItems)) {
+ for (TCharStr::size_type theIter = theItems.find_first_of(L":,");
+ theIter != theItems.npos; theIter = theItems.find_first_of(L":,")) {
+ theList.push_back(theItems.substr(0, theIter));
+ theItems = theItems.substr(theIter + 1);
+ }
+ theList.push_back(theItems);
+ ioItem = theList;
+ if (ioType != CompleteMetaDataType::StringListOrInt)
+ ioType = CompleteMetaDataType::StringList;
+ }
+ }
+ }
+ void EnsureCategory(IDOMWriter &, const TCharStr &, const TCharStr &) {}
+ void EnsureCategory(IDOMReader &, TCharStr &inCategory, const TCharStr &inObjectName)
+ {
+ Qt3DSDMCategoryHandle theCategory = FindCategoryByName(inCategory);
+ if (theCategory.Valid() == false) {
+ if (inObjectName.empty()) {
+ QT3DS_ASSERT(false);
+ } else {
+ if (inCategory.empty())
+ inCategory = inObjectName;
+
+ pair<Qt3DSDMCategoryHandle, bool> theGetOrCreateResult(
+ GetOrCreateCategory(inCategory));
+
+ if (theGetOrCreateResult.second == true) {
+ SetCategoryInfo(theGetOrCreateResult.first, L"Objects-Behavior-Normal.png",
+ L"Objects-Behavior-Normal.png", inCategory);
+ }
+ }
+ }
+ }
+
+ void SerializePropertyBase(IDOMWriter &inArchive, SMetaPropertyBase &inItem)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ if (inItem.m_FormalName != inItem.m_Name)
+ inArchive.Att(L"formalName", inItem.m_FormalName);
+ if (inItem.m_Description != inItem.m_Name)
+ inArchive.Att(L"description", inItem.m_Description);
+ if (inItem.m_CompleteType != CompleteMetaDataType::Float
+ && inItem.m_CompleteType != CompleteMetaDataType::FloatRange
+ && inItem.m_CompleteType != CompleteMetaDataType::LongRange
+ && inItem.m_CompleteType != CompleteMetaDataType::StringList) {
+ inArchive.Att(L"type", inItem.m_CompleteType);
+ }
+
+ // Ensure that all types work
+ if (inItem.GetAdditionalType() != AdditionalMetaDataType::None)
+ SerializeMetaDataData(inArchive, inItem.m_MetaDataData, inItem.GetAdditionalType());
+
+ if (inItem.GetDataType() != DataModelDataType::None) {
+ SValue theGlobalDefault;
+ SetDefault(inItem.GetDataType(), theGlobalDefault);
+ if (!Equals(theGlobalDefault.toOldSkool(), inItem.m_DefaultValue.toOldSkool()))
+ SerializeDataModelValue(inArchive, inItem.m_DefaultValue, inItem.GetDataType());
+ }
+ }
+
+ void SerializePropertyBase(IDOMReader &inArchive, SMetaPropertyBase &inItem)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ inArchive.Att(L"formalName", inItem.m_FormalName);
+ inArchive.Att(L"usage", inItem.m_Usage);
+ inArchive.Att(L"description", inItem.m_Description);
+ inArchive.Att(L"type", inItem.m_CompleteType);
+ // Setup reasonable defaults in the case where the users are specifying little information
+ // in the file format
+ if (inItem.m_FormalName.empty())
+ inItem.m_FormalName = inItem.m_Name;
+ if (inItem.m_Description.empty())
+ inItem.m_Description = inItem.m_FormalName;
+
+ // Ensure that users can use a float type and make minimal decisions
+ SerializeMetaDataData(inArchive, inItem.m_MetaDataData, inItem.m_CompleteType);
+
+ if (inItem.GetDataType() != DataModelDataType::None)
+ SerializeDataModelValue(inArchive, inItem.m_DefaultValue, inItem.GetDataType());
+ }
+
+ void FinalizeCategory(IDOMWriter &, SCategoryInfo &) {}
+
+ void FinalizeCategory(IDOMReader &, SCategoryInfo &inCategory)
+ {
+ if (inCategory.m_Description.empty())
+ inCategory.m_Description = inCategory.m_Name;
+ }
+
+ template <typename TArchiveType>
+ void SerializeItem(TArchiveType &inArchive, SCategoryInfo &inItem)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ inArchive.Att(L"description", inItem.m_Description);
+ inArchive.Att(L"icon", inItem.m_Icon);
+ inArchive.Att(L"highlightIcon", inItem.m_HighlightIcon);
+
+ FinalizeCategory(inArchive, inItem);
+ }
+
+ void SerializeItem(IDOMWriter &inArchive, SMetaDataPropertyInfo &inItem,
+ Qt3DSDMMetaDataPropertyHandle inHandle)
+ {
+ SerializePropertyBase(inArchive, inItem);
+ if (inItem.m_IsHidden == true)
+ inArchive.Att("hidden", inItem.m_IsHidden);
+ if (inItem.m_Animatable == false)
+ inArchive.Att("animatable", inItem.m_Animatable);
+ if (inItem.m_Controllable == true)
+ inArchive.Att("controllable", inItem.m_Controllable);
+ NVConstDataRef<SPropertyFilterInfo> theInfos = GetMetaDataPropertyFilters(inHandle);
+ for (QT3DSU32 idx = 0, end = theInfos.size(); idx < end; ++idx) {
+ const SPropertyFilterInfo &theInfo(theInfos[idx]);
+ Qt3DSDMPropertyDefinition thePropertyInfo(
+ m_DataCore->GetProperty(theInfo.m_FilterProperty));
+
+ const wchar_t *theFilterName;
+ if (theInfo.m_FilterType == PropertyFilterTypes::HideIfEqual)
+ theFilterName = L"HideIfEqual";
+ else
+ theFilterName = L"ShowIfEqual";
+
+ IDOMWriter::Scope filterScope(inArchive, theFilterName);
+ inArchive.Att(L"property", thePropertyInfo.m_Name);
+ SerializeDataModelValue(inArchive, theInfo.m_Value, thePropertyInfo.m_Type, L"value");
+ }
+ }
+
+ void SerializeItem(IDOMReader &inArchive, SMetaDataPropertyInfo &inItem,
+ Qt3DSDMMetaDataPropertyHandle inHandle)
+ {
+ QT3DS_ASSERT(inHandle.Valid());
+
+ SerializePropertyBase(inArchive, inItem);
+ inArchive.Att("hidden", inItem.m_IsHidden);
+ inArchive.Att("animatable", inItem.m_Animatable);
+ inArchive.Att("controllable", inItem.m_Controllable);
+ inArchive.Att(L"category", inItem.m_GroupName);
+ }
+
+ void ReadChildren(IDOMReader &inArchive, SMetaDataPropertyInfo &inItem,
+ Qt3DSDMMetaDataPropertyHandle inHandle)
+ {
+ IDOMReader::Scope __readerScope(inArchive);
+ eastl::vector<SPropertyFilterInfo> theFilters;
+ for (bool success = inArchive.MoveToFirstChild(); success;
+ success = inArchive.MoveToNextSibling()) {
+
+ if (AreEqual(inArchive.GetElementName(), L"ShowIfEqual")) {
+ TCharStr theName;
+ inArchive.Att(L"property", theName);
+ Qt3DSDMPropertyHandle theProperty =
+ m_DataCore->GetAggregateInstancePropertyByName(inItem.m_Instance, theName);
+ if (theProperty.Valid() == false) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ Qt3DSDMPropertyDefinition thePropDef(m_DataCore->GetProperty(theProperty));
+
+ SPropertyFilterInfo theInfo;
+ theInfo.m_FilterType = PropertyFilterTypes::ShowIfEqual;
+ theInfo.m_FilterProperty = theProperty;
+ SerializeDataModelValue(inArchive, theInfo.m_Value, thePropDef.m_Type, L"value");
+ theFilters.push_back(theInfo);
+ } else if (AreEqual(inArchive.GetElementName(), L"HideIfEqual")) {
+ TCharStr theName;
+ inArchive.Att(L"property", theName);
+ Qt3DSDMPropertyHandle theProperty =
+ m_DataCore->GetAggregateInstancePropertyByName(inItem.m_Instance, theName);
+ if (theProperty.Valid() == false) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ Qt3DSDMPropertyDefinition thePropDef(m_DataCore->GetProperty(theProperty));
+
+ SPropertyFilterInfo theInfo;
+ theInfo.m_FilterType = PropertyFilterTypes::HideIfEqual;
+ theInfo.m_FilterProperty = theProperty;
+ SerializeDataModelValue(inArchive, theInfo.m_Value, thePropDef.m_Type, L"value");
+ theFilters.push_back(theInfo);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ if (theFilters.size())
+ SetMetaDataPropertyFilters(
+ inHandle, qt3ds::foundation::toDataRef(theFilters.data(),
+ theFilters.size()));
+ }
+
+ void EnsureEventHandlerBase(IDOMWriter &, SEventAndHandlerBase &) {}
+
+ void EnsureEventHandlerBase(IDOMReader &, SEventAndHandlerBase &inItem)
+ {
+ if (inItem.m_FormalName.empty())
+ inItem.m_FormalName = inItem.m_Name;
+ if (inItem.m_Description.empty())
+ inItem.m_Description = inItem.m_Name;
+ }
+
+ void SerializeItem(IDOMWriter &inArchive, SEvent &inItem, Qt3DSDMEventHandle &)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ if (inItem.m_Name != inItem.m_FormalName)
+ inArchive.Att(L"formalName", inItem.m_FormalName);
+ if (inItem.m_Category != L"Default")
+ inArchive.Att(L"category", inItem.m_Category);
+ if (inItem.m_Description != inItem.m_Name)
+ inArchive.Att(L"description", inItem.m_Description);
+
+ EnsureCategory(inArchive, inItem.m_Category, m_ObjectName);
+ EnsureEventHandlerBase(inArchive, inItem);
+ }
+
+ void SerializeItem(IDOMReader &inArchive, SEvent &inItem, Qt3DSDMEventHandle &)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ inArchive.Att(L"formalName", inItem.m_FormalName);
+ inArchive.Att(L"category", inItem.m_Category);
+ EnsureCategory(inArchive, inItem.m_Category, m_ObjectName);
+ inArchive.Att(L"description", inItem.m_Description);
+ EnsureEventHandlerBase(inArchive, inItem);
+ }
+
+ void SerializeHandlerArgument(IDOMWriter &inArchive, SMetaDataHandlerArgumentInfo &inArgument)
+ {
+ SerializePropertyBase(inArchive, inArgument);
+ if (inArgument.m_ArgType != HandlerArgumentType::None)
+ inArchive.Att(L"argumentType", inArgument.m_ArgType);
+ }
+
+ void SerializeHandlerArgument(IDOMReader &inArchive, SMetaDataHandlerArgumentInfo &inArgument)
+ {
+ SerializePropertyBase(inArchive, inArgument);
+ inArchive.Att(L"argumentType", inArgument.m_ArgType);
+ }
+
+ void SerializeHandlerArguments(IDOMWriter &inWriter, SHandler &inItem, Qt3DSDMHandlerHandle &)
+ {
+ for (size_t idx = 0, end = inItem.m_Arguments.size(); idx < end; ++idx) {
+ SMetaDataHandlerArgumentInfo &theArg(inItem.m_Arguments[idx]);
+ IDOMWriter::Scope __argScope(inWriter, L"Argument");
+ SerializeHandlerArgument(inWriter, theArg);
+ }
+ }
+
+ void SerializeHandlerArguments(IDOMReader &inReader, SHandler &inItem, THandlerHandle &inHandle)
+ {
+ if (inHandle.GetHandleValue() == 0)
+ inHandle = THandlerHandle(GetNextId());
+
+ IDOMReader::Scope __handlerScope(inReader);
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ SMetaDataHandlerArgumentInfo theArg(inHandle);
+ SerializeHandlerArgument(inReader, theArg);
+ inItem.m_Arguments.push_back(theArg);
+ }
+ }
+
+ void SerializeHandlerItem(IDOMWriter &inArchive, SHandler &inItem)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ if (inItem.m_FormalName != inItem.m_Name)
+ inArchive.Att(L"formalName", inItem.m_FormalName);
+ if (inItem.m_Category != L"Default")
+ inArchive.Att(L"category", inItem.m_Category);
+ if (inItem.m_Description != inItem.m_Name)
+ inArchive.Att(L"description", inItem.m_Description);
+ EnsureEventHandlerBase(inArchive, inItem);
+ }
+
+ void SerializeHandlerItem(IDOMReader &inArchive, SHandler &inItem)
+ {
+ inArchive.Att(L"name", inItem.m_Name);
+ inArchive.Att(L"formalName", inItem.m_FormalName);
+ inArchive.Att(L"category", inItem.m_Category);
+ EnsureCategory(inArchive, inItem.m_Category, m_ObjectName);
+ inArchive.Att(L"description", inItem.m_Description);
+ EnsureEventHandlerBase(inArchive, inItem);
+ }
+
+ template <typename TArchiveType>
+ void SerializeItem(TArchiveType &inArchive, SHandler &inItem, Qt3DSDMHandlerHandle &inHandle)
+ {
+ SerializeHandlerItem(inArchive, inItem);
+ SerializeHandlerArguments(inArchive, inItem, inHandle);
+ }
+
+ template <typename TInfoType, typename THandleType, typename TListMapType, typename THashType,
+ typename TNameMapType>
+ void SerializeInstanceData(IDOMWriter &inArchive, TInstanceHandle inInstanceHandle,
+ TCharPtr inElementName,
+ unordered_map<THandleType, TInfoType, THashType> &inMap,
+ TListMapType &inListMap, TNameMapType & /*inNameMap*/)
+ {
+ typedef unordered_map<THandleType, TInfoType, THashType> TMapType;
+ typename TListMapType::iterator find = inListMap.find(inInstanceHandle);
+ if (find == inListMap.end())
+ return;
+
+ vector<THandleType> &itemList = find->second;
+ for (size_t idx = 0, end = itemList.size(); idx < end; ++idx) {
+ typename TMapType::iterator iter = inMap.find(itemList[idx]);
+ if (iter == inMap.end()) {
+ QT3DS_ASSERT(false);
+ continue;
+ }
+ TInfoType &theType = iter->second;
+ IDOMWriter::Scope __elemScope(inArchive, inElementName);
+ SerializeItem(inArchive, theType, itemList[idx]);
+ }
+ }
+
+ void CreateInstanceGroupInfo(SMetaDataPropertyInfo &inProperty)
+ {
+ if (!inProperty.m_GroupName.empty()) {
+ const wchar_t *theGroupName = Intern(inProperty.m_GroupName);
+ bool found = false;
+ pair<typename TInstanceGroupMap::iterator, bool> inserter =
+ m_InstanceGroupMap.insert(make_pair(inProperty.m_Instance, vector<TCharPtr>()));
+ vector<TCharPtr> &itemList = inserter.first->second;
+ for (size_t idx = 0, end = itemList.size(); idx < end; ++idx) {
+ TCharStr curListName = itemList[idx];
+ if (curListName == theGroupName) {
+ found = true;
+ break;
+ }
+ }
+ if (!found && !inProperty.m_IsHidden)
+ inserter.first->second.push_back(theGroupName);
+ }
+ }
+ void CreateInstanceGroupInfo(SEvent &) {}
+ void CreateInstanceGroupInfo(SHandler &) {}
+
+ // Make sure the data core
+ void PostLoad(SMetaDataPropertyInfo &inProperty)
+ {
+ EnsureDataCoreProperty(inProperty);
+ SetPropertyDefault(inProperty, inProperty.GetDataType());
+ }
+
+ void ReadChildren(IDOMReader &, SEvent &, Qt3DSDMEventHandle) {}
+ void ReadChildren(IDOMReader &, SHandler &, Qt3DSDMHandlerHandle) {}
+
+ void PostLoad(SEvent &) {}
+ void PostLoad(SHandler &) {}
+ template <typename TInfoType, typename THandleType, typename TListMapType, typename THashType,
+ typename TNameMapType>
+ void SerializeInstanceData(IDOMReader &inArchive, TInstanceHandle inInstanceHandle,
+ TCharPtr inElementName,
+ unordered_map<THandleType, TInfoType, THashType> &inMap,
+ TListMapType &inListMap, TNameMapType &inNameMap)
+ {
+ // Ensure we pop out to where we were.
+ IDOMReader::Scope __readerScope(inArchive);
+ for (bool success = inArchive.MoveToFirstChild(inElementName); success;
+ success = inArchive.MoveToNextSibling(inElementName)) {
+ TInfoType theInfo(inInstanceHandle);
+ THandleType theHandle(GetNextId());
+ SerializeItem(inArchive, theInfo, theHandle);
+ PostLoad(theInfo);
+ CreateInstanceGroupInfo(theInfo);
+ inMap.insert(make_pair(theHandle, theInfo));
+ this->AddItemToInstanceList(inInstanceHandle, theHandle, inListMap);
+ inNameMap.insert(
+ make_pair(make_pair(inInstanceHandle, Intern(theInfo.m_Name)), theHandle));
+ ReadChildren(inArchive, theInfo, theHandle);
+ }
+ }
+
+ void SerializeInstanceData(IDOMWriter &inArchive, TInstanceHandle inInstance,
+ TCharPtr inElementName, TInstanceStringListMap &inMap)
+ {
+ TInstanceStringListMap::iterator iter = inMap.find(inInstance);
+ if (iter == inMap.end())
+ return;
+ const vector<TCharPtr> &theValueList(iter->second);
+ for (size_t idx = 0, end = theValueList.size(); idx < end; ++idx) {
+ IDOMWriter::Scope __elemScope(inArchive, inElementName);
+ inArchive.Value(theValueList[idx]);
+ }
+ }
+
+ void SerializeInstanceData(IDOMReader &inArchive, TInstanceHandle inInstance,
+ TCharPtr inElementName, TInstanceStringListMap &inMap)
+ {
+ IDOMReader::Scope __readerScope(inArchive);
+ for (bool success = inArchive.MoveToFirstChild(inElementName); success;
+ success = inArchive.MoveToNextSibling(inElementName)) {
+ const wchar_t *theValue;
+ if (inArchive.RegisteredValue(theValue))
+ AddItemToInstanceList(inInstance, theValue, inMap);
+ }
+ }
+
+ template <typename TArchiveType>
+ void SerializeInstance(TArchiveType &inArchive, TInstanceHandle inInstance)
+ {
+ SerializeInstanceData(inArchive, inInstance, L"Property", m_Properties,
+ m_InstanceToProperties, m_InstanceNameToProperties);
+ SerializeInstanceData(inArchive, inInstance, L"Event", m_Events, m_InstanceToEvents,
+ m_InstanceNameToEvents);
+ SerializeInstanceData(inArchive, inInstance, L"Handler", m_Handlers, m_InstanceToHandlers,
+ m_InstanceNameToHandlers);
+ SerializeInstanceData(inArchive, inInstance, L"Reference", m_InstanceToReferences);
+ }
+ void SerializeCategories(IDOMWriter &inWriter)
+ {
+ for (TCategoryMap::iterator iter = m_Categories.begin(), end = m_Categories.end();
+ iter != end; ++iter) {
+ IDOMWriter::Scope __writerScope(inWriter, L"Category");
+ SerializeItem(inWriter, iter->second);
+ }
+ }
+ void SerializeCategories(IDOMReader &inReader)
+ {
+ IDOMReader::Scope __readerScope(inReader);
+ for (bool success = inReader.MoveToFirstChild(L"Category"); success;
+ success = inReader.MoveToNextSibling(L"Category")) {
+ SCategoryInfo theInfo;
+ SerializeItem(inReader, theInfo);
+ TCategoryHandle newHandle(GetNextId());
+ theInfo.m_Canonical = true;
+ m_Categories.insert(make_pair(newHandle, theInfo));
+ m_NameToCategories.insert(make_pair(Intern(theInfo.m_Name), newHandle));
+ }
+ }
+
+ struct SInstanceSorter
+ {
+ const TInstanceStrMap &m_Map;
+ SInstanceSorter(const TInstanceStrMap &inMap)
+ : m_Map(inMap)
+ {
+ }
+ bool operator()(TInstanceHandle lhs, TInstanceHandle rhs)
+ {
+ TInstanceStrMap::const_iterator lhsIter(m_Map.find(lhs));
+ TInstanceStrMap::const_iterator rhsIter(m_Map.find(rhs));
+ if (lhsIter == rhsIter)
+ return false;
+ if (lhsIter == m_Map.end())
+ return false;
+ if (rhsIter == m_Map.end())
+ return true;
+ return wcscmp(lhsIter->second, rhsIter->second) < 0;
+ }
+ };
+
+ void Save(IDOMWriter &inWriter) override
+ {
+ SerializeCategories(inWriter);
+ typedef unordered_set<TInstanceHandle, hash<int>> TInstanceListType;
+ TInstanceListType theInstanceList;
+ // Get the list of instances to serialize.
+
+ AddInstancesFromHash(m_InstanceToProperties, theInstanceList);
+ AddInstancesFromHash(m_InstanceToEvents, theInstanceList);
+ AddInstancesFromHash(m_InstanceToHandlers, theInstanceList);
+ AddInstancesFromHash(m_InstanceToReferences, theInstanceList);
+
+ vector<TInstanceHandle> theInstances;
+ theInstances.reserve(theInstanceList.size());
+ theInstances.insert(theInstances.begin(), theInstanceList.begin(), theInstanceList.end());
+ sort(theInstances.begin(), theInstances.end(), SInstanceSorter(m_InstancesToCanonicalType));
+
+ for (vector<TInstanceHandle>::iterator iter = theInstances.begin(),
+ end = theInstances.end();
+ iter != end; ++iter) {
+ TInstanceHandle instHandle = *iter;
+ Option<TCharStr> theType(GetTypeForCanonicalInstance(*iter));
+ if (theType.hasValue()) {
+ IDOMWriter::Scope __instanceElem(inWriter, theType->wide_str());
+ SerializeInstance(inWriter, *iter);
+ }
+ }
+ }
+
+ // Loading expects the canonical instances to be setup already which means that
+ // it will perform lookups based on
+ void Load(IDOMReader &inReader) override
+ {
+ if (!inReader.Att("NextId", m_NextId))
+ m_NextId = 1;
+ m_ObjectName = L"";
+ SerializeCategories(inReader);
+ IDOMReader::Scope __instanceGatherScope(inReader);
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ const wchar_t *elemName = inReader.GetElementName();
+ TStrInstanceMap::iterator find = m_CanonicalTypeToInstances.find(elemName);
+ if (find == m_CanonicalTypeToInstances.end()) {
+ continue;
+ }
+
+ SerializeInstance(inReader, find->second);
+ }
+ }
+
+ template <typename THandleType, typename TMapType>
+ void RemoveOldItemsAndSetOrder(
+ Qt3DSDMInstanceHandle inInstance, vector<THandleType> &inNewHandles,
+ void (SNewMetaDataImpl::*inGetSpecificFun)(Qt3DSDMInstanceHandle, vector<THandleType> &),
+ void (SNewMetaDataImpl::*inDestroyFun)(THandleType), TMapType &inListMap)
+ {
+ vector<THandleType> theHandles;
+ (this->*inGetSpecificFun)(inInstance, theHandles);
+ for (size_t idx = 0, end = theHandles.size(); idx < end; ++idx)
+ if (find(inNewHandles.begin(), inNewHandles.end(), theHandles[idx])
+ == inNewHandles.end())
+ (this->*inDestroyFun)(theHandles[idx]);
+
+ InsertOrUpdateWithTransaction(make_pair(inInstance, inNewHandles), inListMap);
+ }
+
+ // Load meta data and apply it to just this instance
+ // This needs to be undoable so we have to do this through a slightly different
+ // system than we did before.
+ void LoadInstance(IDOMReader &inReader, Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings) override
+ {
+ const wchar_t *theAtt;
+ vector<Qt3DSDMMetaDataPropertyHandle> theProperties;
+ vector<Qt3DSDMEventHandle> theEvents;
+ vector<Qt3DSDMHandlerHandle> theHandlers;
+ DestroyReferences(inInstance);
+ m_ObjectName = inObjectName;
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ if (AreEqual(inReader.GetElementName(), L"Category")) {
+ SCategoryInfo theInfo;
+ SerializeItem(inReader, theInfo);
+ Qt3DSDMCategoryHandle theCategoryInfo(GetOrCreateCategory(theInfo.m_Name).first);
+ SetCategoryInfo(theCategoryInfo, theInfo.m_Icon, theInfo.m_HighlightIcon,
+ theInfo.m_Description);
+ } else if (AreEqual(inReader.GetElementName(), L"Property")) {
+ SMetaDataPropertyInfo theInfo(inInstance);
+ if (inReader.Att(L"name", theAtt)) {
+ Qt3DSDMMetaDataPropertyHandle theProperty(
+ GetOrCreateSpecificMetaDataProperty(inInstance, theAtt));
+ SerializeItem(inReader, theInfo, theProperty);
+ SetMetaDataPropertyInfo(theProperty, theInfo.m_Name, theInfo.m_FormalName,
+ theInfo.m_Description, theInfo.m_Usage,
+ theInfo.m_CompleteType, theInfo.m_DefaultValue,
+ theInfo.m_MetaDataData, theInfo.m_GroupName,
+ theInfo.m_IsHidden, theInfo.m_Animatable,
+ theInfo.m_Controllable);
+ CreateInstanceGroupInfo(theInfo);
+ theProperties.push_back(theProperty);
+ ReadChildren(inReader, theInfo, theProperty);
+ } else
+ outWarnings.push_back(
+ SMetaDataLoadWarning(MetaDataLoadWarningType::InvalidProperty,
+ MetaDataLoadWarningMessage::MissingName));
+ } else if (AreEqual(inReader.GetElementName(), L"Event")) {
+ SEvent theInfo(inInstance);
+ if (inReader.Att(L"name", theAtt)) {
+ Qt3DSDMEventHandle theEvent(GetOrCreateSpecificEvent(inInstance, theAtt));
+ SerializeItem(inReader, theInfo, theEvent);
+ SetEventInfo(theEvent, theInfo.m_Name, theInfo.m_FormalName, theInfo.m_Category,
+ theInfo.m_Description);
+ theEvents.push_back(theEvent);
+ } else
+ outWarnings.push_back(
+ SMetaDataLoadWarning(MetaDataLoadWarningType::InvalidEvent,
+ MetaDataLoadWarningMessage::MissingName));
+ } else if (AreEqual(inReader.GetElementName(), L"Handler")) {
+ if (inReader.Att(L"name", theAtt)) {
+ Qt3DSDMHandlerHandle theHandler(GetOrCreateSpecificHandler(inInstance, theAtt));
+ SHandler theInfo(inInstance);
+ SerializeHandlerItem(inReader, theInfo);
+ SetHandlerInfo(theHandler, theInfo.m_Name, theInfo.m_FormalName,
+ theInfo.m_Category, theInfo.m_Description);
+ IDOMReader::Scope __argScope(inReader);
+ QT3DSU32 argIdx = 0;
+ for (bool argSuccess = inReader.MoveToFirstChild(); argSuccess;
+ argSuccess = inReader.MoveToNextSibling(), ++argIdx) {
+ SMetaDataHandlerArgumentInfo theArg(theHandler);
+ SerializeHandlerArgument(inReader, theArg);
+ while (argIdx >= GetNumHandlerArguments(theHandler))
+ AddHandlerArgument(theHandler);
+
+ if (argIdx < GetNumHandlerArguments(theHandler)) {
+ SetHandlerArgumentInfo(theHandler, argIdx, theArg.m_Name,
+ theArg.m_FormalName, theArg.m_Description,
+ theArg.m_CompleteType, theArg.m_DefaultValue,
+ theArg.m_MetaDataData, theArg.m_ArgType);
+ }
+ }
+ while (GetNumHandlerArguments(theHandler) > argIdx)
+ DestroyHandlerArgument(theHandler, GetNumHandlerArguments(theHandler) - 1);
+ theHandlers.push_back(theHandler);
+ } else
+ outWarnings.push_back(
+ SMetaDataLoadWarning(MetaDataLoadWarningType::InvalidHandler,
+ MetaDataLoadWarningMessage::MissingName));
+ } else if (AreEqual(inReader.GetElementName(), L"Reference")) {
+ const wchar_t *theValue;
+ if (inReader.Value(theValue))
+ AddReference(inInstance, theValue);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ RemoveOldItemsAndSetOrder(
+ inInstance, theProperties, &SNewMetaDataImpl::GetSpecificMetaDataProperties,
+ &SNewMetaDataImpl::DestroyMetaDataProperty, m_InstanceToProperties);
+ RemoveOldItemsAndSetOrder(inInstance, theEvents, &SNewMetaDataImpl::GetSpecificEvents,
+ &SNewMetaDataImpl::DestroyEvent, m_InstanceToEvents);
+ RemoveOldItemsAndSetOrder(inInstance, theHandlers, &SNewMetaDataImpl::GetSpecificHandlers,
+ &SNewMetaDataImpl::DestroyHandler, m_InstanceToHandlers);
+ }
+
+ // Save just this instances meta data out to the writer
+ void SaveInstance(IDOMWriter &inWriter, Qt3DSDMInstanceHandle inInstance) override
+ {
+ SerializeInstance(inWriter, inInstance);
+ }
+
+ // Helper to convert char to wchar_t
+ eastl::basic_string<qt3ds::foundation::TWCharEASTLConverter::TCharType> m_Buf;
+ const wchar_t *ConvertChar(const char *inName)
+ {
+ if (inName && *inName) {
+ qt3ds::foundation::ConvertUTF(inName, 0, m_Buf);
+ return reinterpret_cast<const wchar_t *>(m_Buf.c_str());
+ }
+ return NULL;
+ }
+
+ void LoadEffectInstance(const char *inShaderFile, Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ qt3ds::foundation::IInStream &inStream) override
+ {
+ QString shaderFile(inShaderFile);
+ if (shaderFile.endsWith(".effect")) {
+ LoadEffectXMLFromSourcePath(inShaderFile, inInstance, inObjectName, outWarnings,
+ inStream);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ bool IsEffectInstanceRegistered(const char *inName) override
+ {
+ return m_EffectMap.find(Intern(inName)) != m_EffectMap.end();
+ }
+
+ inline qt3ds::render::NVRenderTextureFormats::Enum
+ ConvertTypeAndFormatToTextureFormat(const char8_t *inType, const char8_t *inFormat)
+ {
+ qt3ds::render::NVRenderTextureFormats::Enum retval
+ = qt3ds::render::NVRenderTextureFormats::RGBA8;
+ if (AreEqual(inFormat, "source"))
+ retval = qt3ds::render::NVRenderTextureFormats::Unknown;
+ else if (AreEqual(inFormat, "depth24stencil8"))
+ retval = qt3ds::render::NVRenderTextureFormats::Depth24Stencil8;
+ else {
+ if (AreEqual(inType, "ubyte")) {
+ if (AreEqual(inFormat, "rgb"))
+ retval = qt3ds::render::NVRenderTextureFormats::RGB8;
+ else if (AreEqual(inFormat, "rgba"))
+ retval = qt3ds::render::NVRenderTextureFormats::RGBA8;
+ else if (AreEqual(inFormat, "alpha"))
+ retval = qt3ds::render::NVRenderTextureFormats::Alpha8;
+ else if (AreEqual(inFormat, "lum"))
+ retval = qt3ds::render::NVRenderTextureFormats::Luminance8;
+ else if (AreEqual(inFormat, "lum_alpha"))
+ retval = qt3ds::render::NVRenderTextureFormats::LuminanceAlpha8;
+ else if (AreEqual(inFormat, "rg"))
+ retval = qt3ds::render::NVRenderTextureFormats::RG8;
+ } else if (AreEqual(inType, "ushort")) {
+ if (AreEqual(inFormat, "rgb"))
+ retval = qt3ds::render::NVRenderTextureFormats::RGB565;
+ else if (AreEqual(inFormat, "rgba"))
+ retval = qt3ds::render::NVRenderTextureFormats::RGBA5551;
+ } else if (AreEqual(inType, "fp16")) {
+ if (AreEqual(inFormat, "rgba"))
+ retval = qt3ds::render::NVRenderTextureFormats::RGBA16F;
+ else if (AreEqual(inFormat, "rg"))
+ retval = qt3ds::render::NVRenderTextureFormats::RG16F;
+ } else if (AreEqual(inType, "fp32")) {
+ if (AreEqual(inFormat, "rgba"))
+ retval = qt3ds::render::NVRenderTextureFormats::RGBA32F;
+ else if (AreEqual(inFormat, "rg"))
+ retval = qt3ds::render::NVRenderTextureFormats::RG32F;
+ } else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported texture type %s,
+ // defaulting to RGBA8", inType );
+ }
+ }
+ return retval;
+ }
+
+ static inline qt3ds::render::NVRenderTextureMagnifyingOp::Enum
+ ConvertFilterToMagOp(const char8_t *inFilter)
+ {
+ if (AreEqual(inFilter, "linear"))
+ return qt3ds::render::NVRenderTextureMagnifyingOp::Linear;
+ if (IsTrivial(inFilter) || AreEqual(inFilter, "nearest"))
+ return qt3ds::render::NVRenderTextureMagnifyingOp::Nearest;
+ else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported filter type %s, defaulting to
+ // linear", inFilter );
+ return qt3ds::render::NVRenderTextureMagnifyingOp::Linear;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderTextureMinifyingOp::Enum
+ ConvertFilterToMinOp(const char8_t *inFilter)
+ {
+ // we make the decision based on the texture usage
+ if (AreEqual(inFilter, "linear"))
+ return qt3ds::render::NVRenderTextureMinifyingOp::Linear;
+ if (AreEqual(inFilter, "nearest"))
+ return qt3ds::render::NVRenderTextureMinifyingOp::Nearest;
+ if (AreEqual(inFilter, "linearMipmapLinear"))
+ return qt3ds::render::NVRenderTextureMinifyingOp::LinearMipmapLinear;
+ if (AreEqual(inFilter, "nearestMipmapNearest"))
+ return qt3ds::render::NVRenderTextureMinifyingOp::NearestMipmapNearest;
+ if (AreEqual(inFilter, "nearestMipmapLinear"))
+ return qt3ds::render::NVRenderTextureMinifyingOp::NearestMipmapLinear;
+ if (AreEqual(inFilter, "linearMipmapNearest"))
+ return qt3ds::render::NVRenderTextureMinifyingOp::LinearMipmapNearest;
+ else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported filter type %s, defaulting
+ // to linear", inFilter );
+ return qt3ds::render::NVRenderTextureMinifyingOp::Linear;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderTextureCoordOp::Enum
+ ConvertTextureCoordOp(const char8_t *inWrap)
+ {
+ if (IsTrivial(inWrap) || AreEqual(inWrap, "clamp"))
+ return qt3ds::render::NVRenderTextureCoordOp::ClampToEdge;
+ if (AreEqual(inWrap, "repeat"))
+ return qt3ds::render::NVRenderTextureCoordOp::Repeat;
+ else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported wrap type %s, defaulting to
+ // clamp", inWrap );
+ return qt3ds::render::NVRenderTextureCoordOp::ClampToEdge;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderTextureTypeValue::Enum
+ ConvertTextureType(const char8_t *inTexType)
+ {
+ // this usually comes from a MDL description file
+ if (IsTrivial(inTexType))
+ return qt3ds::render::NVRenderTextureTypeValue::Unknown;
+ if (AreEqual(inTexType, "environment"))
+ return qt3ds::render::NVRenderTextureTypeValue::Environment;
+ if (AreEqual(inTexType, "diffuse"))
+ return qt3ds::render::NVRenderTextureTypeValue::Diffuse;
+ if (AreEqual(inTexType, "specular"))
+ return qt3ds::render::NVRenderTextureTypeValue::Specular;
+ if (AreEqual(inTexType, "bump"))
+ return qt3ds::render::NVRenderTextureTypeValue::Bump;
+ if (AreEqual(inTexType, "displacement"))
+ return qt3ds::render::NVRenderTextureTypeValue::Displace;
+ if (AreEqual(inTexType, "shadow"))
+ return qt3ds::render::NVRenderTextureTypeValue::LightmapShadow;
+ if (AreEqual(inTexType, "emissive"))
+ return qt3ds::render::NVRenderTextureTypeValue::Emissive;
+ if (AreEqual(inTexType, "emissive_mask"))
+ return qt3ds::render::NVRenderTextureTypeValue::Emissive2;
+ else {
+ return qt3ds::render::NVRenderTextureTypeValue::Unknown;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderSrcBlendFunc::Enum
+ ConvertToSrcBlendFunc(const char8_t *inFilter)
+ {
+ if (AreEqual(inFilter, "SrcAlpha"))
+ return qt3ds::render::NVRenderSrcBlendFunc::SrcAlpha;
+ if (AreEqual(inFilter, "OneMinusSrcAlpha"))
+ return qt3ds::render::NVRenderSrcBlendFunc::OneMinusSrcAlpha;
+ if (AreEqual(inFilter, "One"))
+ return qt3ds::render::NVRenderSrcBlendFunc::One;
+ else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported filter type %s, defaulting
+ // to linear", inFilter );
+ return qt3ds::render::NVRenderSrcBlendFunc::One;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderDstBlendFunc::Enum
+ ConvertToDstBlendFunc(const char8_t *inFilter)
+ {
+ if (AreEqual(inFilter, "SrcAlpha"))
+ return qt3ds::render::NVRenderDstBlendFunc::SrcAlpha;
+ if (AreEqual(inFilter, "OneMinusSrcAlpha"))
+ return qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha;
+ if (AreEqual(inFilter, "One"))
+ return qt3ds::render::NVRenderDstBlendFunc::One;
+ else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported filter type %s, defaulting
+ // to linear", inFilter );
+ return qt3ds::render::NVRenderDstBlendFunc::One;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderState::Enum ConvertRenderState(const char8_t *inState)
+ {
+ if (AreEqual(inState, "Stencil"))
+ return qt3ds::render::NVRenderState::StencilTest;
+ else {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Unsupported filter type %s, defaulting
+ // to linear", inFilter );
+ return qt3ds::render::NVRenderState::StencilTest;
+ }
+ }
+
+ static inline qt3ds::render::NVRenderImageAccessType::Enum
+ ConvertToImageAccessType(const char8_t *inAccess)
+ {
+ if (AreEqual(inAccess, "read"))
+ return qt3ds::render::NVRenderImageAccessType::Read;
+ if (AreEqual(inAccess, "write"))
+ return qt3ds::render::NVRenderImageAccessType::Write;
+ if (AreEqual(inAccess, "readwrite"))
+ return qt3ds::render::NVRenderImageAccessType::ReadWrite;
+ else
+ QT3DS_ASSERT(false);
+
+ return qt3ds::render::NVRenderImageAccessType::ReadWrite;
+ }
+
+ static inline size_t GetTypeSize(const char8_t *inType)
+ {
+ if (AreEqual(inType, "uint"))
+ return sizeof(QT3DSU32);
+ else if (AreEqual(inType, "int"))
+ return sizeof(QT3DSI32);
+ else if (AreEqual(inType, "uvec4"))
+ return sizeof(QT3DSU32) * 4;
+ else
+ QT3DS_ASSERT(false);
+
+ return 1;
+ }
+
+ inline qt3ds::render::NVRenderBufferBindValues::Enum
+ ConvertFormatToBufferBindFlags(const char8_t *inFormat)
+ {
+ if (AreEqual(inFormat, "storage"))
+ return qt3ds::render::NVRenderBufferBindValues::Storage;
+ else if (AreEqual(inFormat, "indirect"))
+ return qt3ds::render::NVRenderBufferBindValues::Draw_Indirect;
+ else
+ QT3DS_ASSERT(false);
+
+ return qt3ds::render::NVRenderBufferBindValues::Unknown;
+ }
+
+ static inline void AppendShaderUniform(const char8_t *type, const char8_t *name,
+ eastl::string &shaderPrefix)
+ {
+ shaderPrefix.append("uniform ");
+ shaderPrefix.append(type);
+ shaderPrefix.append(" ");
+ shaderPrefix.append(name);
+ shaderPrefix.append(";\n");
+ }
+ static inline void AppendShaderCode(
+ const char8_t *inCode, Qt3DSDMStr &ioStr,
+ eastl::basic_string<qt3ds::foundation::TWCharEASTLConverter::TCharType>
+ &inConvertBuffer)
+ {
+ qt3ds::foundation::ConvertUTF(inCode, 0, inConvertBuffer);
+ ioStr.append(inConvertBuffer);
+ }
+ void HideEffectProperty(Qt3DSDMInstanceHandle inInstance, const char8_t *inParamName)
+ {
+ Qt3DSDMMetaDataPropertyHandle theProp =
+ GetSpecificMetaDataProperty(inInstance, Intern(inParamName));
+ if (theProp.Valid()) {
+ SMetaDataPropertyInfo theInfo = GetMetaDataPropertyInfo(theProp);
+ SetMetaDataPropertyInfo(theProp, theInfo.m_Name, theInfo.m_FormalName,
+ theInfo.m_Description, theInfo.m_Usage, theInfo.m_CompleteType,
+ theInfo.m_DefaultValue, theInfo.m_MetaDataData,
+ theInfo.m_GroupName, true, theInfo.m_Animatable,
+ theInfo.m_Controllable);
+ }
+ }
+
+ static inline void GetShaderName(const TCharStr &inObjectName,
+ const char8_t *inShaderSpecificName,
+ eastl::string &outShaderName)
+ {
+ outShaderName.clear();
+ qt3ds::foundation::ConvertUTF(inObjectName.c_str(), 0, outShaderName);
+ outShaderName.append(" - ");
+ outShaderName.append(inShaderSpecificName);
+ }
+
+ void LoadDynamicObjectProperties(IDOMReader &inStream, SMetaDataDynamicObjectImpl &ioObject,
+ Qt3DSDMInstanceHandle inInstance, const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ eastl::string &shaderPrefix)
+ {
+ eastl::string vertexUniforms;
+ eastl::string fragmentUniforms;
+ vertexUniforms += "#ifdef VERTEX_SHADER\n";
+ fragmentUniforms += "#ifdef FRAGMENT_SHADER\n";
+ using namespace qt3ds::render::dynamic;
+ ioObject.m_Properties.clear();
+ ioObject.ClearEnumValueNames();
+ IDOMReader::Scope __readerScope(inStream);
+ if (inStream.MoveToFirstChild("MetaData")) {
+ {
+ IDOMReader::Scope __readerScope(inStream);
+ LoadInstance(inStream, inInstance, inObjectName, outWarnings);
+ }
+
+ vector<Qt3DSDMMetaDataPropertyHandle> theProperties;
+ GetSpecificMetaDataProperties(inInstance, theProperties);
+ size_t propIdx = 0, propEnd = theProperties.size();
+ for (bool success = inStream.MoveToFirstChild("Property"); success && propIdx < propEnd;
+ success = inStream.MoveToNextSibling("Property"), ++propIdx) {
+ ioObject.m_Properties.push_back();
+ SPropertyDefinition &theNewDefinition = ioObject.m_Properties.back();
+ SMetaDataPropertyInfo theInfo(GetMetaDataPropertyInfo(theProperties[propIdx]));
+ theNewDefinition.m_Name =
+ m_StringTable.GetRenderStringTable().RegisterStr(theInfo.m_Name.c_str());
+ const char8_t *xmlName;
+ inStream.Att("name", xmlName);
+ const char8_t *stage;
+ inStream.Att("stage", stage);
+ eastl::string uniforms;
+ if (AreEqual(xmlName, theNewDefinition.m_Name.c_str())) {
+ switch (theInfo.GetDataType()) {
+ case DataModelDataType::Bool:
+ theNewDefinition.m_DataType =
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSRenderBool;
+ AppendShaderUniform("bool", theNewDefinition.m_Name.c_str(), uniforms);
+ break;
+ case DataModelDataType::Long:
+ theNewDefinition.m_DataType
+ = qt3ds::render::NVRenderShaderDataTypes::QT3DSI32;
+ AppendShaderUniform("int", theNewDefinition.m_Name.c_str(), uniforms);
+ break;
+ case DataModelDataType::Float2:
+ theNewDefinition.m_DataType
+ = qt3ds::render::NVRenderShaderDataTypes::QT3DSVec2;
+ AppendShaderUniform("vec2", theNewDefinition.m_Name.c_str(), uniforms);
+ break;
+ case DataModelDataType::Float3:
+ theNewDefinition.m_DataType
+ = qt3ds::render::NVRenderShaderDataTypes::QT3DSVec3;
+ AppendShaderUniform("vec3", theNewDefinition.m_Name.c_str(), uniforms);
+ break;
+ case DataModelDataType::Float4:
+ theNewDefinition.m_DataType
+ = qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4;
+ AppendShaderUniform("vec4", theNewDefinition.m_Name.c_str(), uniforms);
+ break;
+ case DataModelDataType::String:
+ if (theInfo.m_CompleteType == CompleteMetaDataType::Texture) {
+ theNewDefinition.m_DataType =
+ qt3ds::render::NVRenderShaderDataTypes::NVRenderTexture2DPtr;
+ const char8_t *filter = "linear", *minFilter = "linear",
+ *clamp = "clamp", *usage = "", *path = "";
+ if (inStream.Att("filter", filter))
+ theNewDefinition.m_MagFilterOp = ConvertFilterToMagOp(filter);
+ if (inStream.Att("minfilter", minFilter))
+ theNewDefinition.m_MinFilterOp = ConvertFilterToMinOp(minFilter);
+ if (inStream.Att("clamp", clamp))
+ theNewDefinition.m_CoordOp = ConvertTextureCoordOp(clamp);
+ if (inStream.Att("usage", usage))
+ theNewDefinition.m_TexUsageType = ConvertTextureType(usage);
+ if (inStream.Att("default", path)) {
+ TDataStrPtr theDataStr(
+ theInfo.m_DefaultValue.getData<TDataStrPtr>());
+ theNewDefinition.m_ImagePath =
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theDataStr->GetData());
+ }
+
+ // Output macro so we can change the set of variables used for this
+ // independent of the
+ // meta data system.
+ uniforms.append("SNAPPER_SAMPLER2D(");
+ uniforms.append(theNewDefinition.m_Name.c_str());
+ uniforms.append(", ");
+ uniforms.append(theNewDefinition.m_Name.c_str());
+ uniforms.append(", ");
+ uniforms.append(filter);
+ uniforms.append(", ");
+ uniforms.append(clamp);
+ uniforms.append(", ");
+ uniforms.append("false )\n");
+ } else if (theInfo.m_CompleteType == CompleteMetaDataType::StringList) {
+ theNewDefinition.m_DataType =
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSI32;
+ const TMetaDataStringList &theList =
+ qt3dsdm::get<TMetaDataStringList>(theInfo.m_MetaDataData);
+ ioObject.m_EnumValueNames.push_back(
+ new eastl::vector<qt3ds::foundation::CRegisteredString>());
+ eastl::vector<qt3ds::foundation::CRegisteredString> &theBack =
+ *ioObject.m_EnumValueNames.back();
+ for (QT3DSU32 idx = 0, end = (QT3DSU32)theList.size(); idx < end; ++idx)
+ theBack.push_back(m_StringTable.GetRenderStringTable().RegisterStr(
+ theList[idx].c_str()));
+ theNewDefinition.m_EnumValueNames = VecToCRef(theBack);
+ theNewDefinition.m_IsEnumProperty = true;
+ AppendShaderUniform("int", theNewDefinition.m_Name.c_str(),
+ uniforms);
+ } else if (theInfo.m_CompleteType == CompleteMetaDataType::Image2D) {
+ theNewDefinition.m_DataType =
+ qt3ds::render::NVRenderShaderDataTypes::NVRenderImage2DPtr;
+ const char8_t *format = "", *binding = "", *access = "readonly";
+ uniforms.append("layout(");
+ inStream.Att("format", format);
+ uniforms.append(format);
+ if (inStream.Att("binding", binding)) {
+ uniforms.append(", binding = ");
+ uniforms.append(binding);
+ }
+ uniforms.append(") ");
+
+ // if we have format layout we cannot set an additional access qualifier
+ if (inStream.Att("access", access) && !AreEqual(format, ""))
+ uniforms.append(access);
+
+ uniforms.append(" uniform image2D ");
+ uniforms.append(theNewDefinition.m_Name.c_str());
+ uniforms.append(";\n");
+ } else if (theInfo.m_CompleteType == CompleteMetaDataType::Buffer) {
+ theNewDefinition.m_DataType =
+ qt3ds::render::NVRenderShaderDataTypes::NVRenderDataBufferPtr;
+ const char8_t *align = "std140", *usage = "storage", *binding = "",
+ *format = "float";
+ uniforms.append("layout(");
+
+ inStream.Att("format", format);
+ inStream.Att("usage", usage);
+ if (AreEqual(usage, "storage")) {
+ inStream.Att("align", align);
+ uniforms.append(align);
+
+ if (inStream.Att("binding", binding)) {
+ uniforms.append(", binding = ");
+ uniforms.append(binding);
+ }
+
+ uniforms.append(") ");
+
+ uniforms.append("buffer ");
+ uniforms.append(theNewDefinition.m_Name.c_str());
+ uniforms.append("\n{ \n");
+ uniforms.append(format);
+ uniforms.append(" ");
+ uniforms.append(theNewDefinition.m_Name.c_str());
+ uniforms.append("_data[]; \n};\n");
+ } else {
+ // currently we only handle storage counters
+ QT3DS_ASSERT(false);
+ }
+ }
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ // Fallthrough intentional
+ case DataModelDataType::Float:
+ theNewDefinition.m_DataType = qt3ds::render::NVRenderShaderDataTypes::QT3DSF32;
+ AppendShaderUniform("float", theNewDefinition.m_Name.c_str(), uniforms);
+ break;
+ }
+ } else {
+ // It is conceivable that we not every property tag gets parsed into a property.
+ QT3DS_ASSERT(false);
+ // So we will bump to the next item and try again.
+ --propIdx;
+ }
+
+ if (AreEqual(stage, "vertex")) {
+ vertexUniforms += uniforms;
+ } else if (AreEqual(stage, "fragment")) {
+ fragmentUniforms += uniforms;
+ } else {
+ vertexUniforms += uniforms;
+ fragmentUniforms += uniforms;
+ }
+ }
+ }
+ vertexUniforms += "#endif\n";
+ fragmentUniforms += "#endif\n";
+ shaderPrefix.append(vertexUniforms);
+ shaderPrefix.append(fragmentUniforms);
+ }
+
+ void LoadDynamicObjectShaders(IDOMReader &inStream, SMetaDataDynamicObjectImpl &ioObject,
+ eastl::string &shaderPrefix, const TCharStr &inObjectName)
+ {
+ eastl::string theShaderNameStr;
+ eastl::string theShaderTypeStr;
+ eastl::string theShaderVersionStr;
+ {
+ IDOMReader::Scope __readerScope(inStream);
+ eastl::basic_string<qt3ds::foundation::TWCharEASTLConverter::TCharType> theConvertBuffer;
+ if (inStream.MoveToFirstChild("Shaders")) {
+ const char8_t *globalShared = "";
+ const char8_t *globalVertexShared = "";
+ const char8_t *globalFragmentShared = "";
+ inStream.ChildValue("Shared", globalShared);
+ inStream.ChildValue("VertexShaderShared", globalVertexShared);
+ inStream.ChildValue("FragmentShaderShared", globalFragmentShared);
+
+ inStream.Att("type", theShaderTypeStr); // can be empty
+ inStream.Att("version", theShaderVersionStr); // can be empty
+
+ for (bool success = inStream.MoveToFirstChild(); success;
+ success = inStream.MoveToNextSibling()) {
+ IDOMReader::Scope __shaderScope(inStream);
+ const char8_t *elemName = inStream.GetNarrowElementName();
+ // If this is neither a compute shader nor a normal shader, go on and ignore
+ // element.
+ if (!(AreEqual(elemName, "Shader") || AreEqual(elemName, "ComputeShader")))
+ continue;
+
+ ioObject.m_Shaders.push_back();
+ SMetaDataShader &theShader = ioObject.m_Shaders.back();
+
+ qt3ds::foundation::ConvertUTF(theShaderTypeStr.c_str(), theShaderTypeStr.size(),
+ theShader.m_Type);
+ qt3ds::foundation::ConvertUTF(theShaderVersionStr.c_str(),
+ theShaderVersionStr.size(), theShader.m_Version);
+ const char8_t *theName = "";
+ char8_t theITOABuffer[64] = { 0 };
+ if (!inStream.Att("name", theName)) {
+ sprintf(theITOABuffer, "%d", (int)ioObject.m_Shaders.size() - 1);
+ theName = theITOABuffer;
+ }
+ GetShaderName(inObjectName, theName, theShaderNameStr);
+ qt3ds::foundation::ConvertUTF(theShaderNameStr.c_str(), theShaderNameStr.size(),
+ theShader.m_Name);
+
+ if (AreEqual(elemName, "Shader")) {
+ const char8_t *shaderShared = "";
+ inStream.ChildValue("Shared", shaderShared);
+ const char8_t *vertexCode = "";
+ inStream.ChildValue("VertexShader", vertexCode);
+ if (IsTrivial(vertexCode))
+ vertexCode = "void vert(){}";
+ const char8_t *fragmentCode = "void frag(){}";
+ inStream.ChildValue("FragmentShader", fragmentCode);
+ if (IsTrivial(fragmentCode))
+ fragmentCode = "void frag(){}";
+ const char8_t *geomCode = "";
+ inStream.ChildValue("GeometryShader", geomCode);
+
+ AppendShaderCode(shaderPrefix.c_str(), theShader.m_Code, theConvertBuffer);
+ AppendShaderCode(globalShared, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode(shaderShared, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode("\n#ifdef VERTEX_SHADER\n", theShader.m_Code,
+ theConvertBuffer);
+ AppendShaderCode(globalVertexShared, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode(vertexCode, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode("\n#endif\n", theShader.m_Code, theConvertBuffer);
+ if (!IsTrivial(geomCode)) {
+ AppendShaderCode("\n#ifdef USER_GEOMETRY_SHADER\n", theShader.m_Code,
+ theConvertBuffer);
+ AppendShaderCode(geomCode, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode("\n#endif\n", theShader.m_Code, theConvertBuffer);
+ theShader.m_HasGeomShader = true;
+ }
+ AppendShaderCode("\n#ifdef FRAGMENT_SHADER\n", theShader.m_Code,
+ theConvertBuffer);
+ AppendShaderCode(globalFragmentShared, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode(fragmentCode, theShader.m_Code, theConvertBuffer);
+ AppendShaderCode("\n#endif\n", theShader.m_Code, theConvertBuffer);
+ } else if (AreEqual(elemName, "ComputeShader")) {
+ const char8_t *shaderCode = "";
+ inStream.Value(shaderCode);
+ theShader.m_IsComputeShader = true;
+ AppendShaderCode(shaderCode, theShader.m_Code, theConvertBuffer);
+ }
+ }
+ }
+ }
+ }
+
+ static size_t Align(size_t inValue)
+ {
+ if (inValue % 4)
+ return inValue + (4 - (inValue % 4));
+ return inValue;
+ }
+
+ static qt3ds::render::dynamic::SDepthStencilFlags ParseDepthStencilFlags(const char8_t *inFlags)
+ {
+ eastl::string parseStr(inFlags);
+ eastl::string tokenStr;
+ qt3ds::render::dynamic::SDepthStencilFlags retval;
+ for (uint32_t pos = parseStr.find('|'); parseStr.empty() == false;
+ pos = parseStr.find('|')) {
+ if (pos != eastl::string::npos) {
+ tokenStr = parseStr.substr(pos);
+ parseStr.erase(parseStr.begin(), parseStr.begin() + pos + 1);
+ } else {
+ tokenStr = parseStr;
+ parseStr.clear();
+ }
+ if (AreEqual(tokenStr.c_str(), "clear-stencil"))
+ retval |= qt3ds::render::dynamic::DepthStencilFlagValues::ClearStencil;
+ if (AreEqual(tokenStr.c_str(), "clear-depth"))
+ retval |= qt3ds::render::dynamic::DepthStencilFlagValues::ClearDepth;
+ }
+ return retval;
+ }
+
+ static qt3ds::render::NVRenderBoolOp::Enum ParseBoolOp(const char8_t *inOp)
+ {
+ if (AreEqual(inOp, "never"))
+ return qt3ds::render::NVRenderBoolOp::Never;
+ if (AreEqual(inOp, "less"))
+ return qt3ds::render::NVRenderBoolOp::Less;
+ if (AreEqual(inOp, "less-than-or-equal"))
+ return qt3ds::render::NVRenderBoolOp::LessThanOrEqual;
+ if (AreEqual(inOp, "equal"))
+ return qt3ds::render::NVRenderBoolOp::Equal;
+ if (AreEqual(inOp, "not-equal"))
+ return qt3ds::render::NVRenderBoolOp::NotEqual;
+ if (AreEqual(inOp, "greater"))
+ return qt3ds::render::NVRenderBoolOp::Greater;
+ if (AreEqual(inOp, "greater-than-or-equal"))
+ return qt3ds::render::NVRenderBoolOp::GreaterThanOrEqual;
+ if (AreEqual(inOp, "always"))
+ return qt3ds::render::NVRenderBoolOp::AlwaysTrue;
+
+ QT3DS_ASSERT(false);
+ return qt3ds::render::NVRenderBoolOp::Unknown;
+ }
+
+ static qt3ds::render::NVRenderStencilOp::Enum ParseStencilOp(const char8_t *inOp)
+ {
+
+ if (AreEqual(inOp, "keep"))
+ return qt3ds::render::NVRenderStencilOp::Keep;
+ if (AreEqual(inOp, "zero"))
+ return qt3ds::render::NVRenderStencilOp::Zero;
+ if (AreEqual(inOp, "replace"))
+ return qt3ds::render::NVRenderStencilOp::Replace;
+ if (AreEqual(inOp, "increment"))
+ return qt3ds::render::NVRenderStencilOp::Increment;
+ if (AreEqual(inOp, "increment-wrap"))
+ return qt3ds::render::NVRenderStencilOp::IncrementWrap;
+ if (AreEqual(inOp, "decrement"))
+ return qt3ds::render::NVRenderStencilOp::Decrement;
+ if (AreEqual(inOp, "decrement-wrap"))
+ return qt3ds::render::NVRenderStencilOp::DecrementWrap;
+ if (AreEqual(inOp, "invert"))
+ return qt3ds::render::NVRenderStencilOp::Invert;
+
+ QT3DS_ASSERT(false);
+ return qt3ds::render::NVRenderStencilOp::Unknown;
+ }
+
+ // Reloads an effect if one is already loaded so we can replace the existing effect definition
+ void LoadEffectXML(IDOMReader &inStream, Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ const TCharStr &inSourcePath) override
+ {
+ using namespace qt3ds::render::dynamic;
+ std::pair<TEffectMap::iterator, bool> theInserter =
+ m_EffectMap.insert(std::make_pair(Intern(inObjectName), SMetaDataEffectImpl()));
+ /*if ( inStream.MoveToFirstChild( "Effect" ) == false )
+ {
+ outWarnings.push_back( SMetaDataLoadWarning( MetaDataLoadWarningType::Unknown,
+ MetaDataLoadWarningMessage::GeneralError, L"File doesn't appear to be an effect xml file,
+ missing top level Effect tag" ) );
+ return;
+ }*/
+ eastl::string shaderPrefix = "#include \"effect.glsllib\"\n";
+
+ SMetaDataEffectImpl &theEffect = theInserter.first->second;
+ m_ObjectName = inObjectName;
+ theEffect.m_Name = inObjectName;
+ theEffect.m_SourcePath = inSourcePath;
+ theEffect.ClearEffectCommands();
+ LoadDynamicObjectProperties(inStream, theEffect, inInstance, inObjectName, outWarnings,
+ shaderPrefix);
+ theEffect.m_Shaders.clear();
+ LoadDynamicObjectShaders(inStream, theEffect, shaderPrefix, inObjectName);
+ eastl::string theShaderNameStr;
+ {
+ IDOMReader::Scope __readerScope(inStream);
+ if (inStream.MoveToFirstChild("Passes")) {
+ for (bool success = inStream.MoveToFirstChild(); success;
+ success = inStream.MoveToNextSibling()) {
+ IDOMReader::Scope __passScope(inStream);
+ if (AreEqual("Pass", inStream.GetNarrowElementName())) {
+ bool drawIndirect = false;
+ const char8_t *shader = "", *input = "[source]", *output = "[dest]",
+ *outputFormat = "rgba";
+ inStream.Att("shader", shader);
+ inStream.Att("input", input);
+ inStream.Att("output", output);
+ // this is only for the final output of the effect
+ inStream.Att("format", outputFormat);
+ qt3ds::render::NVRenderTextureFormats::Enum theOutputFormat =
+ ConvertTypeAndFormatToTextureFormat("ubyte", outputFormat);
+ if (AreEqual(output, "[dest]") || IsTrivial(output))
+ theEffect.m_EffectCommands.push_back(new SBindTarget(theOutputFormat));
+ else
+ theEffect.m_EffectCommands.push_back(
+ new SBindBuffer(
+ m_StringTable.GetRenderStringTable().RegisterStr(output),
+ false));
+ GetShaderName(inObjectName, shader, theShaderNameStr);
+ theEffect.m_EffectCommands.push_back(
+ new SBindShader(m_StringTable.GetRenderStringTable().RegisterStr(
+ theShaderNameStr.c_str())));
+ theEffect.m_EffectCommands.push_back(new SApplyInstanceValue());
+ if (AreEqual(input, "[source]") || IsTrivial(input))
+ theEffect.m_EffectCommands.push_back(
+ new SApplyBufferValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(""),
+ m_StringTable.GetRenderStringTable().RegisterStr("")));
+ else
+ theEffect.m_EffectCommands.push_back(
+ new SApplyBufferValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(input),
+ m_StringTable.GetRenderStringTable().RegisterStr("")));
+ for (bool bufParam = inStream.MoveToFirstChild(); bufParam;
+ bufParam = inStream.MoveToNextSibling()) {
+ if (AreEqual("BufferInput", inStream.GetNarrowElementName())) {
+ const char8_t *param = "";
+ const char8_t *value = "";
+ inStream.Att("param", param);
+ inStream.Att("value", value);
+ if (AreEqual("[source]", value))
+ value = "";
+ theEffect.m_EffectCommands.push_back(
+ new SApplyBufferValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ value),
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ param)));
+ HideEffectProperty(inInstance, param);
+ } else if (AreEqual("DepthInput", inStream.GetNarrowElementName())) {
+ const char8_t *param = "";
+ inStream.Att("param", param);
+ theEffect.m_EffectCommands.push_back(
+ new SApplyDepthValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ param)));
+ HideEffectProperty(inInstance, param);
+ } else if (AreEqual("ImageInput", inStream.GetNarrowElementName())) {
+ bool useAsTexture = false;
+ bool needSync = false;
+ const char8_t *param = "";
+ const char8_t *value = "";
+ const char8_t *usage = "";
+ const char8_t *sync = "";
+ inStream.Att("param", param);
+ inStream.Att("value", value);
+ if (AreEqual("[source]", value))
+ value = "";
+ inStream.Att("usage", usage);
+ if (AreEqual("texture", usage))
+ useAsTexture = true;
+ inStream.Att("sync", sync);
+ if (AreEqual("true", sync))
+ needSync = true;
+
+ theEffect.m_EffectCommands.push_back(
+ new SApplyImageValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ value),
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ param), useAsTexture, needSync));
+ HideEffectProperty(inInstance, param);
+ } else if (AreEqual("DataBufferInput",
+ inStream.GetNarrowElementName())) {
+ const char8_t *param = "";
+ const char8_t *usage = "";
+ inStream.Att("param", param);
+ inStream.Att("usage", usage);
+ qt3ds::render::NVRenderBufferBindValues::Enum bufType =
+ ConvertFormatToBufferBindFlags(usage);
+
+ // check if we using an indirect buffer for drawing
+ if (bufType == qt3ds::render::NVRenderBufferBindValues::Draw_Indirect)
+ drawIndirect = true;
+
+ theEffect.m_EffectCommands.push_back(
+ new SApplyDataBufferValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ param), bufType));
+ HideEffectProperty(inInstance, param);
+ } else if (AreEqual("SetParam", inStream.GetNarrowElementName())) {
+ const char8_t *name = "";
+ inStream.Att("name", name);
+ const char8_t *value = "";
+ inStream.Att("value", value);
+ // find the param and the type.
+ qt3ds::foundation::CRegisteredString propName =
+ m_StringTable.GetRenderStringTable().RegisterStr(name);
+ qt3ds::render::dynamic::SPropertyDefinition *theDefinition = NULL;
+ for (uint32_t propIdx = 0, propEnd = theEffect.m_Properties.size();
+ propIdx < propEnd && theDefinition == NULL; ++propIdx) {
+ if (theEffect.m_Properties[propIdx].m_Name == propName)
+ theDefinition = &theEffect.m_Properties[propIdx];
+ }
+ if (theDefinition != NULL) {
+ // Hack it for now because the shader datatypes don't have a
+ // built in sizeof operator.
+ QT3DSU32 valueSize = 4;
+ qt3ds::render::NVRenderShaderDataTypes::Enum theDataType =
+ theDefinition->m_DataType;
+ size_t allocSize = sizeof(SApplyValue) + valueSize;
+ QT3DSU8 *theCommandData = (QT3DSU8 *)malloc(allocSize);
+ QT3DSU8 *theValueData = theCommandData + sizeof(SApplyValue);
+ new (theCommandData) SApplyValue(propName, theDataType);
+ SApplyValue *theCommand =
+ reinterpret_cast<SApplyValue *>(theCommandData);
+ switch (theDataType) {
+ case qt3ds::render::NVRenderShaderDataTypes::QT3DSRenderBool: {
+ bool &target = *reinterpret_cast<bool *>(theValueData);
+ qt3ds::foundation::StringConversion<bool>().StrTo(value,
+ target);
+ } break;
+ case qt3ds::render::NVRenderShaderDataTypes::QT3DSI32: {
+ QT3DSI32 &target = *reinterpret_cast<QT3DSI32 *>(
+ theValueData);
+ qt3ds::foundation::StringConversion<QT3DSI32>().StrTo(
+ value, target);
+ } break;
+ default:
+ QT3DS_ASSERT(false);
+ // Fallthrough intentional
+ case qt3ds::render::NVRenderShaderDataTypes::QT3DSF32: {
+ QT3DSF32 &target = *reinterpret_cast<QT3DSF32 *>(
+ theValueData);
+ qt3ds::foundation::StringConversion<QT3DSF32>().StrTo(
+ value, target);
+ } break;
+ }
+ theCommand->m_Value = NVDataRef<QT3DSU8>(theValueData,
+ valueSize);
+ theEffect.m_EffectCommands.push_back(theCommand);
+ }
+ } else if (AreEqual("Blending", inStream.GetNarrowElementName())) {
+ const char8_t *theSrcBlendFuncStr = "", *theDestBlendFuncStr = "";
+ inStream.Att("source", theSrcBlendFuncStr);
+ inStream.Att("dest", theDestBlendFuncStr);
+
+ qt3ds::render::NVRenderSrcBlendFunc::Enum theSrcBlendFunc =
+ ConvertToSrcBlendFunc(theSrcBlendFuncStr);
+ qt3ds::render::NVRenderDstBlendFunc::Enum theDstBlendFuc =
+ ConvertToDstBlendFunc(theDestBlendFuncStr);
+
+ // this will setup blending
+ theEffect.m_EffectCommands.push_back(
+ new SApplyBlending(theSrcBlendFunc, theDstBlendFuc));
+ } else if (AreEqual("RenderState", inStream.GetNarrowElementName())) {
+ const char8_t *name = "";
+ inStream.Att("name", name);
+ const char8_t *value = "";
+ inStream.Att("value", value);
+ // find the param and the type.
+ bool theStateEnable = false;
+ qt3ds::render::NVRenderState::Enum theState
+ = ConvertRenderState(name);
+ if (AreEqual("true", value))
+ theStateEnable = true;
+
+ // this will setup blending
+ theEffect.m_EffectCommands.push_back(
+ new SApplyRenderState(theState, theStateEnable));
+ } else if (AreEqual("DepthStencil", inStream.GetNarrowElementName())) {
+ const char8_t *bufferName = "";
+ inStream.Att("buffer", bufferName);
+ QT3DSU32 stencilvalue = 0;
+ inStream.Att("reference", stencilvalue);
+ const char8_t *flags = "";
+ inStream.Att("flags", flags);
+ QT3DSU32 mask = QT3DS_MAX_U32;
+ inStream.Att("mask", mask);
+ qt3ds::render::NVRenderBoolOp::Enum stencilFunction =
+ qt3ds::render::NVRenderBoolOp::Equal;
+ qt3ds::render::NVRenderStencilOp::Enum stencilFailOperation =
+ qt3ds::render::NVRenderStencilOp::Keep;
+ qt3ds::render::NVRenderStencilOp::Enum depthPass =
+ qt3ds::render::NVRenderStencilOp::Keep;
+ qt3ds::render::NVRenderStencilOp::Enum depthFail =
+ qt3ds::render::NVRenderStencilOp::Keep;
+ const char8_t *temp;
+ if (inStream.Att("stencil-fail", temp))
+ stencilFailOperation = ParseStencilOp(temp);
+ if (inStream.Att("depth-pass", temp))
+ depthPass = ParseStencilOp(temp);
+ if (inStream.Att("depth-fail", temp))
+ depthFail = ParseStencilOp(temp);
+ if (inStream.Att("stencil-function", temp))
+ stencilFunction = ParseBoolOp(temp);
+
+ qt3ds::render::dynamic::SDepthStencilFlags flagValues =
+ ParseDepthStencilFlags(flags);
+ theEffect.m_EffectCommands.push_back(
+ new SDepthStencil(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ bufferName), flagValues, stencilFailOperation,
+ depthPass, depthFail, stencilFunction, stencilvalue,
+ mask));
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ theEffect.m_EffectCommands.push_back(new SRender(drawIndirect));
+ } else if (AreEqual("Buffer", inStream.GetNarrowElementName())
+ || AreEqual("Image", inStream.GetNarrowElementName())) {
+ SAllocateBufferFlags theFlags;
+ const char8_t *theLifetimeStr = "", *theType = "", *theFormat = "",
+ *theFilter = "", *theWrap = "", *theName = "";
+ QT3DSF32 theSize = 1.0f;
+ bool isImage = AreEqual("Image", inStream.GetNarrowElementName());
+ inStream.Att("name", theName);
+ inStream.Att("lifetime", theLifetimeStr);
+ inStream.Att("type", theType);
+ inStream.Att("format", theFormat);
+ inStream.Att("filter", theFilter);
+ inStream.Att("wrap", theWrap);
+ inStream.Att("size", theSize);
+ // Clamp the size to valid amounts
+ if (theSize <= 0)
+ theSize = 1.0f;
+ if (theSize > 1.0f)
+ theSize = 1.0f;
+ if (AreEqual(theLifetimeStr, "scene"))
+ theFlags.SetSceneLifetime(true);
+ qt3ds::render::NVRenderTextureFormats::Enum theTexFormat =
+ ConvertTypeAndFormatToTextureFormat(theType, theFormat);
+ qt3ds::render::NVRenderTextureMagnifyingOp::Enum theMagOp =
+ ConvertFilterToMagOp(theFilter);
+ qt3ds::render::NVRenderTextureCoordOp::Enum theCoordOp =
+ ConvertTextureCoordOp(theWrap);
+ if (*theName == 0) {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Buffer is missing its
+ // name" );
+ } else if (isImage) {
+ const char8_t *temp;
+ qt3ds::render::NVRenderImageAccessType::Enum theAccess =
+ qt3ds::render::NVRenderImageAccessType::ReadWrite;
+ if (inStream.Att("access", temp))
+ theAccess = ConvertToImageAccessType(temp);
+
+ theEffect.m_EffectCommands.push_back(
+ new SAllocateImage(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theName), theTexFormat, theMagOp, theCoordOp,
+ theSize, theFlags, theAccess));
+ } else {
+ theEffect.m_EffectCommands.push_back(
+ new SAllocateBuffer(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theName), theTexFormat, theMagOp, theCoordOp,
+ theSize, theFlags));
+ }
+ } else if (AreEqual("DataBuffer", inStream.GetNarrowElementName())) {
+ SAllocateBufferFlags theFlags;
+ const char8_t *theLifetimeStr = "", *theType = "", *theWrapName = "",
+ *theWrapType = "", *theFormat = "", *theName = "";
+ QT3DSF32 theSize = 1.0f;
+ qt3ds::render::NVRenderBufferBindValues::Enum bufType,
+ wrapBufType = qt3ds::render::NVRenderBufferBindValues::Unknown;
+
+ inStream.Att("name", theName);
+ inStream.Att("lifetime", theLifetimeStr);
+ inStream.Att("type", theType);
+ inStream.Att("format", theFormat);
+ inStream.Att("size", theSize);
+ if (AreEqual(theLifetimeStr, "scene"))
+ theFlags.SetSceneLifetime(true);
+ bufType = ConvertFormatToBufferBindFlags(theType);
+
+ if (inStream.Att("wrapType", theWrapType)) {
+ wrapBufType = ConvertFormatToBufferBindFlags(theWrapType);
+ inStream.Att("wrapName", theWrapName);
+ if (*theWrapName == 0)
+ QT3DS_ASSERT(false);
+ }
+
+ theSize *= GetTypeSize(theFormat);
+
+ if (theSize <= 0)
+ theSize = 1.0f;
+
+ if (*theName == 0) {
+ QT3DS_ASSERT(false);
+ } else {
+ theEffect.m_EffectCommands.push_back(
+ new SAllocateDataBuffer(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theName), bufType,
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theWrapName), wrapBufType, theSize, theFlags));
+ }
+ } else {
+ QT3DS_ASSERT(false); // Unrecognized effect passes member.
+ }
+ }
+
+ } else {
+ if (theEffect.m_Shaders.size()) {
+ // Create the minimal set of commands that we could run the first shader with.
+ theEffect.m_EffectCommands.push_back(new SBindTarget());
+ theEffect.m_EffectCommands.push_back(
+ new SBindShader(m_StringTable.GetRenderStringTable().RegisterStr(
+ theEffect.m_Shaders[0].m_Name.c_str())));
+ theEffect.m_EffectCommands.push_back(new SApplyInstanceValue());
+ theEffect.m_EffectCommands.push_back(new SRender(false));
+ }
+ }
+ }
+ }
+
+ bool LoadEffectXMLFromSourcePath(const char *inSourcePath,
+ Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ qt3ds::foundation::IInStream &inStream) override
+ {
+ std::shared_ptr<IDOMFactory> theFactory(
+ IDOMFactory::CreateDOMFactory(m_DataCore->GetStringTablePtr()));
+ qt3dsdm::SDOMElement *theElem = CDOMSerializer::Read(*theFactory, inStream, NULL);
+ if (theElem != NULL) {
+ std::shared_ptr<IDOMReader> theReader(
+ IDOMReader::CreateDOMReader(*theElem, m_DataCore->GetStringTablePtr(),
+ theFactory));
+ LoadEffectXML(*theReader, inInstance, inObjectName, outWarnings,
+ TCharStr(Intern(inSourcePath)));
+ return true;
+ }
+ return false;
+ }
+
+ Option<SMetaDataEffect> GetEffectBySourcePath(const char *inSourcePath) override
+ {
+ QDir sourcePath = QDir::cleanPath(QString(inSourcePath));
+ for (TEffectMap::iterator iter = m_EffectMap.begin(), end = m_EffectMap.end(); iter != end;
+ ++iter) {
+ QDir effectPath = QDir::cleanPath(QString::fromWCharArray(
+ iter->second.m_SourcePath.wide_str()));
+ if (effectPath == sourcePath)
+ return iter->second.ToEffect();
+ }
+ return Empty();
+ }
+
+ void LoadMaterialInstance(const char *inShaderFile, Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ qt3ds::foundation::IInStream &inStream) override
+ {
+ QString shaderFile(inShaderFile);
+ if (shaderFile.endsWith(".material") || shaderFile.endsWith(".shader")) {
+ LoadMaterialClassFromSourcePath(inShaderFile, inInstance, inName, outWarnings,
+ inStream);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ bool IsMaterialClassRegistered(const char *inName) override
+ {
+ return m_CustomMaterials.find(Intern(inName)) != m_CustomMaterials.end();
+ }
+
+ void LoadMaterialClassXML(IDOMReader &inStream, Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ const TCharStr &inSourcePath) override
+ {
+ using namespace qt3ds::render::dynamic;
+
+ std::pair<TCustomMaterialMap::iterator, bool> theInserter = m_CustomMaterials.insert(
+ std::make_pair(Intern(inObjectName), SMetaDataCustomMaterialImpl()));
+ /*if ( inStream.MoveToFirstChild( "Effect" ) == false )
+ {
+ outWarnings.push_back( SMetaDataLoadWarning( MetaDataLoadWarningType::Unknown,
+ MetaDataLoadWarningMessage::GeneralError, L"File doesn't appear to be an effect xml file,
+ missing top level Effect tag" ) );
+ return;
+ }*/
+ eastl::string shaderPrefix = "#include \"customMaterial.glsllib\"\n";
+
+ SMetaDataCustomMaterialImpl &theMaterial = theInserter.first->second;
+ m_ObjectName = inObjectName;
+ theMaterial.m_Name = inObjectName;
+ theMaterial.m_SourcePath = inSourcePath;
+ theMaterial.m_HasTransparency = false;
+ theMaterial.m_HasRefraction = false;
+ theMaterial.m_AlwaysDirty = false;
+ theMaterial.m_ShaderKey = 0;
+ theMaterial.m_LayerCount = 0;
+ inStream.Att("always-dirty", theMaterial.m_AlwaysDirty);
+ LoadDynamicObjectProperties(inStream, theMaterial, inInstance, inObjectName, outWarnings,
+ shaderPrefix);
+ LoadDynamicObjectShaders(inStream, theMaterial, shaderPrefix, inObjectName);
+
+ // currently single pass shader only
+ if (theMaterial.m_Shaders.size()) {
+ eastl::string theShaderNameStr;
+
+ // in Passes we store additional render commands
+ IDOMReader::Scope __readerScope(inStream);
+ if (inStream.MoveToFirstChild("Passes")) {
+ for (bool success = inStream.MoveToFirstChild(); success;
+ success = inStream.MoveToNextSibling()) {
+ IDOMReader::Scope __passScope(inStream);
+ if (AreEqual("Pass", inStream.GetNarrowElementName())) {
+ const char8_t *typeStr;
+ if (!inStream.UnregisteredAtt("type", typeStr))
+ typeStr = "render";
+ if (AreEqual(typeStr, "render")) {
+ const char8_t *shader = "", *input = "[source]", *output = "[dest]",
+ *outputFormat = "rgba", *clear = "";
+ bool needsClear = false;
+ inStream.Att("shader", shader);
+ inStream.Att("input", input);
+ inStream.Att("output", output);
+ // for multi pass materials
+ inStream.Att("clear", clear);
+ if (AreEqual("true", clear))
+ needsClear = true;
+
+ GetShaderName(inObjectName, shader, theShaderNameStr);
+ // this is only for the final output of the effect
+ inStream.Att("format", outputFormat);
+ qt3ds::render::NVRenderTextureFormats::Enum theOutputFormat =
+ ConvertTypeAndFormatToTextureFormat("ubyte", outputFormat);
+
+ if (AreEqual(output, "[dest]") || IsTrivial(output)) {
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SBindTarget(theOutputFormat));
+ } else {
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SBindBuffer(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ output), needsClear));
+ }
+
+ // add shader to command stream
+ qt3ds::render::CRegisteredString theShaderName;
+ if (!IsTrivial(shader)) {
+ for (QT3DSU32 idx = 0, end = theMaterial.m_Shaders.size();
+ idx < end && theShaderName.IsValid() == false; ++idx) {
+ qt3ds::render::CRegisteredString thePossibleNameStr =
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theMaterial.m_Shaders[idx].m_Name.c_str());
+ if (AreEqual(thePossibleNameStr.c_str(),
+ theShaderNameStr.c_str()))
+ theShaderName = thePossibleNameStr;
+ }
+ }
+ if (theShaderName.IsValid() == false
+ && theMaterial.m_Shaders.empty() == false)
+ theShaderName = m_StringTable.GetRenderStringTable().RegisterStr(
+ theMaterial.m_Shaders[0].m_Name.c_str());
+ if (theShaderName.IsValid()) {
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SBindShader(theShaderName));
+ // this is a place holder for our input values to the shader
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SApplyInstanceValue());
+
+ for (bool bufParam = inStream.MoveToFirstChild(); bufParam;
+ bufParam = inStream.MoveToNextSibling()) {
+ if (AreEqual("BufferBlit", inStream.GetNarrowElementName())) {
+ const char8_t *value = "";
+ const char8_t *dest = "";
+ const char8_t *source = "";
+ inStream.Att("dest", dest);
+ if (AreEqual("[dest]", dest))
+ value = "";
+ inStream.Att("source", source);
+ if (AreEqual("[source]", source))
+ value = "";
+
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SApplyBlitFramebuffer(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ source),
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ dest)));
+
+ // note need a better way to pass information from MDL to
+ // our input
+ // We use buffer blits to simulate glass refraction
+ theMaterial.m_HasRefraction = true;
+ } else if (AreEqual("BufferInput",
+ inStream.GetNarrowElementName())) {
+ const char8_t *param = "";
+ const char8_t *value = "";
+ inStream.Att("param", param);
+ inStream.Att("value", value);
+ if (AreEqual("[source]", value))
+ value = "";
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SApplyBufferValue(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ value),
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ param)));
+ HideEffectProperty(inInstance, param);
+ } else if (AreEqual("Blending",
+ inStream.GetNarrowElementName())) {
+ const char8_t *theSrcBlendFuncStr = "",
+ *theDestBlendFuncStr = "";
+ inStream.Att("source", theSrcBlendFuncStr);
+ inStream.Att("dest", theDestBlendFuncStr);
+
+ qt3ds::render::NVRenderSrcBlendFunc::Enum theSrcBlendFunc =
+ ConvertToSrcBlendFunc(theSrcBlendFuncStr);
+ qt3ds::render::NVRenderDstBlendFunc::Enum theDstBlendFuc =
+ ConvertToDstBlendFunc(theDestBlendFuncStr);
+
+ // this will setup blending
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SApplyBlending(theSrcBlendFunc,
+ theDstBlendFuc));
+ // if we have blending we have transparency
+ theMaterial.m_HasTransparency = true;
+ } else if (AreEqual("RenderState",
+ inStream.GetNarrowElementName())) {
+ // UdoL Todo: add this one
+ }
+ }
+ }
+ // add the render command as last thing in the pass, it is a render
+ // pass.
+ theMaterial.m_CustomerMaterialCommands.push_back(new SRender(false));
+ }
+ } else if (AreEqual("ShaderKey", inStream.GetNarrowElementName())) {
+ QT3DSU32 theValue = 0;
+ inStream.Att("value", theValue);
+ theMaterial.m_ShaderKey = theValue;
+ } else if (AreEqual("LayerKey", inStream.GetNarrowElementName())) {
+ QT3DSU32 theValue = 0;
+ inStream.Att("count", theValue);
+ theMaterial.m_LayerCount = theValue;
+ } else if (AreEqual("Buffer", inStream.GetNarrowElementName())) {
+ SAllocateBufferFlags theFlags;
+ const char8_t *theLifetimeStr = "", *theType = "", *theFormat = "",
+ *theFilter = "", *theWrap = "", *theName = "";
+ QT3DSF32 theSize = 1.0f;
+ inStream.Att("name", theName);
+ inStream.Att("lifetime", theLifetimeStr);
+ inStream.Att("type", theType);
+ inStream.Att("format", theFormat);
+ inStream.Att("filter", theFilter);
+ inStream.Att("wrap", theWrap);
+ inStream.Att("size", theSize);
+ // Clamp the size to valid amounts
+ if (theSize <= 0)
+ theSize = 1.0f;
+ if (theSize > 1.0f)
+ theSize = 1.0f;
+ if (AreEqual(theLifetimeStr, "scene"))
+ theFlags.SetSceneLifetime(true);
+ qt3ds::render::NVRenderTextureFormats::Enum theTexFormat =
+ ConvertTypeAndFormatToTextureFormat(theType, theFormat);
+ qt3ds::render::NVRenderTextureMagnifyingOp::Enum theMagOp =
+ ConvertFilterToMagOp(theFilter);
+ qt3ds::render::NVRenderTextureCoordOp::Enum theCoordOp =
+ ConvertTextureCoordOp(theWrap);
+ if (*theName == 0) {
+ QT3DS_ASSERT(false);
+ // inFoundation.error( QT3DS_INVALID_PARAMETER, "Buffer is missing its
+ // name" );
+ } else {
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SAllocateBuffer(
+ m_StringTable.GetRenderStringTable().RegisterStr(
+ theName), theTexFormat, theMagOp, theCoordOp,
+ theSize, theFlags));
+ }
+ }
+ }
+ }
+
+ if (theMaterial.m_CustomerMaterialCommands.size() == 0) {
+ // add minimal set
+ // add shader to command stream
+ theMaterial.m_CustomerMaterialCommands.push_back(
+ new SBindShader(m_StringTable.GetRenderStringTable().RegisterStr(
+ theMaterial.m_Shaders[0].m_Name.c_str())));
+ // this is a place holder for our input values to the shader
+ theMaterial.m_CustomerMaterialCommands.push_back(new SApplyInstanceValue());
+ // add the render command as last thing
+ theMaterial.m_CustomerMaterialCommands.push_back(new SRender(false));
+ }
+ }
+ }
+
+ bool LoadMaterialClassFromSourcePath(const char *inSourcePath,
+ Qt3DSDMInstanceHandle inInstance,
+ const TCharStr &inObjectName,
+ std::vector<SMetaDataLoadWarning> &outWarnings,
+ qt3ds::foundation::IInStream &inStream) override
+ {
+ std::shared_ptr<IDOMFactory> theFactory(
+ IDOMFactory::CreateDOMFactory(m_DataCore->GetStringTablePtr()));
+ qt3dsdm::SDOMElement *theElem = CDOMSerializer::Read(*theFactory, inStream, NULL);
+ if (theElem != NULL) {
+ std::shared_ptr<IDOMReader> theReader(
+ IDOMReader::CreateDOMReader(*theElem, m_DataCore->GetStringTablePtr(),
+ theFactory));
+ LoadMaterialClassXML(*theReader, inInstance, inObjectName, outWarnings,
+ TCharStr(Intern(inSourcePath)));
+ return true;
+ }
+ return false;
+ }
+
+ Option<SMetaDataCustomMaterial> GetMaterialBySourcePath(const char *inSourcePath) override
+ {
+ TCharStr theSourcePath(Intern(inSourcePath));
+ for (TCustomMaterialMap::iterator iter = m_CustomMaterials.begin(),
+ end = m_CustomMaterials.end();
+ iter != end; ++iter) {
+ if (iter->second.m_SourcePath == theSourcePath)
+ return iter->second.ToMaterial();
+ }
+ return Empty();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Undo/Redo
+ void SetConsumer(TTransactionConsumerPtr inConsumer) override { m_Consumer = inConsumer; }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Signals
+ virtual TSignalConnectionPtr
+ ConnectInternalCategoryDestroyed(function<void(Qt3DSDMCategoryHandle)> inCallback)
+ {
+ return CONNECT(&SNewMetaDataImpl::internalCategoryDestroyed);
+ }
+ virtual TSignalConnectionPtr
+ ConnectInternalPropertyDestroyed(function<void(Qt3DSDMMetaDataPropertyHandle)> inCallback)
+ {
+ return CONNECT(&SNewMetaDataImpl::internalMetaDataPropertyDestroyed);
+ }
+ virtual TSignalConnectionPtr
+ ConnectInternalEventDestroyed(function<void(Qt3DSDMEventHandle)> inCallback)
+ {
+ return CONNECT(&SNewMetaDataImpl::internalEventDestroyed);
+ }
+ virtual TSignalConnectionPtr
+ ConnectInternalHandlerDestroyed(function<void(Qt3DSDMHandlerHandle)> inCallback)
+ {
+ return CONNECT(&SNewMetaDataImpl::internalHandlerDestroyed);
+ }
+ virtual TSignalConnectionPtr
+ ConnectInternalHandlerArgDestroyed(function<void(Qt3DSDMHandlerHandle, QT3DSU32)> inCallback)
+ {
+ return CONNECT(&SNewMetaDataImpl::internalHandlerArgDestroyed);
+ }
+};
+}
+
+std::shared_ptr<IMetaData> IMetaData::CreateNewMetaData(std::shared_ptr<IDataCore> inDataCore)
+{
+ return std::make_shared<SNewMetaDataImpl>(inDataCore);
+}
+#ifndef QT3DSDM_META_DATA_NO_SIGNALS
+#include "Qt3DSDMMetaData.moc"
+#endif