瀏覽代碼

Merge pull request #2820 from RichardTea/collada_modeller_metadata

Collada and glTF modeller metadata
Kim Kulling 5 年之前
父節點
當前提交
a01d7c4048

+ 2 - 0
code/CMakeLists.txt

@@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/color4.h
   ${HEADER_PATH}/color4.h
   ${HEADER_PATH}/color4.inl
   ${HEADER_PATH}/color4.inl
   ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
   ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
+  ${HEADER_PATH}/commonMetaData.h
   ${HEADER_PATH}/defs.h
   ${HEADER_PATH}/defs.h
   ${HEADER_PATH}/Defines.h
   ${HEADER_PATH}/Defines.h
   ${HEADER_PATH}/cfileio.h
   ${HEADER_PATH}/cfileio.h
@@ -348,6 +349,7 @@ ADD_ASSIMP_IMPORTER( BVH
 )
 )
 
 
 ADD_ASSIMP_IMPORTER( COLLADA
 ADD_ASSIMP_IMPORTER( COLLADA
+  Collada/ColladaHelper.cpp
   Collada/ColladaHelper.h
   Collada/ColladaHelper.h
   Collada/ColladaLoader.cpp
   Collada/ColladaLoader.cpp
   Collada/ColladaLoader.h
   Collada/ColladaLoader.h

+ 3 - 2
code/Collada/ColladaExporter.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "ColladaExporter.h"
 #include "ColladaExporter.h"
 #include <assimp/Bitmap.h>
 #include <assimp/Bitmap.h>
+#include <assimp/commonMetaData.h>
 #include <assimp/MathFunctions.h>
 #include <assimp/MathFunctions.h>
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
 #include <assimp/SceneCombiner.h>
 #include <assimp/SceneCombiner.h>
@@ -277,7 +278,7 @@ void ColladaExporter::WriteHeader() {
         mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
         mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
     }
     }
 
 
-    if (nullptr == meta || !meta->Get("AuthoringTool", value)) {
+    if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) {
         mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
         mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
     } else {
     } else {
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
@@ -287,7 +288,7 @@ void ColladaExporter::WriteHeader() {
         if (meta->Get("Comments", value)) {
         if (meta->Get("Comments", value)) {
             mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
             mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
         }
         }
-        if (meta->Get("Copyright", value)) {
+        if (meta->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) {
             mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
             mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
         }
         }
         if (meta->Get("SourceData", value)) {
         if (meta->Get("SourceData", value)) {

+ 107 - 0
code/Collada/ColladaHelper.cpp

@@ -0,0 +1,107 @@
+/** Helper structures for the Collada loader */
+
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include "ColladaHelper.h"
+
+#include <assimp/commonMetaData.h>
+#include <assimp/ParsingUtils.h>
+
+namespace Assimp {
+namespace Collada {
+
+const MetaKeyPairVector MakeColladaAssimpMetaKeys() {
+    MetaKeyPairVector result;
+    result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
+    result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
+    return result;
+};
+
+const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
+    static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
+    return result;
+}
+
+const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
+    MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
+    for (auto &val : result)
+    {
+        ToCamelCase(val.first);
+    }
+    return result;
+};
+
+const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
+{
+    static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
+    return result;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
+void ToCamelCase(std::string &text)
+{
+    if (text.empty())
+        return;
+    // Capitalise first character
+    auto it = text.begin();
+    (*it) = ToUpper(*it);
+    ++it;
+    for (/*started above*/ ; it != text.end(); /*iterated below*/)
+    {
+        if ((*it) == '_')
+        {
+            it = text.erase(it);
+            if (it != text.end())
+                (*it) = ToUpper(*it);
+        }
+        else
+        {
+            // Make lower case
+            (*it) = ToLower(*it);
+            ++it;               
+        }
+    }
+}
+
+} // namespace Collada
+} // namespace Assimp

+ 11 - 0
code/Collada/ColladaHelper.h

@@ -104,6 +104,17 @@ enum MorphMethod
     Relative
     Relative
 };
 };
 
 
+/** Common metadata keys as <Collada, Assimp> */
+typedef std::pair<std::string, std::string> MetaKeyPair;
+typedef std::vector<MetaKeyPair> MetaKeyPairVector;
+
+// Collada as lower_case (native)
+const MetaKeyPairVector &GetColladaAssimpMetaKeys();
+// Collada as CamelCase (used by Assimp for consistency)
+const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
+
+/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */
+void ToCamelCase(std::string &text);
 
 
 /** Contains all data for one of the different transformation types */
 /** Contains all data for one of the different transformation types */
 struct Transform
 struct Transform

+ 41 - 34
code/Collada/ColladaParser.cpp

@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream>
 #include <sstream>
 #include <stdarg.h>
 #include <stdarg.h>
 #include "ColladaParser.h"
 #include "ColladaParser.h"
+#include <assimp/commonMetaData.h>
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/StringUtils.h>
 #include <assimp/StringUtils.h>
@@ -249,6 +250,9 @@ void ColladaParser::UriDecodePath(aiString& ss)
 bool ColladaParser::ReadBoolFromTextContent()
 bool ColladaParser::ReadBoolFromTextContent()
 {
 {
     const char* cur = GetTextContent();
     const char* cur = GetTextContent();
+    if ( nullptr == cur) {
+        return false;
+    }
     return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur);
     return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur);
 }
 }
 
 
