Browse Source

Save/Load Collada 1.4 Root Asset Metadata

Add Collada 1.4 <asset/> metadata to export and import.
Can store in the Scene or the Root Node for export, will be loaded into the Scene during Import
RichardTea 6 years ago
parent
commit
1f55bdd9a7
4 changed files with 128 additions and 20 deletions
  1. 34 4
      code/ColladaExporter.cpp
  2. 8 3
      code/ColladaLoader.cpp
  3. 72 11
      code/ColladaParser.cpp
  4. 14 2
      code/ColladaParser.h

+ 34 - 4
code/ColladaExporter.cpp

@@ -238,7 +238,11 @@ void ColladaExporter::WriteHeader()
     mOutput << startstr << "<contributor>" << endstr;
     mOutput << startstr << "<contributor>" << endstr;
     PushTag();
     PushTag();
 
 
-    aiMetadata* meta = mScene->mRootNode->mMetaData;
+    // If no Scene metadata, use root node metadata
+    aiMetadata* meta = mScene->mMetaData;
+    if (!meta)
+        meta = mScene->mRootNode->mMetaData;
+
     aiString value;
     aiString value;
     if (!meta || !meta->Get("Author", value))
     if (!meta || !meta->Get("Author", value))
         mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
         mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
@@ -250,13 +254,39 @@ void ColladaExporter::WriteHeader()
     else
     else
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
 
 
-    //mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
-    //mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
+    if (meta)
+    {
+        if (meta->Get("Comments", value))
+            mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
+        if (meta->Get("Copyright", value))
+            mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
+        if (meta->Get("SourceData", value))
+            mOutput << startstr << "<source_data>" << XMLEscape(value.C_Str()) << "</source_data>" << endstr;
+    }
 
 
     PopTag();
     PopTag();
     mOutput << startstr << "</contributor>" << endstr;
     mOutput << startstr << "</contributor>" << endstr;
-    mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+
+    if (!meta || !meta->Get("Created", value))
+        mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+    else
+        mOutput << startstr << "<created>" << XMLEscape(value.C_Str()) << "</created>" << endstr;
+
+    // Modified date is always the date saved
     mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
     mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
+
+    if (meta)
+    {
+        if (meta->Get("Keywords", value))
+            mOutput << startstr << "<keywords>" << XMLEscape(value.C_Str()) << "</keywords>" << endstr;
+        if (meta->Get("Revision", value))
+            mOutput << startstr << "<revision>" << XMLEscape(value.C_Str()) << "</revision>" << endstr;
+        if (meta->Get("Subject", value))
+            mOutput << startstr << "<subject>" << XMLEscape(value.C_Str()) << "</subject>" << endstr;
+        if (meta->Get("Title", value))
+            mOutput << startstr << "<title>" << XMLEscape(value.C_Str()) << "</title>" << endstr;
+    }
+
     mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
     mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
     mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
     mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
     PopTag();
     PopTag();

+ 8 - 3
code/ColladaLoader.cpp

@@ -208,9 +208,14 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
     }
     }
 
 
     // Store scene metadata
     // Store scene metadata
-    for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it)
-    {
-        pScene->mMetaData->Add((*it).first, (*it).second);
+    if (!parser.mAssetMetaData.empty()) {
+        const size_t numMeta(parser.mAssetMetaData.size());
+        pScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
+        size_t i = 0;
+        for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i)
+        {
+            pScene->mMetaData->Set(static_cast<unsigned int>(i), (*it).first, (*it).second);
+        }
     }
     }
 
 
     // store all meshes
     // store all meshes

+ 72 - 11
code/ColladaParser.cpp

