2
0
Эх сурвалжийг харах

Merge branch 'master' into moffsetmatrix_documentation

Kim Kulling 7 жил өмнө
parent
commit
bdb3a73486

+ 10 - 1
code/3MFXmlTags.h

@@ -45,6 +45,7 @@ namespace Assimp {
 namespace D3MF {
 namespace D3MF {
 
 
 namespace XmlTag {
 namespace XmlTag {
+    // Model-data specific tags
     static const std::string model = "model";
     static const std::string model = "model";
     static const std::string model_unit = "unit";
     static const std::string model_unit = "unit";
     static const std::string metadata = "metadata";
     static const std::string metadata = "metadata";
@@ -62,6 +63,8 @@ namespace XmlTag {
     static const std::string v2 = "v2";
     static const std::string v2 = "v2";
     static const std::string v3 = "v3";
     static const std::string v3 = "v3";
     static const std::string id = "id";
     static const std::string id = "id";
+    static const std::string pid = "pid";
+    static const std::string p1 = "p1";
     static const std::string name = "name";
     static const std::string name = "name";
     static const std::string type = "type";
     static const std::string type = "type";
     static const std::string build = "build";
     static const std::string build = "build";
@@ -69,6 +72,13 @@ namespace XmlTag {
     static const std::string objectid = "objectid";
     static const std::string objectid = "objectid";
     static const std::string transform = "transform";
     static const std::string transform = "transform";
 
 
+    // Material definitions
+    static const std::string basematerials = "basematerials";
+    static const std::string basematerials_base = "base";
+    static const std::string basematerials_name = "name";
+    static const std::string basematerials_displaycolor = "displaycolor";
+
+    // Meta info tags
     static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
     static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
     static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
     static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
     static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
     static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
@@ -83,7 +93,6 @@ namespace XmlTag {
     static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
     static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
     static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
     static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
     static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
     static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
-
 }
 }
 
 
 } // Namespace D3MF
 } // Namespace D3MF

+ 134 - 62
code/D3MFImporter.cpp

@@ -61,6 +61,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <unzip.h>
 #include <unzip.h>
 #include <assimp/irrXMLWrapper.h>
 #include <assimp/irrXMLWrapper.h>
 #include "3MFXmlTags.h"
 #include "3MFXmlTags.h"
+#include <assimp/fast_atof.h>
+
+#include <iomanip>
 
 
 namespace Assimp {
 namespace Assimp {
 namespace D3MF {
 namespace D3MF {
@@ -68,7 +71,9 @@ namespace D3MF {
 class XmlSerializer {
 class XmlSerializer {
 public:
 public:
     XmlSerializer(XmlReader* xmlReader)
     XmlSerializer(XmlReader* xmlReader)
-    : xmlReader(xmlReader) {
+    : mMeshes()
+    , mMaterials() 
+    , xmlReader(xmlReader){
 		// empty
 		// empty
     }
     }
 
 
@@ -77,14 +82,21 @@ public:
     }
     }
 
 
     void ImportXml(aiScene* scene) {
     void ImportXml(aiScene* scene) {
+        if ( nullptr == scene ) {
+            return;
+        }
+
         scene->mRootNode = new aiNode();
         scene->mRootNode = new aiNode();
         std::vector<aiNode*> children;
         std::vector<aiNode*> children;
 
 
         while(ReadToEndElement(D3MF::XmlTag::model)) {
         while(ReadToEndElement(D3MF::XmlTag::model)) {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::object) {
+            const std::string nodeName( xmlReader->getNodeName() );
+            if( nodeName == D3MF::XmlTag::object) {
                 children.push_back(ReadObject(scene));
                 children.push_back(ReadObject(scene));
-            } else if(xmlReader->getNodeName() == D3MF::XmlTag::build) {
-
+            } else if( nodeName == D3MF::XmlTag::build) {
+                // 
+            } else if ( nodeName == D3MF::XmlTag::basematerials ) {
+                ReadBaseMaterials();
             }
             }
         }
         }
 
 
@@ -92,11 +104,16 @@ public:
             scene->mRootNode->mName.Set( "3MF" );
             scene->mRootNode->mName.Set( "3MF" );
         }
         }
 
 
-        scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
+        scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
 
 
-        std::copy(meshes.begin(), meshes.end(), scene->mMeshes);
+        std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
 
 
+        scene->mNumMaterials = mMaterials.size();
+        if ( 0 != scene->mNumMaterials ) {
+            scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
+            std::copy( mMaterials.begin(), mMaterials.end(), scene->mMaterials );
+        }
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
 
 
@@ -104,8 +121,7 @@ public:
     }
     }
 
 
 private:
 private:
-    aiNode* ReadObject(aiScene* scene)
-    {
+    aiNode* ReadObject(aiScene* scene) {
         std::unique_ptr<aiNode> node(new aiNode());
         std::unique_ptr<aiNode> node(new aiNode());
 
 
         std::vector<unsigned long> meshIds;
         std::vector<unsigned long> meshIds;
@@ -124,19 +140,16 @@ private:
         node->mParent = scene->mRootNode;
         node->mParent = scene->mRootNode;
         node->mName.Set(name);
         node->mName.Set(name);
 
 
-        size_t meshIdx = meshes.size();
+        size_t meshIdx = mMeshes.size();
 
 
-        while(ReadToEndElement(D3MF::XmlTag::object))
-        {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::mesh)
-            {
+        while(ReadToEndElement(D3MF::XmlTag::object)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
                 auto mesh = ReadMesh();
                 auto mesh = ReadMesh();
 
 
                 mesh->mName.Set(name);
                 mesh->mName.Set(name);
-                meshes.push_back(mesh);
+                mMeshes.push_back(mesh);
                 meshIds.push_back(static_cast<unsigned long>(meshIdx));
                 meshIds.push_back(static_cast<unsigned long>(meshIdx));
-                meshIdx++;
-
+                ++meshIdx;
             }
             }
         }
         }
 
 
@@ -147,19 +160,14 @@ private:
         std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
         std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
 
 
         return node.release();
         return node.release();
-
     }
     }
 
 
     aiMesh* ReadMesh() {
     aiMesh* ReadMesh() {
         aiMesh* mesh = new aiMesh();
         aiMesh* mesh = new aiMesh();
-        while(ReadToEndElement(D3MF::XmlTag::mesh))
-        {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
-            {
+        while(ReadToEndElement(D3MF::XmlTag::mesh)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
                 ImportVertices(mesh);
                 ImportVertices(mesh);
-            }
-            else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles)
-            {
+            } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
                 ImportTriangles(mesh);
                 ImportTriangles(mesh);
             }
             }
         }
         }
@@ -167,14 +175,11 @@ private:
         return mesh;
         return mesh;
     }
     }
 
 
-    void ImportVertices(aiMesh* mesh)
-    {
+    void ImportVertices(aiMesh* mesh) {
         std::vector<aiVector3D> vertices;
         std::vector<aiVector3D> vertices;
 
 
-        while(ReadToEndElement(D3MF::XmlTag::vertices))
-        {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::vertex)
-            {
+        while(ReadToEndElement(D3MF::XmlTag::vertices)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
                 vertices.push_back(ReadVertex());
                 vertices.push_back(ReadVertex());
             }
             }
         }
         }
@@ -182,11 +187,9 @@ private:
         mesh->mVertices = new aiVector3D[mesh->mNumVertices];
         mesh->mVertices = new aiVector3D[mesh->mNumVertices];
 
 
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
-
     }
     }
 
 
