Browse Source

Merge branch 'master' of https://github.com/assimp/assimp

Kim Kulling 8 years ago
parent
commit
a1f773c305
64 changed files with 1178 additions and 599 deletions
  1. 1 1
      .travis.sh
  2. 0 1
      CMakeLists.txt
  3. 2 0
      code/3DSExporter.cpp
  4. 7 8
      code/3DSHelper.h
  5. 34 29
      code/3DSLoader.cpp
  6. 1 1
      code/AMFImporter_Postprocess.cpp
  7. 2 1
      code/ASEParser.cpp
  8. 56 42
      code/BaseImporter.cpp
  9. 8 7
      code/BaseImporter.h
  10. 8 8
      code/BlenderDNA.cpp
  11. 0 1
      code/BlenderLoader.h
  12. 11 2
      code/BlenderScene.h
  13. 2 1
      code/CMakeLists.txt
  14. 18 3
      code/ColladaExporter.cpp
  15. 2 2
      code/ColladaLoader.cpp
  16. 1 1
      code/ColladaParser.cpp
  17. 5 5
      code/ComputeUVMappingProcess.cpp
  18. 1 3
      code/DefaultIOStream.h
  19. 1 3
      code/FBXConverter.cpp
  20. 1 1
      code/GenVertexNormalsProcess.cpp
  21. 255 0
      code/IOStreamBuffer.h
  22. 4 4
      code/IRRLoader.cpp
  23. 4 4
      code/IRRLoader.h
  24. 24 15
      code/Importer.h
  25. 2 2
      code/LWOMaterial.cpp
  26. 6 6
      code/MD3FileData.h
  27. 1 1
      code/MDCLoader.cpp
  28. 27 25
      code/MaterialSystem.cpp
  29. 1 1
      code/OFFLoader.cpp
  30. 40 64
      code/ObjFileData.h
  31. 28 28
      code/ObjFileImporter.cpp
  32. 2 2
      code/ObjFileImporter.h
  33. 78 155
      code/ObjFileParser.cpp
  34. 4 3
      code/ObjFileParser.h
  35. 57 2
      code/ObjTools.h
  36. 1 1
      code/OgreMaterial.cpp
  37. 1 1
      code/PretransformVertices.cpp
  38. 4 4
      code/ProcessHelper.cpp
  39. 5 3
      code/RemoveRedundantMaterials.cpp
  40. 1 1
      code/SIBImporter.cpp
  41. 16 15
      code/STLLoader.cpp
  42. 1 1
      code/SceneCombiner.cpp
  43. 6 6
      code/ScenePreprocessor.cpp
  44. 1 1
      code/SkeletonMeshBuilder.cpp
  45. 13 12
      code/StandardShapes.cpp
  46. 2 2
      code/glTFExporter.cpp
  47. 1 1
      contrib/Open3DGC/o3dgcCommon.h
  48. 2 2
      contrib/Open3DGC/o3dgcTimer.h
  49. 0 3
      include/assimp/Compiler/pushpack1.h
  50. 1 1
      include/assimp/cimport.h
  51. 1 9
      include/assimp/metadata.h
  52. 10 7
      include/assimp/types.h
  53. 4 0
      test/CMakeLists.txt
  54. 62 0
      test/unit/TestIOStream.h
  55. 29 0
      test/unit/TestIOSystem.h
  56. 78 0
      test/unit/utBatchLoader.cpp
  57. 1 18
      test/unit/utDefaultIOStream.cpp
  58. 112 0
      test/unit/utIOStreamBuffer.cpp
  59. 7 22
      test/unit/utIOSystem.cpp
  60. 2 0
      test/unit/utImporter.cpp
  61. 19 34
      test/unit/utTriangulate.cpp
  62. 75 0
      test/unit/utTypes.cpp
  63. 28 22
      tools/assimp_qt_viewer/glview.cpp
  64. 1 1
      tools/assimp_qt_viewer/glview.hpp

+ 1 - 1
.travis.sh

@@ -7,7 +7,7 @@ if [ $ANDROID ]; then
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
 else
     generate \
-    && make \
+    && make -j4 \
     && sudo make install \
     && sudo ldconfig \
     && (cd test/unit; ../../bin/unit) \

+ 0 - 1
CMakeLists.txt

@@ -316,7 +316,6 @@ ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
   ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
 ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
-
 ADD_SUBDIRECTORY( code/ )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   IF ( WIN32 )

+ 2 - 0
code/3DSExporter.cpp

@@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "3DSExporter.h"
 #include "3DSLoader.h"
+#include "3DSHelper.h"
 #include "SceneCombiner.h"
 #include "SplitLargeMeshes.h"
 #include "StringComparison.h"
