소스 검색

Merge branch 'master' into 3mf_basematerial_support

Kim Kulling 7 년 전
부모
커밋
437ae0c839

+ 1 - 1
code/BlenderDNA.h

@@ -205,7 +205,7 @@ enum ErrorPolicy {
 
 // -------------------------------------------------------------------------------
 /** Represents a data structure in a BLEND file. A Structure defines n fields
- *  and their locatios and encodings the input stream. Usually, every
+ *  and their locations and encodings the input stream. Usually, every
  *  Structure instance pertains to one equally-named data structure in the
  *  BlenderScene.h header. This class defines various utilities to map a
  *  binary `blob` read from the file to such a structure instance with

+ 1 - 1
code/BlenderDNA.inl

@@ -502,7 +502,7 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
 {
     // the file blocks appear in list sorted by
     // with ascending base addresses so we can run a
-    // binary search to locate the pointee quickly.
+    // binary search to locate the pointer quickly.
 
     // NOTE: Blender seems to distinguish between side-by-side
     // data (stored in the same data block) and far pointers,

+ 1 - 1
code/BlenderScene.cpp

@@ -116,7 +116,7 @@ template <> void Structure :: Convert<MTex> (
     ReadField<ErrorPolicy_Igno>(temp,"projy",db);
     dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
     ReadField<ErrorPolicy_Igno>(temp,"projz",db);
-    dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
     ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);

+ 80 - 13
code/FBXConverter.cpp

@@ -142,6 +142,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
     nodes.reserve( conns.size() );
 
     std::vector<aiNode*> nodes_chain;
+    std::vector<aiNode*> post_nodes_chain;
 
     try {
         for( const Connection* con : conns ) {
@@ -161,6 +162,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
 
             if ( model ) {
                 nodes_chain.clear();
+                post_nodes_chain.clear();
 
                 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
                 // is employed by fbx) means that we may need multiple aiNode's
                 // to represent a fbx node's transformation.
-                GenerateTransformationNodeChain( *model, nodes_chain );
+                GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain );
 
                 ai_assert( nodes_chain.size() );
 
@@ -213,8 +215,25 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
                 // attach geometry
                 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
-                ConvertNodes( model->ID(), *nodes_chain.back(), new_abs_transform );
+                ConvertNodes( model->ID(), *last_parent, new_abs_transform );
 
                 if ( doc.Settings().readLights ) {
                     ConvertLights( *model );
@@ -396,6 +415,12 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
         return "GeometricRotation";
     case TransformationComp_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
     default:
         break;
@@ -437,6 +462,12 @@ const char* Converter::NameTransformationCompProperty( TransformationComp comp )
         return "GeometricRotation";
     case TransformationComp_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
         break;
     }
@@ -548,17 +579,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
     bool ok;
 
     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 ) {
         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;
         }
 
+        bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
+
         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 );
 }
 
-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 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
     const float zero_epsilon = 1e-6f;
+    const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     bool is_complex = false;
 
     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 );
-    if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) {
+    if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
         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 );
-    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 ] );
+        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 );
     if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
+        is_complex = true;
         GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
+        GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
+        chain[ TransformationComp_GeometricRotationInverse ].Inverse();
     }
 
     const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
     if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
+        is_complex = true;
         aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
+        aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
     }
 
     // is_complex needs to be consistent with NeedsComplexTransformationChain()
@@ -690,10 +750,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
             }
 
             aiNode* nd = new aiNode();
-            output_nodes.push_back( nd );
-
             nd->mName.Set( NameTransformationChainNode( name, comp ) );
             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() );
@@ -2209,8 +2277,7 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
 
             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;
             }

+ 5 - 2
code/FBXConverter.h

@@ -82,7 +82,10 @@ public:
     *  The different parts that make up the final local transformation of a fbx-node
     */
     enum TransformationComp {
-        TransformationComp_Translation = 0,
+        TransformationComp_GeometricScalingInverse = 0,
+        TransformationComp_GeometricRotationInverse,
+        TransformationComp_GeometricTranslationInverse,
+        TransformationComp_Translation,
         TransformationComp_RotationOffset,
         TransformationComp_RotationPivot,
         TransformationComp_PreRotation,
@@ -153,7 +156,7 @@ private:
     /**
     *  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);

+ 11 - 11
code/FBXMeshGeometry.cpp

@@ -428,16 +428,19 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
     const std::vector<unsigned int>& mapping_offsets,
     const std::vector<unsigned int>& mappings)
 {
+    bool isDirect = ReferenceInformationType == "Direct";
+    bool isIndexToDirect = ReferenceInformationType == "IndexToDirect";
 
+    // fallback to direct data if there is no index data element
+    if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) {
+        isDirect = true;
+        isIndexToDirect = false;
+    }
 
     // handle permutations of Mapping and Reference type - it would be nice to
     // deal with this more elegantly and with less redundancy, but right
     // now it seems unavoidable.
-    if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
-        if ( !HasElement( source, indexDataElementName ) ) {
-            return;
-        }
-
+    if (MappingInformationType == "ByVertice" && isDirect) {
         std::vector<T> tempData;
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 
@@ -450,14 +453,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
             }
         }
     }
-    else if (MappingInformationType == "ByVertice" && ReferenceInformationType == "IndexToDirect") {
+    else if (MappingInformationType == "ByVertice" && isIndexToDirect) {
 		std::vector<T> tempData;
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 
         data_out.resize(vertex_count);
-        if ( !HasElement( source, indexDataElementName ) ) {
-            return;
-        }
 
         std::vector<int> uvIndices;
         ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
@@ -472,7 +472,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
             }
         }
     }
-    else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "Direct") {
+    else if (MappingInformationType == "ByPolygonVertex" && isDirect) {
 		std::vector<T> tempData;
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 
@@ -485,7 +485,7 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
 
 		data_out.swap(tempData);
     }
-    else if (MappingInformationType == "ByPolygonVertex" && ReferenceInformationType == "IndexToDirect") {
+    else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) {
 		std::vector<T> tempData;
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 

+ 108 - 63
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()
  *  in order to improve the success rate of file opening ...
  */
+#pragma once
 #ifndef 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    {
 
@@ -64,90 +65,89 @@ class FileSystemFilter : public IOSystem
 public:
     /** Constructor. */
     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
-        base = src_file;
+        mBase = mSrc_file;
         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
         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. */
-    ~FileSystemFilter()
-    {
-        // haha
+    ~FileSystemFilter() {
+        // empty
     }
 
     // -------------------------------------------------------------------
     /** 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;
 
         // Currently this IOSystem is also used to open THE ONE FILE.
-        if (tmp != src_file)    {
+        if (tmp != mSrc_file)    {
             BuildPath(tmp);
             Cleanup(tmp);
         }
 
-        return wrapped->Exists(tmp);
+        return mWrapped->Exists(tmp);
     }
 
     // -------------------------------------------------------------------
     /** Returns the directory separator. */
-    char getOsSeparator() const
-    {
+    char getOsSeparator() const {
         return sep;
     }
 
     // -------------------------------------------------------------------
     /** 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
-        IOStream* s = wrapped->Open(pFile,pMode);
+        IOStream* s = mWrapped->Open(pFile,pMode);
 
-        if (!s) {
+        if (nullptr == s) {
             std::string tmp = pFile;
 
             // Try to convert between absolute and relative paths
             BuildPath(tmp);
-            s = wrapped->Open(tmp,pMode);
+            s = mWrapped->Open(tmp,pMode);
 
-            if (!s) {
+            if (nullptr == s) {
                 // Finally, look for typical issues with paths
                 // and try to correct them. This is our last
                 // resort.
                 tmp = pFile;
                 Cleanup(tmp);
                 BuildPath(tmp);
-                s = wrapped->Open(tmp,pMode);
+                s = mWrapped->Open(tmp,pMode);
             }
         }
 
@@ -156,27 +156,75 @@ public:
 
     // -------------------------------------------------------------------
     /** 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 */
-    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);
     }
 
-private:
+    // -------------------------------------------------------------------
+    /** Pushes a new directory onto the directory stack. */
+    bool PushDirectory(const std::string &path ) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->PushDirectory(path);
+    }
+
+    // -------------------------------------------------------------------
+    /** Returns the top directory from the stack. */
+    const std::string &CurrentDirectory() const {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->CurrentDirectory();
+    }
+
+    // -------------------------------------------------------------------
+    /** Returns the number of directories stored on the stack. */
+    size_t StackSize() const {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->StackSize();
+    }
+
+    // -------------------------------------------------------------------
+    /** Pops the top directory from the stack. */
+    bool PopDirectory() {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->PopDirectory();
+    }
 
+    // -------------------------------------------------------------------
+    /** Creates an new directory at the given path. */
+    bool CreateDirectory(const std::string &path) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->CreateDirectory(path);
+    }
+
+    // -------------------------------------------------------------------
+    /** Will change the current directory to the given path. */
+    bool ChangeDirectory(const std::string &path) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->ChangeDirectory(path);
+    }
+
+    // -------------------------------------------------------------------
+    /** Delete file. */
+    bool DeleteFile(const std::string &file) {
+        ai_assert( nullptr != mWrapped );
+        return mWrapped->DeleteFile(file);
+    }
+
+private:
     // -------------------------------------------------------------------
     /** 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 (in.length() < 3 || wrapped->Exists(in)) {
+        if (in.length() < 3 || mWrapped->Exists(in)) {
             return;
         }
 
@@ -184,8 +232,8 @@ private:
         if (in[1] != ':') {
 
             // 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;
                 return;
             }
@@ -207,7 +255,7 @@ private:
             std::string::size_type last_dirsep = std::string::npos;
 
             while(true) {
-                tmp = base;
+                tmp = mBase;
                 tmp += sep;
 
                 std::string::size_type dirsep = in.rfind('/', last_dirsep);
@@ -223,7 +271,7 @@ private:
                 last_dirsep = dirsep-1;
 
                 tmp += in.substr(dirsep+1, in.length()-pos);
-                if (wrapped->Exists(tmp)) {
+                if (mWrapped->Exists(tmp)) {
                     in = tmp;
                     return;
                 }
@@ -236,15 +284,14 @@ private:
     // -------------------------------------------------------------------
     /** Cleanup the given path
      */