-    aiVector3D ReadVertex()
-    {
+    aiVector3D ReadVertex() {
         aiVector3D vertex;
         aiVector3D vertex;
 
 
         vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
         vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
@@ -196,16 +199,18 @@ private:
         return vertex;
         return vertex;
     }
     }
 
 
-    void ImportTriangles(aiMesh* mesh)
-    {
+    void ImportTriangles(aiMesh* mesh) {
          std::vector<aiFace> faces;
          std::vector<aiFace> faces;
 
 
-
-         while(ReadToEndElement(D3MF::XmlTag::triangles))
-         {
-             if(xmlReader->getNodeName() == D3MF::XmlTag::triangle)
-             {
+         while(ReadToEndElement(D3MF::XmlTag::triangles)) {
+             const std::string nodeName( xmlReader->getNodeName() );
+             if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
                  faces.push_back(ReadTriangle());
                  faces.push_back(ReadTriangle());
+                 const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
+                 if ( nullptr != pidToken ) {
+                     int matIdx( std::atoi( pidToken ) );
+                     mesh->mMaterialIndex = matIdx;
+                 }
              }
              }
          }
          }
 
 
@@ -216,8 +221,7 @@ private:
         std::copy(faces.begin(), faces.end(), mesh->mFaces);
         std::copy(faces.begin(), faces.end(), mesh->mFaces);
     }
     }
 
 
-    aiFace ReadTriangle()
-    {
+    aiFace ReadTriangle() {
         aiFace face;
         aiFace face;
 
 
         face.mNumIndices = 3;
         face.mNumIndices = 3;
@@ -229,45 +233,113 @@ private:
         return face;
         return face;
     }
     }
 
 
+    void ReadBaseMaterials() {
+        while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
+            mMaterials.push_back( readMaterialDef() );
+            xmlReader->read();
+        }
+    }
+
+    bool parseColor( const char *color, aiColor4D &diffuse ) {
+        if ( nullptr == color ) {
+            return false;
+        }
+
+        const size_t len( strlen( color ) );
+        if ( 9 != len ) {
+            return false;
+        }
+
+        const char *buf( color );
+        if ( '#' != *buf ) {
+            return false;
+        }
+        ++buf;
+        char comp[ 3 ] = { 0,0,'\0' };
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) );
+
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
+
+        return true;
+    }
+
+    aiMaterial *readMaterialDef() {
+        aiMaterial *mat( nullptr );
+        const char *name( nullptr );
+        const char *color( nullptr );
+        const std::string nodeName( xmlReader->getNodeName() );
+        if ( nodeName == D3MF::XmlTag::basematerials_base ) {
+            name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
+
+            aiString matName;
+            matName.Set( name );
+            mat = new aiMaterial;
+            mat->AddProperty( &matName, AI_MATKEY_NAME );
+
+            color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
+            aiColor4D diffuse;
+            if ( parseColor( color, diffuse ) ) {
+                mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
+            }
+        }
+
+        return mat;
+    }
+
 private:
 private:
-    bool ReadToStartElement(const std::string& startTag)
-    {
-        while(xmlReader->read())
-        {
-            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag)
-            {
+    bool ReadToStartElement(const std::string& startTag) {
+        while(xmlReader->read()) {
+            const std::string &nodeName( xmlReader->getNodeName() );
+            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
                 return true;
                 return true;
-            }
-            else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END &&
-                     xmlReader->getNodeName() == startTag)
-            {
+            } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
                 return false;
                 return false;
             }
             }
         }
         }
-        //DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
+
         return false;
         return false;
     }
     }
 
 
-    bool ReadToEndElement(const std::string& closeTag)
-    {
-        while(xmlReader->read())
-        {
+    bool ReadToEndElement(const std::string& closeTag) {
+        while(xmlReader->read()) {
+            const std::string &nodeName( xmlReader->getNodeName() );
             if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
             if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
                 return true;
                 return true;
-            }
-            else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END
-                     && xmlReader->getNodeName() == closeTag)
-            {
+            } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
                 return false;
                 return false;
             }
             }
         }
         }
         DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
         DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
