Browse Source

Merge pull request #1842 from assimp/3mf_basematerial_support

3mf basematerial support
Kim Kulling 7 years ago
parent
commit
290dd28c98
7 changed files with 224 additions and 22 deletions
  1. 26 0
      code/D3MFExporter.cpp
  2. 1 0
      code/D3MFExporter.h
  3. 36 3
      code/D3MFImporter.cpp
  4. 2 1
      code/Exporter.cpp
  5. 7 1
      code/SceneCombiner.cpp
  6. 81 17
      include/assimp/metadata.h
  7. 71 0
      test/unit/utMetadata.cpp

+ 26 - 0
code/D3MFExporter.cpp

@@ -117,6 +117,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
     if ( nullptr == m_zipArchive ) {
         return false;
     }
+
     ok |= exportContentTypes();
     ok |= export3DModel();
     ok |= exportRelations();
@@ -181,6 +182,8 @@ bool D3MFExporter::export3DModel() {
     mModelOutput << "<" << XmlTag::resources << ">";
     mModelOutput << std::endl;
 
+    writeMetaData();
+
     writeBaseMaterials();
 
     writeObjects();
@@ -209,6 +212,29 @@ void D3MFExporter::writeHeader() {
     mModelOutput << std::endl;
 }
 
+void D3MFExporter::writeMetaData() {
+    if ( nullptr == mScene->mMetaData ) {
+        return;
+    }
+
+    const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
+    if ( 0 == numMetaEntries ) {
+        return;
+    }
+
+    const aiString *key;
+    const aiMetadataEntry *entry(nullptr);
+    for ( size_t i = 0; i < numMetaEntries; ++i ) {
+        mScene->mMetaData->Get( i, key, entry );
+        std::string k( key->C_Str() );
+        aiString value;
+        mScene->mMetaData->Get(  k, value );
+        mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
+        mModelOutput << value.C_Str();
+        mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
+    }
+}
+
 void D3MFExporter::writeBaseMaterials() {
     mModelOutput << "<basematerials id=\"1\">\n";
     for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {

+ 1 - 0
code/D3MFExporter.h

@@ -76,6 +76,7 @@ public:
 
 protected:
     void writeHeader();
+    void writeMetaData();
     void writeBaseMaterials();
     void writeObjects();
     void writeMesh( aiMesh *mesh );

+ 36 - 3
code/D3MFImporter.cpp

@@ -102,6 +102,8 @@ public:
                 // 
             } else if ( nodeName == D3MF::XmlTag::basematerials ) {
                 ReadBaseMaterials();
+            } else if ( nodeName == D3MF::XmlTag::meta ) {
+                ReadMetadata();
             }
         }
 
@@ -109,19 +111,31 @@ public:
             scene->mRootNode->mName.Set( "3MF" );
         }
 
+        // import the metadata
+        if ( !mMetaData.empty() ) {
+            const size_t numMeta( mMetaData.size() );
+            scene->mMetaData = aiMetadata::Alloc( numMeta );
+            for ( size_t i = 0; i < numMeta; ++i ) {
+                aiString val( mMetaData[ i ].value );
+                scene->mMetaData->Set( i, mMetaData[ i ].name, val );
+            }
+        }
+
+        // import the meshes
         scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
-
         std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
 
+        // import the materials
         scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
         if ( 0 != scene->mNumMaterials ) {
             scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
             std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
         }
+
+        // create the scenegraph
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
-
         std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
     }
 
@@ -180,6 +194,21 @@ private:
         return mesh;
     }
 
+    void ReadMetadata() {
+        const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
+        xmlReader->read();
+        const std::string value = xmlReader->getNodeData();
+
+        if ( name.empty() ) {
+            return;
+        }
+
+        MetaEntry entry;
+        entry.name = name;
+        entry.value = value;
+        mMetaData.push_back( entry );
+    }
+
     void ImportVertices(aiMesh* mesh) {
         std::vector<aiVector3D> vertices;
         while(ReadToEndElement(D3MF::XmlTag::vertices)) {
@@ -371,8 +400,12 @@ private:
         return false;
     }
 
-
 private:
+    struct MetaEntry {
+        std::string name;
+        std::string value;
+    };
+    std::vector<MetaEntry> mMetaData;
     std::vector<aiMesh*> mMeshes;
     MatArray mMatArray;
     unsigned int mActiveMatGroup;

+ 2 - 1
code/Exporter.cpp

@@ -308,7 +308,8 @@ bool IsVerboseFormat(const aiScene* pScene) {
 }
 
 // ------------------------------------------------------------------------------------------------
-aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) {
+aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
+        unsigned int pPreprocessing, const ExportProperties* pProperties) {
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
     // when they create scenes from scratch, users will likely create them not in verbose

+ 7 - 1
code/SceneCombiner.cpp

@@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/SceneCombiner.h>
 #include <assimp/StringUtils.h>
 #include <assimp/fast_atof.h>
+#include <assimp/metadata.h>
 #include <assimp/Hash.h>
 #include "time.h"
 #include <assimp/DefaultLogger.hpp>
@@ -1001,7 +1002,12 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
         *_dest = new aiScene();
     }
     aiScene* dest = *_dest;