-    void Cleanup (std::string& in) const
-    {
-        char last = 0;
+    void Cleanup (std::string& in) const {
         if(in.empty()) {
             return;
         }
 
         // Remove a very common issue when we're parsing file names: spaces at the
         // beginning of the path.
+        char last = 0;
         std::string::iterator it = in.begin();
         while (IsSpaceOrNewLine( *it ))++it;
         if (it != in.begin()) {
@@ -274,9 +321,7 @@ private:
                     it = in.erase(it);
                     --it;
                 }
-            }
-            else if (*it == '%' && in.end() - it > 2) {
-
+            } else if (*it == '%' && in.end() - it > 2) {
                 // Hex sequence in URIs
                 if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
                     *it = HexOctetToDecimal(&*it);
@@ -290,8 +335,8 @@ private:
     }
 
 private:
-    IOSystem* wrapped;
-    std::string src_file, base;
+    IOSystem *mWrapped;
+    std::string mSrc_file, mBase;
     char sep;
 };
 

+ 7 - 7
code/FindInstancesProcess.h

@@ -60,9 +60,9 @@ namespace Assimp    {
  *  @param in Input mesh
  *  @return Hash.
  */
-inline uint64_t GetMeshHash(aiMesh* in)
-{
-    ai_assert(NULL != in);
+inline
+uint64_t GetMeshHash(aiMesh* in) {
+    ai_assert(nullptr != in);
 
     // ... get an unique value representing the vertex format of the mesh
     const unsigned int fhash = GetMeshVFormatUnique(in);
@@ -78,14 +78,14 @@ inline uint64_t GetMeshHash(aiMesh* in)
 /** @brief Perform a component-wise comparison of two arrays
  *
  *  @param first First array
- *  @param second Second aray
+ *  @param second Second array
  *  @param size Size of both arrays
  *  @param e Epsilon
  *  @return true if the arrays are identical
  */
-inline bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
-    unsigned int size, float e)
-{
+inline
+bool CompareArrays(const aiVector3D* first, const aiVector3D* second,
+        unsigned int size, float e) {
     for (const aiVector3D* end = first+size; first != end; ++first,++second) {
         if ( (*first - *second).SquareLength() >= e)
             return false;

+ 1 - 13
code/Importer.cpp

@@ -190,7 +190,7 @@ Importer::~Importer()
     delete pimpl->mIOHandler;
     delete pimpl->mProgressHandler;
 
-    // Kill imported scene. Destructors should do that recursivly
+    // Kill imported scene. Destructor's should do that recursively
     delete pimpl->mScene;
 
     // Delete shared post-processing data
@@ -200,18 +200,6 @@ Importer::~Importer()
     delete pimpl;
 }
 
-// ------------------------------------------------------------------------------------------------
-// Copy constructor - copies the config of another Importer, not the scene
-Importer::Importer(const Importer &other)
-	: pimpl(NULL) {
-    new(this) Importer();
-
-    pimpl->mIntProperties    = other.pimpl->mIntProperties;
-    pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
-    pimpl->mStringProperties = other.pimpl->mStringProperties;
-    pimpl->mMatrixProperties = other.pimpl->mMatrixProperties;
-}
-
 // ------------------------------------------------------------------------------------------------
 // Register a custom post-processing step
 aiReturn Importer::RegisterPPStep(BaseProcess* pImp)

+ 15 - 12
code/OpenGEXImporter.cpp

@@ -731,17 +731,22 @@ enum MeshAttribute {
     TexCoord
 };
 
+static const std::string PosToken = "position";
+static const std::string ColToken = "color";
+static const std::string NormalToken = "normal";
+static const std::string TexCoordToken = "texcoord";
+
 //------------------------------------------------------------------------------------------------
 static MeshAttribute getAttributeByName( const char *attribName ) {
     ai_assert( nullptr != attribName  );
 
-    if ( 0 == strncmp( "position", attribName, strlen( "position" ) ) ) {
+    if ( 0 == strncmp( PosToken.c_str(), attribName, PosToken.size() ) ) {
         return Position;
-    } else if ( 0 == strncmp( "color", attribName, strlen( "color" ) ) ) {
+    } else if ( 0 == strncmp( ColToken.c_str(), attribName, ColToken.size() ) ) {
         return Color;
-    } else if( 0 == strncmp( "normal", attribName, strlen( "normal" ) ) ) {
+    } else if( 0 == strncmp( NormalToken.c_str(), attribName, NormalToken.size() ) ) {
         return Normal;
-    } else if( 0 == strncmp( "texcoord", attribName, strlen( "texcoord" ) ) ) {
+    } else if( 0 == strncmp( TexCoordToken.c_str(), attribName, TexCoordToken.size() ) ) {
         return TexCoord;
     }
 
@@ -1098,14 +1103,12 @@ void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene * /*pS
             return;
         }
         const float floatVal( val->getFloat() );
-        if ( prop->m_value  != nullptr ) {
-            if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
-                m_currentCamera->mHorizontalFOV = floatVal;
-            } else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 3 ) ) {
-                m_currentCamera->mClipPlaneNear = floatVal;
-            } else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
-                m_currentCamera->mClipPlaneFar = floatVal;
-            }
+        if ( 0 == ASSIMP_strincmp( "fov", prop->m_value->getString(), 3 ) ) {
+            m_currentCamera->mHorizontalFOV = floatVal;
+        } else if ( 0 == ASSIMP_strincmp( "near", prop->m_value->getString(), 4 ) ) {
+            m_currentCamera->mClipPlaneNear = floatVal;
+        } else if ( 0 == ASSIMP_strincmp( "far", prop->m_value->getString(), 3 ) ) {
+            m_currentCamera->mClipPlaneFar = floatVal;
         }
     }
 }

+ 7 - 2
code/PostStepRegistry.cpp

@@ -125,6 +125,9 @@ corresponding preprocessor flag to selectively disable steps.
 #ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
 #   include "DeboneProcess.h"
 #endif
+#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
+#   include "ScaleProcess.h"
+#endif
 
 namespace Assimp {
 
@@ -136,7 +139,7 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
     // of sequence it is executed. Steps that are added here are not
     // validated - as RegisterPPStep() does - all dependencies must be given.
     // ----------------------------------------------------------------------------
-    out.reserve(30);
+    out.reserve(31);
 #if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
     out.push_back( new MakeLeftHandedProcess());
 #endif
@@ -197,7 +200,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS)
     out.push_back( new GenFaceNormalsProcess());
 #endif
-
+#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
+    out.push_back( new ScaleProcess());
+#endif
     // .........................................................................
     // DON'T change the order of these five ..
     // XXX this is actually a design weakness that dates back to the time

+ 4 - 0
code/ScaleProcess.cpp

@@ -39,6 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 ----------------------------------------------------------------------
 */
+#ifndef ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS
+
 #include "ScaleProcess.h"
 
 #include <assimp/scene.h>
@@ -104,3 +106,5 @@ void ScaleProcess::applyScaling( aiNode *currentNode ) {
 }
 
 } // Namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS

+ 24 - 23
code/SceneCombiner.cpp

@@ -1256,29 +1256,30 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) {
         aiMetadataEntry& out = dest->mValues[i];
         out.mType = in.mType;
         switch (dest->mValues[i].mType) {
-        case AI_BOOL:
-            out.mData = new bool(*static_cast<bool*>(in.mData));
-            break;
-        case AI_INT32:
-            out.mData = new int32_t(*static_cast<int32_t*>(in.mData));
-            break;
-        case AI_UINT64:
-            out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
-            break;
-        case AI_FLOAT:
-            out.mData = new float(*static_cast<float*>(in.mData));
-            break;
-        case AI_DOUBLE:
-            out.mData = new double(*static_cast<double*>(in.mData));
-            break;
-        case AI_AISTRING:
-            out.mData = new aiString(*static_cast<aiString*>(in.mData));
-            break;
-        case AI_AIVECTOR3D:
-            out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
-            break;
-        default:
-            ai_assert(false);
+            case AI_BOOL:
+                out.mData = new bool(*static_cast<bool*>(in.mData));
+                break;
+            case AI_INT32:
+                out.mData = new int32_t(*static_cast<int32_t*>(in.mData));
+                break;
+            case AI_UINT64:
+                out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData));
+                break;
+            case AI_FLOAT:
+                out.mData = new float(*static_cast<float*>(in.mData));
+                break;
+            case AI_DOUBLE:
+                out.mData = new double(*static_cast<double*>(in.mData));
+                break;
+            case AI_AISTRING:
+                out.mData = new aiString(*static_cast<aiString*>(in.mData));
+                break;
+            case AI_AIVECTOR3D:
+                out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData));
+                break;
+            default:
+                ai_assert(false);
+                break;
         }
     }
 }