+
         return false;
         return false;
     }
     }
 
 
 
 
 private:
 private:
-    std::vector<aiMesh*> meshes;
+    std::vector<aiMesh*> mMeshes;
+    std::vector<aiMaterial*> mMaterials;
     XmlReader* xmlReader;
     XmlReader* xmlReader;
 };
 };
 
 

+ 80 - 13
code/FBXConverter.cpp

@@ -142,6 +142,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
     nodes.reserve( conns.size() );
     nodes.reserve( conns.size() );
 
 
     std::vector<aiNode*> nodes_chain;
     std::vector<aiNode*> nodes_chain;
+    std::vector<aiNode*> post_nodes_chain;
 
 
     try {
     try {
         for( const Connection* con : conns ) {
         for( const Connection* con : conns ) {
@@ -161,6 +162,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
 
 
             if ( model ) {
             if ( model ) {
                 nodes_chain.clear();
                 nodes_chain.clear();
+                post_nodes_chain.clear();
 
 
                 aiMatrix4x4 new_abs_transform = parent_transform;
                 aiMatrix4x4 new_abs_transform = parent_transform;
 
 
@@ -168,7 +170,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
                 // assimp (or rather: the complicated transformation chain that
                 // assimp (or rather: the complicated transformation chain that
                 // is employed by fbx) means that we may need multiple aiNode's
                 // is employed by fbx) means that we may need multiple aiNode's
                 // to represent a fbx node's transformation.
                 // to represent a fbx node's transformation.
-                GenerateTransformationNodeChain( *model, nodes_chain );
+                GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain );
 
 
                 ai_assert( nodes_chain.size() );
                 ai_assert( nodes_chain.size() );
 
 
@@ -213,8 +215,25 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
                 // attach geometry
                 // attach geometry
                 ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
                 ConvertModel( *model, *nodes_chain.back(), new_abs_transform );
 
 
+                // now link the geometric transform inverse nodes,
+                // before we attach any child nodes
+                for( aiNode* postnode : post_nodes_chain ) {
+                    ai_assert( postnode );
+
+                    if ( last_parent != &parent ) {
+                        last_parent->mNumChildren = 1;
+                        last_parent->mChildren = new aiNode*[ 1 ];
+                        last_parent->mChildren[ 0 ] = postnode;
+                    }
+
+                    postnode->mParent = last_parent;
+                    last_parent = postnode;
+
+                    new_abs_transform *= postnode->mTransformation;
+                }
+
                 // attach sub-nodes
                 // attach sub-nodes
-                ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform );
+                ConvertNodes( model->ID(), *last_parent, new_abs_transform );
 
 
                 if ( doc.Settings().readLights ) {
                 if ( doc.Settings().readLights ) {
                     ConvertLights( *model );
                     ConvertLights( *model );
@@ -396,6 +415,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
         return "GeometricRotation";
         return "GeometricRotation";
     case TransformationComp_GeometricTranslation:
     case TransformationComp_GeometricTranslation:
         return "GeometricTranslation";
         return "GeometricTranslation";
+    case TransformationComp_GeometricScalingInverse:
+        return "GeometricScalingInverse";
+    case TransformationComp_GeometricRotationInverse:
+        return "GeometricRotationInverse";
+    case TransformationComp_GeometricTranslationInverse:
+        return "GeometricTranslationInverse";
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
     default:
     default:
         break;
         break;
@@ -437,6 +462,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp )
         return "GeometricRotation";
         return "GeometricRotation";
     case TransformationComp_GeometricTranslation:
     case TransformationComp_GeometricTranslation:
         return "GeometricTranslation";
         return "GeometricTranslation";
+    case TransformationComp_GeometricScalingInverse:
+        return "GeometricScalingInverse";
+    case TransformationComp_GeometricRotationInverse:
+        return "GeometricRotationInverse";
+    case TransformationComp_GeometricTranslationInverse:
+        return "GeometricTranslationInverse";
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
     case TransformationComp_MAXIMUM: // this is to silence compiler warnings
         break;
         break;
     }
     }
@@ -548,17 +579,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
     bool ok;
     bool ok;
 
 
     const float zero_epsilon = 1e-6f;
     const float zero_epsilon = 1e-6f;
+    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
     for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
         const TransformationComp comp = static_cast< TransformationComp >( i );
         const TransformationComp comp = static_cast< TransformationComp >( i );
 
 
-        if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
-                comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
+        if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) {
             continue;
             continue;
         }
         }
 
 
+        bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
+
         const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
         const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
-        if ( ok && v.SquareLength() > zero_epsilon ) {
-            return true;
+        if ( ok && scale_compare ) {
+            if ( (v - all_ones).SquareLength() > zero_epsilon ) {
+                return true;
+            }
+        } else if ( ok ) {
+            if ( v.SquareLength() > zero_epsilon ) {
+                return true;
+            }
         }
         }
     }
     }
 
 
@@ -570,7 +609,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
     return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
     return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
 }
 }
 
 
-void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes )
+void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
 {
 {
     const PropertyTable& props = model.Props();
     const PropertyTable& props = model.Props();
     const Model::RotOrder rot = model.RotationOrder();
     const Model::RotOrder rot = model.RotationOrder();
@@ -582,6 +621,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
 
 
     // generate transformation matrices for all the different transformation components
     // generate transformation matrices for all the different transformation components
     const float zero_epsilon = 1e-6f;
     const float zero_epsilon = 1e-6f;
+    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     bool is_complex = false;
     bool is_complex = false;
 
 
     const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
     const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
@@ -634,7 +674,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
     }
     }
 
 
     const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
     const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