@@ -257,6 +261,9 @@ bool ColladaParser::ReadBoolFromTextContent()
 ai_real ColladaParser::ReadFloatFromTextContent()
 ai_real ColladaParser::ReadFloatFromTextContent()
 {
 {
     const char* cur = GetTextContent();
     const char* cur = GetTextContent();
+    if ( nullptr == cur ) {
+        return 0.0;
+    }
     return fast_atof(cur);
     return fast_atof(cur);
 }
 }
 
 
@@ -276,6 +283,11 @@ void ColladaParser::ReadContents()
                 if (attrib != -1) {
                 if (attrib != -1) {
                     const char* version = mReader->getAttributeValue(attrib);
                     const char* version = mReader->getAttributeValue(attrib);
 
 
+                    // Store declared format version string
+                    aiString v;
+                    v.Set(version);
+                    mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v );
+
                     if (!::strncmp(version, "1.5", 3)) {
                     if (!::strncmp(version, "1.5", 3)) {
                         mFormat = FV_1_5_n;
                         mFormat = FV_1_5_n;
                         ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
                         ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
@@ -434,23 +446,39 @@ void ColladaParser::ReadContributorInfo()
     }
     }
 }
 }
 
 
+static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) {
+    for (size_t i = 0; i < key_renaming.size(); ++i) {
+		if (key_renaming[i].first == collada_key) {
+            found_index = i;
+            return true;
+		}
+	}
+    found_index = std::numeric_limits<size_t>::max();
+    return false;
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a single string metadata item
 // 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)
-    {
+void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) {
+    const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
+	// 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 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);
+		const char *value_char = TestTextContent();
+		if (value_char != nullptr) {
             aiString aistr;
             aiString aistr;
-            aistr.Set(value_char);
-            metadata.emplace(camel_key_str, aistr);
+			aistr.Set(value_char);
+
+            std::string camel_key_str(key_str);
+			ToCamelCase(camel_key_str);
+
+			size_t found_index;
+			if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
+                metadata.emplace(key_renaming[found_index].second, aistr);
+            } else {
+				metadata.emplace(camel_key_str, aistr);
+			}
         }
         }
         TestClosing(key_str.c_str());
         TestClosing(key_str.c_str());
     }
     }
@@ -458,27 +486,6 @@ void ColladaParser::ReadMetaDataItem(StringMetaData &metadata)
         SkipElement();
         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()

+ 1 - 4
code/Collada/ColladaParser.h

@@ -94,12 +94,9 @@ namespace Assimp
         /** Reads contributor information such as author and legal blah */
         /** Reads contributor information such as author and legal blah */
         void ReadContributorInfo();
         void ReadContributorInfo();
 
 
-        /** Reads generic metadata into provided map */
+        /** Reads generic metadata into provided map and renames keys for Assimp */
         void ReadMetaDataItem(StringMetaData &metadata);
         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();
 
 

+ 3 - 0
code/glTF/glTFAssetWriter.inl

@@ -627,6 +627,9 @@ namespace glTF {
         asset.SetObject();
         asset.SetObject();
         asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
         asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
         asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
         asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
+        if (!mAsset.asset.copyright.empty())
+            asset.AddMember("copyright", Value(mAsset.asset.copyright, mAl).Move(), mAl);
+
         mDoc.AddMember("asset", asset, mAl);
         mDoc.AddMember("asset", asset, mAl);
     }
     }
 
 

+ 7 - 0
code/glTF/glTFExporter.cpp

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "glTF/glTFAssetWriter.h"
 #include "glTF/glTFAssetWriter.h"
 #include "PostProcessing/SplitLargeMeshes.h"
 #include "PostProcessing/SplitLargeMeshes.h"
 
 