+ 1 - 1
code/SpatialSort.cpp

@@ -294,7 +294,7 @@ void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition,
         index++;
 
     // Now start iterating from there until the first position lays outside of the distance range.
-    // Add all positions inside the distance range within the tolerance to the result aray
+    // Add all positions inside the distance range within the tolerance to the result array
     std::vector<Entry>::const_iterator it = mPositions.begin() + index;
     while( ToBinary(it->mDistance) < maxDistBinary)
     {

+ 6 - 9
code/VertexTriangleAdjacency.cpp

@@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "VertexTriangleAdjacency.h"
 #include <assimp/mesh.h>
 
-
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
@@ -60,8 +59,8 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
     // compute the number of referenced vertices if it wasn't specified by the caller
     const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
     if (!iNumVertices)  {
-
         for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)   {
+            ai_assert( nullptr != pcFace );
             ai_assert(3 == pcFace->mNumIndices);
             iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
             iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
@@ -69,19 +68,18 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
         }
     }
 
-    this->iNumVertices = iNumVertices;
+    mNumVertices = iNumVertices;
 
     unsigned int* pi;
 
     // allocate storage
     if (bComputeNumTriangles)   {
         pi = mLiveTriangles = new unsigned int[iNumVertices+1];
-        memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
+        ::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
         mOffsetTable = new unsigned int[iNumVertices+2]+1;
-    }
-    else {
+    } else {
         pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
-        memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
+        ::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
         mLiveTriangles = NULL; // important, otherwise the d'tor would crash
     }
 