-    if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) {
+    if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
         aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
         aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
     }
     }
 
 
@@ -644,18 +684,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
     }
     }
 
 
     const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
     const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
-    if ( ok && std::fabs( GeometricScaling.SquareLength() - 1.0f ) > zero_epsilon ) {
+    if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) {
+        is_complex = true;
         aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
         aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
+        aiVector3D GeometricScalingInverse = GeometricScaling;
+        bool canscale = true;
+        for (size_t i = 0; i < 3; ++i) {
+            if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
+                GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
+            } else {
+                FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" );
+                canscale = false;
+                break;
+            }
+        }
+        if (canscale) {
+            aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] );
+        }
     }
     }
 
 
     const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
     const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
     if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
     if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
+        is_complex = true;
         GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
         GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
+        GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
+        chain[ TransformationComp_GeometricRotationInverse ].Inverse();
     }
     }
 
 
     const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
     const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
     if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
     if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
+        is_complex = true;
         aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
         aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
+        aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
     }
     }
 
 
     // is_complex needs to be consistent with NeedsComplexTransformationChain()
     // is_complex needs to be consistent with NeedsComplexTransformationChain()
@@ -690,10 +750,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
             }
             }
 
 
             aiNode* nd = new aiNode();
             aiNode* nd = new aiNode();
-            output_nodes.push_back( nd );
-
             nd->mName.Set( NameTransformationChainNode( name, comp ) );
             nd->mName.Set( NameTransformationChainNode( name, comp ) );
             nd->mTransformation = chain[ i ];
             nd->mTransformation = chain[ i ];
+
+            // geometric inverses go in a post-node chain
+            if ( comp == TransformationComp_GeometricScalingInverse ||
+                 comp == TransformationComp_GeometricRotationInverse ||
+                 comp == TransformationComp_GeometricTranslationInverse
+            ) {
+                post_output_nodes.push_back( nd );
+            } else {
+                output_nodes.push_back( nd );
+            }
         }
         }
 
 
         ai_assert( output_nodes.size() );
         ai_assert( output_nodes.size() );
@@ -2209,8 +2277,7 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
 
 
             has_any = true;
             has_any = true;
 
 
-            if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation &&
-                comp != TransformationComp_GeometricScaling && comp != TransformationComp_GeometricRotation && comp != TransformationComp_GeometricTranslation )
+            if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation )
             {
             {
                 has_complex = true;
                 has_complex = true;
             }
             }

+ 5 - 2
code/FBXConverter.h