+#include <assimp/commonMetaData.h>
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 #include <assimp/StringComparison.h>
 #include <assimp/StringComparison.h>
 #include <assimp/ByteSwapper.h>
 #include <assimp/ByteSwapper.h>
@@ -873,6 +874,12 @@ void glTFExporter::ExportMetadata()
         aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
         aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
 
 
     asset.generator = buffer;
     asset.generator = buffer;
+
+	// Copyright
+	aiString copyright_str;
+	if (mScene->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, copyright_str)) {
+		asset.copyright = copyright_str.C_Str();
+	}
 }
 }
 
 
 inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animation>& animRef, Ref<Buffer>& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond)
 inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animation>& animRef, Ref<Buffer>& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond)

+ 6 - 1
code/glTF/glTFImporter.cpp

@@ -703,7 +703,8 @@ void glTFImporter::ImportCommonMetadata(glTF::Asset& a)
     ai_assert(mScene->mMetaData == nullptr);
     ai_assert(mScene->mMetaData == nullptr);
     const bool hasVersion = !a.asset.version.empty();
     const bool hasVersion = !a.asset.version.empty();
     const bool hasGenerator = !a.asset.generator.empty();
     const bool hasGenerator = !a.asset.generator.empty();
-    if (hasVersion || hasGenerator)
+    const bool hasCopyright = !a.asset.copyright.empty();
+    if (hasVersion || hasGenerator || hasCopyright)
     {
     {
         mScene->mMetaData = new aiMetadata;
         mScene->mMetaData = new aiMetadata;
         if (hasVersion)
         if (hasVersion)
@@ -714,6 +715,10 @@ void glTFImporter::ImportCommonMetadata(glTF::Asset& a)
         {
         {
             mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
             mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
         }
         }
+        if (hasCopyright)
+        {
+            mScene->mMetaData->Add(AI_METADATA_SOURCE_COPYRIGHT, aiString(a.asset.copyright));
+        }
     }
     }
 }
 }
 
 

+ 2 - 0
code/glTF2/glTF2AssetWriter.inl

@@ -720,6 +720,8 @@ namespace glTF2 {
         asset.SetObject();
         asset.SetObject();
         asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
         asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
         asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
         asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
+        if (!mAsset.asset.copyright.empty())
+            asset.AddMember("copyright", Value(mAsset.asset.copyright, mAl).Move(), mAl);
         mDoc.AddMember("asset", asset, mAl);
         mDoc.AddMember("asset", asset, mAl);
     }
     }
 
 

+ 7 - 0
code/glTF2/glTF2Exporter.cpp

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "glTF2/glTF2AssetWriter.h"
 #include "glTF2/glTF2AssetWriter.h"
 #include "PostProcessing/SplitLargeMeshes.h"
 #include "PostProcessing/SplitLargeMeshes.h"
 
 
+#include <assimp/commonMetaData.h>
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 #include <assimp/StringComparison.h>
 #include <assimp/StringComparison.h>
 #include <assimp/ByteSwapper.h>
 #include <assimp/ByteSwapper.h>
@@ -996,6 +997,12 @@ void glTF2Exporter::ExportMetadata()
         aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
         aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
 
 
     asset.generator = buffer;
     asset.generator = buffer;
+
+    // Copyright
+	aiString copyright_str;
+	if (mScene->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, copyright_str)) {
+        asset.copyright = copyright_str.C_Str();
+	}
 }
 }
 
 
 inline Ref<Accessor> GetSamplerInputRef(Asset& asset, std::string& animId, Ref<Buffer>& buffer, std::vector<float>& times)
 inline Ref<Accessor> GetSamplerInputRef(Asset& asset, std::string& animId, Ref<Buffer>& buffer, std::vector<float>& times)

+ 6 - 1
code/glTF2/glTF2Importer.cpp

@@ -1307,7 +1307,8 @@ void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
     ai_assert(mScene->mMetaData == nullptr);
     ai_assert(mScene->mMetaData == nullptr);
     const bool hasVersion = !a.asset.version.empty();
     const bool hasVersion = !a.asset.version.empty();
     const bool hasGenerator = !a.asset.generator.empty();
     const bool hasGenerator = !a.asset.generator.empty();