@@ -90,8 +88,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
     *piEnd++ = 0u;
 
     // first pass: compute the number of faces referencing each vertex
-    for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
-    {
+    for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
         pi[pcFace->mIndices[0]]++;
         pi[pcFace->mIndices[1]]++;
         pi[pcFace->mIndices[2]]++;

+ 9 - 20
code/VertexTriangleAdjacency.h

@@ -60,10 +60,8 @@ namespace Assimp    {
  *  @note Although it is called #VertexTriangleAdjacency, the current version does also
  *    support arbitrary polygons. */
 // --------------------------------------------------------------------------------------------
-class ASSIMP_API VertexTriangleAdjacency
-{
+class ASSIMP_API VertexTriangleAdjacency {
 public:
-
     // ----------------------------------------------------------------------------
     /** @brief Construction from an existing index buffer
      *  @param pcFaces Index buffer
@@ -77,39 +75,30 @@ public:
         unsigned int iNumVertices = 0,
         bool bComputeNumTriangles = true);
 
-
     // ----------------------------------------------------------------------------
     /** @brief Destructor */
     ~VertexTriangleAdjacency();
 
-
-public:
-
     // ----------------------------------------------------------------------------
     /** @brief Get all triangles adjacent to a vertex
      *  @param iVertIndex Index of the vertex
      *  @return A pointer to the adjacency list. */
-    unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const
-    {
-        ai_assert(iVertIndex < iNumVertices);
+    unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const {
+        ai_assert(iVertIndex < mNumVertices);
         return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
     }
 
-
     // ----------------------------------------------------------------------------
     /** @brief Get the number of triangles that are referenced by
      *    a vertex. This function returns a reference that can be modified
      *  @param iVertIndex Index of the vertex
      *  @return Number of referenced triangles */
-    unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex)
-    {
-        ai_assert(iVertIndex < iNumVertices && NULL != mLiveTriangles);
+    unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) {
+        ai_assert( iVertIndex < mNumVertices );
+        ai_assert( nullptr != mLiveTriangles );
         return mLiveTriangles[iVertIndex];
     }
 
-
-public:
-
     //! Offset table
     unsigned int* mOffsetTable;
 
@@ -120,9 +109,9 @@ public:
     unsigned int* mLiveTriangles;
 
     //! Debug: Number of referenced vertices
-    unsigned int iNumVertices;
-
+    unsigned int mNumVertices;
 };
-}
+
+} //! ns Assimp
 
 #endif // !! AI_VTADJACENCY_H_INC

+ 2 - 27
code/glTF2Asset.h

@@ -137,7 +137,7 @@ namespace glTF2
     // Vec/matrix types, as raw float arrays
     typedef float (vec3)[3];
     typedef float (vec4)[4];
-	typedef float (mat4)[16];
+    typedef float (mat4)[16];
 
     namespace Util
     {
@@ -166,33 +166,8 @@ namespace glTF2
 
     //! Magic number for GLB files
 	#define AI_GLB_MAGIC_NUMBER "glTF"
+	#include <assimp/pbrmaterial.h>
 
-    #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0
-	#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
-	#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
-    #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1
-	#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
-	#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
-	#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
-	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
-	#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
-
-	#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
-	#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
-	#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
-	#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
-	#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
-    #define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
-    #define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
-
-	#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
-	#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
-	#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
-	#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
-	#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
-    #define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
-    #define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
-    
     #ifdef ASSIMP_API
         #include "./../include/assimp/Compiler/pushpack1.h"
     #endif

+ 2 - 2
include/assimp/IOStreamBuffer.h

@@ -248,9 +248,9 @@ bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationT
         }
     }
 