@@ -82,7 +82,10 @@ public:
     *  The different parts that make up the final local transformation of a fbx-node
     *  The different parts that make up the final local transformation of a fbx-node
     */
     */
     enum TransformationComp {
     enum TransformationComp {
-        TransformationComp_Translation = 0,
+        TransformationComp_GeometricScalingInverse = 0,
+        TransformationComp_GeometricRotationInverse,
+        TransformationComp_GeometricTranslationInverse,
+        TransformationComp_Translation,
         TransformationComp_RotationOffset,
         TransformationComp_RotationOffset,
         TransformationComp_RotationPivot,
         TransformationComp_RotationPivot,
         TransformationComp_PreRotation,
         TransformationComp_PreRotation,
@@ -153,7 +156,7 @@ private:
     /**
     /**
     *  note: memory for output_nodes will be managed by the caller
     *  note: memory for output_nodes will be managed by the caller
     */
     */
-    void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes);
+    void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void SetupNodeMetadata(const Model& model, aiNode& nd);
     void SetupNodeMetadata(const Model& model, aiNode& nd);

+ 80 - 84
code/FileSystemFilter.h

@@ -42,13 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  Implements a filter system to filter calls to Exists() and Open()
  *  Implements a filter system to filter calls to Exists() and Open()
  *  in order to improve the success rate of file opening ...
  *  in order to improve the success rate of file opening ...
  */
  */
+#pragma once
 #ifndef AI_FILESYSTEMFILTER_H_INC
 #ifndef AI_FILESYSTEMFILTER_H_INC
 #define AI_FILESYSTEMFILTER_H_INC
 #define AI_FILESYSTEMFILTER_H_INC
 
 
-#include "../include/assimp/IOSystem.hpp"
-#include "../include/assimp/DefaultLogger.hpp"
-#include "../include/assimp/fast_atof.h"
-#include "../include/assimp/ParsingUtils.h"
+#include <assimp/IOSystem.hpp>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/fast_atof.h>
+#include <assimp/ParsingUtils.h>
 
 
 namespace Assimp    {
 namespace Assimp    {
 
 
@@ -64,90 +65,89 @@ class FileSystemFilter : public IOSystem
 public:
 public:
     /** Constructor. */
     /** Constructor. */
     FileSystemFilter(const std::string& file, IOSystem* old)
     FileSystemFilter(const std::string& file, IOSystem* old)
-        : wrapped  (old)
-        , src_file (file)
-        , sep(wrapped->getOsSeparator())
-    {
-        ai_assert(NULL != wrapped);
+    : mWrapped  (old)
+    , mSrc_file(file)
+    , sep(mWrapped->getOsSeparator()) {
+        ai_assert(nullptr != mWrapped);
 
 
         // Determine base directory
         // Determine base directory
-        base = src_file;
+        mBase = mSrc_file;
         std::string::size_type ss2;
         std::string::size_type ss2;
-        if (std::string::npos != (ss2 = base.find_last_of("\\/")))  {
-            base.erase(ss2,base.length()-ss2);
-        }
-        else {
-            base = "";
-        //  return;
+        if (std::string::npos != (ss2 = mBase.find_last_of("\\/")))  {
+            mBase.erase(ss2,mBase.length()-ss2);
+        } else {
+            mBase = "";
         }
         }
 
 
         // make sure the directory is terminated properly
         // make sure the directory is terminated properly
         char s;
         char s;
 
 
-        if (base.length() == 0) {
-            base = ".";
-            base += getOsSeparator();
-        }
-        else if ((s = *(base.end()-1)) != '\\' && s != '/') {
-            base += getOsSeparator();
+        if ( mBase.empty() ) {
+            mBase = ".";
+            mBase += getOsSeparator();
+        } else if ((s = *(mBase.end()-1)) != '\\' && s != '/') {
+            mBase += getOsSeparator();
         }
         }
 
 
-        DefaultLogger::get()->info("Import root directory is \'" + base + "\'");
+        DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'");
     }
     }
 
 
     /** Destructor. */
     /** Destructor. */
-    ~FileSystemFilter()
-    {
-        // haha
+    ~FileSystemFilter() {
+        // empty
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Tests for the existence of a file at the given path. */
     /** Tests for the existence of a file at the given path. */
-    bool Exists( const char* pFile) const
-    {
+    bool Exists( const char* pFile) const {
+        ai_assert( nullptr != mWrapped );
+        
         std::string tmp = pFile;
         std::string tmp = pFile;
 
 
         // Currently this IOSystem is also used to open THE ONE FILE.
         // Currently this IOSystem is also used to open THE ONE FILE.
-        if (tmp != src_file)    {
+        if (tmp != mSrc_file)    {
             BuildPath(tmp);
             BuildPath(tmp);
             Cleanup(tmp);
             Cleanup(tmp);
         }
         }
 
 
-        return wrapped->Exists(tmp);
+        return mWrapped->Exists(tmp);
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Returns the directory separator. */
     /** Returns the directory separator. */
-    char getOsSeparator() const
-    {
+    char getOsSeparator() const {
         return sep;
         return sep;
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Open a new file with a given path. */
     /** Open a new file with a given path. */
-    IOStream* Open( const char* pFile, const char* pMode = "rb")
-    {
-        ai_assert(pFile);
-        ai_assert(pMode);
+    IOStream* Open( const char* pFile, const char* pMode = "rb") {
+        ai_assert( nullptr != mWrapped );
+        if ( nullptr == pFile || nullptr == pMode ) {
+            return nullptr;
+        }
+        
+        ai_assert( nullptr != pFile );
+        ai_assert( nullptr != pMode );
 
 
         // First try the unchanged path
         // First try the unchanged path
-        IOStream* s = wrapped->Open(pFile,pMode);
+        IOStream* s = mWrapped->Open(pFile,pMode);
 
 
-        if (!s) {
+        if (nullptr == s) {
             std::string tmp = pFile;
             std::string tmp = pFile;
 
 
             // Try to convert between absolute and relative paths
             // Try to convert between absolute and relative paths
             BuildPath(tmp);
             BuildPath(tmp);
-            s = wrapped->Open(tmp,pMode);
+            s = mWrapped->Open(tmp,pMode);
 
 
-            if (!s) {
+            if (nullptr == s) {
                 // Finally, look for typical issues with paths
                 // Finally, look for typical issues with paths
                 // and try to correct them. This is our last
                 // and try to correct them. This is our last
                 // resort.
                 // resort.
                 tmp = pFile;
                 tmp = pFile;
                 Cleanup(tmp);
                 Cleanup(tmp);
                 BuildPath(tmp);
                 BuildPath(tmp);
-                s = wrapped->Open(tmp,pMode);
+                s = mWrapped->Open(tmp,pMode);
             }
             }
         }
         }
 
 
@@ -156,76 +156,75 @@ public:
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Closes the given file and releases all resources associated with it. */
     /** Closes the given file and releases all resources associated with it. */
-    void Close( IOStream* pFile)
-    {
-        return wrapped->Close(pFile);
+    void Close( IOStream* pFile) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->Close(pFile);
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Compare two paths */
     /** Compare two paths */
-    bool ComparePaths (const char* one, const char* second) const
-    {
-        return wrapped->ComparePaths (one,second);
+    bool ComparePaths (const char* one, const char* second) const {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->ComparePaths (one,second);
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Pushes a new directory onto the directory stack. */
     /** Pushes a new directory onto the directory stack. */
-    bool PushDirectory(const std::string &path)
-    {
-        return wrapped->PushDirectory(path);
+    bool PushDirectory(const std::string &path ) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->PushDirectory(path);
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Returns the top directory from the stack. */
     /** Returns the top directory from the stack. */
-    const std::string &CurrentDirectory() const
-    {
-        return wrapped->CurrentDirectory();
+    const std::string &CurrentDirectory() const {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->CurrentDirectory();
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Returns the number of directories stored on the stack. */
     /** Returns the number of directories stored on the stack. */
-    size_t StackSize() const
-    {
-        return wrapped->StackSize();
+    size_t StackSize() const {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->StackSize();
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Pops the top directory from the stack. */
     /** Pops the top directory from the stack. */
-    bool PopDirectory()
-    {
-        return wrapped->PopDirectory();
+    bool PopDirectory() {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->PopDirectory();
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Creates an new directory at the given path. */
     /** Creates an new directory at the given path. */
-    bool CreateDirectory(const std::string &path)
-    {
-        return wrapped->CreateDirectory(path);
+    bool CreateDirectory(const std::string &path) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->CreateDirectory(path);
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Will change the current directory to the given path. */
     /** Will change the current directory to the given path. */
-    bool ChangeDirectory(const std::string &path)
-    {
-        return wrapped->ChangeDirectory(path);
+    bool ChangeDirectory(const std::string &path) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->ChangeDirectory(path);
     }
     }
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Delete file. */
     /** Delete file. */
-    bool DeleteFile(const std::string &file)
-    {
-        return wrapped->DeleteFile(file);
+    bool DeleteFile(const std::string &file) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->DeleteFile(file);
     }
     }
 
 
 private:
 private:
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Build a valid path from a given relative or absolute path.
     /** Build a valid path from a given relative or absolute path.
      */
      */
-    void BuildPath (std::string& in) const
-    {
+    void BuildPath (std::string& in) const {
+        ai_assert( nullptr != mWrapped );
         // if we can already access the file, great.
         // if we can already access the file, great.
-        if (in.length() < 3 || wrapped->Exists(in)) {
+        if (in.length() < 3 || mWrapped->Exists(in)) {
             return;
             return;
         }
         }
 
 
@@ -233,8 +232,8 @@ private:
         if (in[1] != ':') {
         if (in[1] != ':') {
 
 
             // append base path and try
             // append base path and try
-            const std::string tmp = base + in;
-            if (wrapped->Exists(tmp)) {
+            const std::string tmp = mBase + in;
+            if (mWrapped->Exists(tmp)) {
                 in = tmp;
                 in = tmp;
                 return;
                 return;
             }
             }
@@ -256,7 +255,7 @@ private:
             std::string::size_type last_dirsep = std::string::npos;
             std::string::size_type last_dirsep = std::string::npos;
 
 
             while(true) {
             while(true) {
-                tmp = base;
+                tmp = mBase;
                 tmp += sep;
                 tmp += sep;
 
 
                 std::string::size_type dirsep = in.rfind('/', last_dirsep);
                 std::string::size_type dirsep = in.rfind('/', last_dirsep);
@@ -272,7 +271,7 @@ private:
                 last_dirsep = dirsep-1;
                 last_dirsep = dirsep-1;
 
 
                 tmp += in.substr(dirsep+1, in.length()-pos);
                 tmp += in.substr(dirsep+1, in.length()-pos);
-                if (wrapped->Exists(tmp)) {
+                if (mWrapped->Exists(tmp)) {
                     in = tmp;
                     in = tmp;
                     return;
                     return;
                 }
                 }
@@ -285,15 +284,14 @@ private:
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Cleanup the given path
     /** Cleanup the given path
      */
      */
-    void Cleanup (std::string& in) const
-    {
-        char last = 0;
+    void Cleanup (std::string& in) const {
         if(in.empty()) {
         if(in.empty()) {
             return;
             return;
         }
         }
 
 
         // Remove a very common issue when we're parsing file names: spaces at the
         // Remove a very common issue when we're parsing file names: spaces at the
         // beginning of the path.
         // beginning of the path.
+        char last = 0;
         std::string::iterator it = in.begin();
         std::string::iterator it = in.begin();
         while (IsSpaceOrNewLine( *it ))++it;
         while (IsSpaceOrNewLine( *it ))++it;
         if (it != in.begin()) {
         if (it != in.begin()) {
@@ -323,9 +321,7 @@ private:
                     it = in.erase(it);
                     it = in.erase(it);
                     --it;
                     --it;
                 }
                 }
-            }
-            else if (*it == '%' && in.end() - it > 2) {
-
+            } else if (*it == '%' && in.end() - it > 2) {
                 // Hex sequence in URIs
                 // Hex sequence in URIs
                 if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
                 if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
                     *it = HexOctetToDecimal(&*it);
                     *it = HexOctetToDecimal(&*it);
@@ -339,8 +335,8 @@ private:
     }
     }
 
 
 private:
 private:
-    IOSystem* wrapped;
-    std::string src_file, base;
+    IOSystem *mWrapped;
+    std::string mSrc_file, mBase;
     char sep;
     char sep;
 };
 };
 
 

+ 14 - 13
include/assimp/ParsingUtils.h

@@ -66,49 +66,50 @@ static const unsigned int BufferSize = 4096;
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE char_t ToLower( char_t in)
-{
+AI_FORCE_INLINE
+char_t ToLower( char_t in ) {
     return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in;
     return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in;
 }
 }
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE char_t ToUpper( char_t in) {
+AI_FORCE_INLINE
+char_t ToUpper( char_t in) {
     return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in;
     return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in;
 }
 }
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE bool IsUpper( char_t in)
-{
+AI_FORCE_INLINE
+bool IsUpper( char_t in) {
     return (in >= (char_t)'A' && in <= (char_t)'Z');
     return (in >= (char_t)'A' && in <= (char_t)'Z');
 }
 }
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE bool IsLower( char_t in)
-{
+AI_FORCE_INLINE
+bool IsLower( char_t in) {
     return (in >= (char_t)'a' && in <= (char_t)'z');
     return (in >= (char_t)'a' && in <= (char_t)'z');
 }
 }
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE bool IsSpace( char_t in)
-{
+AI_FORCE_INLINE
+bool IsSpace( char_t in) {
     return (in == (char_t)' ' || in == (char_t)'\t');
     return (in == (char_t)' ' || in == (char_t)'\t');
 }
 }
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE bool IsLineEnd( char_t in)
-{
+AI_FORCE_INLINE
+bool IsLineEnd( char_t in) {
     return (in==(char_t)'\r'||in==(char_t)'\n'||in==(char_t)'\0'||in==(char_t)'\f');
     return (in==(char_t)'\r'||in==(char_t)'\n'||in==(char_t)'\0'||in==(char_t)'\f');
 }
 }
 
 
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-AI_FORCE_INLINE bool IsSpaceOrNewLine( char_t in)
-{
+AI_FORCE_INLINE
+bool IsSpaceOrNewLine( char_t in) {
     return IsSpace<char_t>(in) || IsLineEnd<char_t>(in);
     return IsSpace<char_t>(in) || IsLineEnd<char_t>(in);
 }
 }
 
 

+ 18 - 20
include/assimp/fast_atof.h

@@ -14,8 +14,8 @@
 // ------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------
 
 
 
 
-#ifndef __FAST_A_TO_F_H_INCLUDED__
-#define __FAST_A_TO_F_H_INCLUDED__
+#ifndef FAST_A_TO_F_H_INCLUDED
+#define FAST_A_TO_F_H_INCLUDED
 
 
 #include <cmath>
 #include <cmath>
 #include <limits>
 #include <limits>
@@ -26,15 +26,13 @@
 #include "StringComparison.h"
 #include "StringComparison.h"
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/DefaultLogger.hpp>
 
 
-
 #ifdef _MSC_VER
 #ifdef _MSC_VER
 #  include <stdint.h>
 #  include <stdint.h>
 #else
 #else
 #  include <assimp/Compiler/pstdint.h>
 #  include <assimp/Compiler/pstdint.h>
 #endif
 #endif
 
 
-namespace Assimp
-{
+namespace Assimp {
 
 
 const double fast_atof_table[16] =  {  // we write [16] here instead of [] to work around a swig bug
 const double fast_atof_table[16] =  {  // we write [16] here instead of [] to work around a swig bug
     0.0,
     0.0,
@@ -64,8 +62,9 @@ unsigned int strtoul10( const char* in, const char** out=0) {
     unsigned int value = 0;
     unsigned int value = 0;
 
 
     for ( ;; ) {
     for ( ;; ) {
-        if ( *in < '0' || *in > '9' )
+        if ( *in < '0' || *in > '9' ) {
             break;
             break;
+        }
 
 
         value = ( value * 10 ) + ( *in - '0' );
         value = ( value * 10 ) + ( *in - '0' );
         ++in;
         ++in;
@@ -109,8 +108,7 @@ unsigned int strtoul16( const char* in, const char** out=0) {
             value = ( value << 4u ) + ( *in - 'A' ) + 10;
             value = ( value << 4u ) + ( *in - 'A' ) + 10;
         } else if (*in >= 'a' && *in <= 'f') {
         } else if (*in >= 'a' && *in <= 'f') {
             value = ( value << 4u ) + ( *in - 'a' ) + 10;
             value = ( value << 4u ) + ( *in - 'a' ) + 10;
-        }
-        else {
+        } else {
             break;
             break;
         }
         }
         ++in;
         ++in;
@@ -205,7 +203,6 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
             DefaultLogger::get()->warn( std::string( "Converting the string \"" ) + in + "\" into a value resulted in overflow." );
             DefaultLogger::get()->warn( std::string( "Converting the string \"" ) + in + "\" into a value resulted in overflow." );
             return 0;
             return 0;
         }
         }
-            //throw std::overflow_error();
 
 
         value = new_value;
         value = new_value;
 
 
@@ -213,21 +210,23 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
         ++cur;
         ++cur;
 
 
         if (max_inout && *max_inout == cur) {
         if (max_inout && *max_inout == cur) {
-
             if (out) { /* skip to end */
             if (out) { /* skip to end */
-                while (*in >= '0' && *in <= '9')
+                while ( *in >= '0' && *in <= '9' ) {
                     ++in;
                     ++in;
+                }
                 *out = in;
                 *out = in;
             }
             }
 
 
             return value;
             return value;
         }
         }
     }
     }
-    if (out)
+    if ( out ) {
         *out = in;
         *out = in;
+    }
 
 
-    if (max_inout)
+    if ( max_inout ) {
         *max_inout = cur;
         *max_inout = cur;
+    }
 
 
     return value;
     return value;
 }
 }
@@ -238,7 +237,7 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
 inline
 inline
 int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0) {
 int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inout = 0) {
     bool inv = (*in == '-');
     bool inv = (*in == '-');
-    if (inv || *in == '+') {
+    if ( inv || *in == '+' ) {
         ++in;
         ++in;
     }
     }
 
 
@@ -249,7 +248,6 @@ int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inou
     return value;
     return value;
 }
 }
 
 
-
 // Number of relevant decimals for floating-point parsing.
 // Number of relevant decimals for floating-point parsing.
 #define AI_FAST_ATOF_RELAVANT_DECIMALS 15
 #define AI_FAST_ATOF_RELAVANT_DECIMALS 15
 
 
@@ -258,7 +256,7 @@ int64_t strtol10_64(const char* in, const char** out = 0, unsigned int* max_inou
 //! about 6 times faster than atof in win32.
 //! about 6 times faster than atof in win32.
 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
 // ------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------
-template <typename Real>
+template<typename Real>
 inline
 inline
 const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) {
 const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true) {
     Real f = 0;
     Real f = 0;
@@ -284,10 +282,10 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
             c += 5;
             c += 5;
         }
         }
         return c;
         return c;
-    }
+     }
 
 
     if (!(c[0] >= '0' && c[0] <= '9') &&
     if (!(c[0] >= '0' && c[0] <= '9') &&
-        !((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) {
+            !((c[0] == '.' || (check_comma && c[0] == ',')) && c[1] >= '0' && c[1] <= '9')) {
         throw std::invalid_argument("Cannot parse string "
         throw std::invalid_argument("Cannot parse string "
                                     "as real number: does not start with digit "
                                     "as real number: does not start with digit "
                                     "or decimal point followed by digit.");
                                     "or decimal point followed by digit.");
@@ -322,7 +320,6 @@ const char* fast_atoreal_move(const char* c, Real& out, bool check_comma = true)
     // A major 'E' must be allowed. Necessary for proper reading of some DXF files.
     // A major 'E' must be allowed. Necessary for proper reading of some DXF files.
     // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
     // Thanks to Zhao Lei to point out that this if() must be outside the if (*c == '.' ..)
     if (*c == 'e' || *c == 'E') {
     if (*c == 'e' || *c == 'E') {
-
         ++c;
         ++c;
         const bool einv = (*c=='-');
         const bool einv = (*c=='-');
         if (einv || *c=='+') {
         if (einv || *c=='+') {
@@ -352,6 +349,7 @@ inline
 ai_real fast_atof(const char* c) {
 ai_real fast_atof(const char* c) {
     ai_real ret(0.0);
     ai_real ret(0.0);
     fast_atoreal_move<ai_real>(c, ret);
     fast_atoreal_move<ai_real>(c, ret);
+
     return ret;
     return ret;
 }
 }
 
 
@@ -374,4 +372,4 @@ ai_real fast_atof( const char** inout) {
 
 
 } //! namespace Assimp
 } //! namespace Assimp
 
 
-#endif // __FAST_A_TO_F_H_INCLUDED__
+#endif // FAST_A_TO_F_H_INCLUDED

+ 42 - 7
tools/assimp_cmd/Info.cpp

@@ -47,9 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Main.h"
 #include "Main.h"
 
 
 const char* AICMD_MSG_INFO_HELP_E =
 const char* AICMD_MSG_INFO_HELP_E =
-"assimp info <file> [-r]\n"
+"assimp info <file> [-r] [-v]\n"
 "\tPrint basic structure of a 3D model\n"
 "\tPrint basic structure of a 3D model\n"
-"\t-r,--raw: No postprocessing, do a raw import\n";
+"\t-r,--raw: No postprocessing, do a raw import\n"
+"\t-v,--verbose: Print verbose info such as node transform data\n";
 
 
 
 
 // -----------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------
@@ -184,7 +185,7 @@ std::string FindPTypes(const aiScene* scene)
 
 
 // -----------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------
 void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline,
 void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxline,
-					unsigned int cline, unsigned int cnest=0)
+					unsigned int cline, bool verbose, unsigned int cnest=0)
 {
 {
 	if (cline++ >= maxline || cnest >= maxnest) {
 	if (cline++ >= maxline || cnest >= maxnest) {
 		return;
 		return;
@@ -194,8 +195,29 @@ void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxli
 		printf("-- ");
 		printf("-- ");
 	}
 	}
 	printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes);
 	printf("\'%s\', meshes: %u\n",root->mName.data,root->mNumMeshes);
+
+	if (verbose) {
+		// print the actual transform
+		//printf(",");
+		aiVector3D s, r, t;
+		root->mTransformation.Decompose(s, r, t);
+		if (s.x != 1.0 || s.y != 1.0 || s.z != 1.0) {
+			for(unsigned int i = 0; i < cnest; ++i) { printf("   "); }
+			printf("      S:[%f %f %f]\n", s.x, s.y, s.z);
+		}
+		if (r.x || r.y || r.z) {
+			for(unsigned int i = 0; i < cnest; ++i) { printf("   "); }
+			printf("      R:[%f %f %f]\n", r.x, r.y, r.z);
+		}
+		if (t.x || t.y || t.z) {
+			for(unsigned int i = 0; i < cnest; ++i) { printf("   "); }
+			printf("      T:[%f %f %f]\n", t.x, t.y, t.z);
+		}
+	}
+	//printf("\n");
+
 	for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
 	for (unsigned int i = 0; i < root->mNumChildren; ++i ) {
-		PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,cnest+1);
+		PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1);
 		if(i == root->mNumChildren-1) {
 		if(i == root->mNumChildren-1) {
 			for(unsigned int i = 0; i < cnest; ++i) {
 			for(unsigned int i = 0; i < cnest; ++i) {
 				printf("   ");
 				printf("   ");
@@ -230,10 +252,23 @@ int Assimp_Info (const char* const* params, unsigned int num)
 
 
 	const std::string in  = std::string(params[0]);
 	const std::string in  = std::string(params[0]);
 
 
+	// get -r and -v arguments
+	bool raw = false;
+	bool verbose = false;
+	for(unsigned int i = 1; i < num; ++i) {
+		if (!strcmp(params[i],"--raw")||!strcmp(params[i],"-r")) {
+			raw = true;
+		}
+		if (!strcmp(params[i],"--verbose")||!strcmp(params[i],"-v")) {
+			verbose = true;
+		}
+	}
+
 	// do maximum post-processing unless -r was specified
 	// do maximum post-processing unless -r was specified
 	ImportData import;
 	ImportData import;
-	import.ppFlags = num>1&&(!strcmp(params[1],"--raw")||!strcmp(params[1],"-r")) ? 0
-		: aiProcessPreset_TargetRealtime_MaxQuality;
+	if (!raw) {
+		import.ppFlags = aiProcessPreset_TargetRealtime_MaxQuality;
+	}
 
 
 	// import the main model
 	// import the main model
 	const aiScene* scene = ImportModel(import,in);
 	const aiScene* scene = ImportModel(import,in);
@@ -346,7 +381,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
 
 
 	printf("\nNode hierarchy:\n");
 	printf("\nNode hierarchy:\n");
 	unsigned int cline=0;
 	unsigned int cline=0;
-	PrintHierarchy(scene->mRootNode,20,1000,cline);
+	PrintHierarchy(scene->mRootNode,20,1000,cline,verbose);
 
 
 	printf("\n");
 	printf("\n");
 	return 0;
 	return 0;