-    ai_assert(dest);
+    ai_assert(nullptr != dest);
+
+    // copy metadata
+    if ( nullptr != src->mMetaData ) {
+        dest->mMetaData = new aiMetadata( *src->mMetaData );
+    }
 
     // copy animations
     dest->mNumAnimations = src->mNumAnimations;

+ 81 - 17
include/assimp/metadata.h

@@ -67,6 +67,7 @@ typedef enum aiMetadataType {
     AI_DOUBLE     = 4,
     AI_AISTRING   = 5,
     AI_AIVECTOR3D = 6,
+    AI_META_MAX   = 7,
 
 #ifndef SWIG
     FORCE_32BIT = INT_MAX
@@ -130,42 +131,103 @@ struct aiMetadata {
      */
     aiMetadata()
     : mNumProperties(0)
-    , mKeys(NULL)
-    , mValues(NULL) {
+    , mKeys(nullptr)
+    , mValues(nullptr) {
         // empty
     }
 
+    aiMetadata( const aiMetadata &rhs )
+    : mNumProperties( rhs.mNumProperties )
+    , mKeys( nullptr )
+    , mValues( nullptr ) {
+        mKeys = new aiString[ mNumProperties ];
+        for ( unsigned int i = 0; i < mNumProperties; ++i ) {
+            mKeys[ i ] = rhs.mKeys[ i ];
+        }
+        mValues = new aiMetadataEntry[ mNumProperties ];
+        for ( unsigned int i = 0; i < mNumProperties; ++i ) {
+            mValues[ i ].mType = rhs.mValues[ i ].mType;
+            switch ( rhs.mValues[ i ].mType ) {
+            case AI_BOOL:
+                mValues[ i ].mData = new bool( rhs.mValues[i].mData );
+                break;
+            case AI_INT32: {
+                int32_t v;
+                ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( int32_t ) );
+                mValues[ i ].mData = new int32_t( v );
+                }
+                break;
+            case AI_UINT64: {
+                    uint64_t v;
+                    ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( uint64_t ) );
+                    mValues[ i ].mData = new  uint64_t( v );
+                }
+                break;
+            case AI_FLOAT: {
+                    float v;
+                    ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( float ) );
+                    mValues[ i ].mData = new float( v );
+                }
+                break;
+            case AI_DOUBLE: {
+                    double v;
+                    ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( double ) );
+                    mValues[ i ].mData = new double( v );
+                }
+                break;
+            case AI_AISTRING: {
+                    aiString v;
+                    rhs.Get<aiString>( mKeys[ i ], v );
+                    mValues[ i ].mData = new aiString( v );
+                }
+                break;
+            case AI_AIVECTOR3D: {
+                    aiVector3D v;
+                    rhs.Get<aiVector3D>( mKeys[ i ], v );
+                    mValues[ i ].mData = new aiVector3D( v );
+                }
+                break;
+#ifndef SWIG
+            case FORCE_32BIT:
+#endif
+            default:
+                break;
+            }
+
+        }
+    }
+
     /** 
      *  @brief The destructor.
      */
     ~aiMetadata() {
         delete [] mKeys;
-        mKeys = NULL;
+        mKeys = nullptr;
         if (mValues) {
             // Delete each metadata entry
             for (unsigned i=0; i<mNumProperties; ++i) {
                 void* data = mValues[i].mData;
                 switch (mValues[i].mType) {
                 case AI_BOOL:
-                    delete static_cast<bool*>(data);
+                    delete static_cast< bool* >( data );
                     break;
                 case AI_INT32:
-                    delete static_cast<int32_t*>(data);
+                    delete static_cast< int32_t* >( data );
                     break;
                 case AI_UINT64:
-                    delete static_cast<uint64_t*>(data);
+                    delete static_cast< uint64_t* >( data );
                     break;
                 case AI_FLOAT:
-                    delete static_cast<float*>(data);
+                    delete static_cast< float* >( data );
                     break;
                 case AI_DOUBLE:
-                    delete static_cast<double*>(data);
+                    delete static_cast< double* >( data );
                     break;
                 case AI_AISTRING:
-                    delete static_cast<aiString*>(data);
+                    delete static_cast< aiString* >( data );
                     break;
                 case AI_AIVECTOR3D:
-                    delete static_cast<aiVector3D*>(data);
+                    delete static_cast< aiVector3D* >( data );
                     break;
 #ifndef SWIG
                 case FORCE_32BIT:
@@ -177,7 +239,7 @@ struct aiMetadata {
 
             // Delete the metadata array
             delete [] mValues;
-            mValues = NULL;
+            mValues = nullptr;
         }
     }
 
@@ -208,8 +270,8 @@ struct aiMetadata {
     }
 
 	template<typename T>
-	inline void Add(const std::string& key, const T& value)
-	{
+	inline
+    void Add(const std::string& key, const T& value) {
 		aiString* new_keys = new aiString[mNumProperties + 1];
 		aiMetadataEntry* new_values = new aiMetadataEntry[mNumProperties + 1];
 
@@ -256,7 +318,7 @@ struct aiMetadata {
 
     template<typename T>
     inline 
-    bool Get( unsigned index, T& value ) {
+    bool Get( unsigned index, T& value ) const {
         // In range assertion
         if ( index >= mNumProperties ) {
             return false;
@@ -277,7 +339,7 @@ struct aiMetadata {
 
     template<typename T>
     inline 
-    bool Get( const aiString& key, T& value ) {
+    bool Get( const aiString& key, T& value ) const {
         // Search for the given key
         for ( unsigned int i = 0; i < mNumProperties; ++i ) {
             if ( mKeys[ i ] == key ) {
@@ -288,7 +350,8 @@ struct aiMetadata {
     }
 
     template<typename T>
-    inline bool Get( const std::string& key, T& value ) {
+    inline
+    bool Get( const std::string& key, T& value ) const {
         return Get(aiString(key), value);
     }
 
@@ -297,7 +360,8 @@ struct aiMetadata {
 	/// \param [out] pKey - pointer to the key value.
 	/// \param [out] pEntry - pointer to the entry: type and value.
 	/// \return false - if pIndex is out of range, else - true.
-	inline bool Get(size_t index, const aiString*& key, const aiMetadataEntry*& entry) {
+	inline
+    bool Get(size_t index, const aiString*& key, const aiMetadataEntry*& entry) const {
         if ( index >= mNumProperties ) {
             return false;
         }

+ 71 - 0
test/unit/utMetadata.cpp

@@ -181,3 +181,74 @@ TEST_F( utMetadata, get_set_aiVector3D_Test ) {
     EXPECT_TRUE( success );
 }
 
+TEST_F( utMetadata, copy_test ) {
+    m_data = aiMetadata::Alloc( AI_META_MAX );
+    bool bv = true;
+    m_data->Set( 0, "bool", bv );
+    int32_t i32v = -10;
+    m_data->Set( 1, "int32", i32v );
+    uint64_t ui64v = static_cast<uint64_t>( 10 );
+    m_data->Set( 2, "uint64", ui64v );
+    float fv = 1.0f;
+    m_data->Set( 3, "float", fv );
+    double dv = 2.0;
+    m_data->Set( 4, "double", dv );
+    const aiString strVal( std::string( "test" ) );
+    m_data->Set( 5, "aiString", strVal );
+    aiVector3D vecVal( 1, 2, 3 );
+    m_data->Set( 6, "aiVector3D", vecVal );
+
+    aiMetadata copy( *m_data );
+    EXPECT_EQ( 7, copy.mNumProperties );
+
+    // bool test
+    {
+        bool v;
+        EXPECT_TRUE( copy.Get( "bool", v ) );
+        EXPECT_EQ( bv, v );
+    }
+
+    // int32_t test
+    {
+        int32_t v;
+        bool ok = copy.Get( "int32", v );
+        EXPECT_TRUE( ok );
+        EXPECT_EQ( i32v, v );
+    }
+
+    // uint64_t test
+    {
+        uint64_t v;
+        bool ok = copy.Get( "uint64", v );
+        EXPECT_TRUE( ok );
+        EXPECT_EQ( ui64v, v );
+    }
+
+    // float test
+    {
+        float v;
+        EXPECT_TRUE( copy.Get( "float", v ) );
+        EXPECT_EQ( fv, v );
+    }
+
+    // double test
+    {
+        double v;
+        EXPECT_TRUE( copy.Get( "double", v ) );
+        EXPECT_EQ( dv, v );
+    }
+
+    // bool test
+    {
+        aiString v;
+        EXPECT_TRUE( copy.Get( "aiString", v ) );
+        EXPECT_EQ( strVal, v );
+    }
+
+    // bool test
+    {
+        aiVector3D v;
+        EXPECT_TRUE( copy.Get( "aiVector3D", v ) );
+        EXPECT_EQ( vecVal, v );
+    }
+}