-    bool continuationFound( false ), endOfDataLine( false );
+    bool continuationFound( false );
     size_t i = 0;
-    while ( !endOfDataLine ) {
+    for( ;; ) {
         if ( continuationToken == m_cache[ m_cachePos ] ) {
             continuationFound = true;
             ++m_cachePos;

+ 1 - 1
include/assimp/Importer.hpp

@@ -137,7 +137,7 @@ public:
      * If this Importer owns a scene it won't be copied.
      * Call ReadFile() to start the import process.
      */
-    Importer(const Importer& other);
+    Importer(const Importer& other)=delete;
 
     // -------------------------------------------------------------------
     /** Assignment operator has been deleted

+ 3 - 3
include/assimp/MemoryIOWrapper.h

@@ -99,19 +99,19 @@ public:
     // Seek specific position
     aiReturn Seek(size_t pOffset, aiOrigin pOrigin) {
         if (aiOrigin_SET == pOrigin) {
-            if (pOffset >= length) {
+            if (pOffset > length) {
                 return AI_FAILURE;
             }
             pos = pOffset;
         }
         else if (aiOrigin_END == pOrigin) {
-            if (pOffset >= length) {
+            if (pOffset > length) {
                 return AI_FAILURE;
             }
             pos = length-pOffset;
         }
         else {
-            if (pOffset+pos >= length) {
+            if (pOffset+pos > length) {
                 return AI_FAILURE;
             }
             pos += pOffset;

+ 1 - 1
include/assimp/SGSpatialSort.h

@@ -123,7 +123,7 @@ protected:
 
         Entry() { /** intentionally not initialized.*/ }
         Entry( unsigned int pIndex, const aiVector3D& pPosition, float pDistance,uint32_t pSG)
-            :
+        :
             mIndex( pIndex),
             mPosition( pPosition),
             mSmoothGroups (pSG),

+ 10 - 8
include/assimp/SpatialSort.h

@@ -47,8 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <assimp/types.h>
 
-namespace Assimp
-{
+namespace Assimp {
 
 // ------------------------------------------------------------------------------------------------
 /** A little helper class to quickly find all vertices in the epsilon environment of a given
@@ -148,17 +147,20 @@ protected:
     aiVector3D mPlaneNormal;
 
     /** An entry in a spatially sorted position array. Consists of a vertex index,
-     * its position and its precalculated distance from the reference plane */
-    struct Entry
-    {
+     * its position and its pre-calculated distance from the reference plane */
+    struct Entry {
         unsigned int mIndex; ///< The vertex referred by this entry
         aiVector3D mPosition; ///< Position
         ai_real mDistance; ///< Distance of this vertex to the sorting plane
 
-        Entry() { /** intentionally not initialized.*/ }
+        Entry()
+        : mIndex( 999999999 ), mPosition(), mDistance( 99999. ) {
+            // empty        
+        }
         Entry( unsigned int pIndex, const aiVector3D& pPosition, ai_real pDistance)
-            : mIndex( pIndex), mPosition( pPosition), mDistance( pDistance)
-        {   }
+        : mIndex( pIndex), mPosition( pPosition), mDistance( pDistance) {
+            // empty
+        }
 
         bool operator < (const Entry& e) const { return mDistance < e.mDistance; }
     };

+ 59 - 1
include/assimp/StreamWriter.h

@@ -58,7 +58,7 @@ namespace Assimp {
 // --------------------------------------------------------------------------------------------
 /** Wrapper class around IOStream to allow for consistent writing of binary data in both
  *  little and big endian format. Don't attempt to instance the template directly. Use
- *  StreamWriterLE to read from a little-endian stream and StreamWriterBE to read from a
+ *  StreamWriterLE to write to a little-endian stream and StreamWriterBE to write to a
  *  BE stream. Alternatively, there is StreamWriterAny if the endianness of the output
  *  stream is to be determined at runtime.
  */
@@ -108,6 +108,38 @@ public:
         stream->Flush();
     }
 
+public:
+
+    // ---------------------------------------------------------------------
+    /** Flush the contents of the internal buffer, and the output IOStream */
+    void Flush()
+    {
+        stream->Write(&buffer[0], 1, buffer.size());
+        stream->Flush();
+        buffer.clear();
+        cursor = 0;
+    }
+
+    // ---------------------------------------------------------------------
+    /** Seek to the given offset / origin in the output IOStream.
+     *
+     *  Flushes the internal buffer and the output IOStream prior to seeking. */
+    aiReturn Seek(size_t pOffset, aiOrigin pOrigin=aiOrigin_SET)
+    {
+        Flush();
+        return stream->Seek(pOffset, pOrigin);
+    }
+
+    // ---------------------------------------------------------------------
+    /** Tell the current position in the output IOStream.
+     *
+     *  First flushes the internal buffer and the output IOStream. */
+    size_t Tell()
+    {
+        Flush();
+        return stream->Tell();
+    }
+
 public:
 
     // ---------------------------------------------------------------------
@@ -171,6 +203,32 @@ public:
         Put(n);
     }
 
+    // ---------------------------------------------------------------------
+    /** Write an aiString to the stream */
+    void PutString(const aiString& s)
+    {
+        // as Put(T f) below
+        if (cursor + s.length >= buffer.size()) {
+            buffer.resize(cursor + s.length);
+        }
+        void* dest = &buffer[cursor];
+        ::memcpy(dest, s.C_Str(), s.length);
+        cursor += s.length;
+    }
+
+    // ---------------------------------------------------------------------
+    /** Write a std::string to the stream */
+    void PutString(const std::string& s)
+    {
+        // as Put(T f) below
+        if (cursor + s.size() >= buffer.size()) {
+            buffer.resize(cursor + s.size());
+        }
+        void* dest = &buffer[cursor];
+        ::memcpy(dest, s.c_str(), s.size());
+        cursor += s.size();
+    }
+
 public:
 
     // ---------------------------------------------------------------------

+ 37 - 42
include/assimp/fast_atof.h

@@ -59,69 +59,65 @@ const double fast_atof_table[16] =  {  // we write [16] here instead of [] to wo
 // ------------------------------------------------------------------------------------
 // Convert a string in decimal format to a number
 // ------------------------------------------------------------------------------------
-inline unsigned int strtoul10( const char* in, const char** out=0)
-{
+inline
+unsigned int strtoul10( const char* in, const char** out=0) {
     unsigned int value = 0;
 
-    bool running = true;
-    while ( running )
-    {
+    for ( ;; ) {
         if ( *in < '0' || *in > '9' )
             break;
 
         value = ( value * 10 ) + ( *in - '0' );
         ++in;
     }
-    if (out)*out = in;
+    if ( out ) {
+        *out = in;
+    }
     return value;
 }
 
 // ------------------------------------------------------------------------------------
 // Convert a string in octal format to a number
 // ------------------------------------------------------------------------------------
-inline unsigned int strtoul8( const char* in, const char** out=0)
-{
-    unsigned int value = 0;
-
-    bool running = true;
-    while ( running )
-    {
-        if ( *in < '0' || *in > '7' )
+inline
+unsigned int strtoul8( const char* in, const char** out=0) {
+    unsigned int value( 0 );
+    for ( ;; ) {
+        if ( *in < '0' || *in > '7' ) {
             break;
+        }
 
         value = ( value << 3 ) + ( *in - '0' );
         ++in;
     }
-    if (out)*out = in;
+    if ( out ) {
+        *out = in;
+    }
     return value;
 }
 
 // ------------------------------------------------------------------------------------
 // Convert a string in hex format to a number
 // ------------------------------------------------------------------------------------
-inline unsigned int strtoul16( const char* in, const char** out=0)
-{
-    unsigned int value = 0;
-
-    bool running = true;
-    while ( running )
-    {
-        if ( *in >= '0' && *in <= '9' )
-        {
+inline
+unsigned int strtoul16( const char* in, const char** out=0) {
+    unsigned int value( 0 );
+    for ( ;; ) {
+        if ( *in >= '0' && *in <= '9' ) {
             value = ( value << 4u ) + ( *in - '0' );
-        }
-        else if (*in >= 'A' && *in <= 'F')
-        {
+        } else if (*in >= 'A' && *in <= 'F') {
             value = ( value << 4u ) + ( *in - 'A' ) + 10;
-        }
-        else if (*in >= 'a' && *in <= 'f')
-        {
+        } else if (*in >= 'a' && *in <= 'f') {
             value = ( value << 4u ) + ( *in - 'a' ) + 10;
         }
-        else break;
+        else {
+            break;
+        }
         ++in;
     }
-    if (out)*out = in;
+    if ( out ) {
+        *out = in;
+    }
     return value;
 }
 
@@ -131,15 +127,14 @@ inline unsigned int strtoul16( const char* in, const char** out=0)
 // ------------------------------------------------------------------------------------
 inline
 unsigned int HexDigitToDecimal(char in) {
-    unsigned int out = UINT_MAX;
-    if (in >= '0' && in <= '9')
+    unsigned int out( UINT_MAX );
+    if ( in >= '0' && in <= '9' ) {
         out = in - '0';
-
-    else if (in >= 'a' && in <= 'f')
+    } else if ( in >= 'a' && in <= 'f' ) {
         out = 10u + in - 'a';
-
-    else if (in >= 'A' && in <= 'F')
+    } else if ( in >= 'A' && in <= 'F' ) {
         out = 10u + in - 'A';
+    }
 
     // return value is UINT_MAX if the input is not a hex digit
     return out;
@@ -160,8 +155,9 @@ uint8_t HexOctetToDecimal(const char* in) {
 inline
 int strtol10( const char* in, const char** out=0) {
     bool inv = (*in=='-');
-    if (inv || *in=='+')
+    if ( inv || *in == '+' ) {
         ++in;
+    }
 
     int value = strtoul10(in,out);
     if (inv) {
@@ -197,8 +193,7 @@ uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* max_ino
         throw std::invalid_argument( std::string( "The string \"" ) + in + "\" cannot be converted into a value." );
     }
 
-    bool running = true;
-    while ( running ) {
+    for ( ;; ) {
         if ( *in < '0' || *in > '9' ) {
             break;
         }
@@ -378,6 +373,6 @@ ai_real fast_atof( const char** inout) {
     return ret;
 }
 
-} // end of namespace Assimp
+} //! namespace Assimp
 
 #endif // FAST_A_TO_F_H_INCLUDED

+ 34 - 13
include/assimp/mesh.h

@@ -200,8 +200,7 @@ struct aiFace
 // ---------------------------------------------------------------------------
 /** @brief A single influence of a bone on a vertex.
  */
-struct aiVertexWeight
-{
+struct aiVertexWeight {
     //! Index of the vertex which is influenced by the bone.
     unsigned int mVertexId;
 
@@ -214,15 +213,26 @@ struct aiVertexWeight
     //! Default constructor
     aiVertexWeight()
     : mVertexId(0)
-    , mWeight(0.0f)
-    { }
+    , mWeight(0.0f) {
+        // empty
+    }
 
     //! Initialisation from a given index and vertex weight factor
     //! \param pID ID
     //! \param pWeight Vertex weight factor
-    aiVertexWeight( unsigned int pID, float pWeight)
-        : mVertexId( pID), mWeight( pWeight)
-    { /* nothing to do here */ }
+    aiVertexWeight( unsigned int pID, float pWeight )
+    : mVertexId( pID )
+    , mWeight( pWeight ) {
+        // empty
+    }
+
+    bool operator == ( const aiVertexWeight &rhs ) const {
+        return ( mVertexId == rhs.mVertexId && mWeight == rhs.mWeight );
+    }
+
+    bool operator != ( const aiVertexWeight &rhs ) const {
+        return ( *this == rhs );
+    }
 
 #endif // __cplusplus
 };
@@ -235,8 +245,7 @@ struct aiVertexWeight
  *  which it can be addressed by animations. In addition it has a number of
  *  influences on vertices.
  */
-struct aiBone
-{
+struct aiBone {
     //! The name of the bone.
     C_STRUCT aiString mName;
 
@@ -254,10 +263,10 @@ struct aiBone
 
     //! Default constructor
     aiBone()
-        : mName()
-        , mNumWeights( 0 )
-      , mWeights( NULL )
-    {
+    : mName()
+    , mNumWeights( 0 )
+    , mWeights( nullptr ) {
+        // empty
     }
 
     //! Copy constructor
@@ -298,7 +307,19 @@ struct aiBone
         return *this;
     }
 
+    bool operator == ( const aiBone &rhs ) const {
+        if ( mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
+            return false;
+        }
 
+        for ( size_t i = 0; i < mNumWeights; ++i ) {
+            if ( mWeights[ i ] != rhs.mWeights[ i ] ) {
+                return false;
+            }
+        }
+
+        return true;
+    }
     //! Destructor - deletes the array of vertex weights
     ~aiBone()
     {

+ 76 - 0
include/assimp/pbrmaterial.h

@@ -0,0 +1,76 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2018, 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.
+---------------------------------------------------------------------------
+*/
+
+/** @file pbrmaterial.h
+ *  @brief Defines the material system of the library
+ */
+#ifndef AI_PBRMATERIAL_H_INC
+#define AI_PBRMATERIAL_H_INC
+
+#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0
+#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
+#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
+#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1
+#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
+#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
+#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
+#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
+
+#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
+#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
+#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
+#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
+#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
+#define _AI_MATKEY_GLTF_SCALE_BASE "$tex.scale"
+#define _AI_MATKEY_GLTF_STRENGTH_BASE "$tex.strength"
+
+#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD(type, N) _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
+#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
+#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
+#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
+#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
+#define AI_MATKEY_GLTF_TEXTURE_SCALE(type, N) _AI_MATKEY_GLTF_SCALE_BASE, type, N
+#define AI_MATKEY_GLTF_TEXTURE_STRENGTH(type, N) _AI_MATKEY_GLTF_STRENGTH_BASE, type, N
+
+#endif //!!AI_PBRMATERIAL_H_INC

+ 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"
 
 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"
-"\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,
-					unsigned int cline, unsigned int cnest=0)
+					unsigned int cline, bool verbose, unsigned int cnest=0)
 {
 	if (cline++ >= maxline || cnest >= maxnest) {
 		return;
@@ -194,8 +195,29 @@ void PrintHierarchy(const aiNode* root, unsigned int maxnest, unsigned int maxli
 		printf("-- ");
 	}
 	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 ) {
-		PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,cnest+1);
+		PrintHierarchy(root->mChildren[i],maxnest,maxline,cline,verbose,cnest+1);
 		if(i == root->mNumChildren-1) {
 			for(unsigned int i = 0; i < cnest; ++i) {
 				printf("   ");
@@ -230,10 +252,23 @@ int Assimp_Info (const char* const* params, unsigned int num)
 
 	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
 	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
 	const aiScene* scene = ImportModel(import,in);
@@ -346,7 +381,7 @@ int Assimp_Info (const char* const* params, unsigned int num)
 
 	printf("\nNode hierarchy:\n");
 	unsigned int cline=0;
-	PrintHierarchy(scene->mRootNode,20,1000,cline);
+	PrintHierarchy(scene->mRootNode,20,1000,cline,verbose);
 
 	printf("\n");
 	return 0;