@@ -54,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 using namespace Assimp;
 namespace Assimp    {
+using namespace D3DS;
 
 namespace {
 

+ 7 - 8
code/3DSHelper.h

@@ -369,14 +369,13 @@ struct Material
 {
     //! Default constructor. Builds a default name for the material
     Material()
-        :
-    mDiffuse            (0.6,0.6,0.6), // FIX ... we won't want object to be black
-    mSpecularExponent   (0.0),
-    mShininessStrength  (1.0),
-    mShading(Discreet3DS::Gouraud),
-    mTransparency       (1.0),
-    mBumpHeight         (1.0),
-    mTwoSided           (false)
+    : mDiffuse            ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black
+    , mSpecularExponent   ( ai_real( 0.0 ) )
+    , mShininessStrength  ( ai_real( 1.0 ) )
+    , mShading(Discreet3DS::Gouraud)
+    , mTransparency       ( ai_real( 1.0 ) )
+    , mBumpHeight         ( ai_real( 1.0 ) )
+    , mTwoSided           (false)
     {
         static int iCnt = 0;
 

+ 34 - 29
code/3DSLoader.cpp

@@ -1166,14 +1166,15 @@ void Discreet3DSImporter::ParseMaterialChunk()
 
     case Discreet3DS::CHUNK_MAT_TRANSPARENCY:
         {
-        // This is the material's transparency
-        ai_real* pcf = &mScene->mMaterials.back().mTransparency;
-        *pcf = ParsePercentageChunk();
-
-        // NOTE: transparency, not opacity
-        if (is_qnan(*pcf))
-            *pcf = 1.0;
-        else *pcf = 1.0 - *pcf * (ai_real)0xFFFF / 100.0;
+            // This is the material's transparency
+            ai_real* pcf = &mScene->mMaterials.back().mTransparency;
+            *pcf = ParsePercentageChunk();
+
+            // NOTE: transparency, not opacity
+            if (is_qnan(*pcf))
+                *pcf = ai_real( 1.0 );
+            else 
+                *pcf = ai_real( 1.0 ) - *pcf * (ai_real)0xFFFF / ai_real( 100.0 );
         }
         break;
 
@@ -1199,21 +1200,23 @@ void Discreet3DSImporter::ParseMaterialChunk()
 
     case Discreet3DS::CHUNK_MAT_SHININESS_PERCENT:
         { // This is the shininess strength of the material
-        ai_real* pcf = &mScene->mMaterials.back().mShininessStrength;
-        *pcf = ParsePercentageChunk();
-        if (is_qnan(*pcf))
-            *pcf = 0.0;
-        else *pcf *= (ai_real)0xffff / 100.0;
+            ai_real* pcf = &mScene->mMaterials.back().mShininessStrength;
+            *pcf = ParsePercentageChunk();
+            if (is_qnan(*pcf))
+                *pcf = ai_real( 0.0 );
+            else 
+                *pcf *= (ai_real)0xffff / ai_real( 100.0 );
         }
         break;
 
     case Discreet3DS::CHUNK_MAT_SELF_ILPCT:
         { // This is the self illumination strength of the material
-        ai_real f = ParsePercentageChunk();
-        if (is_qnan(f))
-            f = 0.0;
-        else f *= (ai_real)0xFFFF / 100.0;
-        mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f);
+            ai_real f = ParsePercentageChunk();
+            if (is_qnan(f))
+                f = ai_real( 0.0 );
+            else 
+                f *= (ai_real)0xFFFF / ai_real( 100.0 );
+            mScene->mMaterials.back().mEmissive = aiColor3D(f,f,f);
         }
         break;
 
@@ -1272,7 +1275,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 
     case Discreet3DS::CHUNK_PERCENTD:
         // Manually parse the blend factor
-        pcOut->mTextureBlend = stream->GetF8();
+        pcOut->mTextureBlend = ai_real( stream->GetF8() );
         break;
 
     case Discreet3DS::CHUNK_PERCENTF:
@@ -1282,7 +1285,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 
     case Discreet3DS::CHUNK_PERCENTW:
         // Manually parse the blend factor
-        pcOut->mTextureBlend = (ai_real)((uint16_t)stream->GetI2()) / 100.0;
+        pcOut->mTextureBlend = (ai_real)((uint16_t)stream->GetI2()) / ai_real( 100.0 );
         break;
 
     case Discreet3DS::CHUNK_MAT_MAP_USCALE:
@@ -1355,8 +1358,7 @@ ai_real Discreet3DSImporter::ParsePercentageChunk()
 
 // ------------------------------------------------------------------------------------------------
 // Read a color chunk. If a percentage chunk is found instead it is read as a grayscale color
-void Discreet3DSImporter::ParseColorChunk(aiColor3D* out,
-    bool acceptPercent)
+void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
 {
     ai_assert(out != NULL);
 
@@ -1389,13 +1391,16 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D* out,
     case Discreet3DS::CHUNK_LINRGBB:
         bGamma = true;
     case Discreet3DS::CHUNK_RGBB:
-        if (sizeof(char) * 3 > diff)    {
-            *out = clrError;
-            return;
+        {
+            if ( sizeof( char ) * 3 > diff ) {
+                *out = clrError;
+                return;
+            }
+            const ai_real invVal = ai_real( 1.0 ) / ai_real( 255.0 );
+            out->r = ( ai_real ) ( uint8_t ) stream->GetI1() * invVal;
+            out->g = ( ai_real ) ( uint8_t ) stream->GetI1() * invVal;
+            out->b = ( ai_real ) ( uint8_t ) stream->GetI1() * invVal;
         }
-        out->r = (ai_real)(uint8_t)stream->GetI1() / 255.0;
-        out->g = (ai_real)(uint8_t)stream->GetI1() / 255.0;
-        out->b = (ai_real)(uint8_t)stream->GetI1() / 255.0;
         break;
 
     // Percentage chunks are accepted, too.
@@ -1409,7 +1414,7 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D* out,
 
     case Discreet3DS::CHUNK_PERCENTW:
         if (acceptPercent && 1 <= diff) {
-            out->g = out->b = out->r = (ai_real)(uint8_t)stream->GetI1() / 255.0;
+            out->g = out->b = out->r = (ai_real)(uint8_t)stream->GetI1() / ai_real( 255.0 );
             break;
         }
         *out = clrError;

+ 1 - 1
code/AMFImporter_Postprocess.cpp

@@ -227,7 +227,7 @@ std::string TextureConverted_ID;
 	// check that all textures has same size
 	if(src_texture_4check.size() > 1)
 	{
-		for(uint8_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++)
+		for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++)
 		{
 			if((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
 				(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth))

+ 2 - 1
code/ASEParser.cpp

@@ -618,7 +618,8 @@ void Parser::ParseLV2MaterialBlock(ASE::Material& mat)
             if (TokenMatch(filePtr,"MATERIAL_TRANSPARENCY",21))
             {
                 ParseLV4MeshFloat(mat.mTransparency);
-                mat.mTransparency = 1.0 - mat.mTransparency;continue;
+                mat.mTransparency = ai_real( 1.0 ) - mat.mTransparency;
+                continue;
             }
             // material self illumination
             if (TokenMatch(filePtr,"MATERIAL_SELFILLUM",18))

+ 56 - 42
code/BaseImporter.cpp

@@ -481,7 +481,7 @@ namespace Assimp
         BatchLoader::PropertyMap map;
         unsigned int id;
 
-        bool operator== (const std::string& f) {
+        bool operator== (const std::string& f) const {
             return file == f;
         }
     };
@@ -489,13 +489,22 @@ namespace Assimp
 
 // ------------------------------------------------------------------------------------------------
 // BatchLoader::pimpl data structure
-struct Assimp::BatchData
-{
-    BatchData()
-        : pIOSystem()
-        , pImporter()
-        , next_id(0xffff)
-    {}
+struct Assimp::BatchData {
+    BatchData( IOSystem* pIO, bool validate )
+    : pIOSystem( pIO )
+    , pImporter( nullptr )
+    , next_id(0xffff)
+    , validate( validate ) {
+        ai_assert( NULL != pIO );
+        
+        pImporter = new Importer();
+        pImporter->SetIOHandler( pIO );
+    }
+
+    ~BatchData() {
+        pImporter->SetIOHandler( NULL ); /* get pointer back into our possession */
+        delete pImporter;
+    }
 
     // IO system to be used for all imports
     IOSystem* pIOSystem;
@@ -511,53 +520,59 @@ struct Assimp::BatchData
 
     // Id for next item
     unsigned int next_id;
+
+    // Validation enabled state
+    bool validate;
 };
 
+typedef std::list<LoadRequest>::iterator LoadReqIt;
+
 // ------------------------------------------------------------------------------------------------
-BatchLoader::BatchLoader(IOSystem* pIO)
+BatchLoader::BatchLoader(IOSystem* pIO, bool validate )
 {
     ai_assert(NULL != pIO);
 
-    data = new BatchData();
-    data->pIOSystem = pIO;
-
-    data->pImporter = new Importer();
-    data->pImporter->SetIOHandler(data->pIOSystem);
+    m_data = new BatchData( pIO, validate );
 }
 
 // ------------------------------------------------------------------------------------------------
 BatchLoader::~BatchLoader()
 {
-    // delete all scenes wthat have not been polled by the user
-    for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
-
+    // delete all scenes what have not been polled by the user
+    for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
         delete (*it).scene;
     }
-    data->pImporter->SetIOHandler(NULL); /* get pointer back into our possession */
-    delete data->pImporter;
-    delete data;
+    delete m_data;
 }
 
+// ------------------------------------------------------------------------------------------------
+void BatchLoader::setValidation( bool enabled ) {
+    m_data->validate = enabled;
+}
 
 // ------------------------------------------------------------------------------------------------
-unsigned int BatchLoader::AddLoadRequest    (const std::string& file,
+bool BatchLoader::getValidation() const {
+    return m_data->validate;
+}
+
+// ------------------------------------------------------------------------------------------------
+unsigned int BatchLoader::AddLoadRequest(const std::string& file,
     unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/)
 {
     ai_assert(!file.empty());
 
     // check whether we have this loading request already
-    std::list<LoadRequest>::iterator it;
-    for (it = data->requests.begin();it != data->requests.end(); ++it)  {
-
+    for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it)  {
         // Call IOSystem's path comparison function here
-        if (data->pIOSystem->ComparePaths((*it).file,file)) {
-
+        if ( m_data->pIOSystem->ComparePaths((*it).file,file)) {
             if (map) {
-                if (!((*it).map == *map))
+                if ( !( ( *it ).map == *map ) ) {
                     continue;
+                }
             }
-            else if (!(*it).map.empty())
+            else if ( !( *it ).map.empty() ) {
                 continue;
+            }
 
             (*it).refCnt++;
             return (*it).id;
@@ -565,20 +580,18 @@ unsigned int BatchLoader::AddLoadRequest    (const std::string& file,
     }
 
     // no, we don't have it. So add it to the queue ...
-    data->requests.push_back(LoadRequest(file,steps,map,data->next_id));
-    return data->next_id++;
+    m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id));
+    return m_data->next_id++;
 }
 
 // ------------------------------------------------------------------------------------------------
-aiScene* BatchLoader::GetImport     (unsigned int which)
+aiScene* BatchLoader::GetImport( unsigned int which )
 {
-    for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
-
+    for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
         if ((*it).id == which && (*it).loaded)  {
-
             aiScene* sc = (*it).scene;
             if (!(--(*it).refCnt))  {
-                data->requests.erase(it);
+                m_data->requests.erase(it);
             }
             return sc;
         }
@@ -590,14 +603,15 @@ aiScene* BatchLoader::GetImport     (unsigned int which)
 void BatchLoader::LoadAll()
 {
     // no threaded implementation for the moment
-    for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
+    for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) {
         // force validation in debug builds
         unsigned int pp = (*it).flags;
-#ifdef ASSIMP_BUILD_DEBUG
-        pp |= aiProcess_ValidateDataStructure;
-#endif
+        if ( m_data->validate ) {
+            pp |= aiProcess_ValidateDataStructure;
+        }
+
         // setup config properties if necessary
-        ImporterPimpl* pimpl = data->pImporter->Pimpl();
+        ImporterPimpl* pimpl = m_data->pImporter->Pimpl();
         pimpl->mFloatProperties  = (*it).map.floats;
         pimpl->mIntProperties    = (*it).map.ints;
         pimpl->mStringProperties = (*it).map.strings;
@@ -608,8 +622,8 @@ void BatchLoader::LoadAll()
             DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
             DefaultLogger::get()->info("File: " + (*it).file);
         }
-        data->pImporter->ReadFile((*it).file,pp);
-        (*it).scene = data->pImporter->GetOrphanedScene();
+        m_data->pImporter->ReadFile((*it).file,pp);
+        (*it).scene = m_data->pImporter->GetOrphanedScene();
         (*it).loaded = true;
 
         DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");

+ 8 - 7
code/BaseImporter.h

@@ -347,7 +347,12 @@ public: // static utilities
     static void ConvertUTF8toISO8859_1(
         std::string& data);
 
-    enum TextFileMode { ALLOW_EMPTY, FORBID_EMPTY };
+    // -------------------------------------------------------------------
+    /// @brief  Enum to define, if empty files are ok or not.
+    enum TextFileMode { 
+        ALLOW_EMPTY,
+        FORBID_EMPTY 
+    };
 
     // -------------------------------------------------------------------
     /** Utility for text file loaders which copies the contents of the
@@ -382,14 +387,10 @@ public: // static utilities
         }
     }
 
-    
-
 protected:
-
-    /** Error description in case there was one. */
+    /// Error description in case there was one.
     std::string m_ErrorText;
-
-    /** Currently set progress handler */
+    /// Currently set progress handler.
     ProgressHandler* m_progress;
 };
 

+ 8 - 8
code/BlenderDNA.cpp

@@ -56,10 +56,10 @@ using namespace Assimp::Formatter;
 static bool match4(StreamReaderAny& stream, const char* string) {
     ai_assert( nullptr != string );
     char tmp[] = {
-        (stream).GetI1(),
-        (stream).GetI1(),
-        (stream).GetI1(),
-        (stream).GetI1()
+        (const char)(stream).GetI1(),
+        (const char)(stream).GetI1(),
+        (const char)(stream).GetI1(),
+        (const char)(stream).GetI1()
     };
     return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
 }
@@ -346,10 +346,10 @@ void SectionParser :: Next()
     stream.SetCurrentPos(current.start + current.size);
 
     const char tmp[] = {
-        stream.GetI1(),
-        stream.GetI1(),
-        stream.GetI1(),
-        stream.GetI1()
+        (const char)stream.GetI1(),
+        (const char)stream.GetI1(),
+        (const char)stream.GetI1(),
+        (const char)stream.GetI1()
     };
     current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
 

+ 0 - 1
code/BlenderLoader.h

@@ -105,7 +105,6 @@ public:
     BlenderImporter();
     ~BlenderImporter();
 
-
 public:
 
     // --------------------

+ 11 - 2
code/BlenderScene.h

@@ -91,8 +91,17 @@ namespace Blender {
 //   value for the field.
 //
 
-#define WARN // warn if field is missing, substitute default value
-#define FAIL // fail the import if the field does not exist
+// warn if field is missing, substitute default value
+#ifdef WARN
+#  undef WARN
+#endif
+#define WARN 
+
+// fail the import if the field does not exist
+#ifdef FAIL
+#  undef FAIL
+#endif
+#define FAIL 
 
 struct Object;
 struct MTex;

+ 2 - 1
code/CMakeLists.txt

@@ -172,6 +172,7 @@ SET( Common_SRCS
   Bitmap.h
   XMLTools.h
   Version.cpp
+  IOStreamBuffer.h
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
@@ -462,7 +463,7 @@ ADD_ASSIMP_IMPORTER( IFC
   STEPFileEncoding.h
 )
 if (MSVC AND ASSIMP_BUILD_IFC_IMPORTER)
-  set_source_files_properties(IFCReaderGen.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
+  set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
 endif (MSVC AND ASSIMP_BUILD_IFC_IMPORTER)
 
 ADD_ASSIMP_IMPORTER( XGL

+ 18 - 3
code/ColladaExporter.cpp

@@ -150,7 +150,7 @@ void ColladaExporter::WriteFile()
 // Writes the asset header
 void ColladaExporter::WriteHeader()
 {
-    static const ai_real epsilon = 0.00001;
+    static const ai_real epsilon = ai_real( 0.00001 );
     static const aiQuaternion x_rot(aiMatrix3x3(
         0, -1,  0,
         1,  0,  0,
@@ -636,9 +636,24 @@ void ColladaExporter::WriteMaterials()
     const aiMaterial* mat = mScene->mMaterials[a];
 
     aiString name;
-    if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
+    if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS ) {
       name = "mat";
-    materials[a].name = std::string( "m") + to_string(a) + name.C_Str();
+      materials[a].name = std::string( "m") + to_string(a) + name.C_Str();
+    } else {
+      // try to use the material's name if no other material has already taken it, else append #
+      std::string testName = name.C_Str();
+      size_t materialCountWithThisName = 0;
+      for( size_t i = 0; i < a; i ++ ) {
+        if( materials[i].name == testName ) {
+          materialCountWithThisName ++;
+        }
+      }
+      if( materialCountWithThisName == 0 ) {
+        materials[a].name = name.C_Str();
+      } else {
+        materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName);  
+      }
+    }
     for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
       if( !isalnum_C( *it ) ) {
         *it = '_';

+ 2 - 2
code/ColladaLoader.cpp

@@ -1071,7 +1071,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             continue;
 
         // resolve the data pointers for all anim channels. Find the minimum time while we're at it
-        ai_real startTime = 1e20, endTime = -1e20;
+        ai_real startTime = ai_real( 1e20 ), endTime = ai_real( -1e20 );
         for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
         {
             Collada::ChannelEntry& e = *it;
@@ -1152,7 +1152,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
               resultTrafos.push_back( mat);
 
               // find next point in time to evaluate. That's the closest frame larger than the current in any channel
-              ai_real nextTime = 1e20;
+              ai_real nextTime = ai_real( 1e20 );
               for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
               {
                   Collada::ChannelEntry& channelElement = *it;

+ 1 - 1
code/ColladaParser.cpp

@@ -3075,7 +3075,7 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
             case TF_ROTATE:
             {
                 aiMatrix4x4 rot;
-                ai_real angle = tf.f[3] * ai_real( AI_MATH_PI) / 180.0;
+                ai_real angle = tf.f[3] * ai_real( AI_MATH_PI) / ai_real( 180.0 );
                 aiVector3D axis( tf.f[0], tf.f[1], tf.f[2]);
                 aiMatrix4x4::Rotation( angle, axis, rot);
                 res *= rot;

+ 5 - 5
code/ComputeUVMappingProcess.cpp

@@ -52,7 +52,7 @@ namespace {
     const static aiVector3D base_axis_y(0.0,1.0,0.0);
     const static aiVector3D base_axis_x(1.0,0.0,0.0);
     const static aiVector3D base_axis_z(0.0,0.0,1.0);
-    const static ai_real angle_epsilon = 0.95;
+    const static ai_real angle_epsilon = ai_real( 0.95 );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -109,11 +109,11 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
     // much easier, but I don't know how and am currently too tired to
     // to think about a better solution.
 
-    const static ai_real LOWER_LIMIT = 0.1;
-    const static ai_real UPPER_LIMIT = 0.9;
+    const static ai_real LOWER_LIMIT = ai_real( 0.1 );
+    const static ai_real UPPER_LIMIT = ai_real( 0.9 );
 
-    const static ai_real LOWER_EPSILON = 10e-3;
-    const static ai_real UPPER_EPSILON = 1.0-10e-3;
+    const static ai_real LOWER_EPSILON = ai_real( 10e-3 );
+    const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 );
 
     for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx)
     {

+ 1 - 3
code/DefaultIOStream.h

@@ -105,7 +105,7 @@ public:
     void Flush();
 
 private:
-    //  File datastructure, using clib
+    //  File data-structure, using clib
     FILE* mFile;
     //  Filename
     std::string mFilename;
@@ -114,7 +114,6 @@ private:
     mutable size_t mCachedSize;
 };
 
-
 // ----------------------------------------------------------------------------------
 inline DefaultIOStream::DefaultIOStream () :
     mFile       (NULL),
@@ -124,7 +123,6 @@ inline DefaultIOStream::DefaultIOStream () :
     // empty
 }
 
-
 // ----------------------------------------------------------------------------------
 inline DefaultIOStream::DefaultIOStream (FILE* pFile,
         const std::string &strFilename) :

+ 1 - 3
code/FBXConverter.cpp

@@ -3068,9 +3068,7 @@ void Converter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, c
             const KeyTimeList::value_type timeA = std::get<0>(kfl)->at( id0 );
             const KeyTimeList::value_type timeB = std::get<0>(kfl)->at( id1 );
 
-            // do the actual interpolation in double-precision arithmetics
-            // because it is a bit sensitive to rounding errors.
-            const double factor = timeB == timeA ? 0. : static_cast<double>( ( time - timeA ) / ( timeB - timeA ) );
+            const ai_real factor = timeB == timeA ? 0. : static_cast<ai_real>( ( time - timeA ) ) / ( timeB - timeA );
             const ai_real interpValue = static_cast<ai_real>( valueA + ( valueB - valueA ) * factor );
 
             result[ std::get<2>(kfl) ] = interpValue;

+ 1 - 1
code/GenVertexNormalsProcess.cpp

@@ -154,7 +154,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
     // check whether we can reuse the SpatialSort of a previous step.
     SpatialSort* vertexFinder = NULL;
     SpatialSort  _vertexFinder;
-    ai_real posEpsilon = 1e-5;
+    ai_real posEpsilon = ai_real( 1e-5 );
     if (shared) {
         std::vector<std::pair<SpatialSort,ai_real> >* avf;
         shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);

+ 255 - 0
code/IOStreamBuffer.h

@@ -0,0 +1,255 @@
+#pragma once
+
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include <assimp/types.h>
+#include <assimp/IOStream.hpp>
+#include "ParsingUtils.h"
+
+#include <iostream>
+
+namespace Assimp {
+
+// ---------------------------------------------------------------------------
+/**
+ *  Implementation of a cached stream buffer.
+ */
+template<class T>
+class IOStreamBuffer {
+public:
+    /// @brief  The class constructor.
+    IOStreamBuffer( size_t cache = 4096 * 4096 );
+
+    /// @brief  The class destructor.
+    ~IOStreamBuffer();
+
+    /// @brief  Will open the cached access for a given stream.
+    /// @param  stream      The stream to cache.
+    /// @return true if successful.
+    bool open( IOStream *stream );
+
+    /// @brief  Will close the cached access.
+    /// @return true if successful.
+    bool close();
+
+    /// @brief  Returns the filesize.
+    /// @return The filesize.
+    size_t size() const;
+    
+    /// @brief  Returns the cache size.
+    /// @return The cache size.
+    size_t cacheSize() const;
+
+    /// @brief  Will read the next block.
+    /// @return true if successful.
+    bool readNextBlock();
+
+    /// @brief  Returns the number of blocks to read.
+    /// @return The number of blocks.
+    size_t getNumBlocks() const;
+
+    /// @brief  Returns the current block index.
+    /// @return The current block index.
+    size_t getCurrentBlockIndex() const;
+
+    /// @brief  Returns the current file pos.
+    /// @return The current file pos.
+    size_t getFilePos() const;
+
+    /// @brief  Will read the next line.
+    /// @param  buffer      The buffer for the next line.
+    /// @return true if successful.
+    bool getNextLine( std::vector<T> &buffer );
+
+private:
+    IOStream *m_stream;
+    size_t m_filesize;
+    size_t m_cacheSize;
+    size_t m_numBlocks;
+    size_t m_blockIdx;
+    std::vector<T> m_cache;
+    size_t m_cachePos;
+    size_t m_filePos;
+};
+
+template<class T>
+inline
+IOStreamBuffer<T>::IOStreamBuffer( size_t cache )
+: m_stream( nullptr )
+, m_filesize( 0 )
+, m_cacheSize( cache )
+, m_numBlocks( 0 )
+, m_blockIdx( 0 )
+, m_cachePos( 0 )
+, m_filePos( 0 ) {
+    m_cache.resize( cache );
+    std::fill( m_cache.begin(), m_cache.end(), '\n' );
+}
+
+template<class T>
+inline
+IOStreamBuffer<T>::~IOStreamBuffer() {
+    // empty
+}
+
+template<class T>
+inline
+bool IOStreamBuffer<T>::open( IOStream *stream ) {
+    //  file still opened!
+    if ( nullptr != m_stream ) {
+        return false;
+    }
+
+    //  Invalid stream pointer
+    if ( nullptr == stream ) {
+        return false;
+    }
+
+    m_stream = stream;
+    m_filesize = m_stream->FileSize();
+    if ( m_filesize == 0 ) {
+        return false;
+    }
+    if ( m_filesize < m_cacheSize ) {
+        m_cacheSize = m_filesize;
+    }
+
+    m_numBlocks = m_filesize / m_cacheSize;
+    if ( ( m_filesize % m_cacheSize ) > 0 ) {
+        m_numBlocks++;
+    }
+
+    return true;
+}
+
+template<class T>
+inline
+bool IOStreamBuffer<T>::close() {
+    if ( nullptr == m_stream ) {
+        return false;
+    }
+
+    // init counters and state vars
+    m_stream    = nullptr;
+    m_filesize  = 0;
+    m_numBlocks = 0;
+    m_blockIdx  = 0;
+    m_cachePos  = 0;
+    m_filePos   = 0;
+
+    return true;
+}
+
+template<class T>
+inline
+size_t IOStreamBuffer<T>::size() const {
+    return m_filesize;
+}
+
+template<class T>
+inline
+size_t IOStreamBuffer<T>::cacheSize() const {
+    return m_cacheSize;
+}
+
+template<class T>
+inline
+bool IOStreamBuffer<T>::readNextBlock() {
+    m_stream->Seek( m_filePos, aiOrigin_SET );
+    size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize );
+    if ( readLen == 0 ) {
+        return false;
+    }
+    if ( readLen < m_cacheSize ) {
+        m_cacheSize = readLen;
+    }
+    m_filePos += m_cacheSize;
+    m_cachePos = 0;
+    m_blockIdx++;
+
+    return true;
+}
+
+template<class T>
+inline
+size_t IOStreamBuffer<T>::getNumBlocks() const {
+    return m_numBlocks;
+}
+
+template<class T>
+inline
+size_t IOStreamBuffer<T>::getCurrentBlockIndex() const {
+    return m_blockIdx;
+}
+
+template<class T>
+inline
+size_t IOStreamBuffer<T>::getFilePos() const {
+    return m_filePos;
+}
+
+template<class T>
+inline
+bool IOStreamBuffer<T>::getNextLine( std::vector<T> &buffer ) {
+    buffer.resize( m_cacheSize );
+    if ( m_cachePos == m_cacheSize || 0 == m_filePos ) {
+        if ( !readNextBlock() ) {
+            return false;
+        }
+    }
+    size_t i = 0;
+    while ( !IsLineEnd( m_cache[ m_cachePos ] ) ) {
+        buffer[ i ] = m_cache[ m_cachePos ];
+        m_cachePos++;
+        i++;
+        if ( m_cachePos >= m_cacheSize ) {
+            if ( !readNextBlock() ) {
+                return false;
+            }
+        }
+    }
+    buffer[ i ] = '\n';
+    m_cachePos++;
+
+    return true;
+}
+
+} // !ns Assimp

+ 4 - 4
code/IRRLoader.cpp

@@ -542,7 +542,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
                 {
                     aiVectorKey& key = anim->mPositionKeys[i];
 
-                    const ai_real dt = (i * in.speed * 0.001 );
+                    const ai_real dt = (i * in.speed * ai_real( 0.001 ) );
                     const ai_real u = dt - std::floor(dt);
                     const int idx = (int)std::floor(dt) % size;
 
@@ -556,9 +556,9 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
                     const ai_real u2 = u*u;
                     const ai_real u3 = u2*2;
 
-                    const ai_real h1 = 2.0 * u3 - 3.0 * u2 + 1.0;
-                    const ai_real h2 = -2.0 * u3 + 3.0 * u3;
-                    const ai_real h3 = u3 - 2.0 * u3;
+                    const ai_real h1 = ai_real( 2.0 ) * u3 - ai_real( 3.0 ) * u2 + ai_real( 1.0 );
+                    const ai_real h2 = ai_real( -2.0 ) * u3 + ai_real( 3.0 ) * u3;
+                    const ai_real h3 = u3 - ai_real( 2.0 ) * u3;
                     const ai_real h4 = u3 - u2;
 
                     // compute the spline tangents

+ 4 - 4
code/IRRLoader.h

@@ -116,10 +116,10 @@ private:
 
         explicit Animator(AT t = UNKNOWN)
             : type              (t)
-            , speed             (0.001)
-            , direction         (0.0,1.0,0.0)
-            , circleRadius      (1.0)
-            , tightness         (0.5f)
+            , speed             ( ai_real( 0.001 ) )
+            , direction         ( ai_real( 0.0 ), ai_real( 1.0 ), ai_real( 0.0 ) )
+            , circleRadius      ( ai_real( 1.0) )
+            , tightness         ( ai_real( 0.5 ) )
             , loop              (true)
             , timeForWay        (100)
         {

+ 24 - 15
code/Importer.h

@@ -39,6 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 /** @file Importer.h mostly internal stuff for use by #Assimp::Importer */
+#pragma once
 #ifndef INCLUDED_AI_IMPORTER_H
 #define INCLUDED_AI_IMPORTER_H
 
@@ -133,12 +134,11 @@ struct BatchData;
  *  could, this has not yet been implemented at the moment).
  *
  *  @note The class may not be used by more than one thread*/
-class BatchLoader
+class ASSIMP_API BatchLoader
 {
     // friend of Importer
 
 public:
-
     //! @cond never
     // -------------------------------------------------------------------
     /** Wraps a full list of configuration properties for an importer.
@@ -162,15 +162,29 @@ public:
     //! @endcond
 
 public:
-
-
     // -------------------------------------------------------------------
     /** Construct a batch loader from a given IO system to be used
-     *  to access external files */
-    explicit BatchLoader(IOSystem* pIO);
-    ~BatchLoader();
+     *  to access external files 
+     */
+    explicit BatchLoader(IOSystem* pIO, bool validate = false );
 
+    // -------------------------------------------------------------------
+    /** The class destructor.
+     */
+    ~BatchLoader();
 
+    // -------------------------------------------------------------------
+    /** Sets the validation step. True for enable validation during postprocess.
+     *  @param  enable  True for validation.
+     */
+    void setValidation( bool enabled );
+    
+    // -------------------------------------------------------------------
+    /** Returns the current validation step.
+     *  @return The current validation step.
+     */
+    bool getValidation() const;
+    
     // -------------------------------------------------------------------
     /** Add a new file to the list of files to be loaded.
      *  @param file File to be loaded
@@ -185,7 +199,6 @@ public:
         const PropertyMap* map = NULL
         );
 
-
     // -------------------------------------------------------------------
     /** Get an imported scene.
      *  This polls the import from the internal request list.
@@ -199,20 +212,16 @@ public:
         unsigned int which
         );
 
-
     // -------------------------------------------------------------------
     /** Waits until all scenes have been loaded. This returns
      *  immediately if no scenes are queued.*/
     void LoadAll();
 
 private:
-
     // No need to have that in the public API ...
-    BatchData* data;
+    BatchData *m_data;
 };
 
-}
-
-
+} // Namespace Assimp
 
-#endif
+#endif // INCLUDED_AI_IMPORTER_H

+ 2 - 2
code/LWOMaterial.cpp

@@ -286,7 +286,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
     {
         float fGloss;
         if (mIsLWO2)    {
-            fGloss = std::pow( surf.mGlossiness*10.0+2.0, 2.0);
+            fGloss = std::pow( surf.mGlossiness*ai_real( 10.0 )+ ai_real( 2.0 ), ai_real( 2.0 ) );
         }
         else
         {
@@ -312,7 +312,7 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
 
     // emissive color
     // luminosity is not really the same but it affects the surface in a similar way. Some scaling looks good.
-    clr.g = clr.b = clr.r = surf.mLuminosity*0.8;
+    clr.g = clr.b = clr.r = surf.mLuminosity*ai_real( 0.8 );
     pcMat->AddProperty<aiColor3D>(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
 
     // opacity ... either additive or default-blended, please

+ 6 - 6
code/MD3FileData.h

@@ -261,13 +261,13 @@ inline void LatLngNormalToVec3(uint16_t p_iNormal, ai_real* p_afOut)
 {
     ai_real lat = (ai_real)(( p_iNormal >> 8u ) & 0xff);
     ai_real lng = (ai_real)(( p_iNormal & 0xff ));
-    lat *= 3.141926/128.0;
-    lng *= 3.141926/128.0;
+    const ai_real invVal( ai_real( 1.0 ) / ai_real( 128.0 ) );
+    lat *= ai_real( 3.141926 ) * invVal;
+    lng *= ai_real( 3.141926 ) * invVal;
 
-    p_afOut[0] = std::cos(lat) * std::sin(lng);
-    p_afOut[1] = std::sin(lat) * std::sin(lng);
-    p_afOut[2] = std::cos(lng);
-    return;
+    p_afOut[ 0 ] = std::cos(lat) * std::sin(lng);
+    p_afOut[ 1 ] = std::sin(lat) * std::sin(lng);
+    p_afOut[ 2 ] = std::cos(lng);
 }
 
 

+ 1 - 1
code/MDCLoader.cpp

@@ -408,7 +408,7 @@ void MDCImporter::InternReadFile(
 
                     // copy texture coordinates
                     pcUVCur->x = pcUVs[quak].u;
-                    pcUVCur->y = 1.0-pcUVs[quak].v; // DX to OGL
+                    pcUVCur->y = ai_real( 1.0 )-pcUVs[quak].v; // DX to OGL
                 }
                 pcVertCur->x += pcFrame->localOrigin[0] ;
                 pcVertCur->y += pcFrame->localOrigin[1] ;

+ 27 - 25
code/MaterialSystem.cpp

@@ -42,8 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of the material system of the library
  */
 
-
-
 #include "Hash.h"
 #include "fast_atof.h"
 #include "ParsingUtils.h"
@@ -71,7 +69,7 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
      *  could be improved by hashing, but it's possibly
      *  no worth the effort (we're bound to C structures,
      *  thus std::map or derivates are not applicable. */
-    for (unsigned int i = 0; i < pMat->mNumProperties;++i) {
+    for ( unsigned int i = 0; i < pMat->mNumProperties; ++i ) {
         aiMaterialProperty* prop = pMat->mProperties[i];
 
         if (prop /* just for safety ... */
@@ -151,14 +149,15 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
             iWrite = *pMax;
         }
         // strings are zero-terminated with a 32 bit length prefix, so this is safe
-        const char* cur =  prop->mData+4;
-        ai_assert(prop->mDataLength>=5 && !prop->mData[prop->mDataLength-1]);
-        for (unsigned int a = 0; ;++a) {
+        const char *cur = prop->mData + 4;
+        ai_assert( prop->mDataLength >= 5 );
+        ai_assert( !prop->mData[ prop->mDataLength - 1 ] );
+        for ( unsigned int a = 0; ;++a) {
             cur = fast_atoreal_move<ai_real>(cur,pOut[a]);
-            if(a==iWrite-1) {
+            if ( a==iWrite-1 ) {
                 break;
             }
-            if(!IsSpace(*cur)) {
+            if ( !IsSpace(*cur) ) {
                 DefaultLogger::get()->error("Material property" + std::string(pKey) +
                     " is a string; failed to parse a float array out of it.");
                 return AI_FAILURE;
@@ -170,7 +169,6 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
         }
     }
     return AI_SUCCESS;
-
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -224,8 +222,9 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
             iWrite = *pMax;
         }
         // strings are zero-terminated with a 32 bit length prefix, so this is safe
-        const char* cur =  prop->mData+4;
-        ai_assert(prop->mDataLength>=5 && !prop->mData[prop->mDataLength-1]);
+        const char *cur =  prop->mData+4;
+        ai_assert( prop->mDataLength >= 5 );
+        ai_assert( !prop->mData[ prop->mDataLength - 1 ] );
         for (unsigned int a = 0; ;++a) {
             pOut[a] = strtol10(cur,&cur);
             if(a==iWrite-1) {
@@ -298,7 +297,8 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat,
         // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data
         pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t*>(prop->mData));
 
-        ai_assert(pOut->length+1+4==prop->mDataLength && !prop->mData[prop->mDataLength-1]);
+        ai_assert( pOut->length+1+4==prop->mDataLength );
+        ai_assert( !prop->mData[ prop->mDataLength - 1 ] );
         memcpy(pOut->data,prop->mData+4,pOut->length+1);
     }
     else {
@@ -317,12 +317,12 @@ ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMa
 {
     ai_assert (pMat != NULL);
 
-    /* Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again) */
+    // Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again)
     unsigned int max = 0;
     for (unsigned int i = 0; i < pMat->mNumProperties;++i) {
         aiMaterialProperty* prop = pMat->mProperties[i];
 
-        if (prop /* just a sanity check ... */
+        if ( prop /* just a sanity check ... */
             && 0 == strcmp( prop->mKey.data, _AI_MATKEY_TEXTURE_BASE )
             && prop->mSemantic == type) {
 
@@ -381,14 +381,16 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
     return AI_SUCCESS;
 }
 
+static const unsigned int DefaultNumAllocated = 5;
+
 // ------------------------------------------------------------------------------------------------
 // Construction. Actually the one and only way to get an aiMaterial instance
-aiMaterial::aiMaterial()
-{
+aiMaterial::aiMaterial() 
+: mProperties( NULL )
+, mNumProperties( 0 )
+, mNumAllocated( DefaultNumAllocated ) {
     // Allocate 5 entries by default
-    mNumProperties = 0;
-    mNumAllocated = 5;
-    mProperties = new aiMaterialProperty*[5];
+    mProperties = new aiMaterialProperty*[ DefaultNumAllocated ];
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -543,10 +545,10 @@ aiReturn aiMaterial::AddProperty (const aiString* pInput,
 }
 
 // ------------------------------------------------------------------------------------------------
-uint32_t Assimp :: ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/)
+uint32_t Assimp::ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/)
 {
     uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
-    for (unsigned int i = 0; i < mat->mNumProperties;++i)   {
+    for ( unsigned int i = 0; i < mat->mNumProperties; ++i ) {
         aiMaterialProperty* prop;
 
         // Exclude all properties whose first character is '?' from the hash
@@ -585,15 +587,16 @@ void aiMaterial::CopyPropertyList(aiMaterial* pcDest,
         }
     }
 
-    if(pcOld)
-    	delete[] pcOld;
+    if ( pcOld ) {
+        delete[] pcOld;
+    }
 
     for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i)   {
         aiMaterialProperty* propSrc = pcSrc->mProperties[i];
 
         // search whether we have already a property with this name -> if yes, overwrite it
         aiMaterialProperty* prop;
-        for (unsigned int q = 0; q < iOldNum;++q) {
+        for ( unsigned int q = 0; q < iOldNum; ++q ) {
             prop = pcDest->mProperties[q];
             if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic
                 && prop->mIndex == propSrc->mIndex) {
@@ -617,5 +620,4 @@ void aiMaterial::CopyPropertyList(aiMaterial* pcDest,
         prop->mData = new char[propSrc->mDataLength];
         memcpy(prop->mData,propSrc->mData,prop->mDataLength);
     }
-    return;
 }

+ 1 - 1
code/OFFLoader.cpp

@@ -242,7 +242,7 @@ void OFFImporter::InternReadFile( const std::string& pFile,
     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
     aiMaterial* pcMat = new aiMaterial();
 
-    aiColor4D clr(0.6,0.6,0.6,1.0);
+    aiColor4D clr( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 1.0 ) );
     pcMat->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
     pScene->mMaterials[0] = pcMat;
 

+ 40 - 64
code/ObjFileData.h

@@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
+#pragma once
 #ifndef OBJ_FILEDATA_H_INC
 #define OBJ_FILEDATA_H_INC
 
@@ -56,59 +57,43 @@ struct Material;
 // ------------------------------------------------------------------------------------------------
 //! \struct Face
 //! \brief  Data structure for a simple obj-face, describes discredit,l.ation and materials
-struct Face
-{
+// ------------------------------------------------------------------------------------------------
+struct Face {
     typedef std::vector<unsigned int> IndexArray;
 
     //! Primitive type
     aiPrimitiveType m_PrimitiveType;
     //! Vertex indices
-    IndexArray *m_pVertices;
+    IndexArray m_vertices;
     //! Normal indices
-    IndexArray *m_pNormals;
+    IndexArray m_normals;
     //! Texture coordinates indices
-    IndexArray *m_pTexturCoords;
+    IndexArray m_texturCoords;
     //! Pointer to assigned material
     Material *m_pMaterial;
 
     //! \brief  Default constructor
-    //! \param  pVertices   Pointer to assigned vertex indexbuffer
-    //! \param  pNormals    Pointer to assigned normals indexbuffer
-    //! \param  pTexCoords  Pointer to assigned texture indexbuffer
-    Face( std::vector<unsigned int> *pVertices,
-            std::vector<unsigned int> *pNormals,
-            std::vector<unsigned int> *pTexCoords,
-            aiPrimitiveType pt = aiPrimitiveType_POLYGON) :
-        m_PrimitiveType( pt ),
-        m_pVertices( pVertices ),
-        m_pNormals( pNormals ),
-        m_pTexturCoords( pTexCoords ),
-        m_pMaterial( 0L )
-    {
+    Face( aiPrimitiveType pt = aiPrimitiveType_POLYGON) 
+    : m_PrimitiveType( pt )
+    , m_vertices()
+    , m_normals()
+    , m_texturCoords()
+    , m_pMaterial( 0L ) {
         // empty
     }
 
     //! \brief  Destructor
-    ~Face()
-    {
-        delete m_pVertices;
-        m_pVertices = NULL;
-
-        delete m_pNormals;
-        m_pNormals = NULL;
-
-        delete m_pTexturCoords;
-        m_pTexturCoords = NULL;
+    ~Face() {
+        // empty
     }
 };
 
 // ------------------------------------------------------------------------------------------------
 //! \struct Object
-//! \brief  Stores all objects of an objfile object definition
-struct Object
-{
-    enum ObjectType
-    {
+//! \brief  Stores all objects of an obj-file object definition
+// ------------------------------------------------------------------------------------------------
+struct Object {
+    enum ObjectType {
         ObjType,
         GroupType
     };
@@ -123,29 +108,24 @@ struct Object
     std::vector<unsigned int> m_Meshes;
 
     //! \brief  Default constructor
-    Object() :
-        m_strObjName("")
-    {
+    Object() 
+    : m_strObjName("") {
         // empty
     }
 
     //! \brief  Destructor
-    ~Object()
-    {
-        for (std::vector<Object*>::iterator it = m_SubObjects.begin();
-            it != m_SubObjects.end(); ++it)
-        {
+    ~Object() {
+        for ( std::vector<Object*>::iterator it = m_SubObjects.begin(); it != m_SubObjects.end(); ++it) {
             delete *it;
         }
-        m_SubObjects.clear();
     }
 };
 
 // ------------------------------------------------------------------------------------------------
 //! \struct Material
 //! \brief  Data structure to store all material specific data
-struct Material
-{
+// ------------------------------------------------------------------------------------------------
+struct Material {
     //! Name of material description
     aiString MaterialName;
 
@@ -160,8 +140,8 @@ struct Material
     aiString textureSpecularity;
     aiString textureOpacity;
     aiString textureDisp;
-    enum TextureType
-    {
+
+    enum TextureType {
         TextureDiffuseType = 0,
         TextureSpecularType,
         TextureAmbientType,
@@ -201,22 +181,19 @@ struct Material
 
     //! Constructor
     Material()
-        :   diffuse (0.6,0.6,0.6)
-        ,   alpha   (1.0)
-        ,   shineness (0.0)
-        ,   illumination_model (1)
-        ,   ior     (1.0)
-    {
+    :   diffuse ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) )
+    ,   alpha   (ai_real( 1.0 ) )
+    ,   shineness ( ai_real( 0.0) )
+    ,   illumination_model (1)
+    ,   ior     ( ai_real( 1.0 ) ) {
         // empty
-        for (size_t i = 0; i < TextureTypeCount; ++i)
-        {
-            clamp[i] = false;
+        for (size_t i = 0; i < TextureTypeCount; ++i) {
+            clamp[ i ] = false;
         }
     }
 
     // Destructor
-    ~Material()
-    {
+    ~Material() {
         // empty
     }
 };
@@ -224,6 +201,7 @@ struct Material
 // ------------------------------------------------------------------------------------------------
 //! \struct Mesh
 //! \brief  Data structure to store a mesh
+// ------------------------------------------------------------------------------------------------
 struct Mesh {
     static const unsigned int NoMaterial = ~0u;
     /// The name for the mesh
@@ -254,8 +232,7 @@ struct Mesh {
     }
 
     /// Destructor
-    ~Mesh()
-    {
+    ~Mesh() {
         for (std::vector<Face*>::iterator it = m_Faces.begin();
             it != m_Faces.end(); ++it)
         {
@@ -267,8 +244,8 @@ struct Mesh {
 // ------------------------------------------------------------------------------------------------
 //! \struct Model
 //! \brief  Data structure to store all obj-specific model datas
-struct Model
-{
+// ------------------------------------------------------------------------------------------------
+struct Model {
     typedef std::map<std::string, std::vector<unsigned int>* > GroupMap;
     typedef std::map<std::string, std::vector<unsigned int>* >::iterator GroupMapIt;
     typedef std::map<std::string, std::vector<unsigned int>* >::const_iterator ConstGroupMapIt;
@@ -320,8 +297,7 @@ struct Model
     }
 
     //! \brief  The class destructor
-    ~Model()
-    {
+    ~Model() {
         // Clear all stored object instances
         for (std::vector<Object*>::iterator it = m_Objects.begin();
             it != m_Objects.end(); ++it) {
@@ -352,4 +328,4 @@ struct Model
 } // Namespace ObjFile
 } // Namespace Assimp
 
-#endif
+#endif // OBJ_FILEDATA_H_INC

+ 28 - 28
code/ObjFileImporter.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "ObjFileImporter.h"
 #include "ObjFileParser.h"
 #include "ObjFileData.h"
+#include "IOStreamBuffer.h"
 #include <memory>
 #include <assimp/Importer.hpp>
 #include <assimp/scene.h>
@@ -126,8 +127,11 @@ void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene,
         throw DeadlyImportError( "OBJ-file is too small.");
     }
 
+    IOStreamBuffer<char> streamedBuffer;
+    streamedBuffer.open( fileStream.get() );
+
     // Allocate buffer and read file into it
-    TextFileToBuffer( fileStream.get(),m_Buffer);
+    //TextFileToBuffer( fileStream.get(),m_Buffer);
 
     // Get the model name
     std::string  modelName, folderName;
@@ -150,7 +154,7 @@ void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene,
     const unsigned int updateProgressEveryBytes = 100 * 1024;
     const unsigned int progressTotal = (3*m_Buffer.size()/updateProgressEveryBytes);
     // process all '\'
-    std::vector<char> ::iterator iter = m_Buffer.begin();
+    /*std::vector<char> ::iterator iter = m_Buffer.begin();
     while (iter != m_Buffer.end())
     {
         if (*iter == '\\')
@@ -169,17 +173,19 @@ void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene,
             m_progress->UpdateFileRead(++progress, progressTotal);
             progressCounter = 0;
         }
-    }
+    }*/
 
     // 1/3rd progress
     m_progress->UpdateFileRead(1, 3);
 
     // parse the file into a temporary representation
-    ObjFileParser parser(m_Buffer, modelName, pIOHandler, m_progress, file);
+    ObjFileParser parser( streamedBuffer, modelName, pIOHandler, m_progress, file);
 
     // And create the proper return structures out of it
     CreateDataFromImport(parser.GetModel(), pScene);
 
+    streamedBuffer.close();
+
     // Clean up allocated storage for the next import
     m_Buffer.clear();
 
@@ -291,9 +297,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 
 // ------------------------------------------------------------------------------------------------
 //  Create topology data
-aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData,
-                                         unsigned int meshIndex )
-{
+aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const ObjFile::Object* pData, unsigned int meshIndex ) {
     // Checking preconditions
     ai_assert( NULL != pModel );
 
@@ -322,14 +326,14 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
         ai_assert( NULL != inp  );
 
         if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
-            pMesh->mNumFaces += inp->m_pVertices->size() - 1;
+            pMesh->mNumFaces += inp->m_vertices.size() - 1;
             pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
         } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
-            pMesh->mNumFaces += inp->m_pVertices->size();
+            pMesh->mNumFaces += inp->m_vertices.size();
             pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
         } else {
             ++pMesh->mNumFaces;
-            if (inp->m_pVertices->size() > 3) {
+            if (inp->m_vertices.size() > 3) {
                 pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
             } else {
                 pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
@@ -350,7 +354,7 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
         for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
             ObjFile::Face* const inp = pObjMesh->m_Faces[ index ];
             if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
-                for(size_t i = 0; i < inp->m_pVertices->size() - 1; ++i) {
+                for(size_t i = 0; i < inp->m_vertices.size() - 1; ++i) {
                     aiFace& f = pMesh->mFaces[ outIndex++ ];
                     uiIdxCount += f.mNumIndices = 2;
                     f.mIndices = new unsigned int[2];
@@ -358,7 +362,7 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
                 continue;
             }
             else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
-                for(size_t i = 0; i < inp->m_pVertices->size(); ++i) {
+                for(size_t i = 0; i < inp->m_vertices.size(); ++i) {
                     aiFace& f = pMesh->mFaces[ outIndex++ ];
                     uiIdxCount += f.mNumIndices = 1;
                     f.mIndices = new unsigned int[1];
@@ -367,7 +371,7 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
             }
 
             aiFace *pFace = &pMesh->mFaces[ outIndex++ ];
-            const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_pVertices->size();
+            const unsigned int uiNumIndices = (unsigned int) pObjMesh->m_Faces[ index ]->m_vertices.size();
             uiIdxCount += pFace->mNumIndices = (unsigned int) uiNumIndices;
             if (pFace->mNumIndices > 0) {
                 pFace->mIndices = new unsigned int[ uiNumIndices ];
@@ -432,8 +436,8 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
         ObjFile::Face *pSourceFace = pObjMesh->m_Faces[ index ];
 
         // Copy all index arrays
-        for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_pVertices->size(); vertexIndex++ ) {
-            const unsigned int vertex = pSourceFace->m_pVertices->at( vertexIndex );
+        for ( size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < pSourceFace->m_vertices.size(); vertexIndex++ ) {
+            const unsigned int vertex = pSourceFace->m_vertices.at( vertexIndex );
             if ( vertex >= pModel->m_Vertices.size() ) {
                 throw DeadlyImportError( "OBJ: vertex index out of range" );
             }
@@ -441,8 +445,8 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
             pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
 
             // Copy all normals
-            if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_pNormals->size()) {
-                const unsigned int normal = pSourceFace->m_pNormals->at( vertexIndex );
+            if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_normals.size()) {
+                const unsigned int normal = pSourceFace->m_normals.at( vertexIndex );
                 if ( normal >= pModel->m_Normals.size() ) {
                     throw DeadlyImportError( "OBJ: vertex normal index out of range" );
                 }
@@ -457,9 +461,9 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
             }
 
             // Copy all texture coordinates
-            if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_pTexturCoords->size())
+            if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_texturCoords.size())
             {
-                const unsigned int tex = pSourceFace->m_pTexturCoords->at( vertexIndex );
+                const unsigned int tex = pSourceFace->m_texturCoords.at( vertexIndex );
                 ai_assert( tex < pModel->m_TextureCoord.size() );
 
                 if ( tex >= pModel->m_TextureCoord.size() )
@@ -476,20 +480,16 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
             // Get destination face
             aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
 
-            const bool last = ( vertexIndex == pSourceFace->m_pVertices->size() - 1 );
-            if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last)
-            {
+            const bool last = ( vertexIndex == pSourceFace->m_vertices.size() - 1 );
+            if (pSourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) {
                 pDestFace->mIndices[ outVertexIndex ] = newIndex;
                 outVertexIndex++;
             }
 
-            if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT)
-            {
+            if (pSourceFace->m_PrimitiveType == aiPrimitiveType_POINT) {
                 outIndex++;
                 outVertexIndex = 0;
-            }
-            else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE)
-            {
+            } else if (pSourceFace->m_PrimitiveType == aiPrimitiveType_LINE) {
                 outVertexIndex = 0;
 
                 if(!last)
@@ -498,7 +498,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
                 if (vertexIndex) {
                     if(!last) {
                         pMesh->mVertices[ newIndex+1 ] = pMesh->mVertices[ newIndex ];
-                        if ( !pSourceFace->m_pNormals->empty() && !pModel->m_Normals.empty()) {
+                        if ( !pSourceFace->m_normals.empty() && !pModel->m_Normals.empty()) {
                             pMesh->mNormals[ newIndex+1 ] = pMesh->mNormals[newIndex ];
                         }
                         if ( !pModel->m_TextureCoord.empty() ) {

+ 2 - 2
code/ObjFileImporter.h

@@ -50,8 +50,8 @@ struct aiNode;
 namespace Assimp {
 
 namespace ObjFile {
-struct Object;
-struct Model;
+    struct Object;
+    struct Model;
 }
 
 // ------------------------------------------------------------------------------------------------

+ 78 - 155
code/ObjFileParser.cpp

@@ -38,8 +38,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
-
-
 #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
 
 #include "ObjFileParser.h"
@@ -54,16 +52,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Importer.hpp>
 #include <cstdlib>
 
-
 namespace Assimp {
 
 const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
 
 // -------------------------------------------------------------------
 //  Constructor with loaded data and directories.
-ObjFileParser::ObjFileParser(std::vector<char> &data, const std::string &modelName, IOSystem *io, ProgressHandler* progress, const std::string &originalObjFileName) :
-    m_DataIt(data.begin()),
-    m_DataItEnd(data.end()),
+ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::string &modelName, 
+                              IOSystem *io, ProgressHandler* progress,
+                              const std::string &originalObjFileName) :
+    m_DataIt(),
+    m_DataItEnd(),
     m_pModel(NULL),
     m_uiLine(0),
     m_pIO( io ),
@@ -83,55 +82,50 @@ ObjFileParser::ObjFileParser(std::vector<char> &data, const std::string &modelNa
     m_pModel->m_MaterialMap[ DEFAULT_MATERIAL ] = m_pModel->m_pDefaultMaterial;
 
     // Start parsing the file
-    parseFile();
+    parseFile( streamBuffer );
 }
 
 // -------------------------------------------------------------------
 //  Destructor
-ObjFileParser::~ObjFileParser()
-{
+ObjFileParser::~ObjFileParser() {
     delete m_pModel;
     m_pModel = NULL;
 }
 
 // -------------------------------------------------------------------
 //  Returns a pointer to the model instance.
-ObjFile::Model *ObjFileParser::GetModel() const
-{
+ObjFile::Model *ObjFileParser::GetModel() const {
     return m_pModel;
 }
 
 // -------------------------------------------------------------------
 //  File parsing method.
-void ObjFileParser::parseFile()
-{
-    if (m_DataIt == m_DataItEnd)
-        return;
-
+void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
     // only update every 100KB or it'll be too slow
     const unsigned int updateProgressEveryBytes = 100 * 1024;
     unsigned int progressCounter = 0;
-    const unsigned int bytesToProcess = std::distance(m_DataIt, m_DataItEnd);
+    const unsigned int bytesToProcess = streamBuffer.size();
     const unsigned int progressTotal = 3 * bytesToProcess;
     const unsigned int progressOffset = bytesToProcess;
     unsigned int processed = 0;
+    size_t lastFilePos( 0 );
 
-    DataArrayIt lastDataIt = m_DataIt;
-
-    while (m_DataIt != m_DataItEnd)
-    {
-        // Handle progress reporting
-        processed += std::distance(lastDataIt, m_DataIt);
-        lastDataIt = m_DataIt;
-        if (processed > (progressCounter * updateProgressEveryBytes))
-        {
+    std::vector<char> buffer;
+    while ( streamBuffer.getNextLine( buffer ) ) {
+        m_DataIt = buffer.begin();
+        m_DataItEnd = buffer.end();
+
+        // Handle progress reporting        
+        const size_t filePos( streamBuffer.getFilePos() );
+        if ( lastFilePos < filePos ) {
+            processed += filePos;
+            lastFilePos = filePos;
             progressCounter++;
-            m_progress->UpdateFileRead(progressOffset + processed*2, progressTotal);
+            m_progress->UpdateFileRead( progressOffset + processed * 2, progressTotal );
         }
 
         // parse line
-        switch (*m_DataIt)
-        {
+        switch (*m_DataIt) {
         case 'v': // Parse a vertex texture coordinate
             {
                 ++m_DataIt;
@@ -149,8 +143,8 @@ void ObjFileParser::parseFile()
                     }
                 } else if (*m_DataIt == 't') {
                     // read in texture coordinate ( 2D or 3D )
-                                        ++m_DataIt;
-                                        getVector( m_pModel->m_TextureCoord );
+                    ++m_DataIt;
+                    getVector( m_pModel->m_TextureCoord );
                 } else if (*m_DataIt == 'n') {
                     // Read in normal vector definition
                     ++m_DataIt;
@@ -184,7 +178,7 @@ void ObjFileParser::parseFile()
             {
                 std::string name;
 
-                getName(m_DataIt, m_DataItEnd, name);
+                getNameNoSpace(m_DataIt, m_DataItEnd, name);
 
                 size_t nextSpace = name.find(" ");
                 if (nextSpace != std::string::npos)
@@ -230,8 +224,7 @@ pf_skip_line:
 
 // -------------------------------------------------------------------
 //  Copy the next word in a temporary buffer
-void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
-{
+void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
     size_t index = 0;
     m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
     while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
@@ -247,37 +240,6 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length)
     pBuffer[index] = '\0';
 }
 
-// -------------------------------------------------------------------
-// Copy the next line into a temporary buffer
-void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
-{
-    size_t index = 0u;
-
-    // some OBJ files have line continuations using \ (such as in C++ et al)
-    bool continuation = false;
-    for (;m_DataIt != m_DataItEnd && index < length-1; ++m_DataIt)
-    {
-        const char c = *m_DataIt;
-        if (c == '\\') {
-            continuation = true;
-            continue;
-        }
-
-        if (c == '\n' || c == '\r') {
-            if(continuation) {
-                pBuffer[ index++ ] = ' ';
-                continue;
-            }
-            break;
-        }
-
-        continuation = false;
-        pBuffer[ index++ ] = c;
-    }
-    ai_assert(index < length);
-    pBuffer[ index ] = '\0';
-}
-
 size_t ObjFileParser::getNumComponentsInLine() {
     size_t numComponents( 0 );
     const char* tmp( &m_DataIt[0] );
@@ -291,7 +253,6 @@ size_t ObjFileParser::getNumComponentsInLine() {
     return numComponents;
 }
 
-// -------------------------------------------------------------------
 void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
     size_t numComponents = getNumComponentsInLine();
     ai_real x, y, z;
@@ -403,18 +364,17 @@ static const std::string DefaultObjName = "defaultobject";
 
 // -------------------------------------------------------------------
 //  Get values for a new face instance
-void ObjFileParser::getFace(aiPrimitiveType type) {
-    copyNextLine(m_buffer, Buffersize);
-    char *pPtr = m_buffer;
-    char *pEnd = &pPtr[Buffersize];
-    pPtr = getNextToken<char*>(pPtr, pEnd);
-    if ( pPtr == pEnd || *pPtr == '\0' ) {
+void ObjFileParser::getFace( aiPrimitiveType type ) {
+    //copyNextLine(m_buffer, Buffersize);
+    //char *pPtr = m_DataIt;
+    //char *pPtr = m_buffer;
+    //char *pEnd = &pPtr[Buffersize];
+    m_DataIt = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
+    if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) {
         return;
     }
 
-    std::vector<unsigned int> *pIndices = new std::vector<unsigned int>;
-    std::vector<unsigned int> *pTexID = new std::vector<unsigned int>;
-    std::vector<unsigned int> *pNormalID = new std::vector<unsigned int>;
+    ObjFile::Face *face = new ObjFile::Face( type );
     bool hasNormal = false;
 
     const int vSize = m_pModel->m_Vertices.size();
@@ -424,14 +384,14 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
     const bool vt = (!m_pModel->m_TextureCoord.empty());
     const bool vn = (!m_pModel->m_Normals.empty());
     int iStep = 0, iPos = 0;
-    while (pPtr != pEnd) {
+    while ( m_DataIt != m_DataItEnd ) {
         iStep = 1;
 
-        if ( IsLineEnd( *pPtr ) ) {
+        if ( IsLineEnd( *m_DataIt ) ) {
             break;
         }
 
-        if (*pPtr=='/' ) {
+        if ( *m_DataIt =='/' ) {
             if (type == aiPrimitiveType_POINT) {
                 DefaultLogger::get()->error("Obj: Separator unexpected in point statement");
             }
@@ -443,11 +403,11 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
                 }
             }
             iPos++;
-        } else if( IsSpaceOrNewLine( *pPtr ) ) {
+        } else if( IsSpaceOrNewLine( *m_DataIt ) ) {
             iPos = 0;
         } else {
             //OBJ USES 1 Base ARRAYS!!!!
-            const int iVal( ::atoi( pPtr ) );
+            const int iVal( ::atoi( & ( *m_DataIt ) ) );
 
             // increment iStep position based off of the sign and # of digits
             int tmp = iVal;
@@ -458,65 +418,42 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
                 ++iStep;
             }
 
-            if ( iVal > 0 )
-            {
+            if ( iVal > 0 ) {
                 // Store parsed index
-                if ( 0 == iPos )
-                {
-                    pIndices->push_back( iVal-1 );
-                }
-                else if ( 1 == iPos )
-                {
-                    pTexID->push_back( iVal-1 );
-                }
-                else if ( 2 == iPos )
-                {
-                    pNormalID->push_back( iVal-1 );
+                if ( 0 == iPos ) {
+                    face->m_vertices.push_back( iVal - 1 );
+                } else if ( 1 == iPos ) {
+                    face->m_texturCoords.push_back( iVal - 1 );
+                } else if ( 2 == iPos ) {
+                    face->m_normals.push_back( iVal - 1 );
                     hasNormal = true;
-                }
-                else
-                {
+                } else {
                     reportErrorTokenInFace();
                 }
-            }
-            else if ( iVal < 0 )
-            {
+            } else if ( iVal < 0 ) {
                 // Store relatively index
-                if ( 0 == iPos )
-                {
-                    pIndices->push_back( vSize + iVal );
-                }
-                else if ( 1 == iPos )
-                {
-                    pTexID->push_back( vtSize + iVal );
-                }
-                else if ( 2 == iPos )
-                {
-                    pNormalID->push_back( vnSize + iVal );
+                if ( 0 == iPos ) {
+                    face->m_vertices.push_back( vSize + iVal );
+                } else if ( 1 == iPos ) {
+                    face->m_texturCoords.push_back( vtSize + iVal );
+                } else if ( 2 == iPos ) {
+                    face->m_normals.push_back( vnSize + iVal );
                     hasNormal = true;
-                }
-                else
-                {
+                } else {
                     reportErrorTokenInFace();
                 }
             }
         }
-        pPtr += iStep;
+        m_DataIt += iStep;
     }
 
-    if ( pIndices->empty() ) {
+    if ( face->m_vertices.empty() ) {
         DefaultLogger::get()->error("Obj: Ignoring empty face");
         // skip line and clean up
         m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
-        delete pNormalID;
-        delete pTexID;
-        delete pIndices;
-
         return;
     }
 
-    ObjFile::Face *face = new ObjFile::Face( pIndices, pNormalID, pTexID, type );
-
     // Set active material, if one set
     if( NULL != m_pModel->m_pCurrentMaterial ) {
         face->m_pMaterial = m_pModel->m_pCurrentMaterial;
@@ -536,8 +473,8 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
 
     // Store the face
     m_pModel->m_pCurrentMesh->m_Faces.push_back( face );
-    m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_pVertices->size();
-    m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int)face->m_pTexturCoords[0].size();
+    m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int) face->m_vertices.size();
+    m_pModel->m_pCurrentMesh->m_uiUVCoordinates[ 0 ] += (unsigned int) face->m_texturCoords.size();
     if( !m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal ) {
         m_pModel->m_pCurrentMesh->m_hasNormals = true;
     }
@@ -547,8 +484,7 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
 
 // -------------------------------------------------------------------
 //  Get values for a new material description
-void ObjFileParser::getMaterialDesc()
-{
+void ObjFileParser::getMaterialDesc() {
     // Get next data for material data
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     if (m_DataIt == m_DataItEnd) {
@@ -571,28 +507,26 @@ void ObjFileParser::getMaterialDesc()
 
     // If the current mesh has the same material, we simply ignore that 'usemtl' command
     // There is no need to create another object or even mesh here
-    if (m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString(strName))
+    if ( m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString( strName ) ) {
         skip = true;
+    }
 
-    if (!skip)
-    {
+    if (!skip) {
         // Search for material
         std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find(strName);
-        if (it == m_pModel->m_MaterialMap.end())
-        {
+        if (it == m_pModel->m_MaterialMap.end()) {
             // Not found, use default material
             m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
             DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping");
             strName = m_pModel->m_pDefaultMaterial->MaterialName.C_Str();
-        }
-        else
-        {
+        } else {
             // Found, using detected material
             m_pModel->m_pCurrentMaterial = (*it).second;
         }
 
-        if (needsNewMesh(strName))
-            createMesh(strName);
+        if ( needsNewMesh( strName ) ) {
+            createMesh( strName );
+        }
 
         m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
     }
@@ -603,17 +537,12 @@ void ObjFileParser::getMaterialDesc()
 
 // -------------------------------------------------------------------
 //  Get a comment, values will be skipped
-void ObjFileParser::getComment()
-{
-    while (m_DataIt != m_DataItEnd)
-    {
-        if ( '\n' == (*m_DataIt))
-        {
+void ObjFileParser::getComment() {
+    while (m_DataIt != m_DataItEnd) {
+        if ( '\n' == (*m_DataIt)) {
             ++m_DataIt;
             break;
-        }
-        else
-        {
+        } else {
             ++m_DataIt;
         }
     }
@@ -621,8 +550,7 @@ void ObjFileParser::getComment()
 
 // -------------------------------------------------------------------
 //  Get material library from file.
-void ObjFileParser::getMaterialLib()
-{
+void ObjFileParser::getMaterialLib() {
     // Translate tuple
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     if( m_DataIt == m_DataItEnd ) {
@@ -678,8 +606,7 @@ void ObjFileParser::getMaterialLib()
 
 // -------------------------------------------------------------------
 //  Set a new material definition as the current material.
-void ObjFileParser::getNewMaterial()
-{
+void ObjFileParser::getNewMaterial() {
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
     if( m_DataIt == m_DataItEnd ) {
@@ -692,17 +619,13 @@ void ObjFileParser::getNewMaterial()
         ++m_DataIt;
     }
     std::map<std::string, ObjFile::Material*>::iterator it = m_pModel->m_MaterialMap.find( strMat );
-    if ( it == m_pModel->m_MaterialMap.end() )
-    {
+    if ( it == m_pModel->m_MaterialMap.end() ) {
         // Show a warning, if material was not found
         DefaultLogger::get()->warn("OBJ: Unsupported material requested: " + strMat);
         m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
-    }
-    else
-    {
+    } else {
         // Set new material
-        if ( needsNewMesh( strMat ) )
-        {
+        if ( needsNewMesh( strMat ) ) {
             createMesh( strMat );
         }
         m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex( strMat );

+ 4 - 3
code/ObjFileParser.h

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/vector2.h>
 #include <assimp/vector3.h>
 #include <assimp/mesh.h>
+#include "IOStreamBuffer.h"
 
 namespace Assimp {
 
@@ -72,7 +73,7 @@ public:
 
 public:
     /// \brief  Constructor with data array.
-    ObjFileParser(std::vector<char> &Data, const std::string &strModelName, IOSystem* io, ProgressHandler* progress, const std::string &originalObjFileName);
+    ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::string &strModelName, IOSystem* io, ProgressHandler* progress, const std::string &originalObjFileName);
     /// \brief  Destructor
     ~ObjFileParser();
     /// \brief  Model getter.
@@ -80,11 +81,11 @@ public:
 
 private:
     /// Parse the loaded file
-    void parseFile();
+    void parseFile( IOStreamBuffer<char> &streamBuffer );
     /// Method to copy the new delimited word in the current line.
     void copyNextWord(char *pBuffer, size_t length);
     /// Method to copy the new line.
-    void copyNextLine(char *pBuffer, size_t length);
+//    void copyNextLine(char *pBuffer, size_t length);
     /// Stores the vector
     void getVector( std::vector<aiVector3D> &point3d_array );
     /// Stores the following 3d vector.

+ 57 - 2
code/ObjTools.h

@@ -142,11 +142,52 @@ inline char_t getName( char_t it, char_t end, std::string &name )
     }
 
     char *pStart = &( *it );
-    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) {
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) && !IsSpaceOrNewLine( *it ) ) {
         ++it;
     }
 
-    while( isEndOfBuffer( it, end ) || IsLineEnd( *it ) || IsSpaceOrNewLine( *it ) ) {
+    /*while( isEndOfBuffer( it, end ) || IsLineEnd( *it ) || IsSpaceOrNewLine( *it ) ) {
+        --it;
+    }
+    ++it;
+    */
+    // Get name
+    // if there is no name, and the previous char is a separator, come back to start
+    while (&(*it) < pStart) {
+        ++it;
+    }
+    std::string strName( pStart, &(*it) );
+    if ( strName.empty() )
+        return it;
+    else
+        name = strName;
+
+    return it;
+}
+
+/** @brief  Get a name from the current line. Do not preserve space
+ *    in the middle, but trim it at the end.
+ *  @param  it      set to current position
+ *  @param  end     set to end of scratch buffer for readout
+ *  @param  name    Separated name
+ *  @return Current-iterator with new position
+ */
+template<class char_t>
+inline char_t getNameNoSpace( char_t it, char_t end, std::string &name )
+{
+    name = "";
+    if( isEndOfBuffer( it, end ) ) {
+        return end;
+    }
+
+    char *pStart = &( *it );
+    while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it )
+          && !IsSpaceOrNewLine( *it ) ) {
+        ++it;
+    }
+
+    while( isEndOfBuffer( it, end ) || IsLineEnd( *it )
+          || IsSpaceOrNewLine( *it ) ) {
         --it;
     }
     ++it;
@@ -246,6 +287,20 @@ string_type trim_whitespaces(string_type str)
     return str;
 }
 
+template<class T>
+bool hasLineEnd( T it, T end ) {
+    bool hasLineEnd( false );
+    while ( !isEndOfBuffer( it, end ) ) {
+        it++;
+        if ( IsLineEnd( it ) ) {
+            hasLineEnd = true;
+            break;
+        }
+    }
+
+    return hasLineEnd;
+}
+
 } // Namespace Assimp
 
 #endif // OBJ_TOOLS_H_INC

+ 1 - 1
code/OgreMaterial.cpp

@@ -93,7 +93,7 @@ void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIO
     // Create materials that can be found and parsed via the IOSystem.
     for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i)
     {
-        SubMeshXml *submesh = mesh->GetSubMesh(i);
+        SubMeshXml *submesh = mesh->GetSubMesh( static_cast<uint16_t>(i));
         if (submesh && !submesh->materialRef.empty())
         {
             aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);

+ 1 - 1
code/PretransformVertices.cpp

@@ -690,7 +690,7 @@ void PretransformVertices::Execute( aiScene* pScene)
 
         // find the dominant axis
         aiVector3D d = max-min;
-        const ai_real div = std::max(d.x,std::max(d.y,d.z))*0.5;
+        const ai_real div = std::max(d.x,std::max(d.y,d.z))*ai_real( 0.5);
 
         d = min + d * (ai_real)0.5;
         for (unsigned int a = 0; a <  pScene->mNumMeshes; ++a) {

+ 4 - 4
code/ProcessHelper.cpp

@@ -77,8 +77,8 @@ void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
 void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max,
     const aiMatrix4x4& m)
 {
-    min = aiVector3D (10e10,  10e10, 10e10);
-    max = aiVector3D (-10e10,-10e10,-10e10);
+    min = aiVector3D ( ai_real( 10e10 ), ai_real( 10e10 ), ai_real( 10e10 ) );
+    max = aiVector3D ( ai_real( -10e10 ), ai_real( -10e10 ), ai_real( -10e10 ) );
     for (unsigned int i = 0;i < mesh->mNumVertices;++i)
     {
         const aiVector3D v = m * mesh->mVertices[i];
@@ -144,7 +144,7 @@ void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,
 // -------------------------------------------------------------------------------
 ai_real ComputePositionEpsilon(const aiMesh* pMesh)
 {
-    const ai_real epsilon = 1e-4;
+    const ai_real epsilon = ai_real( 1e-4 );
 
     // calculate the position bounds so we have a reliable epsilon to check position differences against
     aiVector3D minVec, maxVec;
@@ -157,7 +157,7 @@ ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num)
 {
     ai_assert( NULL != pMeshes );
 
-    const ai_real epsilon = 1e-4;
+    const ai_real epsilon = ai_real( 1e-4 );
 
     // calculate the position bounds so we have a reliable epsilon to check position differences against
     aiVector3D minVec, maxVec, mi, ma;

+ 5 - 3
code/RemoveRedundantMaterials.cpp

@@ -177,12 +177,14 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
                     continue;
                 }
 
-                // generate new names for all modified materials
+                // generate new names for modified materials that had no names
                 const unsigned int idx = aiMappingTable[p];
                 if (ppcMaterials[idx]) {
                     aiString sz;
-                    sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
-                    ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
+                    if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) {
+                        sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p);
+                        ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
+                    }
                 } else {
                     ppcMaterials[idx] = pScene->mMaterials[p];
                 }

+ 1 - 1
code/SIBImporter.cpp

@@ -709,7 +709,7 @@ static void ReadLightInfo(aiLight* light, StreamReaderLE* stream)
     // 99% and 1% percentiles.
     //    OpenGL: I = cos(angle)^E
     //   Solving: angle = acos(I^(1/E))
-    ai_real E = 1.0 / std::max(spotExponent, (ai_real)0.00001);
+    ai_real E = ai_real( 1.0 ) / std::max(spotExponent, (ai_real)0.00001);
     ai_real inner = std::acos(std::pow((ai_real)0.99, E));
     ai_real outer = std::acos(std::pow((ai_real)0.01, E));
 

+ 16 - 15
code/STLLoader.cpp

@@ -168,8 +168,7 @@ void addFacesToMesh(aiMesh* pMesh)
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void STLImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
+void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
 {
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
 
@@ -189,7 +188,7 @@ void STLImporter::InternReadFile( const std::string& pFile,
     this->mBuffer = &mBuffer2[0];
 
     // the default vertex color is light gray.
-    clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = 0.6;
+    clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = (ai_real) 0.6;
 
     // allocate a single node
     pScene->mRootNode = new aiNode();
@@ -217,13 +216,13 @@ void STLImporter::InternReadFile( const std::string& pFile,
     s.Set(AI_DEFAULT_MATERIAL_NAME);
     pcMat->AddProperty(&s, AI_MATKEY_NAME);
 
-    aiColor4D clrDiffuse(0.6,0.6,0.6,1.0);
+    aiColor4D clrDiffuse(ai_real(0.6),ai_real(0.6),ai_real(0.6),ai_real(1.0));
     if (bMatClr) {
         clrDiffuse = clrColorDefault;
     }
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
-    clrDiffuse = aiColor4D(0.05,0.05,0.05,1.0);
+    clrDiffuse = aiColor4D( ai_real( 0.05), ai_real( 0.05), ai_real( 0.05), ai_real( 1.0));
     pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
 
     pScene->mNumMaterials = 1;
@@ -416,10 +415,11 @@ bool STLImporter::LoadBinaryFile()
             // read the default vertex color for facets
             bIsMaterialise = true;
             DefaultLogger::get()->info("STL: Taking code path for Materialise files");
-            clrColorDefault.r = (*sz2++) / 255.0;
-            clrColorDefault.g = (*sz2++) / 255.0;
-            clrColorDefault.b = (*sz2++) / 255.0;
-            clrColorDefault.a = (*sz2++) / 255.0;
+            const ai_real invByte = (ai_real)1.0 / ( ai_real )255.0;
+            clrColorDefault.r = (*sz2++) * invByte;
+            clrColorDefault.g = (*sz2++) * invByte;
+            clrColorDefault.b = (*sz2++) * invByte;
+            clrColorDefault.a = (*sz2++) * invByte;
             break;
         }
     }
@@ -481,17 +481,18 @@ bool STLImporter::LoadBinaryFile()
             }
             aiColor4D* clr = &pMesh->mColors[0][i*3];
             clr->a = 1.0;
+            const ai_real invVal( (ai_real)1.0 / ( ai_real )31.0 );
             if (bIsMaterialise) // this is reversed
             {
-                clr->r = (color & 0x31u) / 31.0;
-                clr->g = ((color & (0x31u<<5))>>5u) / 31.0;
-                clr->b = ((color & (0x31u<<10))>>10u) / 31.0;
+                clr->r = (color & 0x31u) *invVal;
+                clr->g = ((color & (0x31u<<5))>>5u) *invVal;
+                clr->b = ((color & (0x31u<<10))>>10u) *invVal;
             }
             else
             {
-                clr->b = (color & 0x31u) / 31.0;
-                clr->g = ((color & (0x31u<<5))>>5u) / 31.0;
-                clr->r = ((color & (0x31u<<10))>>10u) / 31.0;
+                clr->b = (color & 0x31u) *invVal;
+                clr->g = ((color & (0x31u<<5))>>5u) *invVal;
+                clr->r = ((color & (0x31u<<10))>>10u) *invVal;
             }
             // assign the color to all vertices of the face
             *(clr+1) = *clr;

+ 1 - 1
code/SceneCombiner.cpp

@@ -740,7 +740,7 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator
         aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights];
 
         // And copy the final weights - adjust the vertex IDs by the
-        // face index offset of the coresponding mesh.
+        // face index offset of the corresponding mesh.
         for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)  {
             aiBone* pip = (*wmit).first;
             for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) {

+ 6 - 6
code/ScenePreprocessor.cpp

@@ -176,22 +176,22 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim)
         if (anim->mDuration == -1.) {
 
             // Position keys
-            for (unsigned int i = 0; i < channel->mNumPositionKeys;++i) {
-                aiVectorKey& key = channel->mPositionKeys[i];
+            for (unsigned int j = 0; j < channel->mNumPositionKeys;++j) {
+                aiVectorKey& key = channel->mPositionKeys[j];
                 first = std::min (first, key.mTime);
                 last  = std::max (last,  key.mTime);
             }
 
             // Scaling keys
-            for (unsigned int i = 0; i < channel->mNumScalingKeys;++i)  {
-                aiVectorKey& key = channel->mScalingKeys[i];
+            for (unsigned int j = 0; j < channel->mNumScalingKeys;++j )  {
+                aiVectorKey& key = channel->mScalingKeys[j];
                 first = std::min (first, key.mTime);
                 last  = std::max (last,  key.mTime);
             }
 
             // Rotation keys
-            for (unsigned int i = 0; i < channel->mNumRotationKeys;++i) {
-                aiQuatKey& key = channel->mRotationKeys[i];
+            for (unsigned int j = 0; j < channel->mNumRotationKeys;++j ) {
+                aiQuatKey& key = channel->mRotationKeys[ j ];
                 first = std::min (first, key.mTime);
                 last  = std::max (last,  key.mTime);
             }

+ 1 - 1
code/SkeletonMeshBuilder.cpp

@@ -132,7 +132,7 @@ void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode)
     {
         // if the node has no children, it's an end node. Put a little knob there instead
         aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4);
-        ai_real sizeEstimate = ownpos.Length() * 0.18;
+        ai_real sizeEstimate = ownpos.Length() * ai_real( 0.18 );
 
         mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0));
         mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0));

+ 13 - 12
code/StandardShapes.cpp

@@ -193,8 +193,8 @@ unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& positions)
 {
     positions.reserve(positions.size()+60);
 
-    const ai_real t = (1.0 + 2.236067977)/2.0;
-    const ai_real s = std::sqrt(1.0 + t*t);
+    const ai_real t = ( ai_real( 1.0 )+ ai_real( 2.236067977 ) ) / ai_real( 2.0 );
+    const ai_real s = std::sqrt(ai_real(1.0) + t*t);
 
     const aiVector3D v0  = aiVector3D(t,1.0, 0.0)/s;
     const aiVector3D v1  = aiVector3D(-t,1.0, 0.0)/s;
@@ -243,9 +243,9 @@ unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D>& positions
 {
     positions.reserve(positions.size()+108);
 
-    const ai_real a = 1.0 / 1.7320508;
-    const ai_real b = std::sqrt((3.0-2.23606797f)/6.0);
-    const ai_real c = std::sqrt((3.0+2.23606797f)/6.0);
+    const ai_real a = ai_real( 1.0 ) / ai_real(1.7320508);
+    const ai_real b = std::sqrt(( ai_real( 3.0 )- ai_real( 2.23606797))/ ai_real( 6.0) );
+    const ai_real c = std::sqrt(( ai_real( 3.0 )+ ai_real( 2.23606797f))/ ai_real( 6.0) );
 
     const aiVector3D v0  = aiVector3D(a,a,a);
     const aiVector3D v1  = aiVector3D(a,a,-a);
@@ -315,13 +315,14 @@ unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D>& positions)
 {
     positions.reserve(positions.size()+9);
 
-    const ai_real a = 1.41421/3.0;
-    const ai_real b = 2.4494/3.0;
+    const ai_real invThree = ai_real( 1.0 ) / ai_real( 3.0 );
+    const ai_real a = ai_real( 1.41421 ) * invThree;
+    const ai_real b = ai_real( 2.4494 ) * invThree;
 
     const aiVector3D v0  = aiVector3D(0.0,0.0,1.0);
-    const aiVector3D v1  = aiVector3D(2*a,0,-1.0/3.0);
-    const aiVector3D v2  = aiVector3D(-a,b,-1.0/3.0);
-    const aiVector3D v3  = aiVector3D(-a,-b,-1.0/3.0);
+    const aiVector3D v1  = aiVector3D(2*a,0,-invThree );
+    const aiVector3D v2  = aiVector3D(-a,b,-invThree );
+    const aiVector3D v3  = aiVector3D(-a,-b,-invThree );
 
     ADD_TRIANGLE(v0,v1,v2);
     ADD_TRIANGLE(v0,v2,v3);
@@ -336,7 +337,7 @@ unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions,
     bool polygons /*= false*/)
 {
     positions.reserve(positions.size()+36);
-    const ai_real length = 1.0/1.73205080;
+    const ai_real length = ai_real(1.0)/ai_real(1.73205080);
 
     const aiVector3D v0  = aiVector3D(-1.0,-1.0,-1.0)*length;
     const aiVector3D v1  = aiVector3D(1.0,-1.0,-1.0)*length;
@@ -395,7 +396,7 @@ void StandardShapes::MakeCone(ai_real height,ai_real radius1,
     radius1 = std::fabs(radius1);
     radius2 = std::fabs(radius2);
 
-    ai_real halfHeight = height / 2.0;
+    ai_real halfHeight = height / ai_real(2.0);
 
     // radius1 is always the smaller one
     if (radius2 > radius1)

+ 2 - 2
code/glTFExporter.cpp

@@ -447,7 +447,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref<Mesh>& meshRef, Ref<Buffer
 
         unsigned int jointNamesIndex;
         bool addJointToJointNames = true;
-        for (int idx_joint = 0; idx_joint < skinRef->jointNames.size(); ++idx_joint) {
+        for ( unsigned int idx_joint = 0; idx_joint < skinRef->jointNames.size(); ++idx_joint) {
             if (skinRef->jointNames[idx_joint]->jointName.compare(nodeRef->jointName) == 0) {
                 addJointToJointNames = false;
                 jointNamesIndex = idx_joint;
@@ -732,7 +732,7 @@ void glTFExporter::ExportMeshes()
     // Create the Accessor for skinRef->inverseBindMatrices
     if (createSkin) {
         mat4* invBindMatrixData = new mat4[inverseBindMatricesData.size()];
-        for (int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) {
+        for ( unsigned int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) {
             CopyValue(inverseBindMatricesData[idx_joint], invBindMatrixData[idx_joint]);
         }
 

+ 1 - 1
contrib/Open3DGC/o3dgcCommon.h

@@ -376,7 +376,7 @@ namespace o3dgc
 
         if (quantMode == O3DGC_SC3DMC_DIAG_BB)
         {
-            Real diag = 0.0;
+            Real diag = Real( 0.0 );
             Real r;
             for(unsigned long d = 0; d < dim; ++d)
             {

+ 2 - 2
contrib/Open3DGC/o3dgcTimer.h

@@ -26,7 +26,7 @@ THE SOFTWARE.
 
 #include "o3dgcCommon.h"
 
-#ifdef WIN32
+#ifdef _WIN32
 /* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */
 #define NOMINMAX
 #include <windows.h>
@@ -42,7 +42,7 @@ THE SOFTWARE.
 
 namespace o3dgc
 {
-#ifdef WIN32
+#ifdef _WIN32
     class Timer
     {
     public: 

+ 0 - 3
include/assimp/Compiler/pushpack1.h

@@ -36,11 +36,8 @@
 #endif
 
 #if defined(_MSC_VER)
-
 // C4103: Packing was changed after the inclusion of the header, probably missing #pragma pop
 #	pragma warning (disable : 4103) 
 #endif
 
 #define AI_PUSHPACK_IS_DEFINED
-
-

+ 1 - 1
include/assimp/cimport.h

@@ -337,7 +337,7 @@ ASSIMP_API void aiReleaseImport(
  * import process. NULL if there was no error. There can't be an error if you
  * got a non-NULL #aiScene from #aiImportFile/#aiImportFileEx/#aiApplyPostProcessing.
  */
-ASSIMP_API const char* aiGetErrorString();
+ASSIMP_API const char* aiGetErrorString(void);
 
 // --------------------------------------------------------------------------------
 /** Returns whether a given file extension is supported by ASSIMP

+ 1 - 9
include/assimp/metadata.h

@@ -92,14 +92,10 @@ struct aiMetadataEntry
     void* mData;
 };
 
-
-
 #ifdef __cplusplus
 
 #include <string>
 
-
-
 // -------------------------------------------------------------------------------
 /**
   * Helper functions to get the aiType enum entry for a type
@@ -113,11 +109,7 @@ inline aiMetadataType GetAiType( double ) { return AI_DOUBLE; }
 inline aiMetadataType GetAiType( aiString ) { return AI_AISTRING; }
 inline aiMetadataType GetAiType( aiVector3D ) { return AI_AIVECTOR3D; }
 
-
-
-#endif
-
-
+#endif // __cplusplus
 
 // -------------------------------------------------------------------------------
 /**

+ 10 - 7
include/assimp/types.h

@@ -176,11 +176,7 @@ struct aiColor3D
     /** Component-wise comparison */
     // TODO: add epsilon?
     bool operator < (const aiColor3D& other) const {
-        return r < other.r || (
-            r == other.r && (g < other.g ||
-                (g == other.g && b < other.b)
-            )
-        );
+        return r < other.r || ( r == other.r && (g < other.g || (g == other.g && b < other.b ) ) );
     }
 
     /** Component-wise addition */
@@ -210,7 +206,14 @@ struct aiColor3D
 
     /** Access a specific color component */
     ai_real& operator[](unsigned int i) {
-        return *(&r + i);
+        if ( 0 == i ) {
+            return r;
+        } else if ( 1 == i ) {
+            return g;
+        } else if ( 2 == i ) {
+            return b;
+        }
+        return r;
     }
 
     /** Check whether a color is black */
@@ -223,7 +226,7 @@ struct aiColor3D
 
     //! Red, green and blue color values
     ai_real r, g, b;
-} PACK_STRUCT;  // !struct aiColor3D
+} /*PACK_STRUCT*/;  // !struct aiColor3D
 #include "./Compiler/poppack1.h"
 
 // ----------------------------------------------------------------------------------

+ 4 - 0
test/CMakeLists.txt

@@ -55,7 +55,9 @@ SOURCE_GROUP( unit FILES
 )
 
 SET( TEST_SRCS
+  unit/TestIOSystem.h
   unit/AssimpAPITest.cpp
+  unit/utBatchLoader.cpp
   unit/utBlenderIntermediate.cpp
   unit/utBlendImportAreaLight.cpp
   unit/utBlendImportMaterials.cpp
@@ -70,6 +72,7 @@ SET( TEST_SRCS
   unit/utImporter.cpp
   unit/utImproveCacheLocality.cpp
   unit/utIOSystem.cpp
+  unit/utIOStreamBuffer.cpp
   unit/utIssues.cpp
   unit/utJoinVertices.cpp
   unit/utLimitBoneWeights.cpp
@@ -91,6 +94,7 @@ SET( TEST_SRCS
   unit/utTargetAnimation.cpp
   unit/utTextureTransform.cpp
   unit/utTriangulate.cpp
+  unit/utTypes.cpp
   unit/utVertexTriangleAdjacency.cpp
   unit/utVersion.cpp
 )

+ 62 - 0
test/unit/TestIOStream.h

@@ -0,0 +1,62 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2016, 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.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#include "DefaultIOStream.h"
+
+using namespace ::Assimp;
+
+class TestDefaultIOStream : public DefaultIOStream {
+public:
+    TestDefaultIOStream()
+        : DefaultIOStream() {
+        // empty
+    }
+
+    TestDefaultIOStream( FILE* pFile, const std::string &strFilename )
+    : DefaultIOStream( pFile, strFilename ) {
+        // empty
+    }
+
+    virtual ~TestDefaultIOStream() {
+        // empty
+    }
+};
+

+ 29 - 0
test/unit/TestIOSystem.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "UnitTestPCH.h"
+
+#include <assimp/IOSystem.hpp>
+
+using namespace std;
+using namespace Assimp;
+
+static const string Sep = "/";
+class TestIOSystem : public IOSystem {
+public:
+    TestIOSystem() : IOSystem() {}
+    virtual ~TestIOSystem() {}
+    virtual bool Exists( const char* ) const {
+        return true;
+    }
+    virtual char getOsSeparator() const {
+        return Sep[ 0 ];
+    }
+
+    virtual IOStream* Open( const char* pFile, const char* pMode = "rb" ) {
+        return NULL;
+    }
+
+    virtual void Close( IOStream* pFile ) {
+        // empty
+    }
+};

+ 78 - 0
test/unit/utBatchLoader.cpp

@@ -0,0 +1,78 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "Importer.h"
+#include "TestIOSystem.h"
+
+using namespace ::Assimp;
+
+class BatchLoaderTest : public ::testing::Test {
+public:
+    virtual void SetUp() {
+        m_io = new TestIOSystem();
+    }
+
+    virtual void TearDown() {
+        delete m_io;
+    }
+
+protected:
+    TestIOSystem* m_io;
+};
+
+TEST_F( BatchLoaderTest, createTest ) {
+    bool ok( true );
+    try {
+        BatchLoader loader( m_io );
+    } catch ( ... ) {
+        ok = false;
+    }
+}
+
+TEST_F( BatchLoaderTest, validateAccessTest ) {
+    BatchLoader loader1( m_io );
+    EXPECT_FALSE( loader1.getValidation() );
+    loader1.setValidation( true );
+    EXPECT_TRUE( loader1.getValidation() );
+
+    BatchLoader loader2( m_io, true );
+    EXPECT_TRUE( loader2.getValidation() );
+}

+ 1 - 18
test/unit/utDefaultIOStream.cpp

@@ -37,7 +37,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -------------------------------------------------------------------------*/
 #include <gtest/gtest.h>
-#include "DefaultIOStream.h"
+#include "TestIOStream.h"
 
 using namespace ::Assimp;
 
@@ -45,23 +45,6 @@ class utDefaultIOStream : public ::testing::Test {
     // empty
 };
 
-class TestDefaultIOStream : public DefaultIOStream {
-public:
-    TestDefaultIOStream()
-    : DefaultIOStream() {
-        // empty
-    }
-
-    TestDefaultIOStream( FILE* pFile, const std::string &strFilename )
-    : DefaultIOStream( pFile, strFilename ) {
-        // empty
-    }
-
-    virtual ~TestDefaultIOStream() {
-        // empty
-    }
-};
-
 TEST_F( utDefaultIOStream, FileSizeTest ) {
     char buffer[ L_tmpnam ];
     tmpnam( buffer );

+ 112 - 0
test/unit/utIOStreamBuffer.cpp

@@ -0,0 +1,112 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#include "UnitTestPCH.h"
+#include "IOStreamBuffer.h"
+#include "TestIOStream.h"
+
+class IOStreamBufferTest : public ::testing::Test {
+    // empty
+};
+
+using namespace Assimp;
+
+TEST_F( IOStreamBufferTest, creationTest ) {
+    bool ok( true );
+    try {
+        IOStreamBuffer<char> myBuffer;
+    } catch ( ... ) {
+        ok = false;
+    }
+    EXPECT_TRUE( ok );
+}
+
+TEST_F( IOStreamBufferTest, accessCacheSizeTest ) {
+    IOStreamBuffer<char> myBuffer1;
+    EXPECT_NE( 0, myBuffer1.cacheSize() );
+
+    IOStreamBuffer<char> myBuffer2( 100 );
+    EXPECT_EQ( 100, myBuffer2.cacheSize() );
+}
+
+TEST_F( IOStreamBufferTest, open_close_Test ) {
+    IOStreamBuffer<char> myBuffer;
+
+    EXPECT_FALSE( myBuffer.open( nullptr ) );
+    EXPECT_FALSE( myBuffer.close() );
+
+    char buffer[ L_tmpnam ];
+    tmpnam( buffer );
+    std::FILE *fs( std::fopen( buffer, "w+" ) );
+    size_t written( std::fwrite( buffer, 1, sizeof( char ) * L_tmpnam, fs ) );
+    std::fflush( fs );
+
+    TestDefaultIOStream myStream( fs, buffer );
+
+    EXPECT_TRUE( myBuffer.open( &myStream ) );
+    EXPECT_FALSE( myBuffer.open( &myStream ) );
+    EXPECT_TRUE( myBuffer.close() );
+}
+
+TEST_F( IOStreamBufferTest, readlineTest ) {
+    char buffer[ L_tmpnam ];
+    tmpnam( buffer );
+    std::FILE *fs( std::fopen( buffer, "w+" ) );
+    size_t written( std::fwrite( buffer, 1, sizeof( char ) * L_tmpnam, fs ) );
+    std::fflush( fs );
+
+    IOStreamBuffer<char> myBuffer( 26 );
+    EXPECT_EQ( 26, myBuffer.cacheSize() );
+
+    TestDefaultIOStream myStream( fs, buffer );
+    size_t size( myStream.FileSize() );
+    size_t numBlocks( size / myBuffer.cacheSize() );
+    if ( size % myBuffer.cacheSize() > 0 ) {
+        numBlocks++;
+    }
+    EXPECT_TRUE( myBuffer.open( &myStream ) );
+    EXPECT_EQ( numBlocks, myBuffer.getNumBlocks() );
+    EXPECT_TRUE( myBuffer.close() );
+}
+
+TEST_F( IOStreamBufferTest, accessBlockIndexTest ) {
+
+}

+ 7 - 22
test/unit/utIOSystem.cpp

@@ -39,37 +39,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 #include "UnitTestPCH.h"
+#include "TestIOSystem.h"
 
 #include <assimp/IOSystem.hpp>
 
 using namespace std;
 using namespace Assimp;
 
-static const string Sep = "/";
-class TestIOSystem : public IOSystem {
+class IOSystemTest : public ::testing::Test {
 public:
-    TestIOSystem() : IOSystem() {}
-    virtual ~TestIOSystem() {}
-    virtual bool Exists( const char* ) const {
-        return true;
-    }
-    virtual char getOsSeparator() const {
-        return Sep[ 0 ];
+    virtual void SetUp() { 
+        pImp = new TestIOSystem(); 
     }
-
-    virtual IOStream* Open(const char* pFile, const char* pMode = "rb") {
-        return NULL;
-    }
-
-    virtual void Close( IOStream* pFile) {
-        // empty
+    
+    virtual void TearDown() { 
+        delete pImp; 
     }
-};
-
-class IOSystemTest : public ::testing::Test {
-public:
-    virtual void SetUp() { pImp = new TestIOSystem(); }
-    virtual void TearDown() { delete pImp; }
 
 protected:
     TestIOSystem* pImp;

+ 2 - 0
test/unit/utImporter.cpp

@@ -270,3 +270,5 @@ TEST_F(ImporterTest, testMultipleReads)
     EXPECT_TRUE(pImp->ReadFile(ASSIMP_TEST_MODELS_DIR "/X/BCN_Epileptic.X",flags));
     //EXPECT_TRUE(pImp->ReadFile(ASSIMP_TEST_MODELS_DIR "/X/dwarf.x",flags)); # is in nonbsd
 }
+
+// ------------------------------------------------------------------------------------------------

+ 19 - 34
test/unit/utTriangulate.cpp

@@ -47,21 +47,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace std;
 using namespace Assimp;
 
-class TriangulateProcessTest : public ::testing::Test
-{
+class TriangulateProcessTest : public ::testing::Test {
 public:
-
     virtual void SetUp();
     virtual void TearDown();
 
 protected:
-
     aiMesh* pcMesh;
     TriangulateProcess* piProcess;
 };
 
-void TriangulateProcessTest::SetUp()
-{
+void TriangulateProcessTest::SetUp() {
     piProcess = new TriangulateProcess();
     pcMesh = new aiMesh();
 
@@ -72,24 +68,21 @@ void TriangulateProcessTest::SetUp()
     pcMesh->mPrimitiveTypes = aiPrimitiveType_POINT | aiPrimitiveType_LINE |
     aiPrimitiveType_LINE | aiPrimitiveType_POLYGON;
 
-    for (unsigned int m = 0, t = 0, q = 4; m < 1000; ++m)
-    {
+    for (unsigned int m = 0, t = 0, q = 4; m < 1000; ++m) {
         ++t;
         aiFace& face = pcMesh->mFaces[m];
         face.mNumIndices = t;
-        if (4 == t)
-        {
+        if (4 == t) {
             face.mNumIndices = q++;
             t = 0;
 
             if (10 == q)q = 4;
         }
         face.mIndices = new unsigned int[face.mNumIndices];
-        for (unsigned int p = 0; p < face.mNumIndices; ++p)
-        {
-            face.mIndices[p] = pcMesh->mNumVertices;
+        for (unsigned int p = 0; p < face.mNumIndices; ++p) {
+            face.mIndices[ p ] = pcMesh->mNumVertices;
 
-        // construct fully convex input data in ccw winding, xy plane
+            // construct fully convex input data in ccw winding, xy plane
             aiVector3D& v = pcMesh->mVertices[pcMesh->mNumVertices++];
             v.z = 0.f;
             v.x = cos (p * (float)(AI_MATH_TWO_PI)/face.mNumIndices);
@@ -98,51 +91,43 @@ void TriangulateProcessTest::SetUp()
     }
 }
 
-void TriangulateProcessTest::TearDown()
-{
+void TriangulateProcessTest::TearDown() {
     delete piProcess;
     delete pcMesh;
 }
 
-TEST_F(TriangulateProcessTest, testTriangulation)
-{
+TEST_F(TriangulateProcessTest, testTriangulation) {
     piProcess->TriangulateMesh(pcMesh);
 
-    for (unsigned int m = 0, t = 0, q = 4, max = 1000, idx = 0; m < max;++m)
-    {
+    for (unsigned int m = 0, t = 0, q = 4, max = 1000, idx = 0; m < max;++m) {
         ++t;
         aiFace& face = pcMesh->mFaces[m];
-        if (4 == t)
-        {
+        if (4 == t) {
             t = 0;
             max += q-3;
 
             std::vector<bool> ait(q,false);
 
-            for (unsigned int i = 0, tt = q-2; i < tt; ++i,++m)
-            {
+            for (unsigned int i = 0, tt = q-2; i < tt; ++i,++m) {
                 aiFace& face = pcMesh->mFaces[m];
                 EXPECT_EQ(3U, face.mNumIndices);
 
-                for (unsigned int qqq = 0; qqq < face.mNumIndices; ++qqq)
-                {
+                for (unsigned int qqq = 0; qqq < face.mNumIndices; ++qqq) {
                     ait[face.mIndices[qqq]-idx] = true;
                 }
             }
-            for (std::vector<bool>::const_iterator it = ait.begin(); it != ait.end(); ++it)
-            {
+            for (std::vector<bool>::const_iterator it = ait.begin(); it != ait.end(); ++it) {
                 EXPECT_TRUE(*it);
             }
             --m;
             idx+=q;
-            if(++q == 10)q = 4;
-        }
-        else
-        {
+            if ( ++q == 10 ) {
+                q = 4;
+            }
+        } else {
             EXPECT_EQ(t, face.mNumIndices);
 
-            for (unsigned int i = 0; i < face.mNumIndices; ++i,++idx)
-            {
+            for (unsigned int i = 0; i < face.mNumIndices; ++i,++idx) {
                 EXPECT_EQ(idx, face.mIndices[i]);
             }
         }

+ 75 - 0
test/unit/utTypes.cpp

@@ -0,0 +1,75 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2016, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+
+#include <assimp/types.h>
+
+using namespace Assimp;
+
+class utTypes : public ::testing::Test {
+    // empty
+};
+
+TEST_F( utTypes, Color3dCpmpareOpTest ) {
+    aiColor3D col1( 1, 2, 3 );
+    aiColor3D col2( 4, 5, 6 );
+    aiColor3D col3( col1 );
+    
+    EXPECT_FALSE( col1 == col2 );
+    EXPECT_FALSE( col2 == col3 );
+    EXPECT_TRUE( col1 == col3 );
+
+    EXPECT_TRUE( col1 != col2 );
+    EXPECT_TRUE( col2 != col3 );
+    EXPECT_FALSE( col1 != col3 );
+}
+
+TEST_F( utTypes, Color3dIndexOpTest ) {
+    aiColor3D col( 1, 2, 3 );
+    const ai_real r = col[ 0 ];
+    EXPECT_FLOAT_EQ( 1, r );
+
+    const ai_real g = col[ 1 ];
+    EXPECT_FLOAT_EQ( 2, g );
+
+    const ai_real b = col[ 2 ];
+    EXPECT_FLOAT_EQ( 3, b );
+}

+ 28 - 22
tools/assimp_qt_viewer/glview.cpp

@@ -325,7 +325,7 @@ void CGLView::ImportTextures(const QString& pScenePath)
 
 void CGLView::BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign)
 {
-aiMatrix4x4 mat_trans = pParent_TransformationMatrix * pNode.mTransformation;
+    aiMatrix4x4 mat_trans = pParent_TransformationMatrix * pNode.mTransformation;
 
 	// Check if node has meshes
 	for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++)
@@ -437,7 +437,7 @@ void CGLView::LogError(const QString& pMessage)
 
 void CGLView::Draw_Node(const aiNode* pNode)
 {
-aiMatrix4x4 mat_node = pNode->mTransformation;
+    aiMatrix4x4 mat_node = pNode->mTransformation;
 
 	// Apply node transformation matrix.
 	mat_node.Transpose();
@@ -516,7 +516,7 @@ void CGLView::Draw_Mesh(const size_t pMesh_Index)
 
 void CGLView::Draw_BBox(const SBBox& pBBox)
 {
-aiVector3D vertex[8];
+    aiVector3D vertex[8];
 
 	BBox_GetVertices(pBBox, vertex);
 	// Draw
@@ -590,9 +590,27 @@ void CGLView::resizeGL(int pWidth, int pHeight)
 	gluPerspective(mCamera_FOVY, mCamera_Viewport_AspectRatio, 1.0, 100000.0);///TODO: znear/zfar depend on scene size.
 }
 
+void CGLView::drawCoordSystem() {
+    glBindTexture(GL_TEXTURE_1D, 0);
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindTexture(GL_TEXTURE_3D, 0);
+    glEnable(GL_COLOR_MATERIAL);
+    glBegin(GL_LINES);
+    // X, -X
+    qglColor(QColor(Qt::red)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(100000.0, 0.0, 0.0);
+    qglColor(QColor(Qt::cyan)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(-100000.0, 0.0, 0.0);
+    // Y, -Y
+    qglColor(QColor(Qt::green)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 100000.0, 0.0);
+    qglColor(QColor(Qt::magenta)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, -100000.0, 0.0);
+    // Z, -Z
+    qglColor(QColor(Qt::blue)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0);
+    qglColor(QColor(Qt::yellow)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0);
+    glEnd();
+}
+
 void CGLView::paintGL()
 {
-QTime time_paintbegin;
+    QTime time_paintbegin;
 
 	time_paintbegin = QTime::currentTime();
 
@@ -604,23 +622,11 @@ QTime time_paintbegin;
 	glTranslatef(-mHelper_Camera.Translation_ToScene.x, -mHelper_Camera.Translation_ToScene.y, -mHelper_Camera.Translation_ToScene.z);
 	glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_Scene);
 	// Coordinate system
-	if(mLightingEnabled) glDisable(GL_LIGHTING);///TODO: display list
+    if ( mLightingEnabled ) {
+        glDisable( GL_LIGHTING );///TODO: display list
+    }
+    drawCoordSystem();
 
-	glBindTexture(GL_TEXTURE_1D, 0);
-	glBindTexture(GL_TEXTURE_2D, 0);
-	glBindTexture(GL_TEXTURE_3D, 0);
-	glEnable(GL_COLOR_MATERIAL);
-	glBegin(GL_LINES);
-		// X, -X
-		qglColor(QColor(Qt::red)),     glVertex3f(0.0, 0.0, 0.0), glVertex3f(100000.0, 0.0, 0.0);
-		qglColor(QColor(Qt::cyan)),    glVertex3f(0.0, 0.0, 0.0), glVertex3f(-100000.0, 0.0, 0.0);
-		// Y, -Y
-		qglColor(QColor(Qt::green)),   glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 100000.0, 0.0);
-		qglColor(QColor(Qt::magenta)), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, -100000.0, 0.0);
-		// Z, -Z
-		qglColor(QColor(Qt::blue)),    glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0);
-		qglColor(QColor(Qt::yellow)),  glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0);
-	glEnd();
 	glDisable(GL_COLOR_MATERIAL);
 	if(mLightingEnabled) glEnable(GL_LIGHTING);
 
@@ -1015,8 +1021,8 @@ void CGLView::Lighting_DisableSource(const size_t pLightNumber)
 
 void CGLView::Camera_Set(const size_t pCameraNumber)
 {
-SHelper_Camera& hcam = mHelper_Camera;// reference with short name for conveniance.
-aiVector3D up;
+    SHelper_Camera& hcam = mHelper_Camera;// reference with short name for conveniance.
+    aiVector3D up;
 
 	if(mCamera_DefaultAdded || (pCameraNumber >= mScene->mNumCameras))// If default camera used then 'pCameraNumber' doesn't matter.
 	{

+ 1 - 1
tools/assimp_qt_viewer/glview.hpp

@@ -253,7 +253,7 @@ private:
 	/********************************************************************/
 
 protected:
-
+    void drawCoordSystem();
 	/// \fn void initializeGL() override
 	/// Overrided function for initialise OpenGL.
 	void initializeGL() override;