-    if (hasVersion || hasGenerator)
+    const bool hasCopyright = !a.asset.copyright.empty();
+    if (hasVersion || hasGenerator || hasCopyright)
     {
     {
         mScene->mMetaData = new aiMetadata;
         mScene->mMetaData = new aiMetadata;
         if (hasVersion)
         if (hasVersion)
@@ -1318,6 +1319,10 @@ void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
         {
         {
             mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
             mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator));
         }
         }
+        if (hasCopyright)
+        {
+            mScene->mMetaData->Add(AI_METADATA_SOURCE_COPYRIGHT, aiString(a.asset.copyright));
+        }
     }
     }
 }
 }
 
 

+ 4 - 0
include/assimp/commonMetaData.h

@@ -60,4 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /// Not all formats add this metadata.
 /// Not all formats add this metadata.
 #define AI_METADATA_SOURCE_GENERATOR "SourceAsset_Generator"
 #define AI_METADATA_SOURCE_GENERATOR "SourceAsset_Generator"
 
 
+/// Scene metadata holding the source asset copyright statement, if available.
+/// Not all formats add this metadata.
+#define AI_METADATA_SOURCE_COPYRIGHT "SourceAsset_Copyright"
+
 #endif
 #endif

+ 1 - 0
test/models/Collada/lights.dae

@@ -4,6 +4,7 @@
     <contributor>
     <contributor>
       <author>Blender User</author>
       <author>Blender User</author>
       <authoring_tool>Blender 2.74.0 commit date:2015-03-31, commit time:13:39, hash:000dfc0</authoring_tool>
       <authoring_tool>Blender 2.74.0 commit date:2015-03-31, commit time:13:39, hash:000dfc0</authoring_tool>
+      <copyright>BSD</copyright>
     </contributor>
     </contributor>
     <created>2015-05-17T21:55:44</created>
     <created>2015-05-17T21:55:44</created>
     <modified>2015-05-17T21:55:44</modified>
     <modified>2015-05-17T21:55:44</modified>

+ 54 - 5
test/unit/utColladaExportLight.cpp

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "UnitTestPCH.h"
 #include "UnitTestPCH.h"
 
 
 #include <assimp/cexport.h>
 #include <assimp/cexport.h>
+#include <assimp/commonMetaData.h>
 #include <assimp/Exporter.hpp>
 #include <assimp/Exporter.hpp>
 #include <assimp/Importer.hpp>
 #include <assimp/Importer.hpp>
 #include <assimp/scene.h>
 #include <assimp/scene.h>
@@ -75,7 +76,7 @@ TEST_F(ColladaExportLight, testExportLight)
     const char* file = "lightsExp.dae";
     const char* file = "lightsExp.dae";
 
 
     const aiScene* pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/lights.dae", aiProcess_ValidateDataStructure);
     const aiScene* pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/lights.dae", aiProcess_ValidateDataStructure);
-    ASSERT_TRUE(pTest!=NULL);
+    ASSERT_NE(pTest, nullptr);
     ASSERT_TRUE(pTest->HasLights());
     ASSERT_TRUE(pTest->HasLights());
 
 
     const unsigned int origNumLights( pTest->mNumLights );
     const unsigned int origNumLights( pTest->mNumLights );
@@ -86,15 +87,63 @@ TEST_F(ColladaExportLight, testExportLight)
         origLights[ i ] = *(pTest->mLights[ i ]);
         origLights[ i ] = *(pTest->mLights[ i ]);
     }
     }
 
 
-    EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada",file));
+    // Common metadata
+    // Confirm was loaded by the Collada importer
+    aiString origImporter;
+    EXPECT_TRUE(pTest->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, origImporter)) << "No importer format metadata";
+	EXPECT_STREQ("Collada Importer", origImporter.C_Str());
+
+    aiString origGenerator;
+	EXPECT_TRUE(pTest->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, origGenerator)) << "No generator metadata";
+	EXPECT_EQ(strncmp(origGenerator.C_Str(), "Blender", 7), 0) << "AI_METADATA_SOURCE_GENERATOR was: " << origGenerator.C_Str();
+
+    aiString origCopyright;
+	EXPECT_TRUE(pTest->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, origCopyright)) << "No copyright metadata";
+    EXPECT_STREQ("BSD", origCopyright.C_Str());
+
+    aiString origCreated;
+	EXPECT_TRUE(pTest->mMetaData->Get("Created", origCreated)) << "No created metadata";
+    EXPECT_STREQ("2015-05-17T21:55:44", origCreated.C_Str());
+
+    aiString origModified;
+	EXPECT_TRUE(pTest->mMetaData->Get("Modified", origModified)) << "No modified metadata";
+    EXPECT_STREQ("2015-05-17T21:55:44", origModified.C_Str());
+
+    EXPECT_EQ(AI_SUCCESS, ex->Export(pTest, "collada", file));
+
+    // Drop the pointer as about to become invalid
+    pTest = nullptr;
 
 
     const aiScene* imported = im->ReadFile(file, aiProcess_ValidateDataStructure);
     const aiScene* imported = im->ReadFile(file, aiProcess_ValidateDataStructure);
 
 