@@ -267,24 +267,16 @@ void ColladaParser::ReadAssetInfo()
             }
             }
             else if(IsElement("contributor"))
             else if(IsElement("contributor"))
             {
             {
-                // This has no data of its own, will get children next time through
+                ReadContributorInfo();
             }
             }
             else
             else
             {
             {
-                const char* metadata_key = mReader->getNodeName();
-                const char* metadata_value = TestTextContent();
-                if (metadata_key != nullptr && metadata_value != nullptr)
-                {
-                    aiString aistr;
-                    aistr.Set(metadata_value);
-                    mAssetMetaData.emplace(metadata_key, aistr);
-                }
-                //SkipElement();
+                ReadMetaDataItem(mAssetMetaData);
             }
             }
         }
         }
         else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
         else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
         {
         {
-            if( strcmp( mReader->getNodeName(), "asset") != 0)
+            if (strcmp( mReader->getNodeName(), "asset") != 0)
                 ThrowException( "Expected end of <asset> element.");
                 ThrowException( "Expected end of <asset> element.");
 
 
             break;
             break;
@@ -292,6 +284,75 @@ void ColladaParser::ReadAssetInfo()
     }
     }
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Reads the contributor info
+void ColladaParser::ReadContributorInfo()
+{
+    if (mReader->isEmptyElement())
+        return;
+
+    while (mReader->read())
+    {
+        if (mReader->getNodeType() == irr::io::EXN_ELEMENT)
+        {
+            ReadMetaDataItem(mAssetMetaData);
+        }
+        else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+        {
+            if (strcmp(mReader->getNodeName(), "contributor") != 0)
+                ThrowException("Expected end of <contributor> element.");
+            break;
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a single string metadata item
+void ColladaParser::ReadMetaDataItem(StringMetaData &metadata)
+{
+    // Metadata such as created, keywords, subject etc
+    const char* key_char = mReader->getNodeName();
+    if (key_char != nullptr)
+    {
+        const std::string key_str(key_char);
+        const char* value_char = TestTextContent();
+        if (value_char != nullptr)
+        {
+            std::string camel_key_str = key_str;
+            ToCamelCase(camel_key_str);
+            aiString aistr;
+            aistr.Set(value_char);
+            metadata.emplace(camel_key_str, aistr);
+            TestClosing(key_str.c_str());
+        }
+        else
+            SkipElement();
+    }
+    else
+        SkipElement();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Convert underscore_seperated to CamelCase: "authoring_tool" becomes "AuthoringTool"
+void ColladaParser::ToCamelCase(std::string &text)
+{
+    if (text.empty())
+        return;
+    // Capitalise first character
+    text[0] = ToUpper(text[0]);
+    for (auto it = text.begin(); it != text.end(); /*iterated below*/)
+    {
+        if ((*it) == '_')
+        {
+            it = text.erase(it);
+            if (it != text.end())
+                (*it) = ToUpper(*it);
+        }
+        else
+            ++it;
+    }
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads the animation clips
 // Reads the animation clips
 void ColladaParser::ReadAnimationClipLibrary()
 void ColladaParser::ReadAnimationClipLibrary()

+ 14 - 2
code/ColladaParser.h

@@ -66,6 +66,9 @@ namespace Assimp
         friend class ColladaLoader;
         friend class ColladaLoader;
 
 
     protected:
     protected:
+        /** Map for generic metadata as aiString */
+        typedef std::map<std::string, aiString> StringMetaData;
+
         /** Constructor from XML file */
         /** Constructor from XML file */
         ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
         ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
 
 
@@ -81,6 +84,15 @@ namespace Assimp
         /** Reads asset information such as coordinate system information and legal blah */
         /** Reads asset information such as coordinate system information and legal blah */
         void ReadAssetInfo();
         void ReadAssetInfo();
 
 
+        /** Reads contributor information such as author and legal blah */
+        void ReadContributorInfo();
+
+        /** Reads generic metadata into provided map */
+        void ReadMetaDataItem(StringMetaData &metadata);
+
+        /** Convert underscore_seperated to CamelCase "authoring_tool" becomes "AuthoringTool" */
+        static void ToCamelCase(std::string &text);
+
         /** Reads the animation library */
         /** Reads the animation library */
         void ReadAnimationLibrary();
         void ReadAnimationLibrary();
 
 
@@ -343,8 +355,8 @@ namespace Assimp
         /** Which is the up vector */
         /** Which is the up vector */
         enum { UP_X, UP_Y, UP_Z } mUpDirection;
         enum { UP_X, UP_Y, UP_Z } mUpDirection;
 
 
-        typedef std::map<std::string, aiString> AssetMetaData;
-        AssetMetaData mAssetMetaData;
+        /** Asset metadata (global for scene) */
+        StringMetaData mAssetMetaData;
 
 
         /** Collada file format version */
         /** Collada file format version */
         Collada::FormatVersion mFormat;
         Collada::FormatVersion mFormat;