/**************************************************************************** ** ** 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 #include #include #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 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 { QT3DSU32 ToStr(AdditionalMetaDataType::Value item, NVDataRef 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::ToStr(HandlerArgumentType::Value item, NVDataRef 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::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::ToStr(CompleteMetaDataType::Enum item, NVDataRef 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::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(QObject::connect(this, x, inCallback)) #else #define CONNECT(x) std::shared_ptr() struct SNullFunc { template void operator()(TArgType) { } template void operator()(TA1, TA2) { } }; #endif typedef TCharStr TStrType; using std::hash; struct InstanceHandleVecHash { size_t operator()(const vector &inInstances) const { size_t retval = 0; for (size_t idx = 0, end = inInstances.size(); idx < end; ++idx) retval = retval ^ hash()(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 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 &inPair) const { return hash()(inPair.first) ^ hash()(inPair.second); } }; template NVConstDataRef VecToCRef(const eastl::vector &inType) { return NVConstDataRef(inType.data(), (QT3DSU32)inType.size()); } struct SMetaDataDynamicObjectImpl { private: SMetaDataDynamicObjectImpl &operator=(const SMetaDataDynamicObjectImpl &inOther); public: TCharStr m_Name; TCharStr m_SourcePath; eastl::vector m_Shaders; eastl::vector m_Properties; eastl::vector *> 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 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 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 TStrInstanceMap; typedef unordered_map> 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, InstanceHandleVecHash> TDerivationMap; typedef unordered_map> TCategoryMap; typedef unordered_map TNameCategoryMap; typedef unordered_map> TMetaDataPropertyMap; typedef unordered_map, hash> TInstancePropertyMap; typedef unordered_map, TMetaDataPropertyHandle, SInstanceStrHash> TInstancePropertyNamePropertyMap; typedef unordered_map, hash> TMetaDataPropertyFilterMap; typedef unordered_map, hash> TInstanceGroupMap; typedef unordered_map> TEventMap; typedef unordered_map, hash> TInstanceEventMap; typedef unordered_map, TEventHandle, SInstanceStrHash> TInstanceEventNameEventMap; typedef unordered_map> THandlerMap; typedef unordered_map, hash> TInstanceHandlerMap; typedef unordered_map, THandlerHandle, SInstanceStrHash> TInstanceHandlerNameHandlerMap; typedef unordered_map, hash> TInstanceStringListMap; typedef unordered_map TEffectMap; typedef unordered_map TCustomMaterialMap; std::shared_ptr 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 m_Parents; vector m_NextParents; vector m_DerivationChain; unordered_set m_UniqueSet; unordered_set m_SizeTSet; MemoryBuffer m_TempBuffer; MemoryBuffer 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 inDataCore) : m_DataCore(inDataCore) , m_StringTable(inDataCore->GetStringTable()) , m_NextId(1) , m_IgnorePropertyDeleted(false) { #ifndef QT3DSDM_META_DATA_NO_SIGNALS CDataCoreProducer *producer = dynamic_cast(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 static void AddItemToInstanceList(TInstanceHandle inInstance, THandleType inHandle, QT3DSU32 inIdx, TMapType &ioMap) { pair inserter = ioMap.insert(make_pair(inInstance, vector())); inserter.first->second.insert(inserter.first->second.begin() + inIdx, inHandle); } template static QT3DSU32 AddItemToInstanceList(TInstanceHandle inInstance, THandleType inHandle, TMapType &ioMap) { pair inserter = ioMap.insert(make_pair(inInstance, vector())); QT3DSU32 offset = (QT3DSU32)inserter.first->second.size(); inserter.first->second.push_back(inHandle); return offset; } template struct VectorEqualPred { TItemType m_Item; VectorEqualPred(const TItemType &inItem) : m_Item(inItem) { } bool operator()(const TItemType &inOther) const { return m_Item == inOther; } }; template static QT3DSU32 DoRemoveItemFromInstanceList(TInstanceHandle inInstance, THandleType inHandle, TMapType &ioMap) { typename TMapType::iterator find = ioMap.find(inInstance); if (find != ioMap.end()) { typename vector::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 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 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>( inFile, inLine, inInstance, inHandle, std::ref(ioMap), idx, false)); } } } template THandleType CreateItem(const char *inFile, int inLine, Qt3DSDMInstanceHandle inInstance, TMapType &inMap, TInstanceListMapType &inInstanceListMap) { int retval = GetNextId(); pair 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>( inFile, inLine, inInstance, retval, std::ref(inInstanceListMap), idx, true)); } return retval; } template TValueType *FindHashItem(TKeyType inHandle, unordered_map &ioHash) { typename unordered_map::iterator find = ioHash.find(inHandle); if (find != ioHash.end()) return &find->second; return NULL; } template 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 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 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>( 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 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, THandleType> existing(*iter); ioMap.erase(iter); CreateHashMapEraseTransaction(inFile, inLine, m_Consumer, existing, ioMap); } } template 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 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 void AddListMapItems(const std::vector &inMapEntry, TVectorType &outVector) { typedef typename std::vector::const_iterator TIterType; for (TIterType theIter = inMapEntry.begin(), theEnd = inMapEntry.end(); theIter != theEnd; ++theIter) outVector.push_back(*theIter); } template 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 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(m_Impl.Intern(m_Map[inHandle].m_Name)); } }; // Ensure we don't return two items of the same name. template void GetHandleList(Qt3DSDMInstanceHandle inInstance, TListMapType &inMap, TMapType &inTypeName, vector &outHandles) { DoGetHandleList(inInstance, inMap, outHandles, NameSizeTOpType(*this, inTypeName)); } template 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(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 void ForEachItem(Qt3DSDMInstanceHandle inInstance, TListMapType &ioMap, function inOperation) { typename TListMapType::iterator find = ioMap.find(inInstance); if (find != ioMap.end()) { vector 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 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 void InsertWithTransaction(const char *inFile, int inLine, const TEntryType &inEntry, TMapType &inMap) { inMap.insert(inEntry); CreateHashMapInsertTransaction(inFile, inLine, m_Consumer, inEntry, inMap); } template 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 void InsertOrUpdateWithTransaction(const TEntryType &inEntry, TMapType &inMap) { pair 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 GetTypeForCanonicalInstance(Qt3DSDMInstanceHandle inInstance) override { TInstanceStrMap::iterator find = m_InstancesToCanonicalType.find(inInstance); if (find != m_InstancesToCanonicalType.end()) return TCharStr(find->second); return Empty(); } Option GetTypeForInstance(Qt3DSDMInstanceHandle inInstance) override { Option 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 outNames; QT3DSU32 count = GetGroupNamesForInstance(inInstance, outNames); return (count == 0) ? 1 : count; } QT3DSU32 GetGroupNamesForInstance(Qt3DSDMInstanceHandle inInstance, std::vector &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 inserter = m_InstanceGroupMap.insert(make_pair(inInstance, vector())); vector &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 inserter = m_InstanceGroupMap.insert( make_pair(m_DerivationChain[idx], vector())); vector &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 GetGroupFilterNameForInstance(Qt3DSDMInstanceHandle inInstance, long inIndex) override { std::vector outNames; QT3DSU32 count = GetGroupNamesForInstance(inInstance, outNames); if (count > (QT3DSU32)inIndex) return outNames[inIndex]; return Empty(); } //////////////////////////////////////////////////////////////////////////////////// // Categories std::pair 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 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 &outCategories) override { for (TCategoryMap::iterator iter = m_Categories.begin(), end = m_Categories.end(); iter != end; ++iter) outCategories.push_back(iter->first); } Option GetEventCategory(TStrType inName) override { return GetCategoryInfo(FindCategoryByName(inName)); } Option GetHandlerCategory(TStrType inName) override { return GetCategoryInfo(FindCategoryByName(inName)); } //////////////////////////////////////////////////////////////////////////////////// // Properties Qt3DSDMMetaDataPropertyHandle CreateMetaDataProperty(Qt3DSDMInstanceHandle inInstance) override { return CreateItem( __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(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 GetMetaDataPropertyInfo(Qt3DSDMMetaDataPropertyHandle inProperty) override { SMetaDataPropertyInfo *infoPtr = FindProperty(inProperty); if (infoPtr == NULL) { return Empty(); } return *infoPtr; } void GetMetaDataProperties(Qt3DSDMInstanceHandle inInstance, vector &outProperties) override { return GetHandleList(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 &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 inFilters) override { SMetaDataPropertyInfo *infoPtr = FindProperty(inProperty); if (infoPtr == NULL) { QT3DS_ASSERT(false); return; } eastl::vector 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 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(); } 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(__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(inInstance, m_InstanceToEvents, m_Events, outEvents); } Qt3DSDMEventHandle FindEvent(Qt3DSDMInstanceHandle inInstance, TStrType inName) override { return FindItemByName(inInstance, Intern(inName), m_InstanceNameToEvents); } Option 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(__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(inInstance, Intern(inName), m_InstanceNameToHandlers); } Option 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(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( __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( __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( __FILE__, __LINE__, ref(*this), infoPtr->m_Handler, *infoPtr, inIdx, false)); DoRemoveHandlerArgument(infoPtr->m_Handler, *infoPtr); } Option 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 &outArguments) override { SHandler *ownerPtr = FindHandler(inHandler); if (ownerPtr == NULL) { return; } outArguments.insert(outArguments.end(), ownerPtr->m_Arguments.begin(), ownerPtr->m_Arguments.end()); } virtual Option 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>( __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(m_Impl.Intern(inHandle)); } }; void GetReferences(Qt3DSDMInstanceHandle inInstance, vector &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( inInstance, m_InstanceToProperties, bind(&SNewMetaDataImpl::DestroyMetaDataProperty, this, std::placeholders::_1)); ForEachItem(inInstance, m_InstanceToEvents, bind(&SNewMetaDataImpl::DestroyEvent, this, std::placeholders::_1)); ForEachItem(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 void AddInstancesFromHash(THashType &inHash, unordered_set> &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(inItem)); inWriter.Att(L"min", theRange.m_Min); inWriter.Att(L"max", theRange.m_Max); } else if (inType == AdditionalMetaDataType::StringList) { const TMetaDataStringList &theList(get(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().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( 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().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)) { 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 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 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 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 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 void SerializeItem(TArchiveType &inArchive, SHandler &inItem, Qt3DSDMHandlerHandle &inHandle) { SerializeHandlerItem(inArchive, inItem); SerializeHandlerArguments(inArchive, inItem, inHandle); } template void SerializeInstanceData(IDOMWriter &inArchive, TInstanceHandle inInstanceHandle, TCharPtr inElementName, unordered_map &inMap, TListMapType &inListMap, TNameMapType & /*inNameMap*/) { typedef unordered_map TMapType; typename TListMapType::iterator find = inListMap.find(inInstanceHandle); if (find == inListMap.end()) return; vector &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 inserter = m_InstanceGroupMap.insert(make_pair(inProperty.m_Instance, vector())); vector &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 void SerializeInstanceData(IDOMReader &inArchive, TInstanceHandle inInstanceHandle, TCharPtr inElementName, unordered_map &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 &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 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> 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 theInstances; theInstances.reserve(theInstanceList.size()); theInstances.insert(theInstances.begin(), theInstanceList.begin(), theInstanceList.end()); sort(theInstances.begin(), theInstances.end(), SInstanceSorter(m_InstancesToCanonicalType)); for (vector::iterator iter = theInstances.begin(), end = theInstances.end(); iter != end; ++iter) { TInstanceHandle instHandle = *iter; Option 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 void RemoveOldItemsAndSetOrder( Qt3DSDMInstanceHandle inInstance, vector &inNewHandles, void (SNewMetaDataImpl::*inGetSpecificFun)(Qt3DSDMInstanceHandle, vector &), void (SNewMetaDataImpl::*inDestroyFun)(THandleType), TMapType &inListMap) { vector 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 &outWarnings) override { const wchar_t *theAtt; vector theProperties; vector theEvents; vector 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 m_Buf; const wchar_t *ConvertChar(const char *inName) { if (inName && *inName) { qt3ds::foundation::ConvertUTF(inName, 0, m_Buf); return reinterpret_cast(m_Buf.c_str()); } return NULL; } void LoadEffectInstance(const char *inShaderFile, Qt3DSDMInstanceHandle inInstance, const TCharStr &inObjectName, std::vector &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 &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 &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 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()); 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(theInfo.m_MetaDataData); ioObject.m_EnumValueNames.push_back( new eastl::vector()); eastl::vector &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 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 &outWarnings, const TCharStr &inSourcePath) override { using namespace qt3ds::render::dynamic; std::pair 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(theCommandData); switch (theDataType) { case qt3ds::render::NVRenderShaderDataTypes::QT3DSRenderBool: { bool &target = *reinterpret_cast(theValueData); qt3ds::foundation::StringConversion().StrTo(value, target); } break; case qt3ds::render::NVRenderShaderDataTypes::QT3DSI32: { QT3DSI32 &target = *reinterpret_cast( theValueData); qt3ds::foundation::StringConversion().StrTo( value, target); } break; default: QT3DS_ASSERT(false); // Fallthrough intentional case qt3ds::render::NVRenderShaderDataTypes::QT3DSF32: { QT3DSF32 &target = *reinterpret_cast( theValueData); qt3ds::foundation::StringConversion().StrTo( value, target); } break; } theCommand->m_Value = NVDataRef(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 &outWarnings, qt3ds::foundation::IInStream &inStream) override { std::shared_ptr theFactory( IDOMFactory::CreateDOMFactory(m_DataCore->GetStringTablePtr())); qt3dsdm::SDOMElement *theElem = CDOMSerializer::Read(*theFactory, inStream, NULL); if (theElem != NULL) { std::shared_ptr theReader( IDOMReader::CreateDOMReader(*theElem, m_DataCore->GetStringTablePtr(), theFactory)); LoadEffectXML(*theReader, inInstance, inObjectName, outWarnings, TCharStr(Intern(inSourcePath))); return true; } return false; } Option 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 &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 &outWarnings, const TCharStr &inSourcePath) override { using namespace qt3ds::render::dynamic; std::pair 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 &outWarnings, qt3ds::foundation::IInStream &inStream) override { std::shared_ptr theFactory( IDOMFactory::CreateDOMFactory(m_DataCore->GetStringTablePtr())); qt3dsdm::SDOMElement *theElem = CDOMSerializer::Read(*theFactory, inStream, NULL); if (theElem != NULL) { std::shared_ptr theReader( IDOMReader::CreateDOMReader(*theElem, m_DataCore->GetStringTablePtr(), theFactory)); LoadMaterialClassXML(*theReader, inInstance, inObjectName, outWarnings, TCharStr(Intern(inSourcePath))); return true; } return false; } Option 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 inCallback) { return CONNECT(&SNewMetaDataImpl::internalCategoryDestroyed); } virtual TSignalConnectionPtr ConnectInternalPropertyDestroyed(function inCallback) { return CONNECT(&SNewMetaDataImpl::internalMetaDataPropertyDestroyed); } virtual TSignalConnectionPtr ConnectInternalEventDestroyed(function inCallback) { return CONNECT(&SNewMetaDataImpl::internalEventDestroyed); } virtual TSignalConnectionPtr ConnectInternalHandlerDestroyed(function inCallback) { return CONNECT(&SNewMetaDataImpl::internalHandlerDestroyed); } virtual TSignalConnectionPtr ConnectInternalHandlerArgDestroyed(function inCallback) { return CONNECT(&SNewMetaDataImpl::internalHandlerArgDestroyed); } }; } std::shared_ptr IMetaData::CreateNewMetaData(std::shared_ptr inDataCore) { return std::make_shared(inDataCore); } #ifndef QT3DSDM_META_DATA_NO_SIGNALS #include "Qt3DSDMMetaData.moc" #endif