-    ASSERT_TRUE(imported!=NULL);
+    ASSERT_TRUE(imported != NULL);
+
+    // Check common metadata survived roundtrip
+    aiString readImporter;
+    EXPECT_TRUE(imported->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, readImporter)) << "No importer format metadata after export";
+    EXPECT_STREQ(origImporter.C_Str(), readImporter.C_Str()) << "Assimp Importer Format changed";
+
+    aiString readGenerator;
+	EXPECT_TRUE(imported->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, readGenerator)) << "No generator metadata";
+	EXPECT_STREQ(origGenerator.C_Str(), readGenerator.C_Str()) << "Generator changed";
+
+    aiString readCopyright;
+	EXPECT_TRUE(imported->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, readCopyright)) << "No copyright metadata";
+    EXPECT_STREQ(origCopyright.C_Str(), readCopyright.C_Str()) << "Copyright changed";
+
+    aiString readCreated;
+	EXPECT_TRUE(imported->mMetaData->Get("Created", readCreated)) << "No created metadata";
+    EXPECT_STREQ(origCreated.C_Str(), readCreated.C_Str()) << "Created date changed";
+
+    aiString readModified;
+	EXPECT_TRUE(imported->mMetaData->Get("Modified", readModified)) << "No modified metadata";
+    EXPECT_STRNE(origModified.C_Str(), readModified.C_Str()) << "Modified date did not change";
+    EXPECT_GT(readModified.length, ai_uint32(18)) << "Modified date too short";
 
 
+    // Lights
     EXPECT_TRUE(imported->HasLights());
     EXPECT_TRUE(imported->HasLights());
