/**************************************************************************************** Copyright (C) 2016 Autodesk, Inc. All rights reserved. Use of this software is subject to the terms of the Autodesk license agreement provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. ****************************************************************************************/ //! \file fbxcolladaelement.h #ifndef _FBXSDK_FILEIO_COLLADA_ELEMENT_H_ #define _FBXSDK_FILEIO_COLLADA_ELEMENT_H_ #include #include // Utility functions to convert type to array tag used in COLLADA source element template inline const FbxString TypeToArrayTag() { return COLLADA_FLOAT_ARRAY_STRUCTURE; } template <> inline const FbxString TypeToArrayTag() { return COLLADA_BOOL_ARRAY_STRUCTURE; } template <> inline const FbxString TypeToArrayTag() { return COLLADA_INT_ARRAY_STRUCTURE; } template <> inline const FbxString TypeToArrayTag() { return COLLADA_NAME_ARRAY_STRUCTURE; } // Utility functions to convert type to parameter tag used in COLLADA source element template inline const FbxString TypeToParameterTag() { return COLLADA_FLOAT_TYPE; } template <> inline const FbxString TypeToParameterTag() { return COLLADA_BOOL_TYPE; } template <> inline const FbxString TypeToParameterTag() { return COLLADA_INT_TYPE; } template <> inline const FbxString TypeToParameterTag() { return COLLADA_NAME_TYPE; } //----------------------------------------------------------------------------// /** A struct for convenient access to the content of common COLLADA element. */ struct ElementContentAccessor { ElementContentAccessor(); ElementContentAccessor(xmlNode * pElement); virtual ~ElementContentAccessor(); template bool GetNext(TYPE * pData) { return FromString(pData, mPointer, &mPointer); } template int GetArray(TYPE * pArray, int pArraySize, int pSourceUnitOffset = 0, int pSourceUnitValidCount = 1, int pSourceUnitSize = 1, int pDestUnitOffset = 0, int pDestUnitValidCount = 1, int pDestUnitSize = 1, TYPE pDefaultValue = TYPE()) { if (pArray) { return FromStringToArray(mPointer, pArray, pArraySize, pSourceUnitOffset, pSourceUnitValidCount, pSourceUnitSize, pDestUnitOffset, pDestUnitValidCount, pDestUnitSize, pDefaultValue); } return 0; } xmlChar * mContent; const char * mPointer; }; //----------------------------------------------------------------------------// /** A struct for convenient access to the content of COLLADA source element. */ template struct SourceElementContentAccessor : public ElementContentAccessor { SourceElementContentAccessor(xmlNode * pSourceElement) : mCount(0), mStride(1), mOffset(0) { bool lReadCount = true; xmlNode* lTechniqueElement = DAE_FindChildElementByTag(pSourceElement, COLLADA_TECHNIQUE_COMMON_ELEMENT); if (lTechniqueElement) { xmlNode* lAccessorElement = DAE_FindChildElementByTag(lTechniqueElement, COLLADA_ACCESSOR_STRUCTURE); if (lAccessorElement) { DAE_GetElementAttributeValue(lAccessorElement, COLLADA_COUNT_PROPERTY, mCount); DAE_GetElementAttributeValue(lAccessorElement, COLLADA_STRIDE_PROPERTY, mStride); DAE_GetElementAttributeValue(lAccessorElement, COLLADA_OFFSET_PROPERTY, mOffset); } lReadCount = false; } xmlNode * lDataArrayElement = DAE_FindChildElementByTag(pSourceElement, TypeToArrayTag()); // Some COLLADA exporters use IDREF_array instead of Name_array if (!lDataArrayElement && TypeToArrayTag() == COLLADA_NAME_ARRAY_STRUCTURE) lDataArrayElement = DAE_FindChildElementByTag(pSourceElement, COLLADA_IDREF_ARRAY_STRUCTURE); FBX_ASSERT(lDataArrayElement); if (lDataArrayElement && lReadCount) DAE_GetElementAttributeValue(lDataArrayElement, COLLADA_COUNT_PROPERTY, mCount); mContent = xmlNodeGetContent(lDataArrayElement); mPointer = (const char *)mContent; } int mCount; int mStride; int mOffset; }; //----------------------------------------------------------------------------// /** Representing a common COLLADA element. */ class ElementBase { public: enum { MATRIX_STRIDE = 16, }; // The name of user property in FBX which is used to preserve the ID of COLLADA element static const char* smID_PROPERTY_NAME; /** Constructor & Destructor. */ ElementBase(); virtual ~ElementBase(); /** Access for XML element. */ void SetXMLElement(xmlNode * pElement) { mXMLElement = pElement; } xmlNode * GetXMLElement() const { return mXMLElement; } /** Get the ID of the element. * \return Return the ID string. */ const FbxString & GetID() const; /** Get the unit of the element, * which takes effect in this element and its children elements. * \return Return the unit. */ const FbxSystemUnit * GetUnit() const; private: xmlNode * mXMLElement; mutable FbxString * mID; mutable FbxSystemUnit * mUnit; }; /** Convert from ID to URL, just add a prefix "#". * \param pID The ID string. * \return Return the URL string. */ inline const FbxString URL(const FbxString & pID) { return FbxString("#") + pID; } /** Convert the array data to a source element under specific parent element. * \param pParentElement The parent element. * \param pID The ID of the new source element. * \param pData The array data. * \param pCount The length of the array. * \param pStride The stride of each unit in the array. For example, when you * export an array of FbxDouble3 of size 10, you convert it to a double array * of size 30 with a stride 3 and call this method. * \return The new source element. */ template xmlNode * AddSourceElement(xmlNode * pParentElement, const char * pID, const T * pData, int pCount, int pStride = 1) { FBX_ASSERT(pParentElement && pData); if (!pParentElement || !pData) return NULL; xmlNode * lSourceElement = DAE_AddChildElement(pParentElement, COLLADA_SOURCE_STRUCTURE); DAE_AddAttribute(lSourceElement, COLLADA_ID_PROPERTY, pID); FbxString lContent; const int lDataCount = pCount * pStride; for (int lIndex = 0; lIndex < lDataCount; ++lIndex) { lContent += ToString(pData[lIndex]); if (lIndex != lDataCount - 1) lContent += " "; } const FbxString lArrayID = FbxString(pID) + "-array"; xmlNode * lArrayElement = DAE_AddChildElement(lSourceElement, TypeToArrayTag(), lContent); DAE_AddAttribute(lArrayElement, COLLADA_ID_PROPERTY, lArrayID); DAE_AddAttribute(lArrayElement, COLLADA_COUNT_PROPERTY, lDataCount); xmlNode * lTechniqueCommonElement = DAE_AddChildElement(lSourceElement, COLLADA_TECHNIQUE_COMMON_ELEMENT); xmlNode * lAccessElement = DAE_AddChildElement(lTechniqueCommonElement, COLLADA_ACCESSOR_STRUCTURE); DAE_AddAttribute(lAccessElement, COLLADA_SOURCE_PROPERTY, URL(lArrayID)); DAE_AddAttribute(lAccessElement, COLLADA_COUNT_PROPERTY, pCount); DAE_AddAttribute(lAccessElement, COLLADA_STRIDE_PROPERTY, pStride); for (int lStrideIndex = 0; lStrideIndex < pStride; ++lStrideIndex) { xmlNode * lParamElement = DAE_AddChildElement(lAccessElement, COLLADA_PARAMETER_STRUCTURE); DAE_AddAttribute(lParamElement, COLLADA_TYPE_PROPERTY, TypeToParameterTag()); } return lSourceElement; } /** Populate the layer element with direct array and return index array for later use. * \param pLayerElement The layer element to be populated. * \param pSourceElement The source element containing the direct array data. * \param pSize The count of double data of direct array element. * \return Return the index array of the layer element. */ template FbxLayerElementArray * PopulateLayerElementDirectArray(FbxLayerElement * pLayerElement, xmlNode * pSourceElement, int pSize) { SourceElementContentAccessor lSourceElementAccessor(pSourceElement); FbxLayerElementTemplate * lLayerElement = (FbxLayerElementTemplate *)pLayerElement; lLayerElement->SetMappingMode(FbxLayerElement::eByPolygonVertex); lLayerElement->SetReferenceMode(FbxLayerElement::eIndexToDirect); lLayerElement->GetDirectArray().SetCount(lSourceElementAccessor.mCount); TYPE * lArray = NULL; lArray = lLayerElement->GetDirectArray().GetLocked(lArray); lSourceElementAccessor.GetArray((double *)lArray, lSourceElementAccessor.mCount*pSize, 0, pSize, lSourceElementAccessor.mStride, 0, pSize, sizeof(TYPE)/sizeof(double), 1.0); lLayerElement->GetDirectArray().Release(&lArray, lArray); return &(lLayerElement->GetIndexArray()); } #include #endif /* _FBXSDK_FILEIO_COLLADA_ELEMENT_H_ */