-    EXPECT_EQ( origNumLights,imported->mNumLights );
-    for(size_t i=0; i< origNumLights; i++) {
+    EXPECT_EQ(origNumLights, imported->mNumLights);
+    for(size_t i=0; i < origNumLights; i++) {
         const aiLight *orig = &origLights[ i ];
         const aiLight *orig = &origLights[ i ];
         const aiLight *read = imported->mLights[i];
         const aiLight *read = imported->mLights[i];
         EXPECT_EQ( 0,strncmp(origNames[ i ].c_str(),read->mName.C_Str(), origNames[ i ].size() ) );
         EXPECT_EQ( 0,strncmp(origNames[ i ].c_str(),read->mName.C_Str(), origNames[ i ].size() ) );

+ 69 - 54
test/unit/utColladaImportExport.cpp

@@ -40,76 +40,91 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 */
 */
-#include "UnitTestPCH.h"
 #include "AbstractImportExportBase.h"
 #include "AbstractImportExportBase.h"
+#include "UnitTestPCH.h"
 
 
-#include <assimp/Importer.hpp>
-#include <assimp/scene.h>
+#include <assimp/commonMetaData.h>
 #include <assimp/postprocess.h>
 #include <assimp/postprocess.h>
+#include <assimp/scene.h>
+#include <assimp/Importer.hpp>
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
 class utColladaImportExport : public AbstractImportExportBase {
 class utColladaImportExport : public AbstractImportExportBase {
 public:
 public:
-    virtual bool importerTest() {
-        Assimp::Importer importer;
-        const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure);
-        if (scene == nullptr)
-            return false;
-
-        // Expected number of items
-        EXPECT_EQ(scene->mNumMeshes, 1u);
-        EXPECT_EQ(scene->mNumMaterials, 1u);
-        EXPECT_EQ(scene->mNumAnimations, 0u);
-        EXPECT_EQ(scene->mNumTextures, 0u);
-        EXPECT_EQ(scene->mNumLights, 1u);
-        EXPECT_EQ(scene->mNumCameras, 1u);
-
-        return true;
-    }
+	virtual bool importerTest() {
+		Assimp::Importer importer;
+		const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.dae", aiProcess_ValidateDataStructure);
+		if (scene == nullptr)
+			return false;
+
+		// Expected number of items
+		EXPECT_EQ(scene->mNumMeshes, 1u);
+		EXPECT_EQ(scene->mNumMaterials, 1u);
+		EXPECT_EQ(scene->mNumAnimations, 0u);
+		EXPECT_EQ(scene->mNumTextures, 0u);
+		EXPECT_EQ(scene->mNumLights, 1u);
+		EXPECT_EQ(scene->mNumCameras, 1u);
+
+		// Expected common metadata
+		aiString value;
+		EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, value)) << "No importer format metadata";
+		EXPECT_STREQ("Collada Importer", value.C_Str());
+
+		EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, value)) << "No format version metadata";
+		EXPECT_STREQ("1.4.1", value.C_Str());
+
+		EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, value)) << "No generator metadata";
+		EXPECT_EQ(strncmp(value.C_Str(), "Maya 8.0", 8), 0) << "AI_METADATA_SOURCE_GENERATOR was: " << value.C_Str();
+
+		EXPECT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) << "No copyright metadata";
+		EXPECT_EQ(strncmp(value.C_Str(), "Copyright 2006", 14), 0) << "AI_METADATA_SOURCE_COPYRIGHT was: " << value.C_Str();
+
+		return true;
+	}
 };
 };
 
 
 TEST_F(utColladaImportExport, importBlenFromFileTest) {
 TEST_F(utColladaImportExport, importBlenFromFileTest) {
-    EXPECT_TRUE(importerTest());
+	EXPECT_TRUE(importerTest());
 }
 }
 
 
 class utColladaZaeImportExport : public AbstractImportExportBase {
 class utColladaZaeImportExport : public AbstractImportExportBase {
 public:
 public:
-    virtual bool importerTest() {
-        {
-            Assimp::Importer importer;
-            const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure);
-            if (scene == nullptr)
-                return false;
-
-            // Expected number of items
-            EXPECT_EQ(scene->mNumMeshes, 1u);
-            EXPECT_EQ(scene->mNumMaterials, 1u);
-            EXPECT_EQ(scene->mNumAnimations, 0u);
-            EXPECT_EQ(scene->mNumTextures, 1u);
-            EXPECT_EQ(scene->mNumLights, 1u);
-            EXPECT_EQ(scene->mNumCameras, 1u);
-        }
-
-        {
-            Assimp::Importer importer;
-            const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck_nomanifest.zae", aiProcess_ValidateDataStructure);
-            if (scene == nullptr)
-                return false;
-
-            // Expected number of items
-            EXPECT_EQ(scene->mNumMeshes, 1u);
-            EXPECT_EQ(scene->mNumMaterials, 1u);
-            EXPECT_EQ(scene->mNumAnimations, 0u);
-            EXPECT_EQ(scene->mNumTextures, 1u);
-            EXPECT_EQ(scene->mNumLights, 1u);
-            EXPECT_EQ(scene->mNumCameras, 1u);
-        }
-
-        return true;
-    }
+	virtual bool importerTest() {
+		{
+			Assimp::Importer importer;
+			const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure);
+			if (scene == nullptr)
+				return false;
+
+			// Expected number of items
+			EXPECT_EQ(scene->mNumMeshes, 1u);
+			EXPECT_EQ(scene->mNumMaterials, 1u);
+			EXPECT_EQ(scene->mNumAnimations, 0u);
+			EXPECT_EQ(scene->mNumTextures, 1u);
+			EXPECT_EQ(scene->mNumLights, 1u);
+			EXPECT_EQ(scene->mNumCameras, 1u);
+		}
+
+		{
+			Assimp::Importer importer;
+			const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck_nomanifest.zae", aiProcess_ValidateDataStructure);
+			if (scene == nullptr)
+				return false;
+
+			// Expected number of items
+			EXPECT_EQ(scene->mNumMeshes, 1u);
+			EXPECT_EQ(scene->mNumMaterials, 1u);
+			EXPECT_EQ(scene->mNumAnimations, 0u);
+			EXPECT_EQ(scene->mNumTextures, 1u);
+			EXPECT_EQ(scene->mNumLights, 1u);
+			EXPECT_EQ(scene->mNumCameras, 1u);
+		}
+
+		return true;
+	}
 };
 };
 
 
 TEST_F(utColladaZaeImportExport, importBlenFromFileTest) {
 TEST_F(utColladaZaeImportExport, importBlenFromFileTest) {
-    EXPECT_TRUE(importerTest());
+	EXPECT_TRUE(importerTest());